Рассмотрим несколько способов анимации границы в CSS.
Установка границ
Существует несколько методов установки границы элемента: border
, outline
и box-shadow
. Как подробно описано в книге Стефани Эклс «3 метода CSS для добавления границ элементов» , каждый подход имеет свои преимущества и недостатки, особенно когда дело касается анимации границ. Основная причина не использовать правильную border
CSS — для целей анимации.
Недавно мое внимание привлекла статья «Фантастическая CSS-анимация границ» , в которой автор Коко исследовал дополнительные возможности. Вставляя сгенерированный контент с помощью ::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
для заполненияborder-image
рисуется не под установленнымbackground
, а сверху. Это может быть проблематично, если вы хотите, чтобы фон был полупрозрачным.
В заключение
В CSS существует множество возможностей для анимации границ. В зависимости от варианта использования вы можете использовать тот или иной вариант.