Иногда необычная идея дизайнера превращается в задачу, которую действительно интересно реализовывать. Именно так произошло с этим проектом: колонки контента, которые при скролле движутся в противоположные стороны.
Живой демонстрационный пример (CodePen): эффект учитывает настройки reduced motion, поэтому для просмотра его нужно включить. На момент написания статьи работает в Chrome и Safari.
Современный CSS делает это удивительно простым — ключевую роль здесь играют анимации, управляемые скроллом. Давайте разберем подход. Возможно, вы найдете альтернативное решение.
Структура HTML
Три вложенных уровня: родительский контейнер (.opposing-columns), дочерние колонки (.opposing-column) и элементы внутри каждой колонки (.opposing-item).
<div class="opposing-columns">
<div class="opposing-column">
<div class="opposing-item">...</div>
<div class="opposing-item">...</div>
</div>
<div class="opposing-column">
<div class="opposing-item">...</div>
</div>
<div class="opposing-column">
<div class="opposing-item">...</div>
</div>
</div>Вот и всё. Остальное делает CSS.
Адаптивная настройка
Эффект имеет смысл только на больших экранах с достаточным горизонтальным пространством. Оборачиваем всё в медиа-запрос:
@media screen and (width >= 50rem) {
.opposing-columns {
display: flex;
gap: 2rem;
max-inline-size: min(90dvi, 50rem);
margin-inline: auto;
}
}Создание иллюзии маскирования
Элементы в крайних колонках движутся вверх при скролле, а в центральной — вниз. Чтобы они плавно исчезали на границах контейнера, используем псевдоэлементы с градиентами — без трюков с прозрачностью.
Сначала задаем переменную с цветом фона в :root:
:root {
--opposing-bg: lightcyan;
--opposing-mask: 3rem;
background-color: var(--opposing-bg);
}Затем применяем :before и :after к родительскому элементу с тем же цветом фона и z-index: 1, чтобы они находились над колонками:
.opposing-columns {
position: relative;
margin-block: var(--opposing-mask, 3rem);
&:before,
&:after {
content: "";
position: absolute;
inset-inline: 0;
block-size: calc(var(--opposing-mask) * 3);
pointer-events: none;
z-index: 1;
}
}Теперь градиенты:
- Верхний псевдоэлемент (
:before): от сплошного фона к прозрачному, сверху вниз. - Нижний псевдоэлемент (
:after): от прозрачного к сплошному фону, снизу вверх.
.opposing-columns {
&:before {
background-image: linear-gradient(
to bottom,
var(--opposing-bg) var(--opposing-mask),
transparent
);
inset-block-start: calc(var(--opposing-mask) * -1);
}
&:after {
background-image: linear-gradient(
to top,
var(--opposing-bg) var(--opposing-mask),
transparent
);
inset-block-end: calc(var(--opposing-mask) * -1);
}
}Элементы при скролле скользят под эти маски, создавая чистый эффект затухания на верхнем и нижнем краях контейнера.
Практические соображения для бизнеса на Кипре и в ЕС
- Производительность: анимации на основе скролла выполняются в потоке композитора — никаких зависаний из-за JavaScript. Это важно для мобильных пользователей с 4G в Лимассоле или Никосии.
- GDPR и доступность: демонстрационный пример учитывает
prefers-reduced-motion. Всегда добавляйте эту проверку, чтобы не нарушать директивы ЕС по доступности. - Многоязычные сайты (EN/RU/EL): эта CSS-техника работает независимо от переключения языков или RTL-верстки (используйте
inset-inlineиinset-block, как мы сделали). - Оценка бюджета: на подобный кастомный компонент уходит 2–4 часа разработки. В сочетании с полным сайтом (5–10 страниц) типичная стоимость в кипрской веб-студии составляет €1,500–€3,500.