Как сделать привязку разделов прокрутки с помощью CSS Scroll-Snap (альтернатива fullpage.js)

Опубликовано: 2022-07-19

В этом уроке мы собираемся создать страницу, которая переключается с одного полноэкранного раздела на другой по мере прокрутки пользователем. Этот эффект был популяризирован библиотекой fullpage.js . Но теперь есть лучшие варианты из-за изменений в лицензировании для полной страницы (теперь за это нужно платить), нового модуля прокрутки CSS и полной поддержки браузером API-интерфейса наблюдателя пересечения.

Итак, если вы ищете альтернативу fullpage.js, вам может даже не понадобиться целая библиотека, вы можете просто написать ее самостоятельно!

На самом деле эффект привязки — это 100% CSS. JS просто используется для постепенного появления элементов, когда экран «защелкивается» в поле зрения.

Для вдохновения мы воспользуемся этой демонстрацией прокрутки «Парк динозавров» от Мишель Баркер, доступной на CodePen:

https://codepen.io/michellebarker/pen/PowYKXJ См. демонстрацию прокрутки Pen Dinosaur Park от Мишель Баркер (@michellebarker) на CodePen.

Обратите внимание, вы, вероятно, захотите просмотреть это на большом экране, чтобы в полной мере ощутить эффект «привязки прокрутки».

Используя CSS в сочетании с Intersection Observer, мы заставим каждую полноэкранную секцию страницы прокручиваться, а содержимое исчезнет, ​​когда оно попадет в область просмотра.

Более того, это всего ~30 строк JS-кода! Анимации выполняются с помощью CSS; все, что нам нужно сделать, это понять, когда разделы и контент попадают в нашу область просмотра с помощью JS.

1) Создайте свою страницу

Во-первых, нужно будет создать страницу или настроить существующую, чтобы она была совместима с этим простым эффектом. Здесь следует отметить две вещи:

Мы используем элемент <main> , который содержит наши разделы. Этот основной элемент имеет размер 100vh, как и каждый из элементов <section> внутри.

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" data-content >Содержимое внутри</div> </section> </main>

CSS:

/* Поведение при прокрутке */ @media (min-height: 30em) { main { scroll-snap-type: y required; высота: 100вх; переполнение-у: прокрутка; } } .section { цвет: белый; положение: родственник; прокрутка-щелчок-выравнивание: центр; дисплей: гибкий; flex-направление: столбец; мин-высота: 100вх; } @media (min-height: 30em) { .section { height: 100vh; } }

2) Настройте привязку с помощью CSS

изображение-16-11

Здесь мы видим, что есть несколько секций, каждая из которых имеет высоту 100vh.

Элемент <main> также имеет размер 100vh с overflow-y:scroll.

Для пользователя поведение прокрутки такое же, как и у веб-страницы по умолчанию.

Если вы добавили упомянутый выше CSS, эффект привязки уже будет в игре. Давайте посмотрим, как это работает.

Во-первых, запрос « @media (min-height: 30em) » отключает эффект привязки для размеров мобильных экранов, которые слишком малы с точки зрения высоты. В основном разделе есть одно свойство, которое включает привязку:

main { .... тип привязки прокрутки: y обязательный; .... }

Это классное маленькое свойство «устанавливает, насколько строго точки привязки применяются к контейнеру прокрутки, если он есть» (MDN).

И затем в наших разделах у нас есть:

.section { .... прокрутка-щелчок-выравнивание: центр; .... }

Это свойство «свойство указывает положение привязки блока как выравнивание его области привязки (в качестве объекта выравнивания) в пределах привязки его контейнера привязки (в качестве контейнера выравнивания)» (MDN).

Узнайте больше о модуле прокрутки CSS здесь:

И это так просто. Прямые дочерние элементы внутри контейнера <main> (все разделы) будут привязываться к центру контейнера <main>. Поскольку и основной, и раздел имеют размер 100vh, прокрутка будет происходить от раздела к разделу.

3) Исчезновение содержимого при использовании Intersection Observer

К настоящему времени у нас есть эффект полной прокрутки страницы, и если вы не хотите делать ничего другого, вы можете пропустить этот раздел и наслаждаться своим веб-сайтом. Однако, когда каждый полный раздел страницы появляется в поле зрения, я хочу, чтобы содержимое внутри отображалось постепенно — уникальный и классный эффект (также возможный с fullpage.js).

Для этого мы будем использовать наблюдатель пересечений, чтобы понять расположение секций в нашем <main> окне просмотра.

const section = [...document.querySelectorAll("раздел")]; let options = { rootMargin: "0px", threshold: 0.75, }; const callback = (entries,Observer) => { entry.forEach((entry) => { const { target } = entry; if (entry.intersectionRatio >= 0,75) { target.classList.add("is-visible") } else { target.classList.remove ("является видимым"); } }); }; constObserver = новый IntersectionObserver(обратный вызов, параметры); section.forEach((раздел, индекс) => { const sectionChildren = [...section.querySelector("[data-content]").children]; sectionChildren.forEach((el, index) => { el.style .setProperty("--delay", `${index * 250}ms`); });Observer.observe(section); });

Здесь делается две вещи. Во-первых, он определяет, когда раздел находится в области просмотра, и при входе добавляет класс CSS .is-visible . Когда он покидает область просмотра, он удаляет этот класс.

Кроме того, по мере того, как этот раздел входит в область просмотра, он последовательно (один за другим) устанавливает свойство задержки на 250 мс для каждого из дочерних элементов. Это создает эффект ступенчатого затухания.

Он делает это только с дочерними элементами внутри элементов, которые имеют атрибут data-content. Поэтому вам нужно добавить это в обертки вокруг содержимого ваших страниц, если вы хотите эффект затухания.

Теперь, чтобы все заработало, нам нужно настроить анимацию появления для элементов, к которым добавлен класс .is-visible.

@media (min-height: 30em) { .section__content > * { непрозрачность: 0; преобразование: translate3d(0, 4rem, 0); переход: непрозрачность 800 мс var(--delay), преобразование 800 мс кубический-безье (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-коду из начальной демонстрации, вы увидите, что вокруг контента есть div с классом .section__content и атрибутом data-content.

<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" data-content >Содержимое внутри</div> </section> </main>

Это связывает наши JS и CSS вместе. Непрозрачность для содержимого равна 0 до тех пор, пока наблюдатель пересечения не добавит класс .is-visible при входе в окно просмотра. Когда он уходит, он возвращается к непрозрачности, равной 0, поэтому независимо от направления прокрутки всегда будет действовать канал.

Наконец, delay , которая последовательно применяется к каждому дочернему элементу, смещает эффект постепенного появления.

Обратите внимание на третий раздел. Заголовок раздела не находится в разделе содержимого данных, поэтому он не исчезнет (уже будет там).

Весь код

Вот демо:

изотропный-2022-07-15-в-15-00-58

Вот весь код, который мы использовали в нашей демонстрации:

HTML

<main> <section class="section section-1"> <div class="section__content" data-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" data-content > <h2>Содержимое внутри</h2> <p>бла-бла-бла</p> </div> </section> </main>

CSS

@media (min-height: 30em) { main {scroll-snap-type: y required; высота: 100вх; переполнение-у: прокрутка; } } .section { цвет: белый; положение: родственник; прокрутка-щелчок-выравнивание: центр; дисплей: гибкий; flex-направление: столбец; мин-высота: 100вх; } @media (min-height: 30em) { .section { height: 100vh; } } @media (min-height: 30em) { .section__content > * { непрозрачность: 0; преобразование: translate3d(0, 4rem, 0); переход: непрозрачность 800 мс var(--delay), преобразование 800 мс кубический-безье (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 section = [...document.querySelectorAll("раздел")]; пусть параметры = { rootMargin: "0px", порог: 0,75,}; const callback = (entries,Observer) => { entry.forEach((entry) => { const { target } = entry; if (entry.intersectionRatio >= 0,75) { target.classList.add("is-visible") } else { target.classList.remove ("является видимым"); } }); }; constObserver = новый IntersectionObserver(обратный вызов, параметры); section.forEach((раздел, индекс) => { const sectionChildren = [...section.querySelector("[data-content]").children]; sectionChildren.forEach((el, index) => { el.style .setProperty("--delay", `${index * 250}ms`); });Observer.observe(section); });

Вывод

Это идеальная альтернатива fullpage.js, которая не ограничивается только переходом между полноэкранными разделами. Мы также использовали API наблюдателя пересечения, чтобы понимать, когда раздел входит на страницу, а затем динамически применять поэтапную анимацию. Вы можете использовать этот базовый пример, чтобы создать несколько действительно крутых эффектов с минимумом ванильного JS и CSS.