포트폴리오를 만들다가 특정 Section에 CSS 애니메이션이 한번만 동작하도록 코드를 추가했는데 그냥 냅다 애니메이션이 동작하도록 하니까 막상 스크롤을 내려서 해당 Section에 갔을 땐 이미 애니메이션이 끝나있었다.
JS를 이용해서 특정 조건에서 CSS 애니메이션을 다시 동작하도록 하는 방법이 없나 찾아보다가 강제로 재시작 하도록 방법을 발견해냈다!!
.target.effect {
animation: animation 2s;
}
위와 같은 코드로 target
에 effect
라는 className이 추가되면 원하는 animation이 동작하도록 하는 코드가 존재한다고 가정하자.
function restartAnimation () {
const target = ELEMENT;
target.classList.remove("effect");
void target.offsetWidth;
target.classList.add("effect");
}
대충 보면 애니메이션이 적용되는 ELEMENT
에 effect
라는 class를 제거했다가 다시 추가해주는 코드처럼 보인다.
근데 그 사이에 void target.offsetWidth
라는 출처를 알수없는 코드가 한줄 껴있다. (누구세요)
일단 이 코드를 하나하나 살펴보자.
void는 값을 생성하는 표현식을 평가해서 undefined를 반환합니다.
void expression;
출처 MDN
사실 C나 Java를 써본적이 있다면 return 값이 함수를 선언할 때 사용했었다는 것을 기억할 수 있다. 위 설명을 보면 알 수 있듯이 JS에서도 비슷한 맥락으로 쓰인다.
expression
부분을 수행 한 후 undefined
를 반환하는 역할을 한다.
HTMLElement.offsetWidth은 레이아웃의 너비를 반환합니다.
출처 MDN
offsetWidth 메소드는 엘리먼트의 너비를 구할때 사용되며 해당 너비를 리턴한다.
이제 다시 void target.offsetWidth
를 보면 target의 너비를 구해서 undefined를 return 한다는 것을 알 수 있다.
offsetWdith
메소드는 실행될 때 여러가지 연산을 하게 되는데 이때 브라우저가 해당 요소의 정보를 업데이트 한다고 한다.
그냥 class를 제거했다가 추가하는 방법으로는 애니메이션이 재시작 되지 않고 그 사이에 offsetWidth
메소드를 실행하여 브라우저에게 강제로 요소 정보를 업데이트하라고 시킨다.
이 과정에서 연산된 너비값은 필요 없으니 앞에 void
를 붙여주는 것이다.
이 방법은 깔끔하게 애니메이션을 재시작 시킬 수 있다는 장점이 있지만, 브라우저에게 의미없는 일을 강제로 시키기 때문에 만약 이러한 방법을 자주 쓰게 되면 퍼포먼스에 영항을 끼칠 수 있다는 단점이 있다.