Создание шагового компонента

Создание горизонтального и вертикального шагового компонента с помощью CSS flexbox

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

В этой статье я рассмотрю различные конструкции степпинг-компонента и найду лучший способ реализовать каждый из них в HTML и CSS. Вы готовы? Давайте углубимся.

  

Введение

Пошаговый компонент можно использовать для упрощения навигации по длинной веб-странице путем разделения связанных элементов и группировки их вместе.

Создание шагового компонента

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

  

Горизонтальный степпер: пример 1

Горизонтальный степпер - пример 1

В этом примере у нас есть горизонтальный степпер с линией между элементами. Вот ожидания от степпера:


<ol class="c-stepper">
    <li class="c-stepper__item">
        <h3 class="c-stepper__title">Step 1</h3>
        <p class="c-stepper__desc">Some desc text</p>
    </li>
    <!-- Other steps -->
</ol>

В CSS нам нужно использовать flexbox для горизонтального размещения элементов.


.c-stepper {
    display: flex;
    flex-wrap: wrap;
}

.c-stepper__item {
    flex: 1;
    display: flex;
    flex-direction: column;
    text-align: center;
}

.c-stepper__item:before {
    --size: 3rem;
    content: "";
    position: relative;
    z-index: 1;
    display: block;
    width: var(--size);
    height: var(--size);
    border-radius: 50%;
    margin: 1rem auto 0;
}

При этом мы получим следующий результат.

Горизонтальный степпер - пример 1

Как видите, содержимое расположено по центру, и каждый элемент равен другим элементам того же уровня благодаря flex: 1. Далее нам нужно изучить, как добавить линию между ними.


.c-stepper__item:not(:last-child):after {
    content: "";
    height: 2px;
    background-color: #e0e0e0;
}

Горизонтальный степпер - пример 1

Вы можете задаться вопросом, как псевдоэлемент занимает всю ширину, если на самом деле у него нет явной width? Ну, он растягивается, чтобы заполнить все горизонтальное пространство, потому что это гибкий элемент.

Во-первых, нам нужно переместить его наверх. Поскольку это гибкий элемент, мы можем получить преимущество от свойства order.


.c-stepper__item:not(:last-child):after {
    content: "";
    height: 2px;
    background-color: #e0e0e0;
    order: -1;
}

Теперь мы хотим расположить его правильно, но без использования position: absolute, так как это не нужно.


.c-stepper__item:not(:last-child):after {
    content: "";
    position: relative;
    top: 1.5rem;
    left: 50%;
    height: 2px;
    background-color: #e0e0e0;
    order: -1;
}

Вот объяснение приведенного выше CSS:

Горизонтальный степпер - пример 1

  

Версия, в которой есть пробел до и после строки

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

Горизонтальный степпер - пример 1

Прежде чем погрузиться в решение, я хочу показать вам, что линии-разделители, которые у нас есть, на самом деле скрыты под каждым кругом. Я уменьшил opacity для числовых кругов, чтобы вы могли их видеть.

Горизонтальный степпер - пример 1

Это связано с использованием left: 50% для строки. Давайте рассмотрим, как придать ему смещение слева и справа.

Горизонтальный степпер - пример 1

Так как линия имеет left: 50%, она будет начинаться с центра своего родителя.

Горизонтальный степпер - пример 1

Мы используем calc(), чтобы добавить радиус круга, это заставит разделительную линию начинаться с конца круга.

Горизонтальный степпер - пример 1

Добавив нужный интервал (в данном случае 8 пикселей) в функцию calc(), мы получим пробел слева от разделительной линии.

Горизонтальный степпер - пример 1

Наконец, нам нужно создать интервал с другой стороны. Ширина равна 100%, поэтому мы вычитаем ширину круга вместе со значениями интервала слева и справа.

Горизонтальный степпер - пример 1

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


.c-stepper {
    --size: 3rem;
    --spacing: 0.5rem;
}
.c-stepper__item:not(:last-child):after {
    width: calc(100% - var(--size) - calc(var(--spacing) * 2));
    left: calc(50% + calc(var(--size) / 2 + var(--spacing)));
}

Посмотрите видео ниже для демонстрации.

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

Горизонтальный степпер - пример 1

  

Демо

Вот живая демонстрация:

  

Горизонтальный степпер: пример 2

Горизонтальный степпер - пример 2

В этом примере разделительная строка идет сразу после заголовка шага. Разница здесь в том, что длина разделителя зависит от длины заголовка шага.


<ol class="c-stepper">
    <li class="c-stepper__item">
        <h3 class="c-stepper__title">Step 1</h3>
    </li>
    <!-- Other steps -->
</ol>

Как и в предыдущем примере, мы будем использовать flexbox для размещения шагов по горизонтали. Обратите внимание, что мы хотим применить flex: 1 только к первому и второму шагу.


.c-stepper {
    display: flex;
    flex-wrap: wrap;
}

.c-stepper__item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.c-stepper__item:not(:last-child) {
    flex: 1;
}

.c-stepper__item:before {
    --size: 3rem;
    content: "";
    display: block;
    flex: 0 0 var(--size);
    height: var(--size);
    border-radius: 50%;
}

Горизонтальный степпер - пример 2

Строка-разделитель будет добавлена как псевдоэлемент. Он будет иметь flex: 1, чтобы он мог заполнить оставшееся пространство.


.c-stepper__item:not(:last-child):after {
    content: "";
    flex: 1;
    height: 2px;
    background-color: #e0e0e0;
    margin-inline-end: 0.5rem;
}

Горизонтальный степпер - пример 2

Используя gap в .c-stepper__item и логическое свойство margin-inline-end для строки-разделителя, мы можем гарантировать, что компонент будет работать как с документами LTR, так и с RTL.

Горизонтальный степпер - пример 2

  

Демо

Вот живая демонстрация:

  

Вертикальный степпер: пример 3

Вертикальный степпер - пример 3

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


<ol class="c-stepper">
    <li class="c-stepper__item">
        <div class="c-stepper__content">
            <h3 class="c-stepper__title">Step 2</h3>
            <p>Some desc text</p>
        </div>
    </li>
    <!-- Other steps -->
</ol>

.c-stepper__item {
    display: flex;
    gap: 1rem;
}

.c-stepper__item:before {
    --size: 3rem;
    content: "";
    position: relative;
    z-index: 1;
    flex: 0 0 var(--size);
    height: var(--size);
    border-radius: 50%;
    background-color: lightgrey;
}

Теперь к интересной части, а именно к разделительной линии. Строка должна быть немного выше содержимого. Как мы можем добиться этого, избегая использования фиксированной высоты или полей?

Мы можем добавить большое padding-bottom для этой цели.


.c-stepper__item {
    position: relative;
    display: flex;
    gap: 1rem;
    padding-bottom: 4rem;
}

.c-stepper__item:not(:last-child):after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    transform: translateX(1.5rem);
    width: 2px;
    background-color: #e0e0e0;
}

Чтобы создать пробел между разделительной линией и числами, мы можем применить ту же формулу, что и в примере с горизонтальным степпером, или просто использовать свойства top и bottom.

Вертикальный степпер - пример 3


.c-stepper {
    --size: 3rem;
    --spacing: 0.5rem;
}

.c-stepper__item:not(:last-child):after {
    top: calc(var(--size) + var(--spacing));
    transform: translateX(calc(var(--size) / 2));
    bottom: var(--spacing);
}

При этом у нас может быть расстояние между линией и кругом.

Вертикальный степпер - пример 3

  

Демо

Вот живая демонстрация:

  

Вертикальный степпер: пример 4

Это может быть не похоже на степпер, это скорее временная шкала. Независимо от названия, реализовать это можно с помощью flexbox.

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


<ol class="c-timeline">
    <li class="c-timeline__item">
        <div class="c-timeline__content">
            <h3 class="c-timeline__title">Paris</h3>
            <p class="c-timeline__desc">On time</p>
        </div>
        <time class="c-timeline__time">10:03</time>
    </li>
    <!-- Other items -->
</ol>

Вот базовый CSS.


.c-timeline__item {
    display: flex;
    gap: 1.5rem;
}

.c-timeline__content {
    order: 1;
    /* Reorder the content as per the design. */
    padding-bottom: 3rem;
}

При этом мы получим следующий результат. Хорошее начало!

Вертикальный степпер - пример 4

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


/* The separator line */
.c-timeline__item:not(:last-child) .c-timeline__content:before {
    content: "";
    position: absolute;
    right: 100%;
    top: 0;
    height: 100%;
    width: 2px;
    background-color: #d3d3d3;
}

/* The circle */
.c-timeline__content:after {
    content: "";
    position: absolute;
    left: -12px;
    top: 0;
    width: 20px;
    height: 20px;
    background-color: #fff;
    z-index: 1;
    border: 2px solid #d3d3d3;
    border-radius: 50%;
}

Вертикальный степпер - пример 4

Далее нам нужно ограничить ширину элемента времени. Кроме того, содержимое временной шкалы должно занимать оставшееся доступное пространство, поэтому мы будем использовать flex: 1.


.c-timeline__time {
    flex: 0 0 100px;
}

.c-timeline__content {
    flex: 1;
}

Следующий шаг — выровнять содержимое c-timeline__time по правому краю или до конца в логике CSS.


.c-timeline__time {
    flex: 0 0 100px;
    text-align: end;
}

Вертикальный степпер - пример 4

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

По умолчанию гибкие элементы не уменьшаются ниже минимального размера содержимого. Если элемент .c-timeline__time имеет очень длинное содержимое, он будет выглядеть так, даже если у него flex: 0 0 100px.

Вертикальный степпер - пример 4

Чтобы исправить это, нам нужно заставить flexbox уменьшиться ниже минимального размера содержимого, добавив к элементу min-width: 0, а также overflow-wrap, чтобы разбить длинные слова.


.c-timeline__time {
    flex: 0 0 100px;
    text-align: end;
    min-width: 0;
    overflow-wrap: break-word;
    padding-bottom: 1rem;
}

  

Демо

Вот живая демонстрация:

Надеюсь, вам понравилась статья. Спасибо за прочтение!

Ссылка на автора - twitter.com/shadeed9 !


Top

🔖 Выбор по тегам ×

💌 Написать сообщение ×

Все поля обязательны для заполнения!