27
Май
2019

О, так много способов создать строку ссылок в виде треугольных лент!

О, так много способов создать строку ссылок в виде треугольных лент!

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

Вы, наверное, часто встречали этот шаблон. Например, в многошаговых формах и меню хлебных крошек. Для наших целей мы будем называть эти шаблоны «лентами», чтобы вы знали, что мы имеем в виду.

О, так много способов создать строку ссылок в виде треугольных лент!

Подобно многим вещам в Интернете, мы можем создать такие ленты разными способами! Я создал демонстрационную страницу, на которой объединены различные примеры, например, с использованием треугольников CSS, фонов SVG и свойства CSS clip-path.

Начинаем со структуры HTML

Для каждой демонстрации структура HTML будет в основном такой же, у нас есть элемент nav, который действует как родительский контейнер, а затем ссылки внутри него как дочерние элементы.

<nav class="ribbon ribbon--modifier" role="navigation" aria-label="breadcrumbs">
  <a class="ribbon__element" href="https://www.silvestar.codes/">Home</a>
  <a class="ribbon__element" href="https://www.silvestar.codes/categories/articles/">Blog</a>
  <a class="ribbon__element" href="https://www.silvestar.codes/articles/building-an-animated-sticky-header-with-custom-offset/" aria-current="page">Post</a>
</nav>

Обратите внимание, что эти элементы должны быть доступны. Рекомендуется создавать компоненты с учетом доступности, а введение доступности с самого начала — лучший способ предотвратить классическую ситуацию «я забыл сделать ее доступной».

Давайте зададим несколько базовых стилей

Когда дело доходит до подобных вещей, мы хотим убедиться, что размеры элементов заданы правильно. Для этой цели мы собираемся определить размер шрифта элемента-оболочки .ribbon (это то, как мы будем называть эти элементы), а затем используем единицы em для дочерних элементов, которые являются ссылками.

/* Определяем размер шрифта для элемента оболочки */ 
.ribbon {
  font-size: 15px;
}

/* используем em, чтобы определить размер элемента ленты */ 
.ribbon__element {
  font-size: 1.5em;
  letter-spacing: 0.01em;
  line-height: 1.333em;
  padding: 0.667em 0.667em 0.667em 1.333em;
}

Этот конкретный метод будет полезен для определения размера фигуры треугольника для каждой ленты, потому что для расчета треугольника мы будем использовать одинаковые размеры. И поскольку мы используем для вычисления размера элемента ленты единицы em, мы можем изменить размеры всех элементов, переопределив font-size элемента-оболочки.

Давайте использовать для макета CSS Grid , потому что… ну, потому что мы можем это. Мы могли бы сделать это таким образом, чтобы обеспечить более глубокую поддержку браузерами, но мы оставляем это на ваше усмотрение, исходя из ваших требований к поддержке.

Мы собираемся определить четыре столбца:

Три для элементов ленты

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

/* Элемент оболочки 
 * Мы используем CSS Grid, однако убедитесь, что это соответствует вашим требованиям по поддержке браузерами
* Исходим из того, что мы используем autoprefixer для вендорных префиксов и свойств.
 */
  
.ribbon {
  display: grid;
  grid-gap: 1px;
  grid-template-columns: repeat(auto-fill, 1fr) 1em; /* Авто-заполнение трех элементов ленты, плюс один элемент для исправления размеров */
}

Если вы предпочитаете не растягивать элементы ленты на всю ширину, сетку можно определить по-другому. Например, мы можем использовать max-content для настройки столбцов по размеру контента. (Обратите внимание, что max-content не очень хорошо поддерживается в некоторых основных браузерах.)

/* Подстраиваем элементы ленты под максимальный размер контента */
.ribbon--auto {
  grid-template-columns: repeat(3, max-content) 1em;
}

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

Доступность — это не только добавление атрибутов aria. Она также включает в себя цветовой контраст и удобочитаемость, а также добавление состояний наведения и фокуса. Если вам не нравится стиль outline, вы можете использовать другие свойства CSS, например, box-shadow.

/* Используем цвет текущей ссылки, но добавляем подчеркивание для состояния наведения  */
.ribbon__element:hover, 
.ribbon__element:active {
  color: inherit;
  text-decoration: underline;
}

/* Очищаем обведение рамкой по умолчанию и используем внутреннюю тень для состояния выделения фокусом */
.ribbon__element:focus {
  box-shadow: inset 0 -3px 0 0 #343435;
  outline: none;
}

Создание уникальной фигуры треугольника

У нас есть несколько вариантов определения треугольника в конце каждой ленты. Мы могли бы:

Создать треугольник, используя границы с псевдо-элементами

Использовать фоновое изображение SVG для псевдо-элементов

Использовать встроенные изображения SVG

Создать clip-path с помощью функции polygon()

Давайте рассмотрим каждый способ.

Вариант 1: Граница

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

Наш элемент ленты имеет размер содержимого равным значению line-height плюс верхний и нижний отступы:

1.333em + 0.667em + 0.667em = 2.667em

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

/* Левая стрелка */
.ribbon--alpha .ribbon__element:before {
  /* Делаем размер содержимого равным нулю */
  content: '';  
  height: 0;  
  width: 0;

  /* Используем границы, чтобы псевдо-элемент совпадал по размеру с  лентой */
  border-bottom: 1.333em solid transparent;
  border-left: 0.667em solid #fff;
  border-top: 1.333em solid transparent;

  /* Позиционируем элемент абсолютно по левому краю элемента ленты */
  position: absolute;
  top: 0;  
  bottom: 0;  
  left: 0;
}

/* Правая стрелка */
.ribbon--alpha .ribbon__element:after {
  /* Делаем размер контента равным нулю */
  content: '';  
  height: 0;  
  width: 0;

  /* Используем границы, чтобы псевдо-элемент совпадал по размеру  с лентой */
  border-bottom: 1.333em solid transparent;
  border-left: 0.667em solid;
  border-top: 1.333em solid transparent;

  /* Позиционируем элемент абсолютно по левому краю элемента ленты и смещаем его на внешнюю сторону элемента*/
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  -webkit-transform: translateX(0.667em);
  transform: translateX(0.667em);
}

Так как правый треугольник должен соответствовать цвету фона ленты, давайте не забудем добавить правильный цвет границы для каждого псевдо-элемента ленты.

/* Правая стрелка первого элемента */
.ribbon--alpha .ribbon__element:nth-child(1):after {
  border-left-color: #11d295;
}

/* Правая стрелка второго элемента */
.ribbon--alpha .ribbon__element:nth-child(2):after {
  border-left-color: #ef3675;
}

/* Правая стрелка третьего элемента */
.ribbon--alpha .ribbon__element:nth-child(3):after {
  border-left-color: #4cd4e9;
}

Все готово!

Вариант 2: Фоновое изображение

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

В отличие от подхода треугольника с помощью границ, мы хотим, чтобы псевдо-элемент соответствовал высоте нашего элемента ленты, или 100%. Ширина компонента должна соответствовать ширине левой границы треугольника, которая в нашем случае составляет 0,666666 em. Затем нам нужно использовать белый треугольник для фонового изображения с левой стороны, а затем изображения треугольника с цветом, соответствующим фону компонента с правой стороны. Опять же, мы используем абсолютное позиционирование для размещения треугольников на соответствующих сторонах элемента ленты.

/* Левая стрелка */
.ribbon--beta .ribbon__element:before {
  /* Определяем размер стрелки */
  content: '';  
  height: 100%;  
  width: 0.666666em;
  
  /* Определяем изображение фона, которое соответствует цвету фона */
  background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMTAgNDAiIHdpZHRoPSIxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSIjZmZmIj48cGF0aCBkPSJtNSAxNSAyMCAxMGgtNDB6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0ibWF0cml4KDAgLTEgLTEgMCAyNSAyNSkiLz48L3N2Zz4=);
  background-position: center left;
  background-repeat: no-repeat;
  background-size: 100%;
  
  /* Позиционируем элемент абсолютно по левому краю элемента ленты */
  position: absolute;
  bottom: 0;
  top: 0;
  left: 0;
}

/* Правая стрелка */
.ribbon--beta .ribbon__element:after {
  /* Определяем размер стрелки */
  content: '';  
  height: 100%;
  width: 0.667em;

  /* Определяем атрибуты изображения фона */
  background-position: center left;
  background-repeat: no-repeat;
  background-size: 100%;

  /* Позиционируем элемент абсолютно по правому краю элемента ленты и смещаем его на внешнюю сторону элемента */
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  -webkit-transform: translateX(0.667em);
  transform: translateX(0.667em);
}

/* Определяем изображение фона, которое соответствует цвету фона первого элемента */
.ribbon--beta .ribbon__element:nth-child(1):after {
  background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMTAgNDAiIHdpZHRoPSIxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNSAxNSAyMCAxMGgtNDB6IiBmaWxsPSIjMTFkMjk1IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0ibWF0cml4KDAgLTEgLTEgMCAyNSAyNSkiLz48L3N2Zz4=);
}

/* Определяем изображение фона, которое соответствует цвету фона второго элемента */
.ribbon--beta .ribbon__element:nth-child(2):after {
  background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMTAgNDAiIHdpZHRoPSIxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNSAxNSAyMCAxMGgtNDB6IiBmaWxsPSIjZWYzNjc1IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0ibWF0cml4KDAgLTEgLTEgMCAyNSAyNSkiLz48L3N2Zz4=);
}

/* Определяем изображение фона, которое соответствует цвету фона третьего элемента */
.ribbon--beta .ribbon__element:nth-child(3):after {
  background-image: url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMTAgNDAiIHdpZHRoPSIxMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNSAxNSAyMCAxMGgtNDB6IiBmaWxsPSIjNGNkNGU5IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0ibWF0cml4KDAgLTEgLTEgMCAyNSAyNSkiLz48L3N2Zz4=);
}

Вот и все!

Вариант 3: встроенный SVG

Вместо того, чтобы загружать разные SVG-треугольники для каждого фонового изображения, мы могли бы использовать встроенный SVG непосредственно в HTML.

Этот конкретный подход позволяет нам контролировать цвет каждой SVG-стрелки с помощью CSS. Размер стрелки рассчитывается в соответствии с размером ленты. Еще раз, мы используем единицы em, чтобы определить размер, и стрелки расположены абсолютно, как и в других подходах, которые мы рассмотрели до этого.

/* Позиционируем стрелки абсолютно и устанавливаем правильный размер */
.ribbon--gamma .ribbon__element svg {
  height: 2.667em;
  position: absolute;
  top: 0;
  width: 0.667em;
}

/* Левая стрелка */
.ribbon--gamma .ribbon__element svg:first-child {
  fill: #fff; /* Определяем изображение фона, которое соответствует цвету фона */
  left: 0; /* Помещаем левую стрелку с левой стороны элемента ленты */
}

/* Правая стрелка */
.ribbon--gamma .ribbon__element svg:last-child {
  left: 100%; /* Смещаем правую стрелку на внешнюю сторону элемента ленты */
}

/* Определяем цвет заливки, который соответствует цвету фона первого элемента */
.ribbon--gamma .ribbon__element:nth-child(1) svg:last-child {
  fill: #11d295;
}

/* Определяем цвет заливки, который соответствует цвету фона второго элемента */
.ribbon--gamma .ribbon__element:nth-child(2) svg:last-child {
  fill: #ef3675;
}

/* Определяем цвет заливки, который соответствует цвету фона третьего элемента */
.ribbon--gamma .ribbon__element:nth-child(3) svg:last-child {
  fill: #4cd4e9;
}

Вариант 4: clip-path

Мы можем создать треугольники ленты с помощью многоугольника, который маскирует фон. Firefox’s Shape Editor — это фантастический инструмент для рисования фигур с помощью графического интерфейса прямо в браузере. Как и Clippy.

Поскольку многоугольники должны создаваться с использованием процентов, нам нужно подумать над тем, как они будут соответствовать треугольникам. Кроме того, обратите внимание, что процентные многоугольники могут выглядеть немного странно в некоторых окнах просмотра, особенно когда размеры элементов адаптируются к контексту, например, элементам-оболочкам. Рассмотрите возможность переопределения многоугольников для разных окон просмотра.

.ribbon--delta .ribbon__element {
  clip-path: polygon(95% 0, 100% 50%, 95% 100%, 0% 100%, 5% 50%, 0% 0%);
}

Поскольку мы определили элемент-оболочку с помощью CSS Grid, нам нужно расширить элементы ленты, но оставить последний, равным размеру многоугольника, который в нашем случае составляет 5%. Последний элемент ленты должен быть шире по размеру ширины крайнего треугольника, чтобы соответствовать первым двум.

/* Делаем все элементы ленты (кроме последнего) шире на размер многоугольника */
.ribbon--delta .ribbon__element:not(:last-child) {
  width: 105%;
}

/* Делаем последний элемент ленты шире на размер крайнего треугольника */
.ribbon--delta .ribbon__element:last-child {
  width: calc(100% + .667em);
}

Разновидности этих вариантов

Теперь, когда мы научились создавать ленту с хлебными крошками несколькими способами, мы могли бы поэкспериментировать с ней, например, добавить тени или градиенты и разные размеры.

Добавление тени

Мы могли бы добавить тень для наших элементов ленты. Не добавляйте тени слева или справа от элемента ленты.

/* Добавляем тень под каждым элементом ленты */
.ribbon--shadow .ribbon__element {
  box-shadow: 1px 3px 3px -3px black;
}

Использование градиентов для цвета

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

Например, если мы собираемся использовать границу или фоновое изображение, нам нужно использовать в основном горизонтальные (то есть слева направо) градиенты (за исключением некоторых тщательно рассчитанных угловых градиентов). Если мы используем подход clip-path, мы можем использовать любую версию градиента.

/* Добавляем градиент к первому элементу ленты */
.ribbon--gradient .ribbon__element:nth-child(1) {
  background-image: linear-gradient(to right, #11ced2, #11d295);
}

/* Добавляем градиент ко второму элементу ленты */
.ribbon--gradient .ribbon__element:nth-child(2) {
  background-image: linear-gradient(to right, #ef36b2, #ef3675);
}

/* Добавляем градиент к третьему элементу ленты */
.ribbon--gradient .ribbon__element:nth-child(3) {
  background-image: linear-gradient(to right, #4c9fe9, #4cd4e9);
}

Вариации размера

Поскольку размер наших элементов ленты зависит от размера шрифта элемента-оболочки, определить разные размеры довольно просто.

/* Маленькая лента */
.ribbon--small {
  font-size: 10px;
}

/* Большая лента */
.ribbon--big {
  font-size: 20px;
}

Здесь мы используем набор малых лент:

И вот набор коротких лент:

Объединяя все вместе!

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

Другие моменты?

Создание пользовательских элементов с использованием различных методов CSS — это отличный способ улучшить или обновить свои знания. Прежде чем начать, стоит задуматься над поддерживаемостью и модульностью создаваемого компонента. Согласованная конвенция имен, такая как BEM, безусловно, помогает в этом. Доступность также имеет большое значение, поэтому начните с нее и документируйте специальные возможности в процессе.

Мы рассмотрели четыре разных подхода для создания элементов ленты. Вы использовали какой-либо другой подход или знаете о нем? Дайте мне знать в комментариях!

Автор: Silvestar Bistrović

Источник: https://css-tricks.com

Редакция: Команда webformyself.

Share

Тебе может это понравится...