# Стилизация компонентов

Стилизация компонента осуществляется двумя способами:

  1. Использование ungic.theme модуля для работы с цветами
  2. Использование properties для работы с css свойствами

# Работа с цветами

Темизация компонентов происходит благодаря использованию ungic.theme модуля. Темизация дает такие возможности как:

  • Автоматическая генерация компонента или набор компонентов с определенной темой проекта.
  • Автоматическая генерация инверсии темы проекта.
  • Полный контроль написания CSS стилей относительно тем и их инверсий с помощью методов ungic.theme модуля.

# Процесс темизации

Процесс темизации происходит непосредственно с помощью ungic.theme модуля. Данный модуль предоставляет API для работы с цветами активной темы проекта. В режиме разработки, можно выбрать только одну активную тему, при релизе - любое количество.

Благодаря использованию данного API, ungic sass framework автоматически генерирует любые темы проекта с любым набором компонентов. При создании релиза, CSS правила для каждой темы включая инверсию, могут быть вынесены в отдельные файлы.

TIP

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

API ungic.theme модуля позволяет не только получать цвета текущей темы, но и манипулировать ими, осветляя или затемняя их, это необходимо для осуществления автоматической генерации инверсии тем. Также, API позволяет писать правила относительно типа темы (светлой или темной) или относительно определенной темы и тд. То есть, имеется полный контроль для осуществления корректной темизации компонентов!

Обратите внимание!

В случае, если проекту требуется поддержка функционала по автоматическому генерированию тем, все цвета в CSS правилах компонента должны быть заданы с помощью методов ungic.theme модуля!

# Использование CSS переменных new

Теперь темизация происходит двумя способами, кроме выше описанного способа темизации, появился дополнительный способ, который позволяет генерировать CSS переменные! Подробнее о данном способе генерации тем в данном разделе.

# Инверсия тем

Инверсия тем осуществляется автоматически благодаря корректному использования ungic.theme модуля. Инверсия генерируется путем повторной компиляции проекта с текущей темой в режиме инверсии с последующей пост-обработкой и фильтрацией css свойств. Режим инверсии может быть активирован по умолчанию, таким образом алгоритмы меняются в противоположную сторону. Инверсия это не темная или светлая тема, это противоположная версия текущей темы:

  • Если текущая тема - светлая, то при инверсии, получим темную тему!
  • Если текущая тема - темная, то при инверсии, получим светлую!

Инверсия тем происходит благодаря основным двум цветам темы:

  • text-color
  • background-color

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

$colors: (
    text-color: (#000, #FFF),
    background-color: (#FFF, #000)
    ...
)

TIP

Относительное значение - термин который используется при конфигурации темы и обозначает то, что значение для данной переменной, может быть задано в виде SASS списка из двух значений, где первое значение применяется для темы по умолчанию, а второе в режиме инверсии темы!

то есть, в виде SASS списка из двух элементов! Разберем подробнее

// Основные цвета текущей активной темы
$colors: (
    text-color: (#333, #fafafa),
    background-color: (#FFF, #000)
    ...
)

текущая тема в обычном режиме (не в режиме инверсии), будет иметь следующие цвета:

text-color: (#333, #fafafa),
background-color: (#FFF, #000)

  • Цвет текста - #333
  • Цвет фона - #FFF

Цвета первого элемента списка, данная тема является светлой, так как фон светлее текста.

TIP

Если цвет фона светлее текста, то темя считается светлой и наоборот.

В режиме инверсии, наша тема будет иметь следующие цвета:

text-color: (#333, #fafafa),
background-color: (#FFF, #000)

  • Цвет текста - #fafafa
  • Цвет фона - #000

Таким образом, тема по умолчанию - светлая, а в режиме инверсии - темная, но если переключить режим инверсии в положение - правда, тогда, тема по умолчанию будет темной, а при инверсии - светлой. Переключение режима инверсии в HTML документе осуществляется с помощью назначения .un-inverse класса к корневому элементу страницы. Кроме того, если проект генерируется с RTL поддержкой, следует добавить dir атрибут (или тот, что указан в dirAttribute параметрах конфигурации html,scss плагинов) к данному элементу.

# Корневой элемент страницы

Корневым элементом страницы, может быть HTML элемент (по умолчанию), или тот который имеет data-ungic-root атрибут, это зависит от htmlIsRootElement параметра.

# htmlIsRootElement

Параметр конфигурации отвечает за выбор корневого элемента страницы:

  • Если данный параметр - ложь false, то корневым элементом считается тот элемент, который имеет data-ungic-root аттрибут.
  • Если данный параметр - правда true (by default), то HTML элемент является корневым элементом.
<html data-ungic-root class="un-inverse" dir="ltr"></html>

Обратите внимание!

Для того, чтобы переключить тему в режим инверсии необходимо:

  1. При генерации отдельного файла с правилами для инверсии темы, подключить файл к документу!
  2. Добавить к корневому элементу страницы аттрибут data-ungic-root если параметр htmlIsRootElement конфигурации не является истинным.
  3. Если проект генерируется с RTL поддержкой добавить dir атрибут или тот, что указан в dirAttribute параметрах конфигурации html,scss плагинов
  4. Добавить un-inverse класс к данному элементу ([data-ungic-root] или к HTML, в зависимости от htmlIsRootElement параметра).

Обратите внимание!

Рекомендуется использовать HTML элемент в роли корневого элемента страницы (не исключает совместное использование data-ungic-root атрибута), это необходимо для того, чтобы:

  1. обеспечить инверсию всех стилей, включая body элемента
  2. избежать пересечения стилей тем

TIP

Обратите внимание!

Назначение основных цветов тем (text-color, background-color) для текста и фона (не важно какого элемента страницы), автоматически не осуществляется! Для этого, необходимо задать цвета, например для body элемента:

// components/normalize/render.scss
@use "ungic.theme" as theme;
body {
	color: theme.color(text-color);
	background-color: theme.color(background-color);
}

Обратите внимание!

Все цвета темы, включая цвета text-color и background-color, автоматически не назначаются ни одному html элементу! Рекомендуется использовать глобальный компонент (например normalize) для назначения цветов для body элемента страницы.

# Осветление или затемнение цвета

Осветление или затемнение цвета требуется осуществлять с помощью методов ungic.theme модуля, для того, чтобы получить удачно сгенерированный результат инверсии темы.

# Методы

ungic.theme модуль имеет следующие методы для работы с цветом:

Оба метода осветляют или затемняют цвет, разница между ними в том, что brightness кроме кол-ва света, регулирует оттенок цвета (hue) и saturation, а lightness просто изменяет кол-во света в цвете. Оба метода отличаются от работы SASS методов c цветом! Главные их отличия заключаются в следующем:

  • Автоматически применяют методы осветления / затемнения в зависимости от режиме инверсии.
  • Регулируют кол-вом света в цвете относительно самого светлого и самого темного основного цвета темы (text-color, background-color).

TIP

intensity - это число от -1 до 1 которое является процентом интенсивности света относительно самого темного цвета и самого светлого (text-color, background-color).

  • Положительное число - осветляет цвет при светлой теме и затемняет при темной
  • Отрицательное число - затемняет цвет при светлой теме и осветляет при темной

brightness - метод используется в методах color и gray, которые принимают вторым аргументом $color-tint имя палитры или число от -1 до 1 которое будет передано в brightness метод вторым параметром как $intensity:

@use "ungic.theme" as theme;

.label {
	/*
	*	Если активная тема светлая, то осветлит primary цвет на 50%,
	*	а при инверсии затемнит на 50%
	*/
	color: theme.color(primary, .5);
}

TIP

Осветление или затемнение цвета происходит относительно самого темного и самого светлого основного цвета темы (text-color, background-color). Подобное поведение можно контролировать с помощью relative-light-limit параметра конфигурации темы!

Наглядный пример:

// themes/default.scss
...
$colors: (
	primary: #9cef0a,
	text-color: (#3a3b39, #fff9ea),
	background-color: (#fafafa, #202120)
	...
);

// components/app/render.scss

@use "ungic.theme" as *;

// Осветляем primary цвет на 100% 
// относительно светлого цвета темы,
// (в обычном режиме, самым светлым будет цвет фона - #fafafa)
// в таком случае, полученный цвет будет иметь кол-во света
// равное кол-ву света светлого цвета

@debug color(primary, 1);

// в режиме инверсии, primary цвет
// будет затемнен на 100% относительно темного цвета темы
// (темный цвет при инверсии - #202120)
// в таком случае, полученный цвет будет иметь кол-во света
// равное кол-ву света темного цвета

@debug color(primary, 1); //  #3e4100

Осветлять и затемнять цвета можно и с помощью SASS методов отталкиваясь от типа темы с помощью таких методов как:

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

Примеры работы с цветом с помощью subs метода:

TIP

subs($light, $dark) - метод принимает два параметра, первый применяется в случае если тема светлая, второй, если тема темная!

@use "ungic.theme" as *;

// Осветлить цвет при светлой и темной теме на 50%
// в пределах света между text-color и background-color

@debug color(primary, subs(.5, -.5));

// эквивалентное решение
@debug color(primary, subs(.5));
@use "ungic.theme" as *;

// Обычное использование прозрачности
@debug rgba(#000, .5); // rgba(0, 0, 0, 0.5) - светлая тема

// В случае, если есть необходимость
// менять прозрачность, в зависимости от типа темы:

@debug rgba(#000, subs(.5, 1)); // black - темная тема
@use "ungic.theme" as *;
@use "sass:color";

// Использовать цвет относительно типа темы:
@debug subs(#FFF, #000);

// Использовать SASS методы относительно типа темы:
// Затемнить при светлой теме, и осветлить при темной:
@debug color.adjust(#00b800, $lightness: subs(-10%));

TIP

Также, для более точного контролирования оттенками цвета, существует палитра цвета!

# Работа с серым (gray)

Для работы с серым цветом, существует gray метод который позволяет генерировать серый цвет относительно text-color и background-color цветов темы.

TIP

Серый цвет - это 50% света между text-color и background-color цветов темы. Серый цвет может иметь оттенок и его интенсивность, которые настраиваются в конфигурации темы.

@use "ungic.theme" as *;

@debug gray(); // Вернет серый цвет

// Осветляет / затемняет серый цвет на 90%
// относительно text-color и background-color
@debug gray(.9);

Затемнение и осветление серого цвета происходит с помощью brightness метода. Серый цвет, также поддерживает палитры цветов:

// themes/default.scss
$palettes: (
    primary: (
        lighten: #e8f2c7,
        darken: #4c5d15
    ),
    'gray': (
        lighten: #CCC,
        darken: #333
    )
);

// components/app/render.scss

@use "ungic.theme" as theme;

// Получить цвет палитры
@debug gray(lighten); // #CCC

// Получить цвет палитры относительно типа темы
@debug gray(subs(lighten, darken));

Ссылки по теме:

# Работа с css properties

В properties.scss указываются переменные, имена которых эквивалентны именам CSS свойств, значения которых применяются при написании CSS правил, используются для стилизации компонента:

// properties.scss
@use "ungic.theme" as theme;

$border-color: theme.color(gray, .9);
$border-width: 2px;

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

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

Именно поэтому, имена переменных должны соответствовать имени CSS свойству.

# Значения properties по умолчанию

properties по умолчанию
@use "utils";
$font-size: medium;
$line-height:normal;
$font-family: utils.rtl-prepend('-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', 'Heebo', ',');
$animation:none;
$animation-delay:0;
$animation-direction:normal;
$animation-duration:0;
$animation-fill-mode:none;
$animation-iteration-count:1;
$animation-name:none;
$animation-play-state:running;
$animation-timing-function:ease;
$backface-visibility:visible;
$background:0;
$background-attachment:scroll;
$background-clip:border-box;
$background-color:transparent;
$background-image:none;
$background-origin:padding-box;
$background-position:0 0;
$background-position-x:0;
$background-position-y:0;
$background-repeat:repeat;
$background-size:auto auto;
$border:0;
$border-style:none;
$border-width:medium;
$border-color:inherit;
$border-bottom:0;
$border-bottom-color:inherit;
$border-bottom-left-radius:0;
$border-bottom-right-radius:0;
$border-bottom-style:none;
$border-bottom-width:medium;
$border-collapse:separate;
$border-image:none;
$border-left:0;
$border-left-color:inherit;
$border-left-style:none;
$border-left-width:medium;
$border-radius:0;
$border-right:0;
$border-right-color:inherit;
$border-right-style:none;
$border-right-width:medium;
$border-spacing:0;
$border-top:0;
$border-top-color:inherit;
$border-top-left-radius:0;
$border-top-right-radius:0;
$border-top-style:none;
$border-top-width:medium;
$bottom:auto;
$box-shadow:none;
$box-sizing:content-box;
$caption-side:top;
$clear:none;
$clip:auto;
$color:inherit;
$columns:auto;
$column-count:auto;
$column-fill:balance;
$column-gap:normal;
$column-rule:medium none currentColor;
$column-rule-color:currentColor;
$column-rule-style:none;
$column-rule-width:none;
$column-span:1;
$column-width:auto;
$content:normal;
$counter-increment:none;
$counter-reset:none;
$cursor:auto;
$direction:ltr;
$display:inline;
$empty-cells:show;
$float:none;
$font:normal;
$font-style:normal;
$font-variant:normal;
$font-weight:normal;
$height:auto;
$hyphens:none;
$left:auto;
$letter-spacing:normal;
$list-style:none;
$list-style-image:none;
$list-style-position:outside;
$list-style-type:disc;
$margin:0;
$margin-bottom:0;
$margin-left:0;
$margin-right:0;
$margin-top:0;
$max-height:none;
$max-width:none;
$min-height:0;
$min-width:0;
$opacity:1;
$orphans:0;
$outline:0;
$outline-color:invert;
$outline-style:none;
$outline-width:medium;
$overflow:visible;
$overflow-x:visible;
$overflow-y:visible;
$padding:0;
$padding-bottom:0;
$padding-left:0;
$padding-right:0;
$padding-top:0;
$page-break-after:auto;
$page-break-before:auto;
$page-break-inside:auto;
$perspective:none;
$perspective-origin:50% 50%;
$position:static;
$right:auto;
$tab-size:8;
$table-layout:auto;
$text-align:inherit;
$text-align-last:auto;
$text-decoration:none;
$text-decoration-color:inherit;
$text-decoration-line:none;
$text-decoration-style:solid;
$text-indent:0;
$text-shadow:none;
$text-transform:none;
$top:auto;
$transform:none;
$transform-style:flat;
$transition:none;
$transition-delay:0s;
$transition-duration:0s;
$transition-property:none;
$transition-timing-function:ease;
$unicode-bidi:normal;
$vertical-align:baseline;
$visibility:visible;
$white-space:normal;
$width:auto;
$word-spacing:normal;
$z-index:auto;

# Использование properties для написания правил стилей компонента

Для того, чтобы использовать вычисленное значение св-ва при написании стилей компонента, следует воспользоваться prop методом ядра компонента:

// project/properties.scss

@use "ungic.theme" as theme;
// Border
// Назначаем значения по умолчанию для всего проекта
$border-width: 2px;
$border-style: solid;
$border-color: theme.gray(.8);
// components/app/properties.scss
// В компоненте меняем только толщину бордера
$border-width: 1px;
// components/app/render.scss
@use ".core" as this;

.component {
	// Можем получить как вычисленное значение в сокращенном виде,
	border: prop(border); // 1px solid #eaeaec

	// так и отдельное св-во:
	// prop(border-width) // 1px
	// prop(border-style) // solid
}

Как видим выше, значения св-в border-width, border-style, border-color проекта были унаследованы компонентом, а затем, border-width был изменен самим компонентом на 1px, конечный результат сложения - 1px solid #eaeaec.

Данный пример эквивалентен примеру выше:

// project/properties.scss

@use "ungic.theme" as theme;
// Сокращаем
$border: 2px solid theme.gray(.8);
// components/app/properties.scss
// Меняем только толщину бордера
$border-width: 1px;
// components/app/render.scss
@use ".core" as this;

.component {
	// Можем получить как вычисленное значение в сокращенном виде,
	border: prop(border); // 1px solid #eaeaec

	// так и отдельное св-во:
	// prop(border-width) // 1px
	// prop(border-style) // solid
}

Обратите внимание!

Включение properties.scss файла напрямую и использование его переменных, является абсолютно бессмысленным действием. Для получения значений свойства из properties.scss используется метод ядра prop, который возвращает вычисленное значение.

# Использование properties для настройки конфигурации компонента

При жестком использовании prop метода при написании стилей, возникает один большой минус - отсутствие гибкости при стилизации.

Приведу пример:

Имеется компонент который использует border св-во в нескольких местах:

@use ".core" as *;
@use "ungic.theme" as theme;

@include this {
	&-control {
		border: prop(border); // 1px solid #CCC
	}
	&-btn {
		border: prop(border); // 1px solid #CCC
	}
}

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

// components/app/config.scss

// В конфигурационном файле не доступно ядро компонента!
// Именно поэтому используется модуль 'ungic.component.props'
@use "ungic.component.props" as *;

$border-control: prop(border);
$border-btn: prop(border);

// components/app/render.scss

@use ".core" as *;

@include this {
	&-control {
		border: config(border-control);
	}
	&-btn {
		border: config(border-btn);
	}
}

После чего, цвет границы (бордера) кнопки можно изменить непосредственно из config-over.scss файла проекта:

// project/properties-over.scss

@use "sass:map";
$cid: null !default;
$config: () !default;

@use "ungic.theme" as theme;
// Получить доступ к вычисленным properties текущего компонента
@use "ungic.component.props" as props;

@if($cid == app) {
  $config: map.merge($config, (
				 // Сохранили толщину бордера
	border-btn: (props.prop(border-width)
				 // Сохранили стиль бордера
				 props.prop(border-style)
				 // Изменили только цвет
				 theme.gray(.9))
  	));
}

Обратите внимание!

В конфигурационном файле компонента (config.scss), нет доступа к ядру компонента, попытка его включения, приведет к ошибке компиляции, так как, ядро на данном этапе ещё не готово! Для того, чтобы получить доступ к вычисленным properties текущего компонента из config.scss файла, следует включать ungic.component.props модуль!

TIP

Для того, чтобы получить доступ к вычисленным properties текущего компонента из properties-over.scss файла проекта или из config.scss файла компонента, следует включить ungic.component.props модуль!

# Переназначение properties компонента из проекта

Переназначение properties компонента осуществляется из config-over.scss файла проекта, смотрите пример выше.

# Использование properties проекта внутри компонента

Данное действие является бессмысленным и ошибочным, так как properties проекта наследуются компонентом, таким образом, если компонент не назначил собственные properties они будут унаследованы от проекта.

Обратите внимание!

Для получения значений свойств из properties.scss файлов проекта или компонента, необходимо использовать исключительно методы ядра компонента (prop, props).

В любом случае, для того, чтобы получить данные проекта включая properties, необходимо использовать ungic.project модуль:

@use "ungic.component" as this;
@use "ungic.project" as project;

// Получить доступ к properties проекта.
@debug project.props(); // .prop(prop);


Использование project.props() может пригодиться в том случае, если необходимо сбросить все properties компонента на свойства по умолчанию, данное действие выполняется в properties-over.scss файле:

/* --------------------------------------------------*/
//	Don't change this part
@use "sass:map";
$cid: null !default;
$properties: () !default;
/* ------------------------------------------------ */

@use "ungic.project" as project;

@if($cid == mycomponent) {
	// Лучше выполнить объединение, на тот случай,
	// если компонент содержит нестандартное св-во.

  $properties: map.merge($properties, project.props(true));
}