Анімована біжучий рядок тексту в 3D на чистому CSS

22

Від автора: на протязі довгого часу я горів бажанням створити біжучий анімовану рядок тексту, яка б вигиналася на кутах. Є кілька способів зробити такий рядок, серед яких WebGL, але мені хотілося знайти настільки простий спосіб, щоб його можна було написати тільки на HTML і CSS.

Гострі кути

Базова розмітка складається з двох div з однаковим контентом, які знаходяться всередині іншого контейнера

ONE LOVE ONE HEART

Другий div є копією першого, але у нього є атрибут aria-hidden=»true», який робить його недоступним для додатків. Таким чином, текст читається один раз.

Внутрішні DIV и розміщені під кутом один до одного за допомогою 3D ротації, а батьківського контейнера задано відповідне значення властивості perspective. У батьків також встановлено властивість font-size: 0. Це зроблено для того, щоб внутрішні елементи властивість display: inline-block відображалися без будь-яких проміжків:

#marquee {
perspective: 500px;
font-size: 0;
}
#marquee div {
display: inline-block;
height: 12rem;
width: 30rem;
position: relative;
}

Внутрішні div и повернені під дещо різними кутами за допомогою властивості transform-origin. Також внутрішнім блокам задано відрізняється фон (для симуляції напрямку падіння світла) і значення кольору.

#marquee div:first-of-type {
background: #e5233e;
transform-origin: top right;
transform: rotateY(-40deg);
color: #fff;
}
#marquee div:last-of-type {
background: #b31e31;
transform-origin: top left;
transform: rotateY(45deg);
color: #f8c9d9;
}

Текст в блоках поміщений в тег span, який розтягнутий для того, щоб вмістився весь текст. Обрізання тексту, коли він виходить за межі блоків, імітується за допомогою властивості overflow: hidden:

#marquee div {
font-size: 8rem;
overflow: hidden;
}
#marquee div span {
position: absolute;
width: 400%;
line-height: 1.4;
}

Біжучий рядок

Тегів span кілька штук, і вони займають різні позиції: текст праворуч зрушать на 30rem (тобто на ширину контейнера div, щоб текст вийшов за межі видимої області). Текст зліва зрушать вправо вже на дві ширини блоку, а також йому задана тонка тінь text-shadow.

#marquee div:first-of-type span {
transform: translateX(60rem);
animation: leftcrawl 14s linear infinite;
text-shadow: 4px 0px 4px rgba(0,0,0,0.3);
}
#marquee div:last-of-type span {
transform: translateX(30rem);
animation: rightcrawl 14s linear infinite;
}

Якщо батьківським блокам div не задати властивість overflow:hidden і зробити текст різних кольорів, то ви отримаєте приблизно наступне:

Анімована біжучий рядок тексту в 3D на чистому CSS

Обидві рядки тексту потрібно анімувати. Ми не ставимо затримку на ліву рядок тексту, замість цього обидві рядки рухаються одночасно, підходячи до перегину в один і той же момент:

@keyframes leftcrawl {
to { transform: translateX(-100rem); }
}
@keyframes rightcrawl {
to { transform: translateX(-130rem); }
}

Задана лінійна функція анімації, тексту і не прискорюється і не сповільнюється.

Адаптивність

Дана техніка буде працювати незалежно від зміни параметрів, перерахованих нижче. В цьому ви можете переконатися в демо на CodePen:

Текст

Значення перспективи

Кут нахилу DIV ів

Тим не менш, код погано працює на екранах маленької ширини: текст стає менше, а перспектива сильно збільшується, що ускладнює читання рядка, що біжить. Тому якщо ширина видимої області менше 993px, ми замінюємо презентацію на 2D версію і показуємо тільки один із DIV ов:

@all media and (max-width: 993px) {
#marquee {
perspective: none;
}
#marquee div:last-of-type {
opacity: 0;
height: 0;
}
#marquee div:first-of-type {
width: 80%;
}
}

Цікавий факт полягає в тому, що якщо задати елементу властивість display: none, то анімація повністю припиниться і відновиться тільки, коли елемент знову стане видимим. З цієї причини я скористався іншою технікою для приховування елементів: другого div було задано властивості opacity і htight в 0. Таким чином, при розтягуванні або звуженні області перегляду анімація не буде зупинятися.

Висновок і поліпшення

У загальному і цілому, я задоволений результатом. Незабаром сподіваюся застосувати цю техніку на моїх CSS синемаграфах. Однак у дану методику можна внести кілька поліпшень, більша частина з яких пов’язана з дублюванням контенту. JavaScript може легко копіювати елементи і текст, але набагато краще реалізувати це за допомогою псевдоелемент.