От автора: современные веб-приложения сильно загружены изображениями. Они составляют львиную долю загружаемых байтов. Оптимизируя их, вы можете лучше использовать их производительность. Если вы используете в качестве фоновых изображений геометрические фигуры, то есть альтернатива. Вы можете использовать CSS Paint API для программного создания фонов.
В этом руководстве мы рассмотрим возможности CSS Paint API и то, как мы можем использовать его для создания динамических фонов, не зависящих от разрешения. В результате мы должны получить это:
Настройка проекта
Давайте начнем с создания нового файла index.html и заполним его следующим:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>CSS Paint API</title> <link rel="stylesheet" href="styles.css" /> </head> <body> <textarea class="pattern"></textarea> <script> if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('pattern.js'); } </script> </body> </html>
Есть несколько вещей, на которые стоит обратить внимание:
В строке 13 мы загружаем новый рабочий лист для отрисовки. Глобальная поддержка в настоящее время составляет около 63%. Из-за этого мы должны сначала проверить, поддерживается ли paintWorklet.
Я использую textarea для демонстрационных целей, чтобы мы могли видеть, как изменение размера холста вызывает перерисовку шаблона.
Наконец, вам нужно создать pattern.js, который зарегистрирует рабочий лист — а также styles.css, где мы можем определить пару стилей.
Что такое рабочий лист?
Рабочий лист для отрисовки — это класс, который определяет, что следует отрисовывать на холсте. Они работают аналогично элементу canvas. Если вы уже знаете о нем, код будет выглядеть для вас знакомо. Однако они не идентичны на 100%. Например, методы рендеринга текста еще не поддерживаются в рабочих листах.
Пока давайте также определим стили CSS. Здесь мы ссылаемся на то, что хотим использовать рабочий лист:
.pattern { width: 250px; height: 250px; border: 1px solid #000; background-image: paint(pattern); }
Я добавил черную рамку, чтобы мы могли лучше видеть textarea. Чтобы сослаться на рабочий лист, вы должны передать paint(worklet-name) в качестве значения background-image. Но откуда взялось pattern? Мы еще не определили его, поэтому давайте сделаем это на следующем шаге.
Определение рабочего листа
Откройте свой pattern.js и добавьте в него следующий код:
class Pattern { paint(context, canvas, properties) { } } registerPaint('pattern', Pattern);
Здесь вы можете зарегистрировать свой рабочий лист с помощью метода registerPaint. Вы можете ссылаться на первый параметр в CSS, который вы определили здесь. Второй параметр — это класс, который определяет, что следует рисовать на холсте. У метода paint есть три параметра:
context: Возвращает объект PaintRenderingContext2D, который реализует подмножество CanvasRenderingContext2DAPI.
canvas: Это наш холст, объект PaintSize, который имеет только два свойства: ширину и высоту.
properties: Возвращает объект StylePropertyMapReadOnly, который мы можем использовать для чтения свойств CSS и их значений через JavaScript.
Отрисовка прямоугольников
Наш следующий шаг — вывести что-то, поэтому мы нарисуем прямоугольники. Добавьте следующее в метод paint:
paint(context, canvas, properties) { for (let x = 0; x < canvas.height / 20; x++) { for (let y = 0; y < canvas.width / 20; y++) { const bgColor = (x + y) % 2 === 0 ? '#FFF' : '#FFCC00'; context.shadowColor = '#212121'; context.shadowBlur = 10; context.shadowOffsetX = 10; context.shadowOffsetY = 1; context.beginPath(); context.fillStyle = bgColor; context.rect(x * 20, y * 20, 20, 20); context.fill(); } } }
Все, что мы здесь делаем — это создаем вложенный цикл для перемещения по ширине и высоте холста. Поскольку размер прямоугольника равен 20, мы хотим разделить его высоту и ширину на 20.
В строке 4 мы можем переключаться между двумя цветами, используя оператор модуля. Я также добавил несколько теней для глубины. И, наконец, мы рисуем на холсте прямоугольники. Если вы откроете это в браузере, вы должны увидеть следующее:
Создание динамического фона
К сожалению, помимо изменения размера textarea и получения представления о том, как Paint API перерисовывает все, все остальное в основном по прежнему статично. Итак, давайте сделаем вещи более динамичными, добавив пользовательские свойства CSS, которые мы можем изменить. Откройте файл styles.css и добавьте в него следующие строки:
.pattern { width: 250px; height: 250px; border: 1px solid #000; background-image: paint(pattern); + --pattern-color: #FFCC00; + --pattern-size: 23; + --pattern-spacing: 0; + --pattern-shadow-blur: 10; + --pattern-shadow-x: 10; + --pattern-shadow-y: 1; }
Вы можете определить пользовательские свойства CSS, добавив префикс —. Затем они могут быть использованы через функцию var(). Но в нашем случае мы будем использовать их в нашем рабочем приложении для рисования.
Проверка поддержки в CSS
Чтобы убедиться, что Paint API поддерживается, мы также можем проверить поддержку в CSS. Для этого у нас есть два варианта:
Защита правил с помощью правила @supports.
Использование резервного фонового изображения.
/* 1st option */ @supports (background: paint(pattern)) { /** * If this part gets evaluated, it means that the Paint API * is supported **/ } /** * 2nd option * If the Paint API is supported, the latter rule will override * the first one. If it's not, CSS will invalidate it and the one * with url() will be applied **/ .pattern { background-image: url(pattern.png); background-image: paint(pattern); }
Доступ к параметрам в рабочем листе для отрисовки
Чтобы прочитать эти параметры внутри pattern.js, вам нужно добавить новый метод в класс, который определяет рабочий лист для отрисовки:
class Pattern { // Anything that the `inputProperties` method returns // the paint worklet will have access to static get inputProperties() { return [ '--pattern-color', '--pattern-size', '--pattern-spacing', '--pattern-shadow-blur', '--pattern-shadow-x', '--pattern-shadow-y' ]; } }
Чтобы получить доступ к этим свойствам внутри метода paint, вы можете использовать properties.get:
paint(context, canvas, properties) { const props = { color: properties.get('--pattern-color').toString().trim(), size: parseInt(properties.get('--pattern-size').toString()), spacing: parseInt(properties.get('--pattern-spacing').toString()), shadow: { blur: parseInt(properties.get('--pattern-shadow-blur').toString()), x: parseInt(properties.get('--pattern-shadow-x').toString()), y: parseInt(properties.get('--pattern-shadow-y').toString()) } }; }
Для цвета нам нужно преобразовать его в строку. Все остальное нужно будет преобразовать в число. Это потому, что properties.get возвращает CSSUnparsedValue.
Возвращаемое значение properties.get.
Чтобы сделать вещи немного более читаемыми, я создал две новые функции, которые обрабатывают парсинг:
paint(context, canvas, properties) { const getPropertyAsString = property => properties.get(property).toString().trim(); const getPropertyAsNumber = property => parseInt(properties.get(property).toString()); const props = { color: getPropertyAsString('--pattern-color'), size: getPropertyAsNumber('--pattern-size'), spacing: getPropertyAsNumber('--pattern-spacing'), shadow: { blur: getPropertyAsNumber('--pattern-shadow-blur'), x: getPropertyAsNumber('--pattern-shadow-x'), y: getPropertyAsNumber('--pattern-shadow-y') } }; }
Все, что нам нужно сделать сейчас, это заменить все в цикле for соответствующими значениями prop:
for (let x = 0; x < canvas.height / props.size; x++) { for (let y = 0; y < canvas.width / props.size; y++) { const bgColor = (x + y) % 2 === 0 ? '#FFF' : props.color; context.shadowColor = '#212121'; context.shadowBlur = props.shadow.blur; context.shadowOffsetX = props.shadow.x; context.shadowOffsetY = props.shadow.y; context.beginPath(); context.fillStyle = bgColor; context.rect(x * (props.size + props.spacing), y * (props.size + props.spacing), props.size, props.size); context.fill(); } }
Теперь вернитесь в браузер, чтобы увидеть изменения.
Редактирование фона внутри DevTools.
Заключение
Почему CSS Paint API может быть полезен для нас? Каковы варианты использования?
Наиболее очевидным является то, что это уменьшает размер ответов. Исключая использование изображений, вы сохраняете один сетевой запрос и несколько килобайт загружаемых данных. Это улучшает производительность.
Для сложных CSS-эффектов, которые используют элементы DOM, вы также уменьшаете количество узлов на странице. Поскольку вы можете создавать с помощью Paint API сложные анимации, нет необходимости в дополнительных пустых узлах.
На мой взгляд, самым большим преимуществом является то, что он гораздо более настраиваемый, чем статические фоновые изображения. API также создает изображения, независимые от разрешения, поэтому вам не нужно беспокоиться о том, что вам не хватает размера экрана.
Если вы решили использовать CSS Paint API сегодня, убедитесь, что вы предоставляете полифилл, поскольку он все еще не получил широкой поддержки. Если вы хотите настроить готовый проект, вы можете клонировать его из этого репозитория GitHub.
Спасибо, что нашли время, чтобы прочитать эту статью. Удачного кодирования!
Автор: Ferenc Almasi
Источник: https://medium.com
Редакция: Команда webformyself.