Анимация SVG-узоров без единой строки CSS

RedDeveloper
20.01.2023 18:07
Анимация SVG-узоров без единой строки CSS
Image Credit: @e14eak90

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

Проблема

Клиент, для которого я работал, хотел сделать свой логотип более заметным.

Клиент для которого я работал хотел сделать свой логотип более заметным

Поэтому я вспомнил свои предыдущие работы с использованием свойства CSS background. Самое замечательное в этом извечном свойстве CSS то, что вы можете анимировать его на месте, чтобы создать некоторое движение без использования трансформаций.

animation: 5s background-move linear infinite;
background: url('pattern.png') repeat-y 0;
background-size: contain;

@keyframes background-move {
   from { background-position: 0 0; }
   to { background-position: 0 72px }
}

Но как добиться такого же эффекта, используя только SVG-разметку? Например, я подумал, что было бы здорово, если бы я мог просто заставить "волновую" часть логотипа двигаться вертикально сверху вниз, чтобы создать иллюзию движения воды. Оказывается, это возможно, не написав ни строчки CSS!

Встречайте <animateTransform />

Я наткнулся на этот интересный маленький SVG-спецификатор, <animateTransform /> элемент . Из спецификации:

Элемент animateTransform анимирует атрибут трансформации на целевом элементе, что позволяет анимации управлять переводом, масштабированием, вращением и/или перекосом.

Похоже, это именно то, что нам нужно для достижения нашей анимации в отдельном SVG-файле. Самое интересное, что она работает с SVG <pattern /> элементами , что нам и понадобится. Итак, как же нам записать что-то подобное? Во-первых, давайте экспортируем наш SVG, а затем выберем элемент, который вы хотите заполнить повторяющимся узором. Мой элемент - простой <rect /> .

<svg width = "422" height = "72" viewBox = "0 0 211 36" xmlns = "http://www.w3.org/2000/svg">
  <path d = "M0 0.976562H6.72128V35.1164H0V0.976562Z"></path>
  <path d = "M13.4428 17.0699C13.4428 12.6805 12.7227 10.7296 12.7227 10.7296H18.9638C19.2063 11.6892 19.3669 12.6683 19.4439 13.6559H19.684C19.684 13.6559 22.0844 9.99805 27.3654 9.99805C33.6104 9.99805 37.4512 13.8997 37.4512 19.0207V35.1152H31.2062V19.0207C31.2062 15.3629 29.0496 13.1682 25.9252 13.1682C22.0844 13.1682 19.684 17.0699 19.684 17.0699V35.1152H13.4428V17.0699Z"></path>
  <path d = "M43.6869 17.0699C43.6869 12.6805 42.9668 10.7296 42.9668 10.7296H49.208C49.4505 11.6892 49.6111 12.6683 49.6881 13.6559H49.9281C49.9281 13.6559 52.3286 9.99805 57.6096 9.99805C63.8508 9.99805 67.6915 13.8997 67.6915 19.0207V35.1152H61.4503V19.0207C61.4503 15.3629 59.2899 13.1682 56.1693 13.1682C52.3286 13.1682 49.9281 17.0699 49.9281 17.0699V35.1152H43.6869V17.0699Z"></path>
  <path d = "M72.4941 22.9224C72.4941 15.6067 78.0152 9.99805 85.449 9.99805C92.8828 9.99805 98.4038 15.6067 98.4038 22.4347C98.4033 23.173 98.3228 23.909 98.1638 24.6294H78.9754C79.4555 29.2743 82.8161 32.6766 87.1369 32.6766C91.9378 32.6766 94.8184 28.2872 94.8184 28.2872L96.7235 29.9942C96.7235 29.9942 93.3781 35.8661 86.1767 35.8661C78.2552 35.8661 72.4941 29.9942 72.4941 22.9224ZM91.9264 20.987C91.9264 16.3422 88.8058 13.1836 85.449 13.1836C82.0921 13.1836 78.9716 16.3538 78.9716 20.987H91.9264Z"></path>
  <path d = "M102.98 17.0694C102.98 12.68 102.26 10.7291 102.26 10.7291H108.501C108.743 11.6887 108.904 12.6678 108.981 13.6554H109.221C109.221 13.6554 111.622 9.99757 116.903 9.99757C117.593 9.99749 117.916 9.94672 118.88 10.4505V12.5794L118.823 14.6308C117.732 14.3035 116.6 14.1392 115.462 14.1431C112.102 14.1431 109.221 17.0694 109.221 17.0694V35.1147H102.98V17.0694Z"></path>
  <path d = "M121.545 10.4512H127.07L132.671 26.5766H132.911L138.192 10.726H143.953L149.474 26.5766H149.714L154.995 10.726H159.076L150.693 35.1115H145.393L139.632 18.5294H139.392L133.871 35.1115H128.59L121.545 14.9025V10.4512Z"></path>
  <path d = "M160.518 22.9224C160.518 15.6067 166.039 9.99805 173.472 9.99805C180.906 9.99805 186.427 15.6067 186.427 22.4347C186.427 23.173 186.346 23.909 186.187 24.6294H166.984C167.464 29.2743 170.824 32.6766 175.145 32.6766C179.946 32.6766 182.827 28.2872 182.827 28.2872L184.732 29.9942C184.732 29.9942 181.413 35.8661 174.2 35.8661C166.279 35.8661 160.518 29.9942 160.518 22.9224ZM179.95 20.987C179.95 16.3422 176.829 13.1836 173.472 13.1836C170.116 13.1836 166.995 16.3538 166.995 20.987H179.95Z"></path>
  <rect x = "191" y = "0" width = "17.5" height = "36" fill = "currentColor"></rect>
</svg>
Похоже это именно то что нам нужно для достижения нашей анимации в отдельном SVG-файле

Используя этот элемент прямоугольника, мы можем применить к нему заливку узором, используя синтаксис SVG fill url fill='url(#wave)'. Удивительно, но узором может быть любой элемент SVG, включая другие контуры и многоугольники. Итак, давайте возьмем путь волны, который был экспортирован в наш SVG, и переконфигурируем его в элемент узора.

<svg width = "422" height = "72" viewBox = "0 0 211 36" xmlns = "http://www.w3.org/2000/svg">
  <defs>
    <pattern id = "wave" x = "11" y = "0" width = "18" height = "34" patternUnits = "userSpaceOnUse" patternTransform = "translate(0 0)">
      <path d = "M9.82,0H17V34H9.83c0-2.7,1.46-5,1.46-7.79,0-3-1.46-6.48-1.46-9.21,0-3.43,1.46-6,1.46-8.6C11.29,5.54,9.46,3.51,9.82,0Z"></path>
      <path d = "M6.13,34H0V0H6.13c-.34,4.62,1.6,5.35,1.6,8.09,0,3-1.6,6.18-1.6,8.91,0,3.43,1.6,6.3,1.6,8.91C7.76,28.69,6.34,31.23,6.13,34Z"></path>
    </pattern>
  </defs>
  <path d = "M0 0.976562H6.72128V35.1164H0V0.976562Z"></path>
  <path d = "M13.4428 17.0699C13.4428 12.6805 12.7227 10.7296 12.7227 10.7296H18.9638C19.2063 11.6892 19.3669 12.6683 19.4439 13.6559H19.684C19.684 13.6559 22.0844 9.99805 27.3654 9.99805C33.6104 9.99805 37.4512 13.8997 37.4512 19.0207V35.1152H31.2062V19.0207C31.2062 15.3629 29.0496 13.1682 25.9252 13.1682C22.0844 13.1682 19.684 17.0699 19.684 17.0699V35.1152H13.4428V17.0699Z"></path>
  <path d = "M43.6869 17.0699C43.6869 12.6805 42.9668 10.7296 42.9668 10.7296H49.208C49.4505 11.6892 49.6111 12.6683 49.6881 13.6559H49.9281C49.9281 13.6559 52.3286 9.99805 57.6096 9.99805C63.8508 9.99805 67.6915 13.8997 67.6915 19.0207V35.1152H61.4503V19.0207C61.4503 15.3629 59.2899 13.1682 56.1693 13.1682C52.3286 13.1682 49.9281 17.0699 49.9281 17.0699V35.1152H43.6869V17.0699Z"></path>
  <path d = "M72.4941 22.9224C72.4941 15.6067 78.0152 9.99805 85.449 9.99805C92.8828 9.99805 98.4038 15.6067 98.4038 22.4347C98.4033 23.173 98.3228 23.909 98.1638 24.6294H78.9754C79.4555 29.2743 82.8161 32.6766 87.1369 32.6766C91.9378 32.6766 94.8184 28.2872 94.8184 28.2872L96.7235 29.9942C96.7235 29.9942 93.3781 35.8661 86.1767 35.8661C78.2552 35.8661 72.4941 29.9942 72.4941 22.9224ZM91.9264 20.987C91.9264 16.3422 88.8058 13.1836 85.449 13.1836C82.0921 13.1836 78.9716 16.3538 78.9716 20.987H91.9264Z"></path>
  <path d = "M102.98 17.0694C102.98 12.68 102.26 10.7291 102.26 10.7291H108.501C108.743 11.6887 108.904 12.6678 108.981 13.6554H109.221C109.221 13.6554 111.622 9.99757 116.903 9.99757C117.593 9.99749 117.916 9.94672 118.88 10.4505V12.5794L118.823 14.6308C117.732 14.3035 116.6 14.1392 115.462 14.1431C112.102 14.1431 109.221 17.0694 109.221 17.0694V35.1147H102.98V17.0694Z"></path>
  <path d = "M121.545 10.4512H127.07L132.671 26.5766H132.911L138.192 10.726H143.953L149.474 26.5766H149.714L154.995 10.726H159.076L150.693 35.1115H145.393L139.632 18.5294H139.392L133.871 35.1115H128.59L121.545 14.9025V10.4512Z"></path>
  <path d = "M160.518 22.9224C160.518 15.6067 166.039 9.99805 173.472 9.99805C180.906 9.99805 186.427 15.6067 186.427 22.4347C186.427 23.173 186.346 23.909 186.187 24.6294H166.984C167.464 29.2743 170.824 32.6766 175.145 32.6766C179.946 32.6766 182.827 28.2872 182.827 28.2872L184.732 29.9942C184.732 29.9942 181.413 35.8661 174.2 35.8661C166.279 35.8661 160.518 29.9942 160.518 22.9224ZM179.95 20.987C179.95 16.3422 176.829 13.1836 173.472 13.1836C170.116 13.1836 166.995 16.3538 166.995 20.987H179.95Z"></path>
  <rect x = "191" y = "0" width = "17.5" height = "36" fill = "url(#wave)"></rect>
</svg>
Используя этот элемент прямоугольника мы можем применить к нему заливку узором используя

Похоже, мы вернулись к первоначальному дизайну! Отлично, значит, заливка узора сработала. Теперь нам осталось добавить немного движения. Пора увидеть наш <animateTransform /> в действии!

<svg width = "422" height = "72" viewBox = "0 0 211 36" xmlns = "http://www.w3.org/2000/svg">
  <defs>
    <pattern id = "header-wave" x = "11" y = "0" width = "18" height = "34" patternUnits = "userSpaceOnUse" patternTransform = "translate(0 0)">
      <animateTransform attributeType = "xml" attributeName = "patternTransform" type = "translate" from = "0 0" to = "0 34" begin = "0" dur = "5s" repeatCount = "indefinite"></animateTransform>
      <path d = "M9.82,0H17V34H9.83c0-2.7,1.46-5,1.46-7.79,0-3-1.46-6.48-1.46-9.21,0-3.43,1.46-6,1.46-8.6C11.29,5.54,9.46,3.51,9.82,0Z"></path>
      <path d = "M6.13,34H0V0H6.13c-.34,4.62,1.6,5.35,1.6,8.09,0,3-1.6,6.18-1.6,8.91,0,3.43,1.6,6.3,1.6,8.91C7.76,28.69,6.34,31.23,6.13,34Z"></path>
    </pattern>
  </defs>
  <path d = "M0 0.976562H6.72128V35.1164H0V0.976562Z"></path>
  <path d = "M13.4428 17.0699C13.4428 12.6805 12.7227 10.7296 12.7227 10.7296H18.9638C19.2063 11.6892 19.3669 12.6683 19.4439 13.6559H19.684C19.684 13.6559 22.0844 9.99805 27.3654 9.99805C33.6104 9.99805 37.4512 13.8997 37.4512 19.0207V35.1152H31.2062V19.0207C31.2062 15.3629 29.0496 13.1682 25.9252 13.1682C22.0844 13.1682 19.684 17.0699 19.684 17.0699V35.1152H13.4428V17.0699Z"></path>
  <path d = "M43.6869 17.0699C43.6869 12.6805 42.9668 10.7296 42.9668 10.7296H49.208C49.4505 11.6892 49.6111 12.6683 49.6881 13.6559H49.9281C49.9281 13.6559 52.3286 9.99805 57.6096 9.99805C63.8508 9.99805 67.6915 13.8997 67.6915 19.0207V35.1152H61.4503V19.0207C61.4503 15.3629 59.2899 13.1682 56.1693 13.1682C52.3286 13.1682 49.9281 17.0699 49.9281 17.0699V35.1152H43.6869V17.0699Z"></path>
  <path d = "M72.4941 22.9224C72.4941 15.6067 78.0152 9.99805 85.449 9.99805C92.8828 9.99805 98.4038 15.6067 98.4038 22.4347C98.4033 23.173 98.3228 23.909 98.1638 24.6294H78.9754C79.4555 29.2743 82.8161 32.6766 87.1369 32.6766C91.9378 32.6766 94.8184 28.2872 94.8184 28.2872L96.7235 29.9942C96.7235 29.9942 93.3781 35.8661 86.1767 35.8661C78.2552 35.8661 72.4941 29.9942 72.4941 22.9224ZM91.9264 20.987C91.9264 16.3422 88.8058 13.1836 85.449 13.1836C82.0921 13.1836 78.9716 16.3538 78.9716 20.987H91.9264Z"></path>
  <path d = "M102.98 17.0694C102.98 12.68 102.26 10.7291 102.26 10.7291H108.501C108.743 11.6887 108.904 12.6678 108.981 13.6554H109.221C109.221 13.6554 111.622 9.99757 116.903 9.99757C117.593 9.99749 117.916 9.94672 118.88 10.4505V12.5794L118.823 14.6308C117.732 14.3035 116.6 14.1392 115.462 14.1431C112.102 14.1431 109.221 17.0694 109.221 17.0694V35.1147H102.98V17.0694Z"></path>
  <path d = "M121.545 10.4512H127.07L132.671 26.5766H132.911L138.192 10.726H143.953L149.474 26.5766H149.714L154.995 10.726H159.076L150.693 35.1115H145.393L139.632 18.5294H139.392L133.871 35.1115H128.59L121.545 14.9025V10.4512Z"></path>
  <path d = "M160.518 22.9224C160.518 15.6067 166.039 9.99805 173.472 9.99805C180.906 9.99805 186.427 15.6067 186.427 22.4347C186.427 23.173 186.346 23.909 186.187 24.6294H166.984C167.464 29.2743 170.824 32.6766 175.145 32.6766C179.946 32.6766 182.827 28.2872 182.827 28.2872L184.732 29.9942C184.732 29.9942 181.413 35.8661 174.2 35.8661C166.279 35.8661 160.518 29.9942 160.518 22.9224ZM179.95 20.987C179.95 16.3422 176.829 13.1836 173.472 13.1836C170.116 13.1836 166.995 16.3538 166.995 20.987H179.95Z"></path>
  <rect x = "191" y = "0" width = "17.5" height = "36" fill = "url(#header-wave)"></rect>
</svg>

Ключевые моменты, на которые следует обратить внимание:

  • Атрибут patternTransform должен быть добавлен к элементу <pattern />. Здесь вы указываете браузеру, какой тип преобразования будет использоваться, в данном случае translate.
  • attributeName в элементе <animateTransform /> должен быть присоединен к атрибуту, который вы анимируете, в данном случае patternTransform .
  • Элемент <animateTransform /> должен существовать внутри элемента <pattern /> или любого другого элемента, который вы анимируете.

Окончательный результат

<svg width = "422" height = "72" viewBox = "0 0 211 36" xmlns = "http://www.w3.org/2000/svg">
  <defs>
    <pattern id = "wave" x = "11" y = "0" width = "18" height = "34" patternUnits = "userSpaceOnUse" patternTransform = "translate(0 0)">
      <animateTransform attributeType = "xml" attributeName = "patternTransform" type = "translate" from = "0 0" to = "0 34" begin = "0" dur = "5s" repeatCount = "indefinite"></animateTransform>
      <path d = "M9.82,0H17V34H9.83c0-2.7,1.46-5,1.46-7.79,0-3-1.46-6.48-1.46-9.21,0-3.43,1.46-6,1.46-8.6C11.29,5.54,9.46,3.51,9.82,0Z"></path>
      <path d = "M6.13,34H0V0H6.13c-.34,4.62,1.6,5.35,1.6,8.09,0,3-1.6,6.18-1.6,8.91,0,3.43,1.6,6.3,1.6,8.91C7.76,28.69,6.34,31.23,6.13,34Z"></path>
    </pattern>
  </defs>
  <path d = "M0 0.976562H6.72128V35.1164H0V0.976562Z"></path>
  <path d = "M13.4428 17.0699C13.4428 12.6805 12.7227 10.7296 12.7227 10.7296H18.9638C19.2063 11.6892 19.3669 12.6683 19.4439 13.6559H19.684C19.684 13.6559 22.0844 9.99805 27.3654 9.99805C33.6104 9.99805 37.4512 13.8997 37.4512 19.0207V35.1152H31.2062V19.0207C31.2062 15.3629 29.0496 13.1682 25.9252 13.1682C22.0844 13.1682 19.684 17.0699 19.684 17.0699V35.1152H13.4428V17.0699Z"></path>
  <path d = "M43.6869 17.0699C43.6869 12.6805 42.9668 10.7296 42.9668 10.7296H49.208C49.4505 11.6892 49.6111 12.6683 49.6881 13.6559H49.9281C49.9281 13.6559 52.3286 9.99805 57.6096 9.99805C63.8508 9.99805 67.6915 13.8997 67.6915 19.0207V35.1152H61.4503V19.0207C61.4503 15.3629 59.2899 13.1682 56.1693 13.1682C52.3286 13.1682 49.9281 17.0699 49.9281 17.0699V35.1152H43.6869V17.0699Z"></path>
  <path d = "M72.4941 22.9224C72.4941 15.6067 78.0152 9.99805 85.449 9.99805C92.8828 9.99805 98.4038 15.6067 98.4038 22.4347C98.4033 23.173 98.3228 23.909 98.1638 24.6294H78.9754C79.4555 29.2743 82.8161 32.6766 87.1369 32.6766C91.9378 32.6766 94.8184 28.2872 94.8184 28.2872L96.7235 29.9942C96.7235 29.9942 93.3781 35.8661 86.1767 35.8661C78.2552 35.8661 72.4941 29.9942 72.4941 22.9224ZM91.9264 20.987C91.9264 16.3422 88.8058 13.1836 85.449 13.1836C82.0921 13.1836 78.9716 16.3538 78.9716 20.987H91.9264Z"></path>
  <path d = "M102.98 17.0694C102.98 12.68 102.26 10.7291 102.26 10.7291H108.501C108.743 11.6887 108.904 12.6678 108.981 13.6554H109.221C109.221 13.6554 111.622 9.99757 116.903 9.99757C117.593 9.99749 117.916 9.94672 118.88 10.4505V12.5794L118.823 14.6308C117.732 14.3035 116.6 14.1392 115.462 14.1431C112.102 14.1431 109.221 17.0694 109.221 17.0694V35.1147H102.98V17.0694Z"></path>
  <path d = "M121.545 10.4512H127.07L132.671 26.5766H132.911L138.192 10.726H143.953L149.474 26.5766H149.714L154.995 10.726H159.076L150.693 35.1115H145.393L139.632 18.5294H139.392L133.871 35.1115H128.59L121.545 14.9025V10.4512Z"></path>
  <path d = "M160.518 22.9224C160.518 15.6067 166.039 9.99805 173.472 9.99805C180.906 9.99805 186.427 15.6067 186.427 22.4347C186.427 23.173 186.346 23.909 186.187 24.6294H166.984C167.464 29.2743 170.824 32.6766 175.145 32.6766C179.946 32.6766 182.827 28.2872 182.827 28.2872L184.732 29.9942C184.732 29.9942 181.413 35.8661 174.2 35.8661C166.279 35.8661 160.518 29.9942 160.518 22.9224ZM179.95 20.987C179.95 16.3422 176.829 13.1836 173.472 13.1836C170.116 13.1836 166.995 16.3538 166.995 20.987H179.95Z"></path>
  <rect x = "191" y = "0" width = "17.5" height = "36" fill = "url(#wave)"></rect>
</svg>

Вы только посмотрите на это! Наша волна пришла в движение. И это все, друзья. Теперь у вас есть полностью совместимый, автономный SVG-файл с включенной анимацией. Вам даже не пришлось писать ни одной строчки CSS. Надеюсь, вам понравилось читать так же, как мне писать! Спасибо.

Как настроить Tailwind CSS с React.js и Next.js?
Как настроить Tailwind CSS с React.js и Next.js?

03.02.2023 09:34

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

LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу

03.02.2023 08:15

Увеличение подматриц на единицу - LeetCode

Переключение светлых/темных тем
Переключение светлых/темных тем

02.02.2023 09:04

В Microsoft Training - Guided Project - Build a simple website with web pages, CSS files and JavaScript files, мы объясняем, как CSS можно использовать для установки светлых/темных стилей и добавления интерактивных функций с помощью JavaScript. Следуйте инструкциям, и вы готовы к работе!

Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения

02.02.2023 07:39

Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой статье мы расскажем, как создавать и управлять отношениями "многие ко многим" в Laravel с помощью методов присоединения и отсоединения вместо...

В PHP
В PHP

02.02.2023 07:16

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

Карта дорог Беладжар PHP Laravel
Карта дорог Беладжар PHP Laravel

01.02.2023 11:27

Laravel - это PHP-фреймворк, разработанный для облегчения разработки веб-приложений. Laravel предоставляет различные функции, упрощающие разработку приложений, такие как маршрутизация, ORM (Object-Relational Mapping), шаблонизация и аутентификация. Laravel имеет архитектуру на основе...