스크롤 시 축소되는 헤더는 사용자가 아래로 스크롤할 때 페이지 상단의 고정된 헤더 요소가 더 작은 크기로 부드럽게 전환되는 일반적인 UI 패턴입니다. 이 효과는 필수 탐색 또는 브랜딩 요소에 액세스할 수 있도록 유지하면서 기본 콘텐츠의 화면 공간을 극대화하는 데 자주 사용됩니다. CSS 스크롤 기반 애니메이션을 사용하면 애니메이션을 문서의 스크롤 위치에 연결하여 선언적이고 성능이 우수한 방식으로 이 효과를 얻을 수 있습니다.
구현 방법
스크롤 시 축소되는 헤더를 만드는 방법은 다음과 같습니다.
고정 헤더 만들기: 페이지 상단에 고정되고 높이가 미리 정의된 헤더 요소로 시작합니다.
<header>HEADER</header>header { position: fixed; height: 200px; top: 0; left: 0; right: 0; }축소 애니메이션 정의: 헤더의 높이를 변경하는 CSS 애니메이션을 만듭니다.
@keyframes shrink { to { height: 50px; } }애니메이션 및 스크롤 타임라인 적용: 애니메이션을 헤더에 연결하고
scroll()함수를 사용하여 문서의 스크롤 위치에 연결합니다.header { animation: shrink auto linear both; animation-timeline: scroll(block root); }animation-range설정:animation-range속성을 사용하여 애니메이션이 발생해야 하는 스크롤 거리를 지정합니다. 예를 들어 스크롤의 처음 150픽셀에서 헤더를 축소하려면animation-range: 0px 150px;를 사용합니다.header { animation-range: 0px 150px; }
도움말: 헤더 뒤에 오는 콘텐츠가 헤더에 가려지지 않도록 하려면 헤더의 초기 높이와 동일한 padding-top를 body (또는 기본 콘텐츠 컨테이너)에 추가하세요.
팁: 페이지 콘텐츠가 축소되는 헤더와 동기화되어 스크롤되도록 하려면 animation-range-end를 시작 크기와 종료 크기의 차이로 설정하세요. 이렇게 하면 헤더가 최종 크기에 도달할 때 애니메이션이 정확하게 완료됩니다. 이 데모에서는 헤더가 200px에서 50px로 축소되므로 animation-range-end가 150px로 설정됩니다.
예시 코드
@keyframes shrink {
to {
height: 50px;
}
}
header {
animation: shrink auto linear both;
animation-timeline: scroll(block root);
animation-range: 0px 150px;
}
권장사항
스크롤 기반 애니메이션을 사용할 때는 원활하고 접근성 높은 환경을 보장하기 위해 몇 가지 권장사항을 따르는 것이 중요합니다.
- 권장사항: 기능 감지를 포함합니다. 모든 브라우저가 스크롤 기반 애니메이션을 지원하는 것은 아닙니다.
@supports ((animation-timeline: scroll()) and (animation-range: 0% 100%))를 사용하여 지원 여부를 확인하고 지원하지 않는 브라우저에 대체 기능을 제공합니다.- 일부만 지원하는 브라우저를 필터링하려면 여기에
(animation-range: 0% 100%)검사를 포함해야 합니다(MUST). scroll-timeline-polyfill패키지는 기능이 완전하지 않고 알려진 문제가 많으므로 대체 전략에 사용하지 마세요.- 애니메이션이 장식용으로만 간주되는 경우 점진적 개선을 선택하고 대체 기능을 제공하지 마세요.
- 일부만 지원하는 브라우저를 필터링하려면 여기에
- 권장사항 사용자 환경설정 존중: 일부 사용자는 웹에서 모션이 적은 것을 선호합니다.
prefers-reduced-motion미디어 쿼리를 사용하여 이러한 사용자의 애니메이션을 사용 중지하거나 줄입니다. - 권장사항: 성능이 우수한 CSS 속성에만 애니메이션을 적용하세요. 가장 부드러운 애니메이션을 구현하려면 브라우저의 컴포지터 스레드에서 처리할 수 있는 속성(예:
transform및opacity)에만 애니메이션을 적용하세요.width또는height와 같은 다른 속성에 애니메이션을 적용하면 성능 문제가 발생할 수 있습니다. - 권장사항: 올바른 선언 순서를 사용합니다.
animation약식 속성을 사용하는 경우 약식이 타임라인을 재설정하지 않도록animation-timeline및animation-range를 뒤에 선언합니다.
scroll() 함수를 사용하여 스크롤 기반 애니메이션을 만들 때 다음을 참고하세요.
- 선택사항 스크롤러를 명시적으로 지정: 가장 가까운 상위 스크롤러를 타겟팅하지 않는 경우
scroll(root)또는scroll(self)를 사용하여 사용할 스크롤러를 명시적으로 지정합니다.root,nearest또는self가 충분하지 않은 경우 이름이 지정된 scroll-timeline을 사용합니다.
- 선택사항 추적할 축을 명시적으로 지정: 기본
block축을 타겟팅하지 않는 경우 (예: 가로 스크롤러)scroll(block)또는scroll(inline)를 사용하여 추적할 축을 명시적으로 지정합니다.
이 사용 사례의 경우:
animation-range에서 백분율을 사용할 때 애니메이션을 적용하는 요소는position: static또는position: relative가 아니어야 합니다.- 이러한 요소는 '인플로우'로 간주되기 때문입니다. 스크롤할 때 이러한 요소를 축소하면 총 스크롤 거리가 줄어들어 스크롤에 대한 계산된 값(예:
10%)에 영향을 미칩니다.
- 이러한 요소는 '인플로우'로 간주되기 때문입니다. 스크롤할 때 이러한 요소를 축소하면 총 스크롤 거리가 줄어들어 스크롤에 대한 계산된 값(예:
브라우저 지원 및 대체 전략
따라서 일반적으로 대체 전략이 필요합니다.
스크롤 기반 애니메이션을 지원하지 않는 브라우저의 경우 대체 기능을 사용하여 시각 효과를 다시 만들 수 있습니다. 대체는 일반적으로 스크롤 리스너 (ScrollTimeline 효과의 경우) 또는 IntersectionObserver API (ViewTimeline 효과의 경우)를 사용하여 빌드됩니다.
스크롤 기반 애니메이션을 기본적으로 지원하는 브라우저에서는 항상 네이티브 CSS 구현을 사용하세요. 성능이 더 우수합니다.
대체 접근 방식을 사용하여 모든 효과를 다시 만들 수 있는 것은 아닙니다.
이 사용 사례의 경우 다음 스크립트는 스크롤 기반 애니메이션을 지원하지 않는 브라우저에 대체 기능을 적용합니다. 스크롤 리스너를 사용하여 150px 거리에서 문서의 스크롤 위치를 추적하고 이에 따라 헤더의 높이를 업데이트합니다.
// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: scroll()) and (animation-range: 0% 100%)')) {
const header = document.querySelector('header');
const initialHeight = 200;
const finalHeight = 50;
const scrollDistance = 150;
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
const scrollPercent = Math.min(1, scrollY / scrollDistance);
const newHeight = initialHeight - (initialHeight - finalHeight) * scrollPercent;
header.style.height = `${newHeight}px`;
});
}