Анимация 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. Надеюсь, вам понравилось читать так же, как мне писать! Спасибо.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?

20.08.2023 18:21

Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в 2023-2024 годах? Или это полная лажа?".

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией

20.08.2023 17:46

В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.

Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox

19.08.2023 18:39

Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в частности, магию поплавков и гибкость flexbox.

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest

19.08.2023 17:22

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

Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️

18.08.2023 20:33

Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий их языку и культуре.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL

14.08.2023 14:49

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