CSS Scroll-Snap으로 스냅 스크롤 섹션을 만드는 방법(fullpage.js 대안)

게시 됨: 2022-07-19

이 튜토리얼에서는 사용자가 스크롤할 때 전체 화면 섹션에서 다른 섹션으로 스냅되는 페이지를 만들 것입니다. 이 효과는 fullpage.js 라이브러리에서 대중화되었습니다. 그러나 이제 전체 페이지에 대한 라이선스 변경(이제 비용을 지불해야 함), 새로운 CSS 스크롤 스냅 모듈 및 교차 관찰자 API의 완전한 브라우저 지원으로 인해 더 나은 옵션이 있습니다.

따라서 fullpage.js 대안을 찾고 있다면 전체 라이브러리가 필요하지 않을 수도 있습니다. 직접 코딩하면 됩니다!

사실, 스냅 효과는 100% CSS입니다. JS는 화면이 보기에 "스냅"될 때 요소를 페이드 인하는 데 사용됩니다.

영감을 얻기 위해 CodePen에서 사용할 수 있는 Michelle Barker의 "Dinosaur Park scroll snap demo"를 사용할 것입니다.

https://codepen.io/michellebarker/pen/PowYKXJ CodePen에서 Michelle Barker(@michellebarker)의 Pen Dinosaur Park 스크롤 스냅 데모를 참조하십시오.

"스크롤 스냅" 효과를 완전히 경험하려면 더 큰 화면에서 이것을 보고 싶을 것입니다.

Intersection Observer와 결합된 CSS를 사용하여 페이지의 각 전체 화면 섹션을 스냅 스크롤하고 뷰포트에 들어갈 때 콘텐츠를 페이드 인합니다.

더 좋은 점은 JS 코드가 ~30줄에 불과하다는 것입니다! 애니메이션은 CSS로 수행됩니다. 섹션과 콘텐츠가 JS로 뷰포트에 들어오는 시점을 이해하기만 하면 됩니다.

1) 페이지 구축

먼저 페이지를 빌드하거나 이 간단한 효과와 호환되도록 기존 페이지를 구성해야 합니다. 여기서 주의할 두 가지 사항이 있습니다.

섹션이 포함된 <main> 요소를 사용하고 있습니다. 이 주요 요소는 각각의 <section> 요소와 마찬가지로 100vh입니다.

HTML:

<main> <section class="section section-1"> <div class="section__content" data-content >콘텐츠 내부</div> </section> <section class="section section-2"> <div class= "section__content" data-content >콘텐츠 내부</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">탐색 및 발견</h3 > </header> <div class="section__content" 데이터 콘텐츠 >콘텐츠 내부</div> </section> </main>

CSS:

/* 스크롤 동작 */ @media (min-height: 30em) { main { scroll-snap-type: y 필수; 높이: 100vh; overflow-y: 스크롤; } } .section { 색상: 흰색; 위치: 상대; 스크롤 스냅 정렬: 중앙; 디스플레이: 플렉스; 플렉스 방향: 열; 최소 높이: 100vh; } @media (최소 높이: 30em) { .section { 높이: 100vh; } }

2) CSS로 스냅 구성

이미지-16-11

여기에서 각각 높이가 100vh인 여러 섹션이 있음을 알 수 있습니다.

<main> 요소도 overflow-y:scroll이 있는 100vh입니다.

사용자에게 스크롤 동작은 기본 웹페이지와 동일합니다.

위에서 언급한 CSS를 추가했다면 스냅 효과가 이미 작동하고 있을 것입니다. 작동 방식을 살펴보겠습니다.

먼저 " @media (min-height: 30em) " 쿼리는 높이 측면에서 너무 짧은 모바일 화면 크기에 대한 스냅 효과를 비활성화합니다. 기본 섹션 아래에는 스냅을 활성화하는 속성이 하나 있습니다.

main { .... 스크롤 스냅 유형: y 필수; .... }

이것은 "스크롤 컨테이너가 있는 경우 스냅 포인트가 얼마나 엄격하게 적용되는지 설정하는"(MDN) 멋진 작은 속성입니다.

그런 다음 섹션 아래에 다음이 있습니다.

.section { .... 스크롤 스냅 정렬: 가운데; .... }

이 속성은 "상자의 스냅 위치를 스냅 컨테이너의 스냅포트(정렬 컨테이너) 내에서 스냅 영역(정렬 주제)의 정렬로 지정합니다"(MDN).

여기에서 CSS 스크롤 스냅 모듈에 대해 자세히 알아보세요.

그리고 간단합니다. <main> 컨테이너(모든 섹션) 내의 직계 자식은 <main> 컨테이너의 중앙으로 스크롤됩니다. 메인과 섹션이 모두 100vh이기 때문에 스크롤은 섹션에서 섹션으로 스냅됩니다.

3) 교차로 관찰자를 사용하여 콘텐츠 페이드 인

지금은 전체 페이지 스크롤 효과가 있으며 다른 작업을 수행하지 않으려면 이 섹션을 건너뛰고 웹사이트를 즐길 수 있습니다. 그러나 각 전체 페이지 섹션이 보기에 표시될 때 고유하고 멋진 효과(fullpage.js에서도 가능함)인 콘텐츠를 페이드 인하고 싶습니다.

이를 위해 교차 관찰자를 사용하여 <main> 뷰포트 내 섹션의 위치를 ​​이해합니다.

const 섹션 = [...document.querySelectorAll("섹션")]; let options = { rootMargin: "0px", 임계값: 0.75, }; const 콜백 = (항목, 관찰자) => { 항목.forEach((항목) => { const { 대상 } = 항목; if (entry.intersectionRatio >= 0.75) { target.classList.add("is-visible") ; } else { target.classList.remove("표시됨"); } }); }; const 관찰자 = new IntersectionObserver(콜백, 옵션); section.forEach((섹션, 인덱스) => { const sectionChildren = [...section.querySelector("[데이터 콘텐츠]").children]; sectionChildren.forEach((엘, 인덱스) => { 엘.스타일 .setProperty("--delay", `${색인 * 250}ms`); }); 관찰자.관찰(섹션); });

여기서 두 가지 작업이 수행됩니다. 먼저 섹션이 뷰포트에 있을 때 식별하고, 들어갈 때 CSS 클래스 .is-visible 을 추가합니다. 뷰포트를 떠날 때 해당 클래스를 제거합니다.

또한 이 섹션은 뷰포트에 들어갈 때 연속적으로(순서대로) 각 자식 요소에 대해 250ms 동안 지연 속성을 설정합니다. 이것은 엇갈린 페이드 인 효과를 만듭니다.

data-content 속성이 있는 요소 내의 자식에게만 이 작업을 수행합니다. 따라서 페이드 인 효과를 원하는 경우 페이지 콘텐츠 주변의 래퍼에 이를 추가해야 합니다.

이제 이 작업을 수행하려면 .is-visible 클래스가 추가된 요소에 대해 페이드 인 애니메이션을 설정해야 합니다.

@media (최소 높이: 30em) { .section__content > * { 불투명도: 0; 변환: translate3d(0, 4rem, 0); 전환: 불투명도 800ms var(--delay), 변환 800ms 입방 베지어(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { 불투명도: 1; 변환: translate3d(0, 1rem, 0); } .is-visible .section__img { 불투명도: 0.75; }

처음 데모에서 HTML을 다시 참조하면 .section__content 클래스와 data-content 속성으로 콘텐츠를 감싸는 div가 있음을 알 수 있습니다.

<main> <section class="section section-1"> <div class="section__content" data-content >콘텐츠 내부</div> </section> <section class="section section-2"> <div class= "section__content" data-content >콘텐츠 내부</div> </section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">탐색 및 발견</h3 > </header> <div class="section__content" 데이터 콘텐츠 >콘텐츠 내부</div> </section> </main>

이것은 JS와 CSS를 함께 묶습니다. .is-visible 클래스가 뷰포트에 들어갈 때 교차 관찰자가 추가할 때까지 콘텐츠의 불투명도는 0입니다. 나가면 불투명도 0으로 돌아가므로 스크롤 방향에 관계없이 항상 피드가 적용됩니다.

마지막으로 각 자식 요소에 연속적으로 적용되는 delay 은 페이드 인 효과를 엇갈리게 합니다.

세 번째 섹션에 유의하십시오. 섹션 헤더는 데이터 콘텐츠 섹션 내에 있지 않으므로 페이드 인되지 않습니다(이미 있을 것입니다).

모든 코드

데모는 다음과 같습니다.

등방성-2022-07-15-at-15-00-58

데모에서 사용한 모든 코드는 다음과 같습니다.

HTML

<main> <section class="section section-1"> <div class="section__content" 데이터 콘텐츠> <img class="section__img section__img--left" src="https://s3-us-west-2 .amazonaws.com/s.cdpn.io/85648/trex.svg" alt="T-rex" /> <h2>내부 콘텐츠</h2> <p>ㅋㅋㅋㅋ</p> </div> < /section> <section class="section section-2"> <div class="section__content" data-content> <h2>내부 콘텐츠</h2> <p>ㅋㅋㅋㅋ</p> </div> </ section> <section class="section section-3"> <header class="section__header"> <h3 class="section__title">탐색 및 발견</h3> </header> <div class="section__content" 데이터 콘텐츠 > <h2>내용</h2> <p>ㅋㅋㅋㅋ</p> </div> </section> </main>

CSS

@media (최소 높이: 30em) { main { 스크롤 스냅 유형: y 필수; 높이: 100vh; overflow-y: 스크롤; } } .section { 색상: 흰색; 위치: 상대; 스크롤 스냅 정렬: 중앙; 디스플레이: 플렉스; 플렉스 방향: 열; 최소 높이: 100vh; } @media (최소 높이: 30em) { .section { 높이: 100vh; } } @media (최소 높이: 30em) { .section__content > * { 불투명도: 0; 변환: translate3d(0, 4rem, 0); 전환: 불투명도 800ms var(--delay), 변환 800ms 입방 베지어(0.13, 0.07, 0.26, 0.99) var(--delay); } } .is-visible .section__content > * { 불투명도: 1; 변환: translate3d(0, 1rem, 0); } .is-visible .section__img { 불투명도: 0.75; }

JS

const 섹션 = [...document.querySelectorAll("섹션")]; let options = { rootMargin: "0px", 임계값: 0.75, }; const 콜백 = (항목, 관찰자) => { 항목.forEach((항목) => { const { 대상 } = 항목; if (entry.intersectionRatio >= 0.75) { target.classList.add("is-visible") ; } else { target.classList.remove("표시됨"); } }); }; const 관찰자 = new IntersectionObserver(콜백, 옵션); section.forEach((섹션, 인덱스) => { const sectionChildren = [...section.querySelector("[데이터 콘텐츠]").children]; sectionChildren.forEach((엘, 인덱스) => { 엘.스타일 .setProperty("--delay", `${색인 * 250}ms`); }); 관찰자.관찰(섹션); });

결론

이것은 전체 화면 섹션 사이를 스냅하는 데 그치지 않는 완벽한 fullpage.js 대안입니다. 또한 교차 관찰자 API를 사용하여 섹션이 페이지에 들어오는 시점을 파악한 다음 시차를 둔 애니메이션을 동적으로 적용했습니다. 이 기본 예제를 사용하여 최소한의 바닐라 JS 및 CSS로 멋진 효과를 만들어내고 만들 수 있습니다.