안녕하세요! 요즘 프론트엔드 생태계에서 가장 뜨거운 주제 중 하나인 '스크롤 기반 애니메이션(Scroll-driven animations)' 문서를 가져오셨네요!
이전에는 스크롤에 따라 요소가 나타나거나 움직이는 효과를 주려면 반드시 자바스크립트의 scroll 이벤트나 IntersectionObserver를 써야만 했습니다. 하지만 이제는 순수 CSS만으로 이 모든 것을 완벽하게 제어할 수 있게 되었죠. 성능과 개발 경험 면에서 혁명적인 변화입니다.
공식 문서의 모든 내용을 빠짐없이, 제 실무 경험을 담아 알기 쉬운 구어체로 번역해 드릴게요. 자, 시작해봅시다!
사용자가 페이지를 위아래(수직) 또는 좌우(수평)로 스크롤할 때 요소가 애니메이션 되는 것은 매우 흔한 UI 패턴입니다. 이러한 스크롤 기반 애니메이션(scroll-driven animations)은 페이지의 스크롤, 또는 페이지 내부의 넘치는(overflow) 스크롤 컨테이너의 움직임에 직접적으로 반응하여 발생합니다.
CSS 스크롤 기반 애니메이션 (CSS scroll-driven animations) 모듈에 정의된 속성들은 기존의 CSS 애니메이션 (CSS animations) 기능을 확장한 것입니다. 사용자의 스크롤 상호작용(interaction)에 반응하여, @keyframes에 정의된 애니메이션 속성값들을 변화시킬 수 있게 해줍니다.
이 가이드에서는 CSS를 사용하여 스크롤 기반 애니메이션의 타임라인(timelines)과 애니메이션을 생성하는 방법에 대한 전반적인 내용을 다룹니다.
💡 강사의 실무 팁 1
애플(Apple) 웹사이트같이 스크롤을 내릴 때마다 제품이 회전하고 텍스트가 스르륵 나타나는 멋진 효과들 보신 적 있죠? 예전에는 ScrollMagic이나 GSAP 같은 무거운 자바스크립트 라이브러리를 써야 했지만, 이제는 이 문서에 나오는 CSS만으로도 충분히 구현할 수 있습니다!
CSS 스크롤 기반 애니메이션 모듈은 CSS 키프레임 애니메이션을 스크롤 동작과 연결할 수 있게 해주는 속성들을 정의합니다.
자바스크립트 없이도, 시간이 흐름에 따라 진행되는 기본 '문서 타임라인(document timeline)' 대신 '스크롤 기반 타임라인(scroll-based timeline)'을 따라 애니메이션이 진행되도록 설정할 수 있습니다. CSS를 통해 어떤 애니메이션 타임라인을 사용할지 정의할 수 있는데, 여기에는 시간의 흐름이 아니라 스크롤 가능한 요소를 스크롤하는 동작에 따라 요소를 애니메이션 하는 것도 포함됩니다.
CSS 스크롤 기반 애니메이션은 성능이 매우 뛰어납니다. 자바스크립트로 스크롤 기반 애니메이션을 구현하려면 메인 스레드 (main thread)에서 scroll 이벤트 리스너와 IntersectionObserver 객체를 사용해 스크롤포트 (scrollport) 상의 요소들을 추적해야 합니다. 자바스크립트를 사용해 메인 스레드에서 시각적 효과를 렌더링하려고 할 때마다, 메인 스레드를 블로킹(차단)할 위험이 따릅니다. 이는 페이지가 먹통이 되거나 사용자 경험을 해치고, 화면이 끊기는 현상인 쟁크 (jank)를 유발할 수 있습니다.
💡 강사의 실무 팁 2
브라우저는 렌더링 작업을 메인 스레드에서 처리하는데, 자바스크립트 연산이 너무 무거우면 화면을 그리는 작업을 제때 못해서 화면이 버벅거리게 됩니다(Jank). 하지만 CSS 기반 애니메이션은 브라우저가 이걸 별도의 스레드(컴포지터 스레드)에서 GPU를 활용해 처리할 수 있도록 최적화하기 때문에 부드러운 60fps 애니메이션을 훨씬 쉽게 달성할 수 있습니다!
스크롤 기반 애니메이션은 기존의 CSS 애니메이션과 웹 애니메이션 API (Web Animations API)의 기반 위에 구축됩니다. 스크롤 기반 애니메이션을 만들기 전에, 먼저 CSS @keyframes 애니메이션에 대한 이해가 필요합니다. 자세한 내용은 CSS 애니메이션 사용하기 가이드를 참고하세요.
CSS에서 애니메이션은 animation-name 속성 (또는 단축 속성인 animation)을 사용하여 키프레임 애니메이션을 요소에 부착(attach)함으로써 만들어집니다.
기본적으로 애니메이션은 기본 문서 타임라인 위에서 실행됩니다. 시간이 지남에 따라 from 키프레임에서 to 키프레임으로 이동하며, animation-duration 속성에 정의된 시간만큼 지속됩니다. 기본 문서 타임라인에서 실행될 때, 애니메이션은 (예를 들어 animation-play-state가 paused로 설정되거나 요소에서 animation-name이 제거되는 등) 강제로 중단되지 않는 한 끝까지 재생됩니다.
스크롤 기반 애니메이션은 기본 DocumentTimeline에서 실행되지 않는 CSS 애니메이션입니다. 대신, 요소 콘텐츠의 스크롤에 의해 주도되는 스크롤 진행률(scroll-progress) 타임라인이나 뷰 진행률(view-progress) 타임라인 위에서 실행됩니다.
사용자의 스크롤 동작과 @keyframe의 진행 상태 사이에는 직접적인 연결 고리가 생깁니다. 사용자가 위, 아래, 왼쪽, 오른쪽으로 스크롤함에 따라 애니메이션은 키프레임 사이를 앞으로 전진하거나 뒤로 되감기(backward) 됩니다. 스크롤을 멈추면 애니메이션도 멈춥니다. 마치 animation-play-state가 pause로 설정된 것과 똑같죠.
CSS 애니메이션 모듈에 정의된 animation-timeline 속성은 애니메이션에 사용할 타임라인을 설정하는 데 쓰입니다.
CSS 스크롤 기반 애니메이션 모듈은 이 animation-timeline을 스크롤 진행률 타임라인이나 뷰 진행률 타임라인으로 설정할 수 있는 기능들을 제공합니다.
scroll-timeline-*과 view-timeline-* 속성을 사용해 요소를 타임라인 컨트롤러로 명시적으로 지정(이름 짓기)한 다음, 자손 요소의 animation-timeline 속성값으로 그 이름을 설정할 수 있습니다.
또는 scroll() 함수와 view() 함수를 사용하여 익명(이름이 없는) 스크롤 진행률 타임라인과 익명 뷰 진행률 타임라인을 정의할 수도 있습니다.
반대로, animation-timeline 속성을 사용하여 명시적으로 기본 문서 타임라인을 사용하도록 지정하거나, 애니메이션에 타임라인이 없음을 지정하여 아예 애니메이션이 실행되지 않도록 만들 수도 있습니다.
animation-timeline을 명시적으로 auto로 설정하거나, 이 속성을 아예 생략해서 기본값인 auto가 되게 하면 타임라인은 '기본 문서 타임라인(시간 기반)'으로 설정됩니다. 이 기본값 상태에서는 애니메이션의 진행이 animation-duration, animation-delay, 그리고 animation-name 속성을 통해 애니메이션이 요소에 부착된 후 시간이 얼마나 흘렀는지에 따라 결정됩니다. 시간 기반 문서 타임라인은 우리가 전통적으로 알고 있는 CSS 애니메이션의 타임라인입니다.
:checked ~ .container > .item {
animation-name: action;
animation-duration: 3s;
animation-delay: 500ms;
animation-timeline: auto; /* 명시적으로 기본 시간 기반 타임라인 지정 */
}
우리는 action이라는 이름의 회전하는 키프레임 애니메이션을 만들었습니다:
@keyframes action {
from {
rotate: 45deg;
}
to {
rotate: 765deg;
}
}
(체크박스를 통해 요소에 애니메이션을 적용하거나 제거하는 예제 코드입니다.)
<input type="checkbox" id="i" />
<label for="i">
Check to apply the animation. Uncheck to remove the animation
</label>
<div class="container">
<span class="item"></span>
</div>
div {
width: 400px;
height: 100px;
border: 1px solid;
background-color: palegoldenrod;
position: relative;
}
span {
--size: 50px;
height: var(--size);
width: var(--size);
background-color: magenta;
border: 1px solid;
position: absolute;
left: calc(50% - (var(--size) / 2));
top: calc(50% - (var(--size) / 2));
}
체크박스에 체크하면 요소에 action 애니메이션이 적용됩니다. 체크를 해제하면 <div>에서 애니메이션이 제거됩니다.
체크를 하면 처음 0.5초(딜레이 시간) 동안은 아무 일도 일어나지 않습니다. 그런 다음 애니메이션이 시작되면 박스가 즉시 45도 회전한 상태로 점프하고, 그 후 3초에 걸쳐 추가로 720도(두 바퀴)를 회전합니다. 총 3.5초가 지나면 애니메이션이 종료되고 <div>는 회전하지 않은 기본 상태로 되돌아옵니다.
참고 (Note):
animation단축(shorthand) 속성을 사용하면animation-timeline은 자동으로 기본값인auto로 초기화(reset)되어 버립니다. 하지만 단축 속성 안에서 타임라인을 직접 지정할 수는 없습니다. 따라서 스크롤 기반 애니메이션을 만들 때는 항상animation단축 속성을 먼저 선언한 다음, 그 밑에animation-timeline을 따로 선언해야 원하는 효과를 얻을 수 있습니다. (중요!)
스크롤 진행률 타임라인(scroll progress timeline)에서는, 스크롤 가능한 요소(이하 스크롤러(scroller))가 위에서 아래로(또는 왼쪽에서 오른쪽으로) 스크롤되고 다시 돌아오는 과정에 따라 타임라인이 진행됩니다. 기본적으로 스크롤 범위(range) 내의 위치는 진행률 퍼센트(%)로 변환됩니다. 스크롤이 시작되는 지점이 0%이고 끝나는 지점이 100%가 됩니다.
스크롤 진행률 타임라인을 생성하려면, animation-timeline 값이 반드시 스크롤러를 참조해야 합니다. 이때 스크롤러는 이름을 가질 수도 있고 익명일 수도 있습니다.
이름이 지정된 스크롤 진행률 타임라인은 scroll-timeline-name 속성 (또는 단축 속성인 scroll-timeline)을 사용하여 스크롤러의 이름을 명시적으로 지정한 타임라인입니다. 이름은 --로 시작하는 <dashed-ident> 형태여야 합니다. 애니메이션을 적용할 요소의 animation-timeline 속성값으로 이 scroll-timeline-name을 지정하면 두 요소가 연결됩니다.
우리의 HTML에는 3개의 요소가 포함되어 있습니다: 애니메이션 될 item, 스크롤 될 container, 그리고 전체를 감싸는 scroller(main)입니다. container는 부모인 scroller를 넘쳐흐르도록(overflow) 충분히 커야 합니다. 스크롤할 공간이 없다면 스크롤 타임라인도 존재할 수 없으니까요.
<main class="scroller">
<div class="container">
<span class="item"></span>
</div>
</main>
.scroller {
width: 400px;
height: 100px;
overflow: scroll; /* 스크롤바 생성 */
}
.container {
height: 200px; /* 부모보다 커서 스크롤 발생 */
}
조상 요소의 scroll-timeline-name과 일치하는 값을 애니메이션 요소의 animation-timeline에 설정하면 이름이 지정된 스크롤 진행률 타임라인이 생성됩니다. 또한 애니메이션도 포함시켜야 하는데, animation 단축 속성 중 animation-name 값을 앞서 만든 키프레임 애니메이션의 이름(여기서는 action)으로 설정하면 됩니다.
.scroller {
scroll-timeline-name: --rotate; /* 스크롤러에 이름 부여 */
}
.item {
animation: action 1ms linear;
animation-timeline: --rotate; /* 해당 타임라인 이름 참조 */
}
이번에는 체크박스가 없습니다. action 애니메이션의 진행 상황이 넘쳐흐르는 스크롤러의 스크롤에 의해 제어되기 때문입니다. 시간과 달리 스크롤은 '종료(expire)'되지 않습니다.
스크롤이 일어나기 전에는 컨테이너의 위치가 스크롤러의 맨 위에 있고, 애니메이션은 0% 키프레임에 머물러 있습니다. 아래로 스크롤을 시도해 보세요. 스크롤 함에 따라 애니메이션이 타임라인을 통과하며 전진하여 추가로 720도를 회전합니다. 더 이상 스크롤할 수 없는 끝에 다다르면 애니메이션의 진행률은 100%(또는 to) 키프레임에 도달합니다. 애니메이션 된 아이템은 스크롤러를 다시 맨 위로 끌어올리지 않는 이상 기본 회전 상태로 되돌아가지 않습니다.
animation 단축 속성의 지속 시간(animation-duration) 부분이 1ms로 설정된 것을 눈치채셨을 겁니다. CSS 스크롤 기반 애니메이션을 만들 때 animation-duration 값을 지정하는 것은 실제 애니메이션의 지속 시간에 아무런 영향을 주지 않으므로 원래는 불필요합니다.
하지만, 비선형(non-linear) 뷰 진행률 애니메이션 타임라인에서는 지속 시간이 영향을 줄 수 있으며, 특히 파이어폭스(Firefox) 브라우저에서는 요소에 애니메이션을 적용하려면 0이 아닌 animation-duration 값이 반드시 필요합니다. 이러한 이유 때문에 실무에서는 animation-duration을 1ms로 설정하는 것이 일반적인 관행(common practice)이 되었습니다.
💡 강사의 실무 팁 4
이1ms설정은 크로스 브라우징을 위한 일종의 '안전장치(Hack)'라고 생각하시면 됩니다!1ms를 줘도 스크롤에 따라 움직이는 데는 아무 문제가 없고 파이어폭스에서도 잘 작동하게 되죠.
스크롤 진행률 타임라인에 굳이 이름을 지어줄 필요는 없습니다. 대신 익명(이름 없는) 스크롤 진행률 타임라인을 애니메이션과 연결할 수 있습니다.
이 경우, 애니메이션 될 요소의 animation-timeline을 scroll() 함수로 설정합니다. 이 함수는 인자로 넘겨진 옵션에 따라 스크롤 진행률 타임라인을 제공할 스크롤러와 기준 축(axis)을 알아서 찾아냅니다.
첫 번째 매개변수는 애니메이션 요소와 스크롤러 요소의 관계를 정의하는 <scroller> 키워드입니다 (nearest(가장 가까운 조상 스크롤러), root(루트 요소), 또는 self(자기 자신)).
두 번째 매개변수는 스크롤 방향인 <axis> 값입니다 (block(수직), inline(수평), y, 또는 x).
이 예제는 animation-timeline을 scroll() 함수로 설정했다는 점만 빼면 이전 예제와 동일한 CSS를 사용합니다. 스크롤 방향을 바꾸기 위해 컨테이너의 크기도 살짝 수정했습니다:
.item {
animation: action 1ms linear;
animation-timeline: scroll(nearest inline); /* 가장 가까운 조상 중 수평 스크롤러 추적 */
}
.container {
inline-size: 800px; /* 수평(inline) 방향으로 스크롤이 생기도록 부모보다 크게 설정 */
block-size: 100%;
}
이제 요소를 인라인(수평) 방향으로 스크롤해 보세요. 스크롤 함에 따라 아이템이 회전하는 것을 볼 수 있습니다.
스크롤러 내부에서 요소의 가시성(visibility) 변화를 기반으로 애니메이션을 진행시킬 수도 있습니다. 이것은 뷰 진행률 타임라인(view progress timelines)을 통해 이루어집니다.
뷰 진행률 타임라인은 스크롤 컨테이너의 절대적인 스크롤 오프셋(위치)을 추적하는 대신, 스크롤포트 안에서 주체(subject)라고 불리는 특정 요소의 상대적인 위치를 추적합니다. 애니메이션 키프레임의 진행은 스크롤러 안에서 이 주체 요소가 얼마나 보이는가(visibility)에 따라 결정됩니다.
스크롤 진행률 타임라인과는 달리, 뷰 진행률 타임라인에서는 추적할 스크롤러를 임의로 지정할 수 없습니다. 주체 요소의 가시성은 항상 가장 가까운 조상 스크롤러(nearest ancestor scroller) 안에서만 추적됩니다.
뷰 진행률 타임라인 애니메이션은 요소가 스크롤포트(보이는 화면 영역) 안에 들어와 있을 때만 실행됩니다.
추적되는 주체 요소가 화면의 끝자락(block/inline end edge)에 살짝 보이기 시작할 때 타임라인의 진행률은 0%에서 시작합니다. 그리고 요소가 화면을 완전히 빠져나가기 시작하는 반대쪽 끝자락(block/inline start edge)에 닿았을 때 100%가 됩니다.
일반적으로 요소가 뷰포트를 완전히 떠날 때 100%에 도달하기 때문에, 여러분은 요소가 화면 밖으로 사라지기 훨씬 전에 애니메이션의 최종 효과가 완성되기를 바랄 것입니다. 요소가 아직 화면에 보이고 있는 동안 애니메이션이 끝마쳐지도록 하려면, to나 100% 키프레임 대신 20%, 50%, 80% 등의 중간 키프레임 블록에 완성된 상태의 효과를 설정하면 됩니다.
뷰 진행률 타임라인을 사용하면, 요소가 "보인다"고 판단하는 범위(view progress visibility range)를 조절할 수도 있습니다.
view-timeline 단축 속성의 일부인 view-timeline-inset을 사용하면 주체 요소가 화면에 들어왔다고 간주하는 시점을 미세 조정할 수 있습니다. 기본값은 auto입니다. auto가 아닌 값(예: 20%)을 주면 마치 스크롤 포트의 경계선을 옮긴 것과 같은 효과를 냅니다. 양수 값은 경계선을 안쪽으로 조이고(inward), 음수 값은 바깥쪽으로 확장(outward)합니다.
스크롤 진행률 타임라인과 마찬가지로 뷰 진행률 타임라인도 이름을 지정하거나 익명으로 사용할 수 있습니다.
💡 강사의 실무 팁 5: Scroll과 View의 결정적 차이!
scroll()은 단순히 스크롤바가 전체 문서에서 어느 위치에 있냐(퍼센트)에 따라 애니메이션이 도는 것이고,view()는 내가 타겟으로 잡은 DOM 요소가 화면에 들어오고 나갈 때 애니메이션이 도는 것입니다. 스크롤 내릴 때 박스들이 페이드인(Fade-in) 되면서 스르륵 나타나는 효과들 있죠? 그건 전부view()타임라인을 쓴 겁니다!
이름이 지정된 뷰 진행률 타임라인은 view-timeline 단축 속성의 구성요소인 view-timeline-name 속성을 사용해 주체 요소를 명시적으로 이름 지은 것입니다. 이 <dashed-ident> 이름은 애니메이션을 적용할 요소의 animation-timeline 속성값으로 지정되어 서로 연결됩니다.
이름이 지정된 뷰 진행률 타임라인의 강력한 점은, 애니메이션을 실행할 요소와 가시성(보이는 정도)을 추적할 주체 요소가 서로 달라도 된다는 것입니다.
다시 말해, 타임라인을 제어하는 요소와 실제로 춤을 추는(애니메이션 되는) 요소가 달라도 됩니다. 이를 통해 컨테이너 안에서 A 요소가 움직이는 정도를 바탕으로 B 요소를 애니메이션 할 수 있습니다.
아래 예제에서는 view-timeline-name 속성을 사용해 요소 자체를 뷰 진행률 타임라인의 출처(source)로 지정하고 이름을 붙였습니다. 그리고 그 이름을 animation-timeline 속성값으로 설정했습니다.
.item {
animation: action 1ms linear;
view-timeline-name: --a-name; /* 자신을 추적 대상으로 명명 */
animation-timeline: --a-name; /* 그 타임라인을 자신의 애니메이션에 적용 */
}
animation 단축 속성이 animation-timeline을 auto로 리셋시켜버리기 때문에, 애니메이션 타임라인을 항상 animation 선언 뒤에 작성해야 한다는 점을 잊지 마세요.
이번 애니메이션은 이전 예제들과 약간 다르게, 회전 효과가 타임라인의 20% 지점에서 시작해서 80% 지점에서 끝납니다. 이는 요소가 처음 화면에 시야에 들어올 때는 적극적으로 돌지 않다가, 완전히 시야에서 사라지기 전에 회전을 멈춘다는 것을 의미합니다.
@keyframes action {
0%,
20% { /* 화면에 진입하고 20% 지날 때까지는 45도 유지 */
rotate: 45deg;
}
80%,
100% { /* 80% 지점에서 720도 도달 후 화면에서 나갈 때까지 유지 */
rotate: 720deg;
}
}
요소를 스크롤해서 시야에 들어오게 해보세요. 요소가 조상 스크롤러의 보이는 영역(가시 영역)을 통과해 지나갈 때 @keyframes 애니메이션이 실행되는 것을 볼 수 있습니다.
view() 함수 (Anonymous view progress timeline: the view() function)다른 방법으로, animation-timeline 속성의 값으로 view() 함수를 설정하여 해당 요소의 애니메이션 타임라인이 익명 뷰 진행률 타임라인임을 지정할 수 있습니다. 이렇게 하면 요소는 가장 가까운 부모 스크롤러 안에서 자신의 위치(보이는 정도)를 기반으로 애니메이션 됩니다.
view() 함수는 뷰 타임라인을 생성합니다. animation-timeline 속성을 사용해 애니메이션 시키고 싶은 요소에 이 타임라인을 부착하면 됩니다. 이 함수는 선택자에 일치하는 각 요소마다 개별적인 뷰 타임라인을 만듭니다.
아래 예제에서는 역시 animation을 animation-timeline보다 먼저 정의하여 타임라인이 리셋되지 않게 했습니다. 그런 다음 매개변수가 없는 view() 함수를 포함했습니다. 뷰 타임라인의 정의상 주체 요소의 가시성은 항상 '가장 가까운 조상 스크롤러'에 의해 추적되므로 스크롤러를 따로 지정할 필요가 없습니다.
.item {
animation: action 1ms linear;
animation-timeline: view();
}
view() 함수의 매개변수 (Parameters of the view() function)view() 함수는 최대 3개의 선택적 인자(arguments)를 가질 수 있습니다:
<axis> 매개변수. 설정되면, 애니메이션이 진행될 스크롤 축을 지정합니다.auto 키워드 하나, 또는 0개, 1개, 2개의 <length-percentage> inset(안쪽 여백) 값들. 설정되면, 이 값들은 스크롤포트의 시작점과/또는 끝점의 오프셋(보정값)을 지정합니다.그냥 view()라고 선언하는 것은 view(block auto)와 완전히 같습니다. 이는 타임라인을 제공하는 부모 요소의 block(수직) 축을 기준으로 삼고, 애니메이션이 시작하고 끝나는 가시 영역 내의 inset 값을 scroll-padding (보통 기본값 0)으로 정의하겠다는 뜻입니다.
이 함수는 내부적으로 view-timeline-axis와 view-timeline-inset 속성의 값을 설정합니다.
view-timeline-inset 인자는 스크롤포트의 시작과 끝을 조절하는 inset(양수일 때 안쪽으로 좁힘) 또는 outset(음수일 때 바깥쪽으로 넓힘)을 지정합니다. 이 값들은 요소가 "시야에 들어왔다(in view)"고 판단하는 스크롤 위치를 결정하는 데 사용되며, 이는 결과적으로 애니메이션 타임라인의 길이를 결정합니다. 다른 말로 하면, 애니메이션이 스크롤포트의 순수한 시작점과 끝점에서 시작하고 끝나는 것이 아니라, inset으로 조정(축소)된 시야의 시작점과 끝점에서 일어난다는 뜻입니다.
스크롤 타임라인의 scroll() 함수와 달리 view() 함수에는 <scroller> 인자가 없습니다. 왜냐하면 뷰 타임라인은 항상 가장 가까운 조상 스크롤 컨테이너 내에서 주체를 추적하기 때문입니다.
아래 예제에서는 view() 함수 안에서 inset 값(20% 20%)을 사용해 애니메이션 발동 구간을 좁혀주었기 때문에, 키프레임 내부에서 20%, 80%처럼 복잡하게 나눌 필요 없이 깔끔하게 from과 to 키프레임 선택자 (keyframe selectors)를 사용할 수 있습니다.
@keyframes action {
from {
rotate: 45deg;
}
to {
rotate: 720deg;
}
}
.item {
animation: action 1ms linear;
/* 수직(block) 스크롤 기준,
화면 위/아래에서 각각 20% 안쪽으로 들어온 구간에서만 애니메이션 실행 */
animation-timeline: view(block 20% 20%);
}
다른 모든 애니메이션 및 트랜지션과 마찬가지로, 사용자의 prefers-reduced-motion 환경 설정(움직임 줄이기 옵션)을 항상 고려해야 합니다. 화려한 스크롤 애니메이션은 어떤 사용자들에게는 멀미나 어지러움을 유발할 수 있습니다.
animation-timeline: none으로 설정하면, 요소가 기본 시간 기반 문서 타임라인을 포함한 모든 애니메이션 타임라인과의 연결이 끊어집니다. 즉, 요소가 전혀 애니메이션 되지 않습니다. 일부 필수적인 애니메이션은 놔두더라도, 사용자의 prefers-reduced-motion 설정에 따라 불필요한 스크롤 애니메이션은 다음과 같이 제거할 수 있습니다:
@media (prefers-reduced-motion: reduce) {
.optionalAnimations {
animation-timeline: none; /* 애니메이션 무효화 */
}
}
앞서 배웠듯이 animation 단축 속성은 animation-timeline을 auto로 덮어써버립니다. 따라서 미디어 쿼리 안에서 animation-timeline: none을 줄 때는, 여러분의 animation 단축 선언들에 의해 무시되지 않도록 충분한 명시도(specificity)를 가진 선택자를 사용해야 합니다.
MDN 향상에 도움 주기 (Help improve MDN)
요즘 프론트엔드 채용 트렌드에서 '자바스크립트의 부하를 줄이고 CSS의 네이티브 기능을 활용해 렌더링 성능을 최적화할 줄 아는가?'는 아주 중요한 평가 요소입니다. 이 스크롤 기반 애니메이션(Scroll-driven animations) 기술을 포트폴리오 사이트나 책 소개 페이지의 스크롤 인터랙션에 적용해 보세요. 면접관의 눈길을 사로잡는 엄청난 무기가 될 것입니다!