Atomic CSS Deep Dive

Валентин Ульянов

Atomic CSS Deep Dive

Валентин Ульянов

Обложка

Обо мне

Фото Валентина Ульянова

Я и Atomic CSS

Я и Atomic CSS

Я и Atomic CSS

Я и Atomic CSS

Содержание

База

Пример кода, как выглядит Atomic CSS

Почему Atomic CSS

В сравнении с рукописным CSS

Почему Atomic CSS

В сравнении с рукописным CSS

Почему Atomic CSS

В сравнении с рукописным CSS
Основные мифы об Atomic CSS

State of Atomic CSS

Актуальные и популярные инструменты

  1. Tailwindcss
  2. UnoCSS
  3. Atomizer

Актуальные проблемы

Актуальные проблемы

Актуальные проблемы

Актуальные проблемы

Неконсистентный нейминг 👎

Неконсистентный нейминг 👎

Неконсистентный нейминг 👎

Неконсистентный нейминг 👎

Неконсистентный нейминг 👎

Сложные утилиты 😢

[@media(any-hover:hover){&:hover}]:opacity-100

Пример сложной утилиты из Tailwind

Сложные утилиты 😢

[&:not(:first-child)]:rounded-full

Пример сложной утилиты из Tailwind

Сложные утилиты 😢

supports-[margin:1svw]:ml-[1svw]

Пример сложной утилиты из Tailwind

Страшная тайна Atomic CSS 😱

В большинстве проектов, небольшую часть CSS вам придется написать руками!

Связь с рукописным CSS 🤡

Пример связи рукописного CSS с Tailwind

Связь с рукописным CSS 🤡

Пример связи рукописного CSS с Tailwind

Связь с рукописным CSS 🤡

Пример связи рукописного CSS с Tailwind

Связь с рукописным CSS 🤡

Пример связи рукописного CSS с Tailwind

Связь с рукописным CSS 🤡

Пример связи рукописного CSS с Tailwind
*Да, часть можно подключить с PostCSS, и они не всем нужны

Связь с рукописным CSS 🤡

Windi Lang Draft

Неудобно расширять 🥴

Пример добавления утилиты в Tailwind

Неудобно расширять 🥴

Пример добавления variant в UnoCSS

Актуальное решение 😎

mlut

Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity

Мем с бабочкой: это Tailwind на Sass?

Не стоит хоронить Sass

Количество релизов Sass за последние полгода Количество скачиваний Sass за неделю
Мем 'ща буит мясо'

Как устроены утилиты

Схема устройства утилит

Нейминг

Схема устройства утилит где выделен нейминг

Tailwind 😢

Opinionated названия, созвучные с CSS свойствами/значениями

Tailwind 😢

Opinionated названия, созвучные с CSS свойствами/значениями

Tailwind 😢

Opinionated названия, созвучные с CSS свойствами/значениями

Tailwind 😢

Opinionated названия, созвучные с CSS свойствами/значениями

Unocss во многом похож на Tailwind

Unocss (Tachyons) 😭

Unocss (Tachyons) 😭

Unocss (Tachyons) 😭

Atomizer 🥱

Сокращения Emmet + додуманные

Atomizer 🥱

Сокращения Emmet + додуманные

Atomizer 🥱

Сокращения Emmet + додуманные

Atomizer 🥱

Сокращения Emmet + додуманные

mlut 😎

Единный алгоритм для всех сокращений

mlut 😎

Единный алгоритм для всех сокращений

mlut 😎

Единный алгоритм для всех сокращений

mlut 😎

Единный алгоритм для всех сокращений

Почему сокращения?

Мем с Карлом: лаконичный код, удобнее писать

Почему сокращения?

Сокращения везде

Зачем алгоритм сокращений?

Зачем алгоритм сокращений?

Зачем алгоритм сокращений?

Сокращения Emmet неплохи, но в них нет четких правил
(confirmed by @sergeche)

Как это было

Как это было

Как это было

Как это было

Скриншот json данных mdn
Скриншот спецификаций CSS
статистика CSS свойств Chrome
Скриншот таблицы CSS свойств

Общий алгоритм сокращений кратко

  1. Находим свойства, которые начинаются с одинаковой буквы

Общий алгоритм сокращений кратко

  1. Находим свойства, которые начинаются с одинаковой буквы
  2. Составляем их рейтинг

Общий алгоритм сокращений кратко

  1. Находим свойства, которые начинаются с одинаковой буквы
  2. Составляем их рейтинг
  3. Выделяем группы

Общий алгоритм сокращений кратко

  1. Находим свойства, которые начинаются с одинаковой буквы
  2. Составляем их рейтинг
  3. Выделяем группы
  4. Составляем сокращения внутри групп

I. Алгоритм сокращения одной сущности

Название сокращаем до первой буквы свойства/значения

color => C

II. Алгоритм сокращения одной сущности

Если название из N слов, то берется первая буква из каждого слова

color-adjust => Ca

III. Алгоритм сокращения одной сущности

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

  1. color => C
  2. cursor => Cs

IV. Алгоритм сокращения одной сущности

Если название из N слов, то буква добавляется в соответствующем по порядку слове

  1. color => C
  2. cursor => Cs
  3. color-scheme => Csc

I. Порядок добавления буквы

Согласная следующего слога

cursor => Cs

I. Порядок добавления буквы

Согласная следующего слога

cursor => Cs

Если следующий слог начинается на гласную, то берется ближайшая предыдущая согласная от нее

II. Порядок добавления буквы

Следующая согласная

  1. content => Сt
  2. contain => Cn

III. Порядок добавления буквы

Следующая гласная (без перескока через согласную)

  1. content => Сt
  2. counter-increment => Coi

Ps

Ps => position

Fnw

Fnw =>
font-weight

Tf

Tf => transform

Flg

Flg =>
flex-grow

Слабые места 🫣

Слабые места 🫣

Слабые места 🫣

Синтаксис

Схема устройства утилит где выделены states и at-rules

Tailwind 😢

Tailwind 😢

Tailwind: утилита и значение 😢

Tailwind: утилита и значение 😢

Tailwind: утилита и значение 😢

Tailwind: утилита и значение 😢

Tailwind: variants 😢

Tailwind: variants 😢

Tailwind: variants 😢

Tailwind: arbitrary variants 😢

Tailwind: arbitrary variants 😢

Tailwind: arbitrary variants 😢

Unocss во многом похож на Tailwind

Atomizer 🥱

Atomizer 🥱

[<context>[:<pseudo-class>]<combinator>]<Style>[(<value>,<value>?,...)][<!>][:<pseudo-class>][::<pseudo-element>][--<breakpoint_identifier>]

mlut: components syntax 😎

@:ah_O1_h

mlut: components syntax 😎

@:ah_O1_h =>

				@media (any-hover) {
				  .\@\:ah_O1_h:hover {
				    opacity: 1
				  }
				}
			
Мем: как нарисовать сову

Зачем проектировать синтаксис?

Основная цель - концептуальная близость с CSS для органичного развития вместе с ним

Minimum opinions - maximum standards!

Зачем проектировать синтаксис?

Зачем проектировать синтаксис?

Зачем проектировать синтаксис?

Зачем проектировать синтаксис?

Процесс исследования CSS
Муки выбора: сделать синтаксический сахар или оставить спецсимволы для новых фич CSS

Utility components syntax

Синтаксис, в котором утилита разделяется на компоненты, каждый из которых, соответствует части CSS-правила

Utility components syntax

@:ah_O1_h

Utility components syntax

@:ah_O1_h =>

				@media (any-hover) {
				 
				 
				 
				}
			

Utility components syntax

@:ah_O1_h =>

				@media (any-hover) {
				  .\@\:ah_O1_h { 
				 
				  }
				}
			

Utility components syntax

@:ah_O1_h =>

				@media (any-hover) {
				  .\@\:ah_O1_h { 
				    opacity: 1
				  }
				}
			

Utility components syntax

@:ah_O1_h =>

				@media (any-hover) {
				  .\@\:ah_O1_h:hover {
				    opacity: 1
				  }
				}
			
Схема components syntax
  1. CSS at-rule: брейкпоинты, @supports, etc
Схема components syntax
  1. CSS at-rule: брейкпоинты, @supports, etc
  2. pre-states - часть селектора перед классом утилиты
Схема components syntax
  1. CSS at-rule: брейкпоинты, @supports, etc
  2. pre-states - часть селектора перед классом утилиты
  3. Имя
  4. Значение
Схема components syntax
  1. CSS at-rule: брейкпоинты, @supports, etc
  2. pre-states - часть селектора перед классом утилиты
  3. Имя
  4. Значение
  5. post-states - часть селектора после класса утилиты

Конвертация в mlut

Конвертация - превращение сокращения из названия класса в реальную CSS-сущность

Конвертация в mlut

Конвертация - превращение сокращения из названия класса в реальную CSS-сущность

Селекторы в CSS

Селекторы в CSS

Селекторы в CSS

Селекторы в CSS

States в mlut

States - это упрощенный selector list

Схема устройства утилит где выделены states

States в mlut

States - это упрощенный selector list

Bgc-red_h,f

Bgc-red_h,f =>

				.Bgc-red_h\,f {
				  background-color: red
				}
			

Bgc-red_h,f =>

				.Bgc-red_h\,f:hover,
				.Bgc-red_h\,f:focus {
				  background-color: red
				}
			

^:lc:>_D-f

^:lc:>_D-f =>

				.-Ctx:last-child > .\^one\:lc\>_D-f {
				 
				}
			

^:lc:>_D-f =>

				.-Ctx:last-child > .\^one\:lc\>_D-f {
				  display: flex
				}
			

Conditional at-rules в CSS

Conditional at-rules в CSS

Conditional at-rules в CSS

@supports value definition syntax

Conditional at-rules в CSS

Conditional at-rules в CSS

Conditional at-rules в CSS

media features value definition syntax

At-rules в mlut

Схема устройства утилит где выделены at-rules

At-rules в mlut

Для составления сложных выражений:

Rules

У каждого правила свое:

Rules

У каждого правила свое:

Rules

У каждого правила свое:

Rules

У каждого правила свое:

Синтаксис закрывает весь класс фич

@:dm-s:h>=20r_Mxw35r

@:dm-s:h>=20r_Mxw35r =>

				@media (display-mode: standalone) {
				 
				 
				 
				}
			

@:dm-s:h>=20r_Mxw35r =>

				@media (display-mode: standalone) and (min-height: 20rem) {
				 
				 
				 
				}
			

@:dm-s:h>=20r_Mxw35r =>

				@media (display-mode: standalone) and (min-height: 20rem) {
				  .\@\:dm-s\:h\>\=20r_Mxw35r {
				 
				  }
				}
			

@:dm-s:h>=20r_Mxw35r =>

				@media (display-mode: standalone) and (min-height: 20rem) {
				  .\@\:dm-s\:h\>\=20r_Mxw35r {
				    max-width: 35rem
				  }
				}
			

At-rules можно комбинировать!

@s:apcr4/3@:dm_Mxw40u

At-rules можно комбинировать!

@s:apcr4/3@:dm_Mxw40u =>

				@supports (aspect-ratio: 4/3) {
				 
				 
				 
				 
				 
				}
			

At-rules можно комбинировать!

@s:apcr4/3@:dm_Mxw40u =>

				@supports (aspect-ratio: 4/3) {
				  @media (display-mode: fullscreen) {
				 
				 
				 
				  }
				}
			

At-rules можно комбинировать!

@s:apcr4/3@:dm_Mxw40u =>

				@supports (aspect-ratio: 4/3) {
				  @media (display-mode: fullscreen) {
				    .\@s\:apcr4\/3\@\:dm_Mxw40u {
				 
				    }
				  }
				}
			

At-rules можно комбинировать!

@s:apcr4/3@:dm_Mxw40u =>

				@supports (aspect-ratio: 4/3) {
				  @media (display-mode: fullscreen) {
				    .\@s\:apcr4\/3\@\:dm_Mxw40u {
				      max-width: 10rem
				    }
				  }
				}
			
Кадр из фильма, где священник говорит: 'ну нафиг'

Слабые места 🫣

Слабые места 🫣

Конвертация значений

Схема устройства утилит где выделены значения

Конвертация значений

Превращение сокращения из названия класса в реальное CSS-значение

Tailwind 😢

Tailwind 😢

Tailwind 😢

Tailwind 😢

Unocss во многом похож на Tailwind

Atomizer 🥱

Atomizer 🥱

Atomizer 🥱

Atomizer 🥱

Atomizer 🥱

mlut 😎

Система конвертации для почти произвольных значений

mlut 😎

Система конвертации для почти произвольных значений

mlut 😎

Система конвертации для почти произвольных значений

Зачем система конвертации?

Зачем система конвертации?

Зачем система конвертации?

Значения в CSS

Value definition syntax в спеке
Обложна доклада про value definition syntax

Пример value definition syntax

Пример value definition syntax

Пример value definition syntax

Пример value definition syntax

Пример value definition syntax

Пример value definition syntax

Syntaxes в CSS data

Основные понятия конвертации

Основные понятия конвертации

Основные понятия конвертации

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

Опции утилиты

				'Apcr': (
				  'properties': aspect-ratio,
				  'conversion': 'num-length', // тип конвертации
				),
			

Общий конфиг для утилит

				'conversion-types': (
				  //...
				  'num-length': ('num-length', 'global-kw', 'cust-prop')
				                // ^цепочка конвертеров
				),
			

Общая схема работы конвертации

  1. Полное значение утилиты разбивается (по пробелам или разделителю) на простые значения

Общая схема работы конвертации

  1. Полное значение утилиты разбивается (по пробелам или разделителю) на простые значения
  2. Каждое простое значение проходит по цепочки конвертеров до тех пор, пока 1 из них не сработает

Общая схема работы конвертации

  1. Полное значение утилиты разбивается (по пробелам или разделителю) на простые значения
  2. Каждое простое значение проходит по цепочки конвертеров до тех пор, пока 1 из них не сработает
  3. К CSS значению применяется трансформер

Общая схема работы конвертации

  1. Полное значение утилиты разбивается (по пробелам или разделителю) на простые значения
  2. Каждое простое значение проходит по цепочки конвертеров до тех пор, пока 1 из них не сработает
  3. К CSS значению применяется трансформер
  4. Итоговое значение подставляется в CSS правило

Конвертеры

@function convert-uv-number($value, $data: ())

Конвертеры

@function convert-uv-number($value, $data: ())

Конвертеры

@function convert-uv-number($value, $data: ())

Конвертеры

@function convert-uv-number($value, $data: ())

Конвертеры

@function convert-uv-number($value, $data: ())

Трансформеры

@function gradient($value, $data: ())

Кейс: утилита для градиентов

				'-Gdl': (
				  'properties': background-image,
				  'transformer': 'gradient',
				  'css-function': 'linear-gradient',
				  'conversion': 'gradient',
				  'multi-list-separator': ',',
				  'keywords': ('position', 'gradient'),
				),
			

Кейс: утилита для градиентов

				'conversion-types': (
				  //...
				  'gradient': (
				    'keyword', 'color', 'cust-prop', 'Pl',
				    'number', 'angle', 'global-kw'
				  ),
				),
			

Кейс: утилита для градиентов

-Gdl-r,$action;30p,red;80p,tp

Кейс: утилита для градиентов

-Gdl-r,$action;30p,red;80p,tp =>
				.-Gdl-r\,\$action\;30p\,\red\;80p\,tp {
				 
				 
				 
				}
			

Кейс: утилита для градиентов

-Gdl-r,$action;30p,red;80p,tp =>
				.-Gdl-r\,\$action\;30p\,\red\;80p\,tp {
				  background-image: linear-gradient(
				 
				  );
				}
			

Кейс: утилита для градиентов

-Gdl-r,$action;30p,red;80p,tp =>
				.-Gdl-r\,\$action\;30p\,\red\;80p\,tp {
				  background-image: linear-gradient(
				    to right, var(--ml-action) 30%, red 80%, transparent
				  );
				}
			
Что ты такое?

Слабые места 🫣

Слабые места 🫣

Конфигурация

Настройка инструмента

Настройка инструмента

Настройка инструмента

Добавить значения в Tailwind 🙂

Добавление значения в Tailwind

Добавить утилиту в Tailwind 😢

Надо написать плагин!

Статическая утилита в Tailwind

Статическая утилита в Tailwind

Добавление статической утилиты в Tailwind

Динамическая утилита в Tailwind

Динамическая утилита в Tailwind

Динамическая утилита в Tailwind

Динамическая утилита в Tailwind

Добавление динамической утилиты в Tailwind

Добавить значения в Unocss 🙂

Добавление значение в Unocss

Добавить утилиту в Unocss 🥴

Добавить утилиту в Unocss 🥴

Добавить утилиту в Unocss 🥴

Добавить утилиту в Unocss 🥴

Добавление утилит в UnoCSS

mlut 😎

Все расширения в одном конфиге за пару строк кода

mlut 😎

Все расширения в одном конфиге за пару строк кода

Добавить утилиту в mlut

Добавление утилит в mlut

Простая утилита в mlut из коробки

Простая утилита в mlut из коробки

Простая утилита в mlut из коробки

Простая утилита в mlut из коробки

Диспетчеризация

Поиск и выбор, какая функция будет вызываться для типа данных

Диспетчеризация

Поиск и выбор, какая функция будет вызываться для типа данных

Статическая диспетчеризация

Пример статической диспетчеризации

Динамическая диспетчеризация (ДД)

Пример динамической диспетчеризации

ДД в mlut

Пример динамической диспетчеризации в mlut
Добавление container queries в mlut

JIT engine

Старые CSS фреймворки

Инструменты старого поколения: AOT

  1. Генерируем over9000 утилит

Инструменты старого поколения: AOT

  1. Генерируем over9000 утилит
  2. Смотрим, какие используются

Инструменты старого поколения: AOT

  1. Генерируем over9000 утилит
  2. Смотрим, какие используются
  3. Удаляем лишние

Проблемы старых инструментов

Проблемы старых инструментов

Проблемы старых инструментов

Современные инструменты Atomic CSS

Инструменты нового поколения: JIT

  1. Смотрим, какие утилиты используются
  2. Генерируем только их

Общая схема работы JIT движка

  1. Находим файлы с контентом

Общая схема работы JIT движка

  1. Находим файлы с контентом
  2. Сканируем их и достаем утилиты

Общая схема работы JIT движка

  1. Находим файлы с контентом
  2. Сканируем их и достаем утилиты
  3. Генерируем CSS для найденных утилит

Tailwind 🥴

Tailwind 🥴

Unocss 😎

Unocss 😎

Unocss 😎

Unocss 😎

Atomizer 🙂

Atomizer 🙂

Atomizer 🙂

mlut 🥴

mlut 🥴

Фронт: TypeScript

  • CLI / плагин
  • JIT движок

mlut 🥴

Фронт: TypeScript

  • CLI / плагин
  • JIT движок

Бэк: Sass

  • Генератор утилит и конфиги
  • CSS библиотека
  • Компилятор Sass

Связь Sass и JS

Связь Sass и JS

Мем с рукопожатием

Sass in JS

  1. Загружаем код нужного Sass-модуля

Sass in JS

  1. Загружаем код нужного Sass-модуля
  2. Дописываем в него код

Sass in JS

  1. Загружаем код нужного Sass-модуля
  2. Дописываем в него код
  3. Компилируем итоговый скрипт в CSS

Sass in JS

  1. Загружаем код нужного Sass-модуля
  2. Дописываем в него код
  3. Компилируем итоговый скрипт в CSS
  4. (при необходимости) Достаем данные из вывода

Sass in JS: конфиг по молчанию

Sass in JS: конфиг по молчанию

Sass in JS: js

Sass in JS: конфиг по молчанию

Sass in JS: js

Sass in JS: CSS вывод скрипта

Особенности работы с Sass

Особенности работы с Sass

Особенности работы с Sass

Заключение

Инсайты

Инсайты

Инсайты

Зачем?

Зачем?

Зачем?

Вопросы?

Валентин Ульянов
Презентация:
qr-код на презентацию