Несколько способов анимировать границу с помощью CSS
Настройка границ
Задать границу элемента можно несколькими способами: border, outline и box-shadow. Как подробно описано в статье Стефани Эклс Три метода CSS для добавления границ элементов, у каждого подхода есть свои преимущества и недостатки, особенно когда речь идет об анимации границ. Основная причина, по которой не стоит использовать правильный CSS border, – это анимация.
outline-offset, Кевин Дж. PowellНедавно мне попалась статья Fantastic CSS border animation (Потрясающая анимация границ CSS), в которой автор Coco рассматривает дополнительные варианты. Добавляя сгенерированный контент с помощью ::before и ::after, они создают искусственную границу, которая затем анимируется.
Больше всего мне запомнились анимированные визуализации, которые использовались в статье. Они действительно помогают объяснить, что именно делается для достижения желаемого эффекта.
Белый слой и цветные линии – это сгенерированный контент. Постепенно увеличивая и уменьшая прозрачность белого слоя, можно понять, как они накладываются друг на друга и как работает анимация.
Сохранение блочной модели
Недостаток использования сгенерированного контента для имитации границы заключается в том, что вы получаете сломанную блочную модель: контент теперь может скрывать искусственную границу, потому что указанная "граница" нарисована под ней. Чтобы устранить проблему, необходимо применить нужный border-width в качестве padding.
Чтобы получить настоящую границу и сохранить работу блочной модели, можно использовать несколько фонов, которые затем растягиваются в область границы.
Основные сведения
Для начала создадим пунктирную границу и добавим несколько фонов.
/* Size of the border */
--border-size: 0.5rem;
/* Create a dotted border */
border: var(--border-size) dotted lime;
/* Create two background layers:
1. A white semi-transparent
2. A layer with the colored boxes
*/
background-image:
linear-gradient(to right, rgb(255 255 255 / 0.5), rgb(255 255 255 / 0.5)),
conic-gradient(
from 45deg,
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
)
;
Размеры фоновых изображений с background-origin
Как видите, с фоном происходит что-то странное: он закрашен в границах, но conic-gradient, похоже, совсем не то. Это ожидаемое поведение: по умолчанию фоновые изображения не заходят на границы, поскольку их начало координат – padding-box элемента. Чтобы создать границу, фоновые изображения повторяются в самой границе, что приводит к странному визуальному эффекту.
Чтобы решить эту проблему, нужно растянуть фон так, чтобы он занимал и размер границы. Вы можете сделать это вручную, растянув и переместив фон, но лучше использовать свойство background-origin, чтобы подогнать размер фона под размер border-box.
/* Manually add or offset the size of the border where needed */ background-position: calc(var(--border-size) * -1) calc(var(--border-size) * -1); background-size: calc(var(--border-size) * 2 + 100%) calc(var(--border-size) * 2 + 100%);
background-origin: border-box;
Это одно дополнение делает все намного лучше:
Уменьшение белого фонового слоя с помощью background-clip
Поскольку фоновые изображения теперь занимают все пространство, полупрозрачный слой нужно снова уменьшить. Вместо того чтобы снова возиться с background-size, можно использовать более простой способ: задать для background-clip значение padding-box. В этом случае фон не будет отображаться под границей.
background-clip:
padding-box, /* Clip white semi-transparent to the padding-box */
border-box /* Clip colored boxes to the border-box (default) */
;
Наконец, сделайте границу transparent, чтобы получить полный эффект.
border: 0.3rem dotted transparent;
Анимация
Чтобы восстановить анимацию границы, можно изменить начальный угол conic-gradient.
--angle: 0deg;
conic-gradient(
from var(--angle),
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
);
Благодаря @property это становится проще простого в браузерах, которые его поддерживают:
@property --angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
@keyframes rotate {
to {
--angle: 360deg;
}
}
В результате код будет выглядеть следующим образом:
Бонусный контент: border-image
Ранее мы уже рассказывали, как нарисовать градиентную рамку с помощью свойства CSS border-image.
Это позволяет упростить код, поскольку вам не нужно иметь дело с перекрывающимися фонами. Анимацию можно применять так же, как и раньше.
/* Create a border */
border: 0.5rem solid transparent;
/* Paint an image in the border */
border-image:
conic-gradient(
from var(--angle),
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
) 1
;
Однако при таком подходе некоторые функции перестанут работать:
border-imageне повторяетborder-radiusи всегда остается прямоугольной.- Если для свойства
border-image-sliceзадано значение fill, тоborder-imageрисуется не подbackground, а поверх него. Это может быть неудобно, если вы хотите сделать фон полупрозрачным.
В заключение
В CSS есть множество возможностей для анимации границ. В зависимости от ситуации вы можете выбрать один из них.