CSS-border с анимированным градиентом

Здесь речь пойдёт о применении градиентной заливки для CSS-border и её анимации для перемещения цветов градиента вдоль границ блока.

Самый очевидный способ реализации рамки с градиентом — установить какой-либо тип CSS-градиента в качестве значения CSS-свойству border-image:

div {
  border: 3em solid;
  border-image: linear-gradient(to right, green, yellow) 1;
}

See this code CSS Gradient Border on x.xhtml.ru.

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

Чтобы анимировать градиентную заливку CSS-border, нужно с помощью настраиваемого свойства (CSS-переменной) добавить градиенту угол (--angle) поворота, а для анимации изменять его значение в @keyframes.

div {
  --angle: 0deg;
  /* … */
  border-image: linear-gradient(var(--angle), green, yellow) 1;
  animation: 10s rotate linear infinite;
}

@keyframes rotate {
  to {
    --angle: 360deg;
  }
}

Используя CSS-переменную, можно заставить браузер правильно автоматически изменять её значение от 0 до 360 градусов, вместо того, чтобы добавлять отдельные ключевые кадры для каждого увеличения на 1 градус. Чтобы это работало, нужно зарегистрировать настраиваемое свойство с помощью правила @property.

@property --angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

Поскольку @property поддерживается только в Chromium, примеры ниже будут работать только в браузерах, основанных на нём. Для браузеров, которые его не поддерживают, можно добавить отдельные ключевые кадры для каждого шага, но здесь в примерах обойдёмся без усложнений.

See this code CSS Gradient Border (Animated) on x.xhtml.ru.

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

See this code CSS Rainbow Gradient Border (Animated, Attempt 1) on x.xhtml.ru.

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

Чтобы исправить это и сделать движение плавным, сперва можно подумать об использовании радиального градиента, но на самом деле тут нужен конический градиент:

конический градиент против радиального

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

div {
  /* … */
  border-image: conic-gradient(from var(--angle), red, yellow, lime, aqua, blue, magenta, red) 1;
}

Чтобы конец градиента красиво переходил в его начальный цвет, нужно в конце списка цветов повторить первый, здесь в примере это — red.

See this code CSS Rainbow Gradient Border (Animated) on x.xhtml.ru.

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