javascript

API CSS Paint

  • суббота, 14 июля 2018 г. в 03:31:03
https://habr.com/company/ruvds/blog/417075/
  • Разработка веб-сайтов
  • Веб-дизайн
  • JavaScript
  • CSS
  • Блог компании RUVDS.com


По словам автора материала, перевод которого мы публикуем сегодня, API CSS Paint — это невероятно интересная технология. Причём, речь идёт не только о её текущих возможностях, но и о представляемых ей явлениях, и о том, что её возникновение знаменует собой начало весьма примечательных изменений в мире CSS. Здесь мы поговорим об API CSS Paint и о причинах его появления, расскажем о том, как им пользоваться.



Что такое API CSS Paint?


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

API CSS Paint позволяет вызывать функцию paint() в ситуациях, когда в обычных условиях работа велась бы, например, с неким значением, описывающим какое-то изображение. Обычный пример подобного — это свойство background-image, при работе с которым можно использовать функцию url() для передачи системе ссылки на файл изображения:

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

API CSS Paint позволяет вызывать, вместо подобной функции, функцию paint(), и передавать ей так называемый ворклет (worklet), описанный средствами JavaScript. Ворклет можно воспринимать как некий фрагмент кода, который позволяет разработчику программно рисовать практически всё, что ему захочется. И, так как речь идёт о JavaScript, изображение можно сделать динамическим. Сам по себе этот API очень похож на API Canvas HTML5 и сейчас мы поговорим о том, как всё это работает.

Особенности API CSS Paint


Если сейчас у вас появилось ощущение, что звучит всё это хорошо, но выглядит сложно, и вы думаете о том, что вас вполне устраивает использование обычных изображений, учтите, что обычные изображения с приходом новой технологии актуальности не теряют. Использовать их, так же, как это делалось всегда — это совершенно нормально. То, что на горизонте появилось что-то новое, и, вероятно, перспективное, не означает, что всем тут же надо использовать это новое для решения всех существующих задач. Однако, обычные изображения статичны. Новый API привлекает идеей создания динамических изображений.

Поразмыслим о CSS-функции linear-gradient. Штука это очень мощная. Взгляните, например, на это. Но можете ли вы представить себе насколько легче было бы добиться такого же эффекта, формируемого наложением слоёв, если не пришлось бы использовать множество фоновых изображений? Однако, дело не только в этом. Если углубиться в API CSS Paint, можно разобраться с тем, как подобные изображения создаются во время выполнения программы, а это может оказаться весьма полезным (собственно говоря, этим мы и планируем тут заняться).

А как насчёт CSS-функции conic-gradient? Она, можно сказать, пока не поддерживается браузерами без полифилла. Использование нового API позволяет создавать конические градиенты, настраивать их параметры, которые не особенно отличаются от того, что есть в спецификации. Всё это значит, что на практике, пользуясь новым API, вы сможете создавать собственные нативные полифиллы. А это — просто замечательно.

Не забывайте о том, что всё это является частью более объёмной группы возможностей, известной как CSS Houdini. Вот что об этом написано в документации проекта: «Цель CSS-TAG Houdini Task Force (CSS Houdini) заключается в том, чтобы совместно разрабатывать механизмы, которые срывают покровы таинственности с технологий стилизации веб-страниц и построения их макетов».

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

Процесс стандартизации новых технологий может занять определённое время. Сначала делается предложение новой возможности CSS. Далее — пишется спецификация, происходят другие процессы. В итоге производители браузеров реализуют новые спецификации. И, так как разработчикам часто не терпится как можно скорее приступить к использованию новых возможностей, им приходится принимать во внимание то, что старые браузеры могут не поддерживать новшества, и то, что если некая спецификация пока не полностью реализована, она может, в ходе своего развития, серьёзно измениться. Пожалуй, нечего и говорить о типичных нюансах реализации разных технологий в различных браузерах. Проект Houdini может зайти довольно далеко в смягчении этих проблем, позволяя нам разрабатывать браузерную функциональность самостоятельно, пользоваться ей и спокойно ждать появления реализации тех или иных возможностей производителями браузеров. Вот пара материалов на эту тему. Первый посвящён сильным сторонам Houdini, а второй — использованию возможностей этого проекта для создания сложной анимации.

Поддержка API CSS Paint браузерами


Можно ли пользоваться API CSS Paint уже сегодня? На этот вопрос можно дать положительный ответ, хотя надо отметить, что поддерживают эту технологию пока далеко не все браузеры. Для того чтобы получить сведения о поддержке данного API, можете воспользоваться ресурсом caniuse.com.


Поддержка API CSS Paint различными браузерами (июль 2018 года)

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

Шаг №1: CSS


Напомним, что за формирование изображения при использовании API CSS Paint отвечают ворклеты — фрагменты JS-кода. Поэтому нам, для начала, нужно дать ворклету имя и вызывать его в CSS. Назовём его awesomePattern. В результате CSS-код будет выглядеть так:

section {
  background-image: url('fallback.png');
  background-image: paint(awesomePattern);
};

Предварительные приготовления завершены, но, пока не окажутся готовыми остальные части нашего примера, всё это работать не будет.

Шаг №2: JavaScript


Теперь нам нужно описать ворклет средствами JS. Здесь показано, как, в главном скрипте, осуществляется загрузка другого скрипта, реализующего необходимый нам функционал.

CSS.paintWorklet.addModule('patternWorklet.js');

На данном, этапе, опять же, ничего не происходит, так как самое интересное скрыто в файле patternWorklet.js.

В файле patternWorklet.js нам нужно зарегистрировать класс ворклета:

registerPaint('awesomePattern', Shape);

Здесь мы вызываем функцию registerPaint() и передаём ей то, что мы считаем ворклетом, в данном случае — это awesomePattern. Кроме того, мы передаём этой функции ссылку на класс, который мы ещё напишем, в данном случае — Shape. Эту команду надо добавить после объявления соответствующего класса. При объявлении и использовании классов нельзя полагаться на нечто вроде механизма подъёма объявлений функций. Прежде чем можно будет использовать класс, его необходимо объявить.

Далее, мы собираемся использовать синтаксис объявления классов ECMAScript 2015 и написать класс, который и будет рисовать фоновое изображение. Так как сейчас этот класс зарегистрирован в качестве класса ворклета, мы можем пользоваться в нём некоторыми специальными механизмами, которые будут доступны в нём автоматически.

class Shape {
  paint(ctx, geom, properties) {

    ctx.strokeStyle = 'white';
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.arc( 200, 200, 50, 0, 2*Math.PI);
    ctx.stroke();
    ctx.closePath();

  }
}

В коллбэке paint() имеются параметры ctx, geom и properties. Параметр ctx — это то же самое, что и контекст 2D-рендеринга, который можно получить от элемента <canvas>. Ну, это почти то же самое. Дело в том, что элемент <canvas> позволяет считывать пиксельные данные, а вот API CSS Paint такого не позволяет. Несмотря на отличия, используя ctx, мы можем применять те же методы вывода графических объектов, которые применяются при работе с элементом <canvas>. В этом примере с помощью функции arc() мы рисуем круг.

Первые два значения, передаваемые функции arc() — это координаты X и Y центра круга, в пикселях, относительно начала координат, расположенного в левом верхнем углу элемента. Однако мне хочется, чтобы круг оказался бы по центру элемента. Для решения этой задачи нам пригодится параметр geom. Он даёт доступ к объекту PaintSize, который представляет собой описание параметров изображения. В частности, обращаясь к нему, мы можем прочитать параметры width и height, а это — именно то, что нам нужно для того, чтобы отцентровать круг.

В результате мы придём к такому коду:

class Shape {
  paint(ctx, geom, properties) {
    
    let x = geom.width/2;
    let y = geom.height/2;

    ctx.strokeStyle = 'white';
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.arc(x, y, 50, 0, 2*Math.PI);
    ctx.stroke();
    ctx.closePath();
    
  }
}
registerPaint('awesomePattern', Shape);

Посмотреть работающий вариант примера можно на CodePen. Собственно говоря, вот что выводит этот код.


Круг, созданный средствами API CSS Paint

Всё это хорошо, но наш пример очень уж прост. Давайте, вместо обычного круга, нарисуем что-нибудь поинтереснее. Например — такую вот звёздочку — логотип сайта css-tricks.com.


Звёздочка, созданная средствами API CSS Paint

Вот проект на CodePen, который позволяет это сделать.

Когда будете смотреть JS-код этого проекта, обратите внимание на метод drawStar() и на множество функций, таких же, которые используются при работе с элементом <canvas>.

Шаг №3: пользовательские свойства CSS


Используя новую технологию, мы можем пойти гораздо дальше рисования кругов и звёздочек. Мы можем обратиться к мощным возможностям пользовательских свойств CSS (переменных). Они, кстати, даже сами по себе, весьма интересны. В нашем же случае они оказываются особенно полезными.

Предположим, мы хотим получить возможность менять размер или цвет ранее созданного логотипа. Эти параметры можно поместить в CSS-код в виде пользовательских свойств, после чего задействовать их в программе через третий параметр, передаваемый коллбэку paint(). Речь идёт о параметре properties.

Добавим в наш CSS-код свойство --star-scale, которое направлено на управление изменением размера изображения, и свойство --star-color, предназначенное для организации изменения цвета логотипа прямо в CSS. Вот что у нас получилось:

section {
  --star-scale: 2;
  --star-color: hsla(200, 50%, 50%, 1);
  background-image: paint(awesomePattern)
};

Теперь вернёмся в класс ворклета. Тут нам надо взаимодействовать с вышеописанными пользовательскими свойствами. Делается это с помощью метода inputProperties, который даёт нам доступ ко всем CSS-свойствам и назначенным им значениям.

static get inputProperties() { return ['--star-scale','--star-color']; }

Теперь работать с ними можно в методе paint():

const size = parseInt(properties.get('--shape-size').toString());

Естественно, полученные значения допустимо использовать в коде, ответственном за формирование изображения. Это ведёт к тому, что если мы, в CSS-коде, поменяем значение свойства --star-scale или --start-color, это тут же отразится на том, как будет выглядеть изображение.

image

Влияние пользовательских свойств CSS на готовое изображение

Этот функционал реализован в том же проекте на CodePen, который мы упоминали выше.

Кстати, стоит отметить, что при использовании нового API все обычные CSS-свойства, касающиеся настройки фона элементов, такие, как background-size и background-repeat, будут работать так же, как и раньше. Они не потеряли актуальности.

Итоги


API CSS Paint — это весьма мощная технология, возможности которой не ограничиваются созданием фоновых изображений.

Представьте, что у элемента должна быть особая граница, например, такая, которая видна не полностью, или двойная. Возможно, для достижения подобных эффектов вы обычно используете псевдоэлементы ::before или ::after, а может быть — специально настроенную тень box-shadow. Границы (и многое другое) можно реализовать средствами API CSS Paint и свойства border-image.

API CSS Paint собирает воедино множество замечательных механизмов, таких, как ворклеты, классы ECMAScript 2015 и возможности элемента <canvas>. Кроме того, оно даёт разработчику средства программного управления созданием изображений, основанные на JavaScript. Например, воспользовавшись механизмом событий, можно организовать обновление пользовательских свойств, а значит — самого изображения, как, например, сделано здесь, где событие click запускает процесс обновления свойств в функции requestAnimationFrame, что позволяет создавать анимацию каждый раз, когда пользователь щёлкает по кнопке. Причём, во внимание принимаются даже координаты указателя мыши при щелчке.

На первый взгляд всё это может показаться слегка запутанным, но давайте взглянем на некоторые другие части проекта Houdini, с которыми мы можем встретиться:

  • API CSS Layout позволяет разработчику делать нечто вроде display: layout('myCustomLayout'). Типичный пример — это создание собственных макетов в стиле библиотеки Masonry, но диапазон использования этой возможности гораздо шире.
  • API CSS Properties and Values даёт возможность задавать типы пользовательских свойств.
  • API CSS Animation Worklet выводит операции по обработке анимации за пределы главного потока, что должно выразиться в виде идеально плавных анимаций.

В результате можно сказать, что, буквально у нас на глазах, происходит появление технологий, которые открывают веб-разработчикам множество новых возможностей. Процессы их стандартизации и реализации в браузерах идут не так уж и быстро, но они, вполне возможно, окажут огромнейшее влияние на всё, что связано со стилизацией веб-страниц.

Уважаемые читатели! Какие направления применения API CSS Paint кажутся вам наиболее интересными?