원본은 codehouse의 Ink Transition Effect 입니다.
데모 페이지 에서 확인하실 수 있듯, 버튼을 누르면 잉크가 퍼지는 효과와 함께 모달 창이 열립니다.
원본 스크립트에서 jQuery를 제거하고, 자바스크립트에서 처리할 필요 없이 css에서 처리하면 되는 건 css로 옮겨뒀습니다.
깃허브 에서 파일들을 내려받으실 수 있습니다.
Clone or download 버튼을 클릭하셔서 zip 파일을 내려받으시거나
index.html
css>style.css
js>main.vanilla.js
img>모든 파일
정도만 받으셔서 수정하셔도 됩니다.
자바스크립트
document . addEventListener ( " DOMContentLoaded " , () => {
const modalTrigger = document . querySelector ( " .cd-modal-trigger " ) ,
transitionLayer = document . querySelector ( " .cd-transition-layer " ) ,
transitionBackground = transitionLayer . querySelector ( " .bg-layer " ) ,
modalWindow = document . querySelector ( " .cd-modal " ) ;
const frameProportion = 1.70 ,
frames = 25 ;
let resize ;
function setLayerDimensions () {
const windowWidth = window . innerWidth ,
windowHeight = window . innerHeight ,
condition = windowWidth / windowHeight > frameProportion ;
let layerHeight , layerWidth ;
layerWidth = ` ${ condition ? windowWidth : windowHeight * 1.2 * frameProportion } ` ,
layerHeight = ` ${ condition ? layerWidth / frameProportion : windowHeight * 1.2 } ` ,
transitionBackground . style . width = ` ${ layerWidth * frames } px ` ,
transitionBackground . style . height = ` ${ layerHeight } px ` ,
resize = false ;
}
function animationEndHandler () {
const animEnd = () => {
transitionLayer . classList . contains ( " closing " ) && (
transitionLayer . classList . remove ( " closing " , " opening " , " visible " )
)
};
transitionBackground . addEventListener ( " animationend " , animEnd ) ,
transitionBackground . addEventListener ( " webkitAnimationend " , animEnd )
}
setLayerDimensions () ,
animationEndHandler () ,
modalTrigger . addEventListener ( " click " , e => {
const delay = document . querySelector ( " .no-cssanimations " ) ? 0 : 600 ;
e . preventDefault () ,
transitionLayer . classList . add ( " visible " , " opening " ) ;
setTimeout ( () => {
modalWindow . classList . add ( " visible " )
}, delay )
} ) ,
modalWindow . querySelector ( " .modal-close " ) . addEventListener ( " click " , e => {
e . preventDefault () ,
transitionLayer . classList . add ( " closing " ) ,
modalWindow . classList . remove ( " visible " )
} ) ,
window . addEventListener ( " resize " , () => {
resize || (
resize = true ,
( ! window . requestAnimationFrame ) ? setTimeout ( setLayerDimensions , 300 ) : window . requestAnimationFrame ( setLayerDimensions )
)
} )
} ) ;
단순히 원본 스크립트를 vanilla javascript로 작성한 버전입니다. (main.vanilla.js 파일)
위 스크립트에서 setLayerDimension()이 배경 레이어의 크기를 정하는 함순데, 별 거 없이 화면 비 1.7을 기준으로 배경 레이어의 크기만 정하는 간단한 함수입니다.
css의 (min-aspect-ratio), (max-aspect-ratio) 옵션을 이용해 대체할 수 있으니 관련 스크립트는 싹 지우면
document . addEventListener ( " DOMContentLoaded " , () => {
const modalTrigger = document . querySelector ( " .cd-modal-trigger " ) ,
transitionLayer = document . querySelector ( " .cd-transition-layer " ) ,
transitionBackground = transitionLayer . querySelector ( " .bg-layer " ) ,
modalWindow = document . querySelector ( " .cd-modal " ) ;
function animationEndHandler () {
const animEnd = () => {
transitionLayer . classList . contains ( " closing " ) && (
transitionLayer . classList . remove ( " closing " , " opening " , " visible " )
)
};
transitionBackground . addEventListener ( " animationend " , animEnd ) ,
transitionBackground . addEventListener ( " webkitAnimationend " , animEnd )
}
animationEndHandler () ,
modalTrigger . addEventListener ( " click " , e => {
const delay = document . querySelector ( " .no-cssanimations " ) ? 0 : 600 ;
e . preventDefault () ,
transitionLayer . classList . add ( " visible " , " opening " ) ;
setTimeout ( () => {
modalWindow . classList . add ( " visible " )
}, delay )
} ) ,
modalWindow . querySelector ( " .modal-close " ) . addEventListener ( " click " , e => {
e . preventDefault () ,
transitionLayer . classList . add ( " closing " ) ,
modalWindow . classList . remove ( " visible " )
} )
} ) ;
이만큼만 남습니다.
CSS
. cd-transition-layer . bg-layer {
width : 5100 vh ;
height : 120 vh ;
}
@media screen and ( min-aspect-ratio : 17 / 10 ) {
. cd-transition-layer . bg-layer {
width : 2500 vw ;
height : calc ( 100 vw / 1.7 )
}
}
setLayerDimension()을 CSS로 처리하는 방법입니다.
.cd-transition-layer .bg-layer의 width와 height을 위처럼 수정하시고, @media부터 제일 아래까진 복사해서 css 제일 아래에 붙여 넣으시면 됩니다.
잉크 색상 수정 (포토샵)
오른쪽 아래의 fx 버튼을 클릭하시고 색상 오버레이를 클릭하시면 위 화면이 뜹니다.
혼합 모드 표준으로 두시고 원하는 색상으로 변경하시면 잉크의 색상이 변경됩니다.
활용 (페이지 전환 효과에 사용)
예전에 다뤘던 페이지 전환 효과에도 이를 활용할 수 있습니다.
HTML과 CSS는 필요한 부분만 가져오며 일부 수정했고, 자바스크립트는 목적에 맞게 적당히 수정했습니다.
< div class = " cd-transition-layer visible opened color " >
< div class = " bg-layer " ></ div >
</ div >
visible, opened, color 세 class를 추가해 .cd-transition-layer를 복사해왔습니다.
. cd-transition-layer {
position : fixed ;
top : 0 ;
left : 0 ;
height : 100 % ;
width : 100 % ;
opacity : 0 ;
pointer-events : none ;
overflow : hidden ;
z-index : 999999
}
. cd-transition-layer . bg-layer {
position : absolute ;
left : 50 % ;
top : 50 % ;
-webkit-transform : translateY ( -50 % ) translateX ( -2 % );
transform : translateY ( -50 % ) translateX ( -2 % );
width : 5100 vh ;
height : 120 vh ;
background : url ( ink.png주소 ) no-repeat 0 0 ;
background-size : 100 % 100 % ;
}
. cd-transition-layer . color . bg-layer {
background : # 3f2f44
}
. cd-transition-layer . visible {
opacity : 1 ;
}
. cd-transition-layer . opening . bg-layer {
-webkit-animation : cd-sequence 0.8 s steps ( 24 );
animation : cd-sequence 0.8 s steps ( 24 );
-webkit-animation-fill-mode : forwards ;
animation-fill-mode : forwards ;
}
. cd-transition-layer . closing . bg-layer {
-webkit-animation : cd-sequence-reverse 0.8 s steps ( 24 );
animation : cd-sequence-reverse 0.8 s steps ( 24 );
-webkit-animation-fill-mode : forwards ;
animation-fill-mode : forwards ;
}
. cd-transition-layer . opened . bg-layer {
transform : translateY ( -50 % ) translateX ( -98 % )
}
@media screen and ( min-aspect-ratio : 17 / 10 ) {
. cd-transition-layer . bg-layer {
width : 2500 vw ;
height : calc ( 100 vw / 1.7 )
}
}
ink.png의 주소만 변경해주시면 됩니다.
레이어가 열린 상태여야 하니 opened란 class를 추가해 transform을 추가해뒀고, 이미지를 불러오지 않으면 투명한 레이어가 표시되니 이미지가 로딩될 때까지 색상을 표시할 수 있도록 color란 class를 추가해 배경에 이미지 대신 색상이 표시되도록 해뒀습니다.
ink.png의 색상을 수정하셨으면 그 색에 맞게 #3f2f44를 수정하셔야 합니다.
const modalTrigger = document . querySelector ( " .cd-modal-trigger " ) ,
transitionLayer = document . querySelector ( " .cd-transition-layer " ) ,
transitionBackground = transitionLayer . querySelector ( " .bg-layer " ) ,
modalWindow = document . querySelector ( " .cd-modal " ) ;
function pageTransition ( nodeList ) {
nodeList . forEach ( a => {
const href = a . getAttribute ( " href " ) ;
const hash = a . hash || " tmp " ;
href && href [ 0 ] !== " # " && a . target !== " _blank " && a . href !== ` ${ location . protocol } // ${ location . hostname }${ location . pathname }${ hash } ` && (
a . addEventListener ( " click " , e => {
e . preventDefault () ,
setTimeout ( () => {
transitionLayer . classList . contains ( " visible " ) && (
location . href = href
)
}, 800 ) ,
transitionLayer . classList . add ( " visible " , " opening " )
} )
)
} )
}
function inkTransitionInit () {
const animEnd = () => {
transitionLayer . classList . contains ( " closing " ) && (
transitionLayer . classList . remove ( " closing " , " opening " , " visible " , " opened " )
)
};
const bgImg = new Image () ;
bgImg . src = " ink.png주소 " ,
bgImg . onload = () => {
setTimeout ( () => {
transitionLayer . classList . remove ( " color " )
}, 200 ) ,
setTimeout ( () => {
transitionLayer . classList . add ( " closing " )
}, 300 )
},
transitionBackground . addEventListener ( " animationend " , animEnd ) ,
transitionBackground . addEventListener ( " webkitAnimationend " , animEnd )
}
inkTransitionInit () ,
pageTransition ( document . querySelectorAll ( " a " ))
pageTransition 함수는 이 글 에서 설명해뒀습니다.
inkTransitionInit은 앞서 작성했던 스크립트의 animationEndHandler와 .modal-close를 클릭했을 때 작동하던 함수를 가져온 형식입니다.
배경 이미지가 불러진 걸 감지하기 위해 new Image()를 추가했습니다.
다른 상황에 잉크가 지워지도록 하고 싶으시면 transitionLayer.classList.add("closing")을 다른 위치로 옮기시면 됩니다.
ⓒ 2020. Marshall K All rights reserved