Как настроить цветовые схемы приложения с помощью пользовательских свойств CSS

Опубликовано: 2022-03-10
Краткое резюме ↬ В этой статье Артур Басак представляет современный подход к настройке пользовательских свойств CSS, которые реагируют на цвета приложения. Идея разделения цветов на три уровня может быть весьма полезной: палитра (или схема), функциональные цвета (или тема) и составляющие цвета (локальная область).

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

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

См. Pen [Пользовательские свойства цветов] (https://codepen.io/smashingmag/pen/RwaNqxW) Артура Басака.

См. «Пользовательские свойства пера для цветов» Артура Басака.

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

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

Еще после прыжка! Продолжить чтение ниже ↓

Настройка цветовой палитры

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

Согласно теории цвета существует всего несколько вариантов цветовых схем:

  • Монохроматическая схема (один основной цвет)
  • Дополнительная схема (два основных цвета)
  • Триадная схема (три основных цвета)
  • Тетрадическая схема (четыре основных цвета)
  • Смежный узор (два или три основных цвета)

Для моего примера я сгенерирую триадную цветовую схему с помощью сервиса Paletton:

Цветовой круг с установленной триадной схемой: вариации зеленого, синего и красного.
Paletton Service: Триадная цветовая схема. (Большой превью)

Теперь у меня три основных цвета. На их основе я буду вычислять тона и средние тона (формат HSL в сочетании с функцией calc — очень полезный инструмент для этого). Изменяя значение яркости, я могу создать несколько дополнительных цветов для палитры.

См. Pen [HSL Palette] (https://codepen.io/smashingmag/pen/OJNPaQW) Артура Басака.

См. палитру Pen HSL от Артура Басака.

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

Если вы предпочитаете форматы HEX или RGB, то это не имеет значения; палитра может быть сформирована на этапе компиляции проекта с соответствующими функциями препроцессора (например, с SCSS и функцией color-adjust ). Как я уже упоминал ранее, этот слой в основном статичен; Крайне редко палитра может быть изменена в работающем приложении. Вот почему мы можем вычислить его с помощью препроцессоров.

Примечание . Я рекомендую также генерировать литерал HEX и RGB для каждого цвета. Это позволит в будущем играть с альфа-каналом.

См. Pen [SCSS Palette] (https://codepen.io/smashingmag/pen/oNxgQqv) Артура Басака.

См. палитру Pen SCSS от Артура Басака.

Уровень палитры — это единственный уровень, на котором цвет закодирован непосредственно в именах переменных, т. е. мы можем однозначно идентифицировать цвет, читая имя.

Определите тему или функциональные цвета

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

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

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

С помощью трех кнопок вверху вы можете переключать темы (менять фирменный цвет элементов управления). Изменение происходит с помощью соответствующего API CSSOM (setProperty).

См. Pen [Функциональные цвета] (https://codepen.io/smashingmag/pen/poyvQLL) Артура Басака.

См. Pen Functional Colors от Артура Басака.

Такой подход удобен не только для тематики, но и для настройки отдельных веб-страниц. Например, на сайте zubry.by я использовал общую таблицу стилей и функциональную переменную --page-color , чтобы раскрасить логотип, заголовки, элементы управления и выделение текста для всех страниц. И в собственных стилях каждой страницы я просто переопределил эту переменную, чтобы установить для страницы ее индивидуальный основной цвет.

3 веб-страницы сайта ZUBRY.BY: страница марок, страница открыток и страница открыток.
Сайт ZUBRY.BY, где каждая страница имеет свой основной цвет. (Большой превью)

Используйте цвета компонентов

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

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

Первый — это когда компоненты, которые в соответствии с руководством по стилю приложения повторяются с разными настройками, например, кнопки для разных нужд, такие как основная (фирменная) кнопка, вторичная кнопка, третья и так далее.

Различные стили кнопок для приложения Tispr.
Руководство по стилю приложения Tispr. Кнопки. (Большой превью)

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

Более редкий случай, когда могут пригодиться переменные компонента, — функционал «белой метки». «Белая метка» — это сервисная функция, которая позволяет пользователю настраивать или маркировать некоторые части пользовательского интерфейса, чтобы улучшить взаимодействие со своими клиентами. Например, электронные документы, которыми пользователь делится со своими клиентами через сервис или шаблоны электронной почты. В этом случае переменные на уровне компонентов помогут настроить отдельные компоненты отдельно от остальной цветовой темы приложения.

В приведенном ниже примере я добавил элементы управления для настройки цветов основной (фирменной) кнопки. Используя цветовые переменные уровня компонента, мы можем настроить элементы управления пользовательского интерфейса отдельно друг от друга.

См. Pen [Цвета компонентов] (https://codepen.io/smashingmag/pen/LYNEXdw) Артура Басака.

См. Цвета компонентов пера Артура Басака.

Как определить, какой уровень имеет переменная?

Наткнулся на вопрос, как понять, что можно положить в корень (тема или функциональный уровень), а что оставить на уровне компонента. Это отличный вопрос, на который трудно ответить, не видя ситуации, с которой вы работаете.

К сожалению, тот же подход, что и в программировании, не работает с цветами и стилями, если мы видим три одинаковых куска кода, то его нужно рефакторить.

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

См. Pen [Color Split: Only Palette] (https://codepen.io/smashingmag/pen/YzqPRLX) Артура Басака.

См. палитру Pen Color Split: Only Palette Артура Басака.

Повторяется темно-серый цвет — это граница поля ввода, цвет заливки иконки закрытия и фон второстепенной кнопки. Но эти компоненты никак не связаны друг с другом. Если изменится цвет границы поля ввода, то мы не будем менять фон дополнительной кнопки. Для такого случая мы должны оставить здесь только переменную из палитры.

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

Как насчет зеленого? Мы можем четко определить его как основной или фирменный цвет, скорее всего, если изменится цвет основной кнопки, то изменится и цвет ссылки и шапки первого уровня.

Как насчет красного? Недопустимое состояние полей ввода, сообщения об ошибках и деструктивные кнопки будут иметь одинаковый цвет на уровне всего приложения. Это закономерность. Теперь я могу определить несколько общих функциональных переменных в корневом разделе:

См. Pen [Color Split: Functional Level] (https://codepen.io/smashingmag/pen/MWyYzGX) Артура Басака.

См. «Разделение цвета пера: функциональный уровень» Артура Басака.

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

Кнопка повторяется с разными настройками, цвет фона и текст меняются для разных вариантов использования — первичный, вторичный, третичный, деструктивный или негативный.

Поле ввода имеет два состояния — неправильное и нормальное, где различаются цвета фона и границ. И так, занесем эти настройки в цветовые переменные на уровне соответствующих компонентов.

Для остальных компонентов не обязательно определять локальные цветовые переменные, это будет лишним.

См. Pen [Color Split: Component Level] (https://codepen.io/smashingmag/pen/BaKyGVR) Артура Басака.

См. «Разделение цвета пера: уровень компонентов» Артура Басака.

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

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

Почему бы не поместить все в корневой раздел?

У меня был такой опыт. На проекте Lition мы с командой столкнулись с тем, что нам нужно было поддерживать IE11 для веб-приложения, но не для сайта и лендингов. Между проектами использовался общий UI Kit, и мы решили вынести все переменные в корень, это позволит переопределить их на любом уровне.

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

Главная страница сайта Lition с открытыми инструментами разработки браузера
Сайт Литион ССР. Все переменные в корневом разделе. (Большой превью)

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

Во-вторых, это не лучшее решение с точки зрения производительности. Да, изменение цвета вызывает только процесс перерисовки, а не переплавки/верстки, само по себе это не слишком затратно, но при внесении каких-то изменений на самом высоком уровне вы будете использовать больше ресурсов для проверки всего дерева, чем когда эти изменения носят небольшой локальный характер. Я рекомендую прочитать тест производительности переменных CSS от Lisi Linhart для более подробной информации.

На моем текущем проекте Tispr мы с командой используем split и не сбрасываем все в корень, на высоком уровне только палитра и функциональные цвета. Также нас не пугает IE11, потому что эту проблему решает соответствующий полифилл. Просто установите модуль npm ie11-custom-properties и импортируйте библиотеку в пакет JS вашего приложения:

 // Use ES6 syntax import "ie11-custom-properties"; // or CommonJS require('ie11-custom-properties');

Или добавьте модуль по тегу script:

 <script async src="./node_modules/ie11-custom-properties/ie11CustomProperties.js">

Также вы можете добавить библиотеку без npm через CDN. Работа этого полифилла основана на том, что IE11 имеет минимальную поддержку пользовательских свойств, где свойства можно определять и читать на основе каскада. Это невозможно для свойств, начинающихся с двойного дефиса, но возможно с одинарного дефиса (механизм аналогичен префиксам поставщиков). Подробнее об этом можно прочитать в документации репозитория, а также ознакомиться с некоторыми лимитами. Другие браузеры будут игнорировать этот полифилл.

Ниже представлена ​​палитра веб-приложения Tispr, а также элементы управления функциональностью «белой метки» для электронных документов (таких как пользовательские контракты, счета-фактуры или предложения).

Сетка со следующими столбцами: цвет, название цвета, цвет HEX, цвет RGB.
Руководство по стилю Tispr: цветовая палитра. (Большой превью)
Пользовательский компонент пользовательского интерфейса выбора цвета
Руководство по стилю Tispr: выбор бренда для функциональности White Label. (Большой превью)

Почему бы не хранить переменные цвета на стороне JavaScript?

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

В JavaScript нет нативных функций или API для работы с цветами. В CSS Color Module 5 будет много возможностей сделать производные цвета или как-то их вычислить. С точки зрения будущего, пользовательские свойства CSS будут богаче и гибче, чем переменные JS. Кроме того, с переменными JS не будет возможности использовать каскадное наследование, и это главный недостаток.

Заключение

Разделение цветов на три уровня (палитра, функциональность и компонент) может помочь вам лучше адаптироваться к изменениям и новым требованиям при работе над проектом. Я считаю, что пользовательские свойства CSS — это правильный инструмент для организации цветового разделения — неважно, что вы используете для стилизации: чистый CSS, препроцессоры или подход CSS-in-JS.

Я пришел к этому подходу на собственном опыте, но я не одинок. Сара Суэйдан описала в своей статье аналогичный подход, в котором она разделила переменные на глобальный и компонентный уровни.

Также хочу предложить прочитать статью Lea Verou, где она описывает возможные случаи применения CSS-переменных (не только с точки зрения цвета).