Интересный эффект изменения текста: от сплошного цвета до knockout-стиля (когда у текста есть фон). Реализован на HTML и CSS.
Для создания такого эффекта нам потребуются два контейнера с фиксированными элементами <h1>. Первый контейнер с белым фоном и knockout-текстом, второй — с фоновым изображением и белым текстом. Используя интересный трюк с вырезанием мы спрячем текст первого контейнера, когда до него дойдет скролл, и наоборот. Это создаст иллюзию того, что фон текста изменяется.
Верстка
Для начала создадим общую HTML-структуру — два одинаковых контейнера с элементами h1
, обернутыми в блок с классом title_wrapper
.
<header>
<!-- Первый контейнер -->
<div class="container container_solid">
<div class="title_wrapper">
<h1>The Great Outdoors</h1>
</div>
</div>
<!-- Второй контейнер -->
<div class="container container_image">
<div class="title_wrapper">
<h1>The Great Outdoors</h1>
</div>
</div>
</header>
Каждый контейнер имеет основной класс container
и дополнительный класс — .container_solid
или .container_image
. Это позволит нам установить для них общие стили, а также добавить специфическое оформление.
Основные стили
Теперь добавим немножко CSS.
Каждый контейнер должен растягиваться на всю высоту экрана. У первого контейнера (.container_solid
) сплошной белый фон, а у второго (.container_image
) — фиксированное фоновое изображение.
/* Общие стили */
.container {
height: 100vh;
}
/* Первый контейнер */
.container_solid {
background: white;
}
/* Второй контейнер */
.container_image {
background-image: url(https://images.unsplash.com/photo-1575058752200-a9d6c0f41945?&q=85);
background-size: 100vw auto;
background-position: center;
background-attachment: fixed;
}
Теперь нужно стилизовать заголовок.
Для .container_image
все просто — мы просто красим текст в белый цвет. Но для создания knockout-эффекта внутри .container_solid
придется повозиться.
Мы используем фоновое изображение, а затем обрежем его по границе текста с помощью свойств text-fill-color
и background-clip.
Обратите внимание, фон элемента h1
имеет точно такой же размер и положение, что и фон контейнера .container_image
. Важно, чтобы они совпадали, иначе эффект не получится.
.container_solid .title_wrapper h1 {
/* Фон для заголовка */
background: url(https://images.unsplash.com/photo-1575058752200-a9d6c0f41945?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ);
background-size: 100vw auto;
background-position: center;
/* Обрезаем фон текста */
-webkit-text-fill-color: transparent;
text-fill-color: transparent;
-webkit-background-clip: text;
background-clip: text;
/* Фоллбэк для браузеров, которые не поддерживают обрезку фона */
color: black;
}
.container_image .title_wrapper h1 {
color: white;
}
Зафиксируем текст по центру. Для этого добавим фиксированное позиционирование классу .title_wrapper
и выровняем его вертикально и горизонтально:
.header-text {
display: block;
position: fixed;
margin: auto;
width: 100%;
/* Вертикальное выравнивание */
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.header-text h1 {
/* Горизонтальное выравнивание */
text-align: center;
}
Сейчас элементы h1 в обоих блоках расположены точно друг над другом и не перемещаются при скролле.
Вот полный код на текущий момент (добавлены тени, чтобы спозиционированный текст было лучше видно.
See the Pen Knockout Text Scroll Reveal (Part 2) by Blake Eric (@blakeeric) on CodePen.
Вырезание текста и контейнеров
А теперь начинаются действительно интересные вещи.
Мы хотим, чтобы заголовок внутри контейнера был виден только тогда, когда он визуально находится внутри этого контейнера (с учетом прокрутки). Обычно это делается с помощью overflow: hidden
для родительского элемента. Но оба наших элемента спозиционированы относительно окна браузера, а не относительно своего родителя. В этом случае overflow: hidden
не будет иметь эффекта.
Мы можем использовать для родительских контейнеров свойство clip
с абсолютным позиционированием, чтобы спрятать переполняющий фиксированный контент. При этом браузер будет скрывать весь контент, выходящий за пределы элемента.
.container {
/* Скрыть переполняющий фиксированный контент */
clip: rect(0, auto, auto, 0);
/* Не работает, если overflow = visible */
overflow: hidden;
/* Работает только с абсолютным позиционированием */
position: absolute;
/* Контейнеры должны занимать всю ширину и высоту */
height: 100vh;
left: 0;
width: 100%;
}
Так как контейнеры теперь абсолютно спозиционированы, они выпадают из нормального потока элементов. Мы должны вручную разместить их внутри родительского контейнера.
.container_solid {
/* ... */
/* Первый контейнер размещаем вверху родительского */
top: 0;
}
.container_image {
/* ... */
/* Второй контейнер размещаем сразу под первым*/
top: 100vh;
}
На этом этапе эффект уже виден. При прокрутке создается иллюзия перехода сплошного текста в вырезанный. На самом деле, это просто наша маска, скрывающая текст, который выходит за пределы своего родителя.
Порадуем Safari
Если вы используете Safari, то можете заметить, что движок рендера некорректно обновляет представление при скролле. Добавим следующий код, чтобы пофиксить это:
.container {
/* ... */
/* Хак для Safari */
-webkit-mask-image: -webkit-linear-gradient(top, #ffffff 0%,#ffffff 100%);
}
Вот полный код проекта на данный момент:
See the Pen Knockout Text Scroll Reveal (Part 3) by Blake Eric (@blakeeric) on CodePen.
Время уборки
Давайте убедимся, что наш HTML соответствует рекомендациям по обеспечению доступности.
Пользователи, которые не используют вспомогательные технологии, не заметят, что на странице есть два идентичных блока, но скринридеры, конечно, прочитают оба заголовка. Чтобы скрыть один из них, добавим на второй контейнер aria-hidden:
<!-- Второй контейнер -->
<div class="container container_image" aria-hidden="true">
<div class="title_wrapper">
<h1>The Great Outdoors</h1>
</div>
</div>
Теперь вы можете свободно изменять дизайн текста: менять шрифт и размер текста. Можно даже добавить эффект параллакса или вместо фонового изображения использовать видео, главное, не забудьте немного поработать над доступность.
Это было не так уж трудно, не так ли?
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="MWwGpmR" data-user="blakeeric" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
<span>See the Pen <a href="https://codepen.io/blakeeric/pen/MWwGpmR">
Knockout Text Scroll Reveal (Final)</a> by Blake Eric (<a href="https://codepen.io/blakeeric">@blakeeric</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
0 комментариев