Новые возможности в Chrome 65
CSS Paint API (также известный как «CSS Custom Paint» или «Рабочая программа рисования Houdini») включен по умолчанию, начиная с Chrome 65. Что это такое? Что вы можете с этим сделать? И как это работает? Ну, читайте дальше, ладно…
CSS Paint API позволяет программно генерировать изображение всякий раз, когда свойство CSS ожидает изображение. Такие свойства, как background-image
или border-image
обычно используются с url()
для загрузки файла изображения или со встроенными функциями CSS, такими как linear-gradient()
. Вместо их использования теперь вы можете использовать paint(myPainter)
для ссылки на рабочий файл рисования .
Написание программы рисования
Чтобы определить рабочую программу рисования под названием myPainter
, нам нужно загрузить файл рабочей программы рисования CSS с помощью CSS.paintWorklet.addModule('my-paint-worklet.js')
. В этом файле мы можем использовать функцию registerPaint
для регистрации класса рисования:
class MyPainter {
paint(ctx, geometry, properties) {
// ...
}
}
registerPaint('myPainter', MyPainter);
Внутри обратного вызова paint()
мы можем использовать ctx
так же, как и CanvasRenderingContext2D
, известный нам из <canvas>
. Если вы знаете, как рисовать в <canvas>
, вы можете рисовать в Paint! geometry
сообщает нам ширину и высоту холста, который находится в нашем распоряжении. properties
которые я объясню позже в этой статье.
В качестве вводного примера давайте напишем программу рисования шахматной доски и используем ее в качестве фонового изображения <textarea>
. (Я использую текстовую область, потому что по умолчанию ее размер можно изменить.):
<!-- index.html -->
<!doctype html>
<style>
textarea {
background-image: paint(checkerboard);
}
</style>
<textarea></textarea>
<script>
CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
paint(ctx, geom, properties) {
// Use `ctx` as if it was a normal canvas
const colors = ['red', 'green', 'blue'];
const size = 32;
for(let y = 0; y < geom.height/size; y++) {
for(let x = 0; x < geom.width/size; x++) {
const color = colors[(x + y) % colors.length];
ctx.beginPath();
ctx.fillStyle = color;
ctx.rect(x * size, y * size, size, size);
ctx.fill();
}
}
}
}
// Register our class under a specific name
registerPaint('checkerboard', CheckerboardPainter);
Если вы раньше использовали <canvas>
, этот код должен показаться вам знакомым. Смотрите живую демонстрацию здесь.
Отличие от использования обычного фонового изображения заключается в том, что шаблон будет перерисовываться по требованию всякий раз, когда пользователь изменяет размер текстовой области. Это означает, что фоновое изображение всегда имеет такой размер, какой ему необходимо, включая компенсацию для дисплеев с высокой плотностью изображения.
Это довольно круто, но это также довольно статично. Захотим ли мы писать новый ворлет каждый раз, когда нам нужен тот же узор, но с квадратами разного размера? Ответ — нет!
Параметризация вашего рабочего листа
К счастью, инструмент рисования может получить доступ к другим свойствам CSS, и именно здесь в игру вступают дополнительные properties
параметров. Присвоив классу статический атрибут inputProperties
, вы можете подписаться на изменения любого свойства CSS, включая пользовательские свойства. Значения будут предоставлены вам через параметр properties
.
<!-- index.html -->
<!doctype html>
<style>
textarea {
/* The paint worklet subscribes to changes of these custom properties. */
--checkerboard-spacing: 10;
--checkerboard-size: 32;
background-image: paint(checkerboard);
}
</style>
<textarea></textarea>
<script>
CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
// inputProperties returns a list of CSS properties that this paint function gets access to
static get inputProperties() { return ['--checkerboard-spacing', '--checkerboard-size']; }
paint(ctx, geom, properties) {
// Paint worklet uses CSS Typed OM to model the input values.
// As of now, they are mostly wrappers around strings,
// but will be augmented to hold more accessible data over time.
const size = parseInt(properties.get('--checkerboard-size').toString());
const spacing = parseInt(properties.get('--checkerboard-spacing').toString());
const colors = ['red', 'green', 'blue'];
for(let y = 0; y < geom.height/size; y++) {
for(let x = 0; x < geom.width/size; x++) {
ctx.fillStyle = colors[(x + y) % colors.length];
ctx.beginPath();
ctx.rect(x*(size + spacing), y*(size + spacing), size, size);
ctx.fill();
}
}
}
}
registerPaint('checkerboard', CheckerboardPainter);
Теперь мы можем использовать один и тот же код для всех типов шахматных досок. Но что еще лучше, теперь мы можем зайти в DevTools и поиграть со значениями, пока не найдем правильный вид.
Браузеры, которые не поддерживают работу с краской
На момент написания только Chrome реализовал работу с краской. Хотя есть положительные сигналы от всех других поставщиков браузеров, особого прогресса не наблюдается. Чтобы быть в курсе событий, проверьте «Готов ли Гудини?» регулярно. А пока обязательно используйте прогрессивное улучшение, чтобы ваш код продолжал работать, даже если нет поддержки рисования. Чтобы убедиться, что все работает так, как ожидалось, вам необходимо настроить свой код в двух местах: CSS и JS.
Обнаружить поддержку рисования в JS можно, проверив объект CSS
: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); }
Что касается CSS, у вас есть два варианта. Вы можете использовать @supports
:
@supports (background: paint(id)) {
/* ... */
}
Более компактный трюк — использовать тот факт, что CSS делает недействительным и впоследствии игнорирует все объявление свойства, если в нем есть неизвестная функция. Если вы укажете свойство дважды — сначала без рисования, а затем с рисованием — вы получите прогрессивное улучшение:
textarea {
background-image: linear-gradient(0, red, blue);
background-image: paint(myGradient, red, blue);
}
В браузерах с поддержкой рисования второе объявление background-image
перезапишет первое. В браузерах без поддержки рисования второе объявление недействительно и будет отброшено, оставив в силе первое объявление.
CSS Paint Полифилл
Для многих целей также можно использовать CSS Paint Polyfill , который добавляет поддержку CSS Custom Paint и Paint Worklets в современные браузеры.
Варианты использования
Существует множество вариантов использования программ рисования, некоторые из них более очевидны, чем другие. Один из наиболее очевидных — использование Paint Worklet для уменьшения размера DOM. Часто элементы добавляются исключительно для украшения с помощью CSS. Например, в Material Design Lite кнопка с эффектом пульсации содержит 2 дополнительных элемента <span>
для реализации самой пульсации. Если у вас много кнопок, это может привести к увеличению количества элементов DOM и привести к снижению производительности на мобильных устройствах. Если вместо этого вы реализуете эффект ряби с помощью рисования , у вас останется 0 дополнительных элементов и только один рисование. Кроме того, у вас есть что-то, что гораздо проще настроить и параметризовать.
Еще одним преимуществом использования Paint Worklet является то, что в большинстве сценариев решение, использующее Paint Worklet, имеет небольшой размер в байтах. Конечно, есть компромисс: ваш код рисования будет запускаться всякий раз, когда изменяется размер холста или любой из параметров. Поэтому, если ваш код сложен и занимает много времени, это может привести к зависаниям. Chrome работает над удалением рабочих процессов рисования из основного потока, чтобы даже длительные рабочие процессы рисования не влияли на скорость реагирования основного потока.
На мой взгляд, самая захватывающая перспектива заключается в том, что работа с краской позволяет эффективно использовать функции CSS, которых пока нет в браузере. Одним из примеров может быть полифиллинг конических градиентов до тех пор, пока они не появятся в Chrome изначально. Другой пример: на собрании CSS было решено, что теперь вы можете использовать несколько цветов границ. Пока эта встреча еще продолжалась, мой коллега Ян Килпатрик написал полифилл для этого нового поведения CSS, используя ворлет рисования.
Мышление вне «коробки»
Большинство людей начинают думать о фоновых изображениях и изображениях границ, когда узнают о работе с краской. Еще один менее интуитивно понятный вариант использования рисования — это mask-image
, позволяющая придать элементам DOM произвольную форму. Например, бриллиант :
mask-image
принимает изображение размером с элемент. Области, где изображение маски прозрачно, элемент является прозрачным. Области, где изображение маски непрозрачно, элемент непрозрачен.
Теперь в Chrome
Работа с краской уже давно присутствует в Chrome Canary. В Chrome 65 он включен по умолчанию. Попробуйте новые возможности, которые открывает работа с краской, и покажите нам, что вы создали! Для большего вдохновения взгляните на коллекцию Винсента Де Оливейры .