JavaScript API для динамического создания изображений в сочетании с CSS

Для будущих студентов курса "JavaScript Developer. Professional" подготовили перевод материала.

Также приглашаем посетить открытый вебинар на тему
«Vue 3 — возможности новой версии одного из самых популярных фронтенд фреймворков». На занятии участники вместе с экспертом:

— рассмотрят ключевые отличия в синтаксисе vue2 от vue3;
— разберут, как работать с vue-router и VueX в новой версии фреймворка;
— попробуют создать проект на Vue 3 с нуля с помощью Vue-cli.

Присоединяйтесь!


Картинки вносят колорит в приложения. Однако, как мы все знаем, наличие большого количества изображений высокого разрешения влияет на время загрузки страницы. Для иллюстраций продуктов, сценариев и так далее, у нас нет другого выбора, кроме как добавить эти изображения и оптимизировать приложение путем их кэширования. Но если вам нужно геометрическое изображение в приложении, тогда не потребуется включать его в качестве дополнительного ресурса.

Вы можете программно генерировать геометрические изображения «на лету», используя API CSS Painting.

Давайте выясним, что это за API и как сгенерировать изображение с его помощью.

Введение в API CSS Painting

CSS Painting API позволяет разработчикам писать JavaScript-функции для отрисовки изображений в свойствах CSS, таких как background-image и border-image. Он предоставляет набор API, который дает разработчикам доступ к CSSOM. Это часть CSS Houdini (Houdini — коллекция новых API браузера, предоставляющая разработчикам доступ к самому CSS на более низком уровне).

Традиционный подход к добавлению изображения следующий:

div {
  background-image: url('assets/background.jpg);
}

С помощью CSS Painting API можно вызвать функцию paint() и передать ей ворклет (worklet), который написан с помощью JS, вместо вышеуказанного способа.

div {
  background-image: paint(background);
}

В этом случае рабочий процесс будет выглядеть следующим образом.

Возможно, вы столкнулись с неизвестными терминами в вышеуказанном разделе. Например, что это за worklets, о которых мы продолжаем говорить?

Вкратце, JavaScript-код, написанный для программной генерации изображения, называется Paint Worklet (Рабочий пакет для рисования). Worklet — это точка расширения в канале рендеринга браузера. Есть и другие типы ворклетов (worklets), помимо worklets для рисования, например, worklets анимации, макетирования и т.д.

Теперь давайте рассмотрим пошаговый подход к программной генерации изображения.

Использование API CSS Painting на практике

В этой статье мы рассмотрим, как создать пузырьковый фон.

Шаг 1: Добавить функцию paint() в CSS

Прежде всего, вам нужно добавить функцию paint() в свойство CSS, на котором должно быть изображение.

.bubble-background {
  width: 400px;
  height: 400px;
  background-image: paint(bubble);
}

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


Совет: поделитесь своими многократно используемыми компонентами между проектами, используя Bit (Github).

Bit упрощает совместное использование, документирование и повторное использование независимых компонентов между проектами. Используйте его, чтобы максимизировать повторное использование кода, сохранить единый дизайн, ускорить доставку и построить приложения, которые будут расширяться.

Bit поддерживает Node, TypeScript, React, Vue, Angular и многое другое.

Анимация. Пример: исследование компонентов React многоразового использования, совместно используемых на Bit.dev.


Шаг 2: Создание ворклета (worklet)

Ворклеты (worklets) должны храниться во внешнем JS-файле. Ворклет для рисования (paint worklet) будет class. Например: - class Bubble { …. } . Этот ворклет (worklet) необходимо зарегистрировать с помощью метода registerPaint().

class Bubble {
    paint(context, canvas, properties) {
        ........
    }
}
registerPaint('bubble', Bubble);

Первым параметром метода registerPaint() должна быть ссылка, которую вы включили в CSS.

Теперь нарисуем фон.

class Bubble {
    paint(context, canvas, properties) {
        const circleSize = 10; 
        const bodyWidth = canvas.width;
        const bodyHeight = canvas.height;

        const maxX = Math.floor(bodyWidth / circleSize);
        const maxY = Math.floor(bodyHeight / circleSize); 

        for (let y = 0; y < maxY; y++) {
          for (let x = 0; x < maxX; x++) {
            context.fillStyle = '#eee';
            context.beginPath();
            context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
            context.closePath();
            context.fill();
          }
       }
    }
}
registerPaint('bubble', Bubble);

Логика создания изображения находится внутри метода paint(). Вам понадобится немного знаний о создании холста, чтобы рисовать изображения, как описано выше. Обратитесь к документации по  Canvas API, если вы не знакомы с ним.

Шаг 3: Запустите ворклет (worklet)

Последним шагом будет запуск ворклета (worklet) в HTML-файле.

<div class="bubble-background"></div>
<script>
 CSS.paintWorklet.addModule('https://codepen.io/viduni94/pen/ZEpgMja.js');
</script>

Готово!

Вы программно сгенерировали изображение всего за 3 шага.

Сгенерированное изображение

Результат того, что мы создали, будет выглядеть следующим образом.

View in Editor (просмотр в редакторе)

Что еще мы можем сделать с помощью этого API CSS Painting?

Возможности CSS Painting API еще не исчерпаны. Есть другие вещи, которые вы можете с ним сделать.

1. Вы можете создавать динамические изображения

Например, можно динамически изменять цвет пузырьков. Для этого применяются переменные CSS. Чтобы применить CSS-переменные, браузер должен заранее знать, что мы их используем. Для этого мы можем задействовать метод inputProperties().

registerPaint('bubble', class {
  static get inputProperties() {
   return ['--bubble-size', '--bubble-color'];
  }

  paint() {
    /* ... */
  }
});

Переменные могут быть назначены с помощью третьего параметра, переданного в метод paint().

paint(context, canvas, properties) {
   const circleSize = parseInt(properties.get('--bubble-size').toString());
   const circleColor = properties.get('--bubble-color').toString();
   const bodyWidth = canvas.width;
   const bodyHeight = canvas.height;

   const maxX = Math.floor(bodyWidth / circleSize);
   const maxY = Math.floor(bodyHeight / circleSize); 

   for (let y = 0; y < maxY; y++) {
     for (let x = 0; x < maxX; x++) {
       context.fillStyle = circleColor;
       context.beginPath();
       context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
       context.closePath();
       context.fill();
     }
   }
}

2. Вы можете генерировать случайные изображения с помощью Math.random() в методе paint().

// CSS
body {
  width: 200px;
  height: 200px;
  background-image: paint(random);
}
// JS
function getRandomHexColor() {
  return '#'+ Math.floor(Math.random() * 16777215).toString(16)
}
class Random {
  paint(context, canvas) {
    const color1 = getRandomHexColor();
    const color2 = getRandomHexColor();

    const gradient = context.createLinearGradient(0, 0, canvas.width, 0);
    gradient.addColorStop(0, color1);
    gradient.addColorStop(1, color2);

    context.fillStyle = gradient;
    context.fillRect(0, 0, canvas.width, canvas.height);
  }
}
registerPaint('random', Random);

Если вы хотите узнать больше о том, как это реализовать, дайте мне знать в разделе комментариев ниже.

Это потрясающе, не так ли?

Но каждая хорошая вещь имеет хотя бы одну плохую сторону. Этот API имеет очень ограниченную поддержку в браузерах.

Поддержка браузеров

Источник: Can I Use
Источник: Can I Use

Большинство браузеров, включая Firefox, не поддерживают CSS Paint API. Только браузеры на основе Chrome и Chromium пока что имеют полную поддержку. Будем надеяться, что поддержка браузеров улучшится в ближайшем будущем.

Резюме

CSS Paint API чрезвычайно полезен для сокращения времени отклика сетевых запросов. Это достигается путем генерации некоторых изображений программно, а не путем их получения через сетевые запросы.

Кроме того, основные преимущества, на мой взгляд, следующие.

  • Возможность создавать полностью настраиваемые изображения в отличие от статических.

  • Создание изображений, не зависящих от разрешения (больше никаких изображений плохого качества на вашем сайте).

Важным моментом является то, что вы можете использовать полифил (polyfill) в качестве обходного пути для поддержки таких браузеров, как Firefox, которые еще не реализовали CSS Painting API.

Сообщите ваши мысли по этому поводу тоже. Спасибо за чтение!


Узнать подробнее о курсе "JavaScript Developer. Professional".

Смотреть открытый вебинар на тему «Vue 3 — возможности новой версии одного из самых популярных фронтенд фреймворков».