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

Примечание. Исходный код демонстрации, обсуждаемой во второй половине этой статьи, можно найти на GitLab.

вступление

Как я уже упоминал в своей недавней статье об анимации холста внутри компонентов React, я люблю холст HTML. Так что я был очень взволнован, узнав о новых API-интерфейсах CSS Houdini, когда читал короткую статью об этом на css-tricks.com, написанную Стивеном Фулгхамом.

Основная причина моего восхищения заключается в том, что API рисования позволяет создавать пользовательские изображения CSS путем рисования на PaintRenderingContext2D (который в значительной степени является точной копией 2D-контекста, который мы рисуем, когда используем обычный Canvas API - за исключением небольшого набора функций).

Используя API рисования, мы можем программно рисовать изображения и использовать эти изображения в нашем CSS. При рисовании мы можем получать параметры с информацией, поступающей из DOM и применяемых таблиц стилей.

Веб-документы MDN описывают это так:

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

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



В этой статье мы рассмотрим CSS Painting APIWorklets).

Важное примечание. В целом CSS Houdini все еще является экспериментальной технологией. Но, как упоминалось ранее, большинство браузеров реализуют это или серьезно рассматривают возможность реализации. Google Chrome - это ранний адаптер, который поддерживает Painting API начиная с версии 65, так что это браузер, который мы будем использовать сегодня.

CSS Painti API-интерфейс

Используя этот API, мы можем программно рисовать изображения и использовать эти изображения в нашем CSS. Вот что мы создадим:

Как ни странно, это три элемента DIV и только три элемента DIV.

Об этом свидетельствует наш файл index.html:

«Стилизация» (рисование…) фона трех панелей выполняется программно с помощью API рисования. Все три панели нарисованы одной и той же функцией.

Давайте посмотрим на CSS-класс pane в нашей таблице стилей:

Мы рисуем что-то, называемое pane, в строке 2. Это требует объяснения, и мы скоро его рассмотрим.

Важно отметить, что функция рисования не выполняется только один раз. Он выполняется - и перерисовывает изображение - всякий раз, когда движок рендеринга браузера дает ему инструкции сделать это. Примеры этого: когда пользователь изменяет размер окна браузера или когда другие свойства CSS элемента DIV изменяются, и элемент DIV получает другое измерение.

Поскольку наша функция будет «подключена» к механизму рендеринга, это очень эффективная и недорогая операция.

Кроме того, стоит упомянуть, что все наши панели имеют разный размер шрифта (имейте это в виду, мы еще вернемся к нему позже). И мы видим, что используются две пользовательские переменные CSS:

  • ‑‑dot‑spacing
  • ‑‑pane‑color

В переменных CSS нет ничего нового. Они существуют с 2014/2016 (соответственно Firefox / Google Chrome). Но один из новых API-интерфейсов CSS Houdini, называемый API свойств и значений CSS, позволяет нам зарегистрировать эти пользовательские переменные, чтобы браузер узнал о них больше. удобно.

Внутри нашей таблицы стилей мы можем зарегистрировать их следующим образом:

Обратите внимание, что мы также могли сделать это на JavaScript. Результат будет таким же.

Так зачем мы это делаем? Теперь наш браузер и его движок визуализации знают подробности об этих свойствах. Он знает, что ‑‑pane‑color содержит значение цвета и что значение по умолчанию - «# 646464». И ‑‑dot‑spacing содержит значение длины, значение по умолчанию - «5 пикселей».

Две наши новые переменные теперь называются зарегистрированными пользовательскими переменными.

Вернемся к этой строке:

background-image: paint(pane);

API рисования позволяет нам рисовать изображение. Функция paint получает один параметр. Этот параметр представляет собой класс JavaScript, зарегистрированный как Paint в файле с именем worklet.js:

Но! Этот код не может быть выполнен в нашей обычной среде выполнения JavaScript. Он должен выполняться внутри так называемого - отсюда и название файла - Worklet:

«Интерфейс Worklet - это облегченная версия Web Workers, которая дает разработчикам доступ к низкоуровневым частям конвейера рендеринга. С помощью Worklets вы можете запускать код JavaScript и WebAssembly для рендеринга графики или обработки звука там, где требуется высокая производительность ».

Мы можем убедиться, что Worklet будет выполнен, добавив следующую строку в наш обычный файл JavaScript (main.js), который загружается внутри index.html, например:

// main.js
CSS.paintWorklet.addModule("worklet.js");

Если этот вызов возвращает ошибку, ваш браузер не поддерживает Painting API.

Теперь наш класс Paint «Pane» зарегистрирован под именем «pane», и мы можем использовать его в нашем CSS, как мы видели ранее:

background-image: paint(pane);

Подробная информация о панели класса Paint

Давайте подробно рассмотрим класс Paint внутри worklet.js:

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

Значение, возвращаемое contextOptions, указывает, что мы хотим использовать прозрачность в нашем холсте.

И, наконец, в строке 10 - функция paint. В этой функции мы сделаем фактический рисунок. В нашем случае он получает три параметра:

  1. ctx: 2D-контекст нашего холста. Это должно стать сигналом, если вы знакомы с обычным элементом HTML Canvas.
  2. size: экземпляр PaintSize с двумя свойствами: .width и .height. Это вычисленные размеры элемента HTML, для которого мы рисуем изображение. Включая отступы, если они установлены.
  3. styleMap: доступное только для чтения представление блока CSS-декларации (источник). Это экземпляр StylePropertyMapReadOnly и содержит значения только тех свойств, которые мы определили внутри статической функции inputProperties.

Подробнее о последнем параметре вы можете прочитать об API типизированной объектной модели CSS и / или прочитать об интерфейсе StylePropertyMapReadOnly.

Совет. Вы можете получить полный StylePropertyMapReadOnly (содержащий все вычисленные стили CSS) для любого элемента HTML в DOM, вызвав computedStyleMap в браузерах, которые его поддерживают:

const styleMap =
  document.getElementById('myElement').computedStyleMap();

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

Рисование актуального образа

Вернемся к логике нашей маленькой демонстрации. Осталось только содержимое тела нашей функции рисования.

Мы могли бы начать с простого рисования заполненного прямоугольника в качестве фонового изображения (вы должны распознать команды рисования на обычном холсте HTML):

… Который будет выглядеть так:

Обратите внимание, как мы использовали наше настраиваемое свойство CSS ‑‑pane‑color для динамической установки стиля заливки.

Используя инструменты разработчика нашего браузера, мы можем даже обновить значение цвета, и фоновое изображение будет мгновенно перекрашено!

Если мы обновим нашу функцию рисования с помощью более причудливой логики (вы можете посмотреть подробности в файле worklet.js в репозитории), наше фоновое изображение будет выглядеть так:

CSS переходы

Обратите внимание на последовательность точек в правом нижнем углу. Расстояние между этими точками определяется значением настраиваемого свойства CSS ‑‑dot‑spacing, которое имеет значение по умолчанию «5 пикселей».

Давайте немного повеселимся, добавив к этому свойству переход. Мы также увеличиваем значение расстояния между точками, когда наводим курсор на наш элемент .pane:

… Что приводит к плавной анимации при наведении курсора на наши элементы:

Он показывает, насколько производительна наша настраиваемая функция рисования и что она может выполняться более 60 раз в секунду.

Причина, по которой мы можем добавить переход к пользовательской переменной CSS, заключается в том, что мы зарегистрировали свойство ранее (см. Строки 1–5 в сути).

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

Заключение

Я нахожу Houdini Painting API не только интересным, но и простым для понимания и мощным (производительным). Я полон идей по использованию этой новой функции, но мне нужно набраться терпения и подождать, пока все основные браузеры не поддержат ее, прежде чем мы сможем рассмотреть возможность ее использования в производственной среде.

Спасибо за ваше время!