Java, UX, HTML, CSS, WEB-design

HTML5 SVG Fill Animation с помощью CSS3 и ванильного JavaScript

Краткое описание по статье HTML5 SVG Fill Animation с помощью CSS3 и ванильного JavaScript

Название: HTML5 SVG Fill Animation с помощью CSS3 и ванильного JavaScript . Краткое описание: ⭐ Марина Фер . Дата публикации: 25.01.2022 . Автор: Алишер Валеев .

Для чего создан сайт Novosti-Nedeli.ru

Данный сайт посвящен новостям мира и мира технологий . Также тут вы найдете руководства по различным девайсам.

Сколько лет сайту?

Возраст составляет 3 года


  • Марина Феррейра

  • 0 Комментарии

HTML5 SVG Fill Animation с помощью CSS3 и ванильного JavaScript

  • 12 минут чтения

  • JavaScript, CSS, HTML, SVG, анимация

Краткое резюме ↬

В этой статье вы узнаете, как создать анимированное отображение заметок с веб-сайта Awwwards. В нем обсуждается элемент круга HTML5 SVG, его свойства обводки и способы их анимации с помощью переменных CSS и ванильного JavaScript.

SVG означает Скалибруемый Вектор гraphics и является стандартным языком разметки на основе XML для векторной графики. Он позволяет рисовать пути, кривые и фигуры, определяя набор точек на 2D-плоскости. Кроме того, вы можете добавить свойства подергивания на эти пути (такие как обводка, цвет, толщина, заливка и т. д.) для создания анимации.

С апреля 2017 года модуль CSS Level 3 Fill and Stroke позволяет задавать цвета SVG и шаблоны заливки из внешней таблицы стилей вместо установки атрибутов для каждого элемента. В этом уроке мы будем использовать простой простой шестнадцатеричный цвет, но свойства заливки и обводки также принимают узоры, градиенты и изображения в качестве значений.

Примечание: При посещении веб-сайта Awwwards отображение анимированной заметки можно просмотреть только в том случае, если ширина браузера установлена ​​на 1024 пикселя или больше.

Примечание Отображение демонстрационной версии проекта
Демонстрация конечного результата (Большой превью)
  • 🕹 Демонстрация: проект отображения заметок
  • 📂 Репозиторий: Репозиторий отображения заметок

Еще после прыжка! Продолжить чтение ниже ↓

Структура файла

Начнем с создания файлов в терминале:

🌹  mkdir note-display
🌹  cd note-display
🌹  touch index.html styles.css scripts.js

HTML

Вот исходный шаблон, который связывает оба css и js файлы:

<html lang="en">
<head>
  <meta charset="UTF-8">

  <title>Note Display</title>

  <link rel="stylesheet" href="https://www.smashingmagazine.com/2019/01/html5-svg-fill-animation-css3-vanilla-javascript/./styles.css">
</head>
<body>
  <script src="./scripts.js"></script>
</body>
</html>

Каждый элемент примечания состоит из элемента списка: li который держит circle, note значение, и его label.

Элемент элемента списка и прямые дочерние элементы

Элемент элемента списка и его прямые дочерние элементы: .circle, .percent и .label. (Большой превью)

То .circle_svg — это элемент SVG, который заключает в себе два элемента . Первый — это путь, который нужно заполнить, а второй — заливка, которая будет анимирована.

SVG-элементы

SVG-элементы. Обертка SVG и круговые теги. (Большой превью)

То note разделены на целые и десятичные числа, поэтому к ним можно применять разные размеры шрифта. То label простой <span>. Итак, все это вместе выглядит так:

<li class="note-display">
  <div class="circle">
    <svg width="84" height="84" class="circle__svg">
      <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
      <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
    </svg>

    <div class="percent">
      <span class="percent__int">0.</span>
      <span class="percent__dec">00</span>
    </div>
  </div>

  <span class="label">Transparent</span>
</li>

То cx и cy Атрибуты определяют центральную точку оси x и оси y окружности. То r атрибут определяет его радиус.

Вы, наверное, заметили шаблон подчеркивания/дефиса в именах классов. Это БЭМ, что означает block, element и modifier. Это методология, которая делает ваши имена элементов более структурированными, организованными и семантическими.

Рекомендуемое чтение: Объяснение БЭМ и зачем оно вам нужно

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

Оболочка ненумерованного списка

Оболочка ненумерованного списка содержит четыре li дети (большой превью)

<ul class="display-container">
  <li class="note-display">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Transparent</span>
  </li>

  <li class="note-display">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Reasonable</span>
  </li>

  <li class="note-display">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Usable</span>
  </li>

  <li class="note-display">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Exemplary</span>
  </li>
</ul>

Вы, должно быть, спрашиваете себя, какие ярлыки Transparent, Reasonable, Usable и Exemplary значит. Чем больше вы будете знакомиться с программированием, тем больше поймете, что написание кода — это не только создание функционального приложения, но и гарантия того, что его можно будет поддерживать и масштабировать в долгосрочной перспективе. Это достигается только в том случае, если ваш код легко изменить.

«Акроним TRUE должен помочь решить, сможет ли код, который вы пишете, приспособиться к изменениям в будущем или нет».

Итак, в следующий раз спросите себя:

  • Transparent: Ясны ли последствия изменений кода?
  • Reasonable: Стоит ли оно того?
  • Usable: Смогу ли я повторно использовать его в неожиданных сценариях?
  • Exemplary: Представляет ли он высокое качество в качестве примера для будущего кода?

Примечание: «Практическое объектно-ориентированное проектирование в Ruby» Санди Мец объясняет TRUE наряду с другими принципами и способами их достижения с помощью шаблонов проектирования. Если вы еще не потратили время на изучение шаблонов проектирования, подумайте о том, чтобы добавить эту книгу к чтению перед сном.

CSS

Давайте импортируем шрифты и применим сброс ко всем элементам:


@import url('https://fonts.googleapis.com/css?family=Nixie+One|Raleway:200');

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

То box-sizing: border-box Свойство включает значения отступов и границ в общую ширину и высоту элемента, что упрощает вычисление его размеров.

Примечание: Для наглядного пояснения box-sizing, пожалуйста, прочтите «Сделайте свою жизнь проще с помощью CSS Box Sizing».

body {
  height: 100vh;
  color: #fff;
  display: flex;
  background: #3E423A;
  font-family: 'Nixie One', cursive;
}

.display-container {
  margin: auto;
  display: flex;
}

Совмещая правила display: flex в body и margin-auto в .display-container, дочерний элемент можно центрировать как по вертикали, так и по горизонтали. То .display-container элемент также будет flex-container; таким образом, его дочерние элементы будут размещены в одном ряду вдоль главной оси.

То .note-display элемент списка также будет flex-container. Так как детей для центрирования много, сделаем это через justify-content и align-items характеристики. Все flex-items будет сосредоточено вдоль cross и main ось. Если вы не уверены, что это такое, ознакомьтесь с разделом выравнивания в «Визуальном руководстве по основам CSS Flexbox».

.note-display {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0 25px;
}

Давайте применим обводку к кругам, установив правила stroke-width, stroke-opacity и stroke-linecap что в целом стиль инсульта в прямом эфире заканчивается. Далее давайте добавим цвет к каждому кругу:

.circle__progress {
  fill: none;
  stroke-width: 3;
  stroke-opacity: 0.3;
  stroke-linecap: round;
}

.note-display:nth-child(1) .circle__progress { stroke: #AAFF00; }
.note-display:nth-child(2) .circle__progress { stroke: #FF00AA; }
.note-display:nth-child(3) .circle__progress { stroke: #AA00FF; }
.note-display:nth-child(4) .circle__progress { stroke: #00AAFF; }

Для того, чтобы расположить percent элемент абсолютно, надо знать абсолютно к чему. То .circle элемент должен быть ссылкой, поэтому давайте добавим position: relative к этому.

Примечание: Для более глубокого визуального объяснения абсолютного позиционирования, пожалуйста, прочитайте «Как понять абсолютную позицию CSS раз и навсегда».

Другой способ центрирования элементов состоит в объединении top: 50%, left: 50% и transform: translate(-50%, -50%); которые располагают центр элемента в центре его родителя.

.circle {
  position: relative;
}

.percent {
  width: 100%;
  top: 50%;
  left: 50%;
  position: absolute;
  font-weight: bold;
  text-align: center;
  line-height: 28px;
  transform: translate(-50%, -50%);
}

.percent__int { font-size: 28px; }
.percent__dec { font-size: 12px; }

.label {
  font-family: 'Raleway', serif;
  font-size: 14px;
  text-transform: uppercase;
  margin-top: 15px;
}

К настоящему времени шаблон должен выглядеть так:

Готовый первоначальный шаблон

Готовые элементы и стили шаблона (большой предварительный просмотр)

Заполнить переход

Круговую анимацию можно создать с помощью двух свойств круга SVG: stroke-dasharray и stroke-dashoffset.

stroke-dasharray определяет штрих-промежуток в штрихе».

Может принимать до четырех значений:

  • Когда установлено только целое число (stroke-dasharray: 10), штрихи и пробелы имеют одинаковый размер;
  • Для двух значений (stroke-dasharray: 10 5), первый применяется к тире, второй к пробелам;
  • Третья и четвертая формы (stroke-dasharray: 10 5 2 и stroke-dasharray: 10 5 2 3) создаст штрихи и пробелы разных размеров.
Значения свойства Stroke dasharray
stroke-dasharray значения свойств (большой предварительный просмотр)

На изображении слева показано свойство stroke-dasharray устанавливается от 0 до 238 пикселей, что является длиной окружности круга.

Второе изображение представляет stroke-dashoffset свойство, которое смещает начало массива тире. Он также устанавливается от 0 до длины окружности.

Stroke dasharray и свойства dashoffset
stroke-dasharray и штрих-тиреофсет свойства (большой предварительный просмотр)

Для создания эффекта заполнения мы установим stroke-dasharray на длину окружности так, чтобы вся ее длина была заполнена большой чертой, а не пробелом. Мы также сместим его на то же значение, чтобы оно стало «скрытым». Тогда stroke-dashoffset будет обновлен до соответствующего значения ноты, заполняя штрих в соответствии с длительностью перехода.

Обновление свойств будет выполняться в сценариях через переменные CSS. Давайте объявим переменные и установим свойства:

.circle__progress--fill {
  --initialStroke: 0;
  --transitionDuration: 0;
  stroke-opacity: 1;
  stroke-dasharray: var(--initialStroke);
  stroke-dashoffset: var(--initialStroke);
  transition: stroke-dashoffset var(--transitionDuration) ease;
}

Чтобы установить начальное значение и обновить переменные, начнем с выбора всех .note-display элементы с document.querySelectorAll. То transitionDuration будет установлен на 900 миллисекунды.

Затем мы перебираем массив дисплеев, выбираем его .circle__progress.circle__progress--fill и извлеките r атрибут, установленный в HTML для расчета длины окружности. При этом мы можем установить начальное --dasharray и --dashoffset ценности.

Анимация будет происходить, когда --dashoffset переменная обновляется через 100 мс setTimeout:

const displays = document.querySelectorAll('.note-display');
const transitionDuration = 900;

displays.forEach(display => {
  let progress = display.querySelector('.circle__progress--fill');
  let radius = progress.r.baseVal.value;
  let circumference = 2 * Math.PI * radius;

  progress.style.setProperty('--transitionDuration', `${transitionDuration}ms`);
  progress.style.setProperty('--initialStroke', circumference);

  setTimeout(() => progress.style.strokeDashoffset = 50, 100);
});

Чтобы получить переход, начинающийся сверху, .circle__svg элемент должен быть повернут:

.circle__svg {
  transform: rotate(-90deg);
}
Переход свойств штриха
Переход свойств обводки (большой предварительный просмотр)

Теперь давайте посчитаем dashoffset value — относительно ноты. Значение ноты будет вставлено в каждую li элемент через атрибут data-*. То * можно переключить на любое имя, которое соответствует вашим потребностям, а затем его можно получить в JavaScript через набор данных элемента: element.dataset.*.

Примечание: Подробнее об атрибуте data-* можно прочитать в веб-документах MDN.

Наш атрибут будет называться «data-note”:

<ul class="display-container">
+ <li class="note-display" data-note="7.50">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Transparent</span>
  </li>

+ <li class="note-display" data-note="9.27">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Reasonable</span>
  </li>

+ <li class="note-display" data-note="6.93">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Usable</span>
  </li>

+ <li class="note-display" data-note="8.72">
    <div class="circle">
      <svg width="84" height="84" class="circle__svg">
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--path"></circle>
        <circle cx="41" cy="41" r="38" class="circle__progress circle__progress--fill"></circle>
      </svg>

      <div class="percent">
        <span class="percent__int">0.</span>
        <span class="percent__dec">00</span>
      </div>
    </div>

    <span class="label">Exemplary</span>
  </li>
</ul>

То parseFloat метод преобразует строку, возвращаемую display.dataset.note в число с плавающей запятой. То offset представляет процент, которого не хватает для достижения максимального балла. Итак, для 7.50 заметьте, у нас было бы (10 - 7.50) / 10 = 0.25, что означает circumference длина должна быть смещена на 25% от его стоимости:

let note = parseFloat(display.dataset.note);
let offset = circumference * (10 - note) / 10;

Обновление scripts.js:

const displays = document.querySelectorAll('.note-display');
const transitionDuration = 900;

displays.forEach(display => {
  let progress = display.querySelector('.circle__progress--fill');
  let radius = progress.r.baseVal.value;
  let circumference = 2 * Math.PI * radius;
+ let note = parseFloat(display.dataset.note);
+ let offset = circumference * (10 - note) / 10;

  progress.style.setProperty('--initialStroke', circumference);
  progress.style.setProperty('--transitionDuration', `${transitionDuration}ms`);

+ setTimeout(() => progress.style.strokeDashoffset = offset, 100);
});
Переход свойств штриха до значения ноты
Переход свойств штриха к значению ноты (большой предварительный просмотр)

Прежде чем мы двинемся дальше, давайте извлечем переход стока в его собственный метод:

const displays = document.querySelectorAll('.note-display');
const transitionDuration = 900;

displays.forEach(display => {
- let progress = display.querySelector('.circle__progress--fill');
- let radius = progress.r.baseVal.value;
- let circumference = 2 * Math.PI * radius;
  let note = parseFloat(display.dataset.note);
- let offset = circumference * (10 - note) / 10;

- progress.style.setProperty('--initialStroke', circumference);
- progress.style.setProperty('--transitionDuration', `${transitionDuration}ms`);

- setTimeout(() => progress.style.strokeDashoffset = offset, 100);

+ strokeTransition(display, note);
});

+ function strokeTransition(display, note) {
+   let progress = display.querySelector('.circle__progress--fill');
+   let radius = progress.r.baseVal.value;
+   let circumference = 2 * Math.PI * radius;
+   let offset = circumference * (10 - note) / 10;

+   progress.style.setProperty('--initialStroke', circumference);
+   progress.style.setProperty('--transitionDuration', `${transitionDuration}ms`);

+   setTimeout(() => progress.style.strokeDashoffset = offset, 100);
+ }

Примечание Увеличение значения

Есть еще нотный переход от 0.00 к значению ноты, которое будет построено. Первое, что нужно сделать, это разделить целые и десятичные значения. Мы будем использовать строковый метод split() (он принимает аргумент, определяющий, где будет разорвана строка, и возвращает массив, содержащий обе разорванные строки). Они будут преобразованы в числа и переданы в качестве аргументов increaseNumber() функцию, наряду с display элемент и флаг, указывающий, является ли он целым числом или десятичным числом.

const displays = document.querySelectorAll('.note-display');
const transitionDuration = 900;

displays.forEach(display => {
  let note = parseFloat(display.dataset.note);
+ let [int, dec] = display.dataset.note.split('.');
+ [int, dec] = [Number(int), Number(dec)];

  strokeTransition(display, note);

+ increaseNumber(display, int, 'int');
+ increaseNumber(display, dec, 'dec');
});

в increaseNumber() функции, мы выбираем либо .percent__int или .percent__dec элемент, в зависимости от className, а также в том случае, если вывод должен содержать десятичную точку или нет. Мы установили наш transitionDuration к 900ms. Теперь, чтобы оживить число от 0 до 7, например, продолжительность должна быть разделена на ноту 900 / 7 = 128.57ms. Результат показывает, сколько времени займет каждая итерация увеличения. Это означает, что наша setInterval будет стрелять каждый 128.57ms.

Установив эти переменные, давайте определим setInterval. То counter переменная будет добавлена ​​к элементу в виде текста и будет увеличиваться на каждой итерации:

function increaseNumber(display, number, className) {
  let element = display.querySelector(`.percent__${className}`),
      decPoint = className === 'int' ? '.' : '',
      interval = transitionDuration / number,
      counter = 0;

  let increaseInterval = setInterval(() => {
    element.textContent = counter + decPoint;
    counter++;
  }, interval);
}
Бесконечное увеличение счетчика
Бесконечное увеличение счетчика (большой предварительный просмотр)

Прохладный! Это увеличивает значения, но это делает это навсегда. Нам нужно очистить setInterval когда ноты достигают желаемого значения. Это делается с clearInterval функция:

function increaseNumber(display, number, className) {
  let element = display.querySelector(`.percent__${className}`),
      decPoint = className === 'int' ? '.' : '',
      interval = transitionDuration / number,
      counter = 0;

  let increaseInterval = setInterval(() => {
+   if (counter === number) { window.clearInterval(increaseInterval); }

    element.textContent = counter + decPoint;
    counter++;
  }, interval);
}
Готовый проект отображения заметок
Готовый проект (Большой превью)

Теперь число обновляется до значения ноты и очищается с помощью clearInterval() функция.

Это в значительной степени все для этого урока. Я надеюсь, что вам понравилось!

Если вам хочется создать что-то более интерактивное, ознакомьтесь с моим учебным пособием по игре на память, созданным с помощью ванильного JavaScript. Он охватывает основные концепции HTML5, CSS3 и JavaScript, такие как позиционирование, перспектива, переходы, Flexbox, обработка событий, тайм-ауты и троичные элементы.

Удачного кодирования! 🌹

Сокрушительная редакция
(дм, ра, ил)




Source: https://smashingmagazine.com

Заключение

Вы ознакомились с статьей — HTML5 SVG Fill Animation с помощью CSS3 и ванильного JavaScript

Пожалуйста оцените статью, и напишите комментарий.

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован.

Кнопка «Наверх»