У вас включен AdBlock или иной блокировщик рекламы.

Пожалуйста, отключите его, доход от рекламы помогает развитию сайта и появлению новых статей.

Спасибо за понимание.

В другой раз
DevGang блог о програмировании
Авторизоваться

Вплетение линии в текст на CSS

Ранее в этом году я наткнулся на демо от Florin Pop, которое заставляет строку проходить либо над, либо под буквами заголовка одной строки. Я думал, что это крутая идея, но в реализации было несколько мелочей, которые я мог бы упростить и улучшить одновременно.

Во-первых, оригинальная демоверсия дублирует текст заголовка, который, как я знал, можно было легко избежать. Тогда есть факт, что длина строки, проходящей через текст, является магическим числом, что не очень гибкий подход. И, наконец, мы не можем избавиться от JavaScript?

Итак, давайте посмотрим, как я в конечном итоге сделал это.

HTML структура

Флорин помещает текст в элемент заголовка, а затем дублирует этот заголовок, используя Splitting.js, чтобы заменить текстовое содержимое дублированного заголовка интервалами, каждая из которых содержит одну букву исходного текста.

- let text = 'We Love to Play';
- let arr = text.split('');

h1(role='image' aria-label=text)
  - arr.forEach(letter => {
    span.letter #{letter}
  - });

Поскольку расщепление текст на несколько элементов не могут работать хорошо для чтения с экрана, мы задали дополнительные атрибуты, role и aria-label.

Это генерирует следующий HTML:

<h1 role="image" aria-label="We Love to Play">
  <span class="letter">W</span>
  <span class="letter">e</span>
  <span class="letter"> </span>
  <span class="letter">L</span>
  <span class="letter">o</span>
  <span class="letter">v</span>
  <span class="letter">e</span>
  <span class="letter"> </span>
  <span class="letter">t</span>
  <span class="letter">o</span>
  <span class="letter"> </span>
  <span class="letter">P</span>
  <span class="letter">l</span>
  <span class="letter">a</span>
  <span class="letter">y</span>
</h1>

Основные стили

Мы помещаем заголовок в центр его родителя (в данном случае body), используя grid:

body {
  display: grid;
  place-content: center;
}
Заголовок не простирается через своего родителя, чтобы покрыть его полностью, но вместо этого помещается в середине.
Заголовок не простирается через своего родителя, чтобы покрыть его полностью, но вместо этого помещается в середине.

Мы также можем добавить дополнительные стили, например, font или background у контейнере.

Далее мы создаем линию с абсолютно позиционированным псевдоэлементом ::after:

$h: .125em;
$r: .5*$h;

h1 {
  position: relative;
  
  &::after {
    position: absolute;
    top: calc(50% - #{$r}); right: 0;
    height: $h;
    border-radius: 0 $r $r 0;
    background: crimson;
  }
}

Приведенный выше код заботится о позиционировании псевдоэлемента и его толщине height, но как насчет width? Как заставить его растягиваться от левого края области просмотра до правого края текста заголовка?

Длина линии

Итак, поскольку у нас есть grid, в котором заголовок выровнен по центру по горизонтали, это означает, что вертикальная средняя линия окна просмотра совпадает с средней линией заголовка, разделяя обе части на две равные по ширине половины:

Выровненный по середине заголовок.
Выровненный по середине заголовок.

Следовательно, расстояние между левым краем области просмотра и правым краем заголовка составляет половину ширины области просмотра (50vw) плюс половину ширины заголовка %, что может быть выражено как значение при использовании при вычислении его псевдоэлементов width.

Итак, width нашего псевдоэлемента ::after:

width: calc(50vw + 50%);

Заставить линию идти снова и снова

Пока что результат - просто красная линия, пересекающая черный текст:

Мы хотим, чтобы некоторые буквы отображались в верхней части строки. Чтобы получить этот эффект, мы даем им (или не даем) случайным образом класс .over. Для этого мы изменим немного код Pug:

- let text = 'We Love to Play';
- let arr = text.split('');

h1(role='image' aria-label=text)
  - arr.forEach(letter => {
    span.letter(class=Math.random() > .5 ? 'over' : null) #{letter}
  - });

Затем мы сопоставляем буквы с классом .over и даем им положительный z-index.

.over {
  position: relative;
  z-index: 1;
}
Моя первоначальная идея заключалась в использовании translatez(1px) вместо z-index: 1, но потом мне показалось, что использование z-index имеет лучшую поддержку браузера и требует меньше усилий.

Линия проходит над некоторыми буквами:

Оживи это!

Теперь, когда мы преодолели сложную часть, мы также можем добавить animation, чтобы линия двигалась. Это означает, что малиновая линия сместилась влево (в отрицательном направлении оси x, поэтому знак будет минус) его полная ширина width(100%) в начале, только чтобы затем позволить ему вернуться в нормальное положение.

@keyframes slide { 0% { transform: translate(-100%); } }
animation: slide 2s ease-out 1s backwards;

3D сенсорный

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

Это требует реального 3D и несколько небольших настроек.

Во- первых, мы устанавливаем на заголовок transform-style, так как мы хотим preserve-3d, чтобы все его потомки (и псевдо-элементы) могли быть частью одной и той же 3D сборки.

Затем мы хотим повернуть каждую букву вокруг своей оси y, причем направление вращения зависит от наличия случайно назначенного класса (имя которого мы меняем на .rev

Однако, прежде чем мы сделаем это, мы должны помнить, что наши элементы span все еще являются встроенными в данный момент, и установка transform для встроенного элемента не имеет абсолютно никакого эффекта.

Чтобы обойти эту проблему, мы поставили заголовку display: flex. Однако это создает новую проблему, и это тот факт, что элементы span, содержащие только пробел (" "), обнуляют ширину.

Осматривать пространство только span в Firefox DevTools.
Осматривать пространство только span в Firefox DevTools.

Простое решение этой проблемы - установить класс .letter с white-space: pre.

Как только мы это сделаем, мы сможем повернуть наши спаны на угол $a... в одном или другом направлении!

$a: 2deg;

.letter {
  white-space: pre;
  transform: rotatey($a);
}

.rev { transform: rotatey(-$a); }

Поскольку вращение вокруг оси Y сжимает наши буквы по горизонтали, мы можем масштабировать их вдоль оси X с помощью коэффициента ($f), обратного косинусу $a.

$a: 2deg;
$f: 1/cos($a)

.letter {
  white-space: pre;
  transform: rotatey($a) scalex($f)
}

.rev { transform: rotatey(-$a) scalex($f) }

Вот и все! Теперь у нас есть 3D-результат, к которому мы стремились! Однако обратите внимание, что используемый здесь шрифт был выбран так, что наш результат выглядит хорошо, и другой шрифт может не работать так же хорошо.

Источник:

#CSS #HTML
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться