Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
CSS глазами машин
Роман Дворнов
Avito
Москва 2018
Работаю в Avito
Open source:

basis.js, CSSO, 

component-inspector, 

csstree, rempl и другие
Доклад о том, как машины* 

понимают CSS и обрабатывают его,

какие есть сложности и проблемы
3
* программы для анализа и трансформации CSS
– Андрей Ситник
“Машины должны страдать!”
4
Но сейчас больше 

страдают разработчики
5
Но сейчас больше 

страдают разработчики
5
Сложно обрабатывать CSS,
т.к. очень много нюансов
«создатели»
Но сейчас больше 

страдают разработчики
5
Сложно обрабатывать CSS,
т.к. очень много нюансов
«создатели»
Баги и непредсказуемость
результатов
«пользователи»
Рассказываю, потому что подгорает :)
• CSSO (мейнтейнер) – минификатор CSS
• CSSTree (автор) – набор инструментов по работе
с CSS, включающий parser, walker, lexer,
generator и т.д.
6
Вводная
CSS
#практики #методологии #трюки #тонкости
#возможности #multitarget...
8
Сложности
• Большое количество директив, свойств, функций и т.д.
• Исключения и особые правила
• Белые пятна в спецификациях
• CSS меняется
• Разная поддержка браузерами
• Баги браузеров
• Хаки
9
Проблемы
• К CSS меньше внимания чем к другим веб-технологиям
• Низкий уровень знания CSS
• Препроцессоры
• FCSS (Fantasy CSS из доклада Вадима Макеева)
• Много CSS кода в проектах (мегабайты)
• Недооценивание масштаба проблем (я оптимист!)
10
• Директивы (at-rule) – 40
• Медиа фичи (media feature) – 69
• Псевдо-классы – 125
• Псевдо-элементы – 146
• Свойства – 1150
• Функции – 69
• Единицы измерения (unit) – 30
11
• Цифры включают легаси и
вендорные имена
• Собрано для словарей CSSTree 

в рамках проекта real-web-css
Без машин не справиться!
12
Программы для анализа
и трансформации CSS

#каксейчас #проблемы #вызовы
А вы задумывались ...
• Как машины видят CSS?
• Как понимают его значение?
• Как понимают что правильно, а что нет?
• Что нужно, чтобы объяснить им как должно быть?
• ...
14
Немного терминологии
Rule (правило)
16
.foo, body > .bar:hover
{
color: red;
}
Rule (правило)
16
.foo, body > .bar:hover
{
color: red;
}
Prelude (прелюдия)
Rule (правило)
16
.foo, body > .bar:hover
{
color: red;
}
Prelude (прелюдия)
Block (блок)
Rule (правило)
16
.foo, body > .bar:hover
{
color: red;
}
Prelude (прелюдия)
Block (блок)
Selector (селектор*)
* в докладе термин "селектор" ссылается на complex selector
Rule (правило)
16
.foo, body > .bar:hover
{
color: red;
}
Prelude (прелюдия)
Block (блок)
Declaration (декларация)
Selector (селектор*)
* в докладе термин "селектор" ссылается на complex selector
At-rule (директива*)
17
@media all, (max-width: 800px)
{
...
}
* перевод из словаря терминов по фронтенду
At-rule (директива*)
17
@media all, (max-width: 800px)
{
...
}
At-keyword
(ключ директивы*)
* перевод из словаря терминов по фронтенду
At-rule (директива*)
17
@media all, (max-width: 800px)
{
...
}
Prelude (прелюдия)
At-keyword
(ключ директивы*)
* перевод из словаря терминов по фронтенду
At-rule (директива*)
17
@media all, (max-width: 800px)
{
...
}
Prelude (прелюдия)
Block (блок)
At-keyword
(ключ директивы*)
* перевод из словаря терминов по фронтенду
Как машины видят CSS
19
CSS РезультатПрограмма
Перевод на
«машинный»
Правила
AST*
структура данных 

для представления исходного кода
20
* Abstract Syntax Tree, тот самый «машинный»
21
.foo {
color: red;
}
{
type: "Rule",
prelude: ".foo",
declarations: [
{
type: "Declaration",
property: "color",
value: "red"
}
]
}
Исходный код AST
Строка (набор символов),
сложно определить где какая часть
Структура (дерево), 

все разложено по полочкам
22
Код
(Строка)
РезультатASTParser
Walker
Generator
Lexer
Обход узлов AST
Применение лексических правил
Преобразование

строки в AST
(перевод 

на «машинный»)
Обычно новый
код (строка) 

+ source map
Преобразование

AST в другое 

представление
(обратное к Parser)
Общая схема по работе с кодом
Так работают ...
• Линтеры (проверяют ошибки)
• Минификаторы
• Подсказки в IDE/редакторах
• Программы форматирования кода
• Пре- и пост-процессоры
• Autoprefixer и т.д.
23
Формат AST
Современные JavaScript парсеры

(esprima, acorn, babylon, ...)

используют спецификацию ESTree
для формата AST
25
Современные CSS парсеры

(PostCSS, CSSTree, Gonzales PE...)
используют каждый свой формат AST, 

общей спецификации нет
26
Какие сложности это вызывает
• Нет совместимости между инструментами с разными
парсерами
• Разработчики парсеров решают одни и те же проблемы
• Сложно с именованием типов узлов и их свойств
• Открытые вопросы как представлять разные части CSS
• Конфликт интересов в формате для разных задач
• Не понятно как правильно
27
Спецификации CSS 

не рассматривают формат AST, 

так как они нацелены на браузеры
28
Что получается у меня:
29
Формат AST в CSSTree
По прежнему есть открытые вопросы :(
Уровень деталей
Пример
31
width: 100px
Пример
31
width: 100px
PostCSS
"100px"
не разбирает значения
Пример
31
width: 100px
PostCSS
"100px"
не разбирает значения
CSSTree
{
type: "Dimension",
value: "100",
unit: "px"
}
1 узел
Пример
31
width: 100px
PostCSS
"100px"
не разбирает значения
CSSTree
{
type: "Dimension",
value: "100",
unit: "px"
}
1 узел
Gonzales-pe
{
type: "dimension",
content: [{
type: "number",
content: "100"
}, {
type: "ident",
content: "px"
}]
}
3 узла
Детальность
32
Меньше Больше
• Больше типов узлов
• Больше памяти на хранение узлов
• Больше времени на обход дерева
• Необходим дополнительный разбор
• Так как "доразбор" на стороне
пользователя: больше зависимостей
и шансов сломаться
Пример: перевод px в rem
33
// !singlequotes|!doublequotes|!url()|pixelunit
var pxRegex = /"[^"]+"|'[^']+'|url([^)]+)|(d*.?d+)px/ig;
ast.walkDecls(function (decl, i) {
...
decl.value = decl.value.replace(pxRegex, function (m, $1) {
// 16px -> 1rem
});
});
postcss-pxtorem (PostCSS плагин)
(недетальное AST)
Та же задача с детальным AST
34
csstree.walk(ast, function (node) {
...
if (node.type === 'Dimension' && node.unit === 'px') {
// ... вычисление нового значения (newValue)
node.value = newValue;
node.unit = 'rem';
}
});
(как мог бы выглядеть плагин на CSSTree)
Пример: подсчет specificity
35
...
attributeRegex = /([[^]]+])/g,
idRegex = /(#[^#s+>~.[:]+)/g,
classRegex = /(.[^s+>~.[:]+)/g,
pseudoElementRegex = /(::[^s+>~.[:]+|:first-line|:first-letter|:before|:after)/gi,
pseudoClassWithBracketsRegex = /(:[w-]+([^)]*))/gi,
pseudoClassRegex = /(:[^s+>~.[:]+)/g,
elementRegex = /([^s+>~.[:]+)/g;
...
specificity (1.2M downloads/month, 32 dependants)
(не детальное AST)
Пример: подсчет specificity
36
...
var A = 0, B = 0, C = 0;
simpleSelector.children.each(function walk(node) {
switch (node.type) {
case 'SelectorList':
case 'Selector':
node.children.each(walk); break;
case 'IdSelector':
A++; break;
case 'ClassSelector':
case 'AttributeSelector':
B++; break;
...
модуль подсчета
specificity в CSSO
(57 SLOC)
(детальное AST)
Детальность AST
• Нужный уровень детальности зависит от задачи 

(например, если обрабатываются только селекторы, 

не нужно разбирать значения деклараций)
• Уровень детализации зависит от парсера
• В некоторых парсерах можно управлять
уровнем детализации
37
Несколько примеров
• PostCSS

Не разбирает (оставляет строкой): прелюдии у директив и правил
(selector list), значения деклараций. Детализация не настраивается
• CSSTree

Не разбирает значения custom properties, но можно включить
настройкой парсера. Можно отключить разбор прелюдий и значений
деклараций
• Gonzales PE

Самой большой уровень детализации. Детализация не настраивается
38
Детальность в CSSTree
39
csstree.parse('@example 1 2;');
{
"type": "Atrule",
"prelude": {
"type": "AtrulePrelude",
"children": [
{ "type": "Number", "value": "1" },
{ "type": "WhiteSpace", "value": " " },
{ "type": "Number", "value": "2" }
]
},
"block": null
}
Детальность в CSSTree
40
csstree.parse('@example 1 2;', {
parseAtrulePrelude: false
});
{
"type": "Atrule",
"prelude": {
"type": "Raw",
"value": "1 2"
},
"block": null
}
Паритет CSSTree с PostCSS
41
csstree.parse(css, {
positions: true,
parseAtrulePrelude: false,
parseRulePrelude: false,
parseValue: false
});
Разбор
CSS is hard
• at-rules @media, @supports, @font-face, …
• необязательные кавычки url(…), [name=value], …
• сложные функции calc(), var(), attr(), …
• экранирование
• bad-url, bad-string…
• …
43
44
#31  + 2 {
content: "hello
world";
background: url(p(4).jpg);
}
Экранирование
drafts.csswg.org/cssom/#the-css.escape()-method
В идентификаторах можно
использовать любые
символы, если экранировать;
в браузерах есть метод для
этого – CSS.escape()
CSS.escape('1 + 2') === '31  + 2'
45
#31  + 2 {
content: "hello
world";
background: url(p(4).jpg);
}
Экранирование
www.w3.org/TR/CSS22/grammar.html#grammar
Можно экранировать
перевод строки в строках, 

как в JavaScript
46
#31 +2 {
content: "hello
world";
background: url(p(4).jpg);
}
Экранирование
www.w3.org/TR/CSS22/grammar.html#grammar
Можно экранировать
специальные символы 

в url()
47
Экранирование
Браузер поймет правильно
Когда парсер плох (Chrome DevTools)
48
@supports (display: flex) {
.simple {
display: flex;
}
}
@supports
49
@supports (display: flex) {
.simple {
display: flex;
}
}
@supports
Декларация
50
@supports (display: flex) {
.simple {
display: flex;
}
}
@supports
Декларация
Тоже декларация
51
@supports (background: top calc(25% + 2px) !important) {
…
}
@supports
С точки зрения спецификаций разрешается все, 

что можно в декларации, даже !important
www.w3.org/TR/css3-conditional/#at-supports
CSS Syntax Module Level 3
Когда возникает ошибка в CSS, парсер постепенно
восстанавливается, выкидывая минимальное количество
контента перед возвращением к разбору в обычном режиме.
Это связано с тем, что ошибки не всегда являются ошибками –
новый синтаксис выглядит как ошибка для старых парсеров, и
это полезно для добавления нового синтаксиса в язык ...
52
§ 2.2. Error Handling
Парсеры CSS толерантные к ошибкам
• CSSTree – толерантный к ошибкам согласно
спецификации
• PostCSS – толерантен к ошибкам, если используется
postcss-safe-parser вместо стандартного парсера.
Соответствие спецификации не известно
• Это все варианты, что я знаю...
53
* парсеры написанные на JavaScript
Итоги
Ключевое
• Нет общего формата AST для CSS
• Уровень детализации AST может быть разный
• Детальное AST может требовать больше ресурсов, 

но удобнее для анализа и трансформации
• Парсинг CSS в AST сложная задача, много нюансов
• CSS парсер должен быть толерантным к ошибкам
55
Формат AST и его свойства,

определяют что и как 

машины могут делать с CSS
56
Обход и поиск
Обход осуществляет walker, обходит все
узлы дерева и вызывает функцию
обработчик
58
Обход
Сложности: декларация
60
@supports (display: flex) {
.foo {
font-family: "Open Sans";
}
}
@font-face {
font-family: "Open Sans";
}
Сложности: декларация
61
@supports (display: flex) {
.foo {
font-family: "Open Sans";
}
}
@font-face {
font-family: "Open Sans";
}
В CSSTree это все декларации
(тип узла Declaration):
• Декларации внутри @supports
обычно обходить не нужно, их
приходится игнорировать (а если
нужны?)
• Внутри @font-face на самом деле не
декларация, а дескриптор
(decscriptor); для них, например,
нельзя применять !important (будет
считать ошибкой и браузер
проигнорирует дескриптор)
Сложности: селекторы
62
@page :first {
...
}
@keyframes name {
from { ... }
25%, 75% { ... }
to { ... }
}
.foo {
...
}
Сложности: селекторы
63
@page :first {
...
}
@keyframes name {
from { ... }
25%, 75% { ... }
to { ... }
}
.foo {
...
}
В CSSTree это все селекторы
(тип узла SelectorList):
• Но обходить селекторы в @page
обычно не нужно; да и по спеке это
<page-selector-list>
• Внутри @keyframes это не обычные
селекторы – <keyframe-selector>; а
блок <keyframe-block>, хотя внутри
все те же декларации
• Все это подталкивает к новым
типам узлов, усложнению парсера и
волкера
Поиск «правильного» формата AST 

и правил обхода – 

сложный процесс проб и ошибок
64
Поиск
Давайте найдем 

все значения цвета?
66
Цвет это ...
• HexColor
• rgb(), rgba(), hls(), hlsa()
• named colors
• deprecated system colors
• vendor named colors
• ...
• CSS Color Module Level 4
• изменения HexColor, rgb(a)/hls(a)
• новое: hwb(), lab(), lch(), color(), color-mod(), device-cmyk()
67
В целом, можно победить – ведь ищем
один узел... если бы не семантика
68
Поиск цвета
69
selector {
font: 10px arial black;
animation-name: red;
whatever: green;
width: blue;
color: superpurple;
}
Сколько значений цвета?
Поиск цвета
70
selector {
font: 10px arial black;
animation-name: red;
whatever: green;
width: blue;
color: superpurple;
}
Ни одного!
Часть имени шрифта

"arial black"
Имя анимации
Неизвестное свойство
В width нельзя указывать цвет
Нет такого цвета
Повышаем ставки – давайте
найдем имена анимаций
71
Типичная задача для удаления не используемых @keyframes
Поиск имени анимации
72
Что является именем анимации?
selector {
animation: infinite forwards normal forwards;
animation: reverse normal forwards;
animation: "reverse" normal forwards;
animation: reverse rotate normal;
animation: "reverse" normal rotate;
}
Поиск имени анимации
73
selector {
animation: infinite forwards normal forwards;
animation: reverse normal forwards;
animation: "reverse" normal forwards;
animation: reverse rotate normal;
animation: "reverse" normal rotate;
}
Сдавайтесь! Это нетривиальная задача
Нет времени объяснять (с) 

тут могут помочь только машины, об этом дальше
Короче, чтобы решать такие задачи
нужно понимать лексическое значение
74
Лексическое значение
76
background: top 100% url(..) no-repeat #008800;
Identifier Url Identifier HexColorPercentage
AST – абстрактные узлы
77
background: top 100% url(..) no-repeat #008800;
Лексическое значение
77
background: top 100% url(..) no-repeat #008800;
background-position
background-image
background-repeat
background-color
Лексическое значение
Как вы поняли что означает

та или иная часть значения?
78
А как должна понять машина?
79
В спецификации
80
В спецификации
80
Грамматика

CSS Values and Units Module
похоже на RegExp, но немного проще
81
drafts.csswg.org/css-values/#value-defs
Шаг первый
Идея, которая поменяла мир (немного)
Идея!
• Собрать синтаксисы в словарь
• Разобрать
• Научиться мапить на AST
• ...
• PROFIT!!!
83
В 2016м нашелся готовый словарь
Mozilla Template:CSSData
84
Таблицы описания свойств из спецификаций
в формате JSON;
использовалось для генерации страниц
developer.mozilla.org
Реализовал разбор грамматики,
загрузил словари, построил граф
зависимостей и тут...
85
CSSData был составлен людьми,
и использовался для генерации страниц для людей
(developer.mozilla.org)
86
😱
О – открытие
Хьюстон, у нас проблемы!
• Ошибки в синтаксисе (нельзя разобрать)
• Некоторые синтаксисы ссылались 

на несуществующие определения
• ...
• Люди не замечали это годами...
87
Я погуглил, пофиксил, 

часть законтрибьютил в CSSData 

(через bugtracker, sic!)
88
Забегая вперед
• Mozilla Template:CSSData – был служебным шаблоном в недрах MDN
• 20 сентября 2016 – дискуссия в багтреке CSSTree относительно словарей
• Призвали ребят из MDN
• Пропушили их разместить CSSData на github
• 19 октября 2016 появился репозиторий mdn/data
• Запушил большую часть фиксов из CSSTree, добавил JSON Schema
• 22 июня 2017 ребята из MDN опубликовали пакет mdn-data 1.0 на npm
• 🎉
89
Словарь mdn/data (CSSData)
стал пригодным для машин
90
🤖
До CSSTree никто не парсил синтаксисы
из спек, авторы спецификаций (пока) не
автоматизируют проверку
91
О – открытие #2
Исправлены ошибки и неточности 

не только в словаре, но и в спецификациях
92
93
background-image: image-set( "foo.png" 1x,
"foo-2x.png" 2x,
"foo-print.png" 600dpi );
Поддерживается в Chrome и Safari
94
background-image: image-set( "foo.png" 1x,
"foo-2x.png" 2x,
"foo-print.png" 600dpi );
Поддерживается в Chrome и Safari
WTF?!
Clarification `Nx` as <resolution>
• Пример нельзя было провалидировать
• Не нашел в спецификациях об этом
• Создал тикет 

https://github.com/w3c/csswg-drafts/issues/461
• В CSS Working Group обсудили вопрос
• Внесены изменения CSS Values and Units Module Level 4
• Роботы победили! 🤖
95
96
Маленькая но важная правка
Спецификации не идеальны,

каждый может помочь сделать их лучше
97
Возможное будущее:
спецификации
адаптированы для машин
98
Сегодня:
спецификации
написаны людьми для людей
Шаг второй
Валидация и побочные продукты
Сразу не получилось полноценно матчить
AST узлы на синтаксисы,
но получилось валидировать
100
Инструменты «хелперы»
на CSSTree для нужд CSSTree
101
102
csstree.github.io/docs/syntax.html
Документация CSS синтаксиса
103
csstree.github.io/docs/validator.html
Валидатор CSS (пока только значения)
Прикладное применение
104
Плагины/пакеты
• csstree-validator – npm пакет + консольная команда
• stylelint-csstree-validator – плагин для stylelint
• gulp-csstree – плагин для gulp
• SublimeLinter-contrib-csstree – плагин для Sublime Text
• vscode-csstree – плагин для VS Code
• atom-plugin – плагин для Atom
105
Огромное спасибо Сергею Мелюкову за его вклад и поддержку!
Шаг третий
Кто ищет – тот найдет
Доработка матчинга – 

новые возможности
107
Вспомним пример ...
108
Теперь CSSTree так видит значение 🤘
Можно трассировать каждый узел
109
Узнать у CSSTree лексический тип
110
csstree.lexer
.matchDeclaration(this.declaration)
.isType(node, 'color')
Используется в CSSO при минификации значений цвета
Синтаксис цвета (без L4)
Синтаксис свойства animation
Поиск с CSSTree
113
// найти все цвета
csstree.lexer.matchAllFragments(ast, 'Type', 'color')
// ... имена анимаций
csstree.lexer.matchAllFragments(ast, 'Type', 'keyframes-name')
// ... имена шрифтов
csstree.lexer.matchAllFragments(ast, 'Type', 'family-name')
Что дальше?
Чтобы добавить новые свойства и
синтаксисы – не нужно менять код, 

достаточно обновить словарь
115
Возможность экспериментировать с новыми синтаксисами,

создавать свои синтаксисы
Решение других задач
• Разворачивание и свертка shorthand-свойств

(например, background <-> background-*)
• Мапинг значения на initial value
• Применение не только для значений деклараций
• Исправить проблемы для сложных случаев
• ...
116
Почему стоит начать изучать грамматику 

CSS Values and Units Module
уже сегодня
117
CSS Properties and Values API Level 1
Позволит задавать свой синтаксис 

для ваших Custom properties
Итоги
Ключевое
• Появился инструмент для работы с грамматикой 

CSS Values and Units Module, которая может стать прикладной
• Приведен в порядок словарь mdn/data (теперь для машин)
• Можно искать фрагменты значений по лексическому типу
• Несколько действительно полезных инструментов –
информационных и прикладных (пощупайте!)
• Новые возможности для ваших идей
119
Словари
Дальнейшее совершенствование
инструментов не возможно без словарей
для машин
121
Словари
• mdn/data – описание свойств (таблицы из спек),
директив, селекторов и т.д.
• mdn/browser-compat-data – поддержка разных
возможностей (JS/CSS/API) браузерами
• known-css-properties – список известных свойств
• caniuse – поддержка браузерами некоторых частей CSS
122
CSS свойств
•mdn/data – 367
•Alexa Top 250 – 483
•Известных свойств – 1150
Что можно сделать:
• найти неописанное свойство
• нагуглить описание
• сделать PR с описанием в JSON
real-web-css
124
real-web-css
125
Заключение
• Всё сложно
• Много нерешенный вопросов в обработке CSS
• Инструменты совершенствуются и переходят на
новый уровень
• Новые возможности
• Словари наше всё
• Вы можете помочь!
127
Обратите внимание на CSS
Роман Дворнов
@rdvornov
rdvornov@gmail.com
Спасибо!
CSSTree
github.com/csstree

More Related Content

CSS глазами машин

  • 1. CSS глазами машин Роман Дворнов Avito Москва 2018
  • 2. Работаю в Avito Open source:
 basis.js, CSSO, 
 component-inspector, 
 csstree, rempl и другие
  • 3. Доклад о том, как машины* 
 понимают CSS и обрабатывают его,
 какие есть сложности и проблемы 3 * программы для анализа и трансформации CSS
  • 4. – Андрей Ситник “Машины должны страдать!” 4
  • 5. Но сейчас больше 
 страдают разработчики 5
  • 6. Но сейчас больше 
 страдают разработчики 5 Сложно обрабатывать CSS, т.к. очень много нюансов «создатели»
  • 7. Но сейчас больше 
 страдают разработчики 5 Сложно обрабатывать CSS, т.к. очень много нюансов «создатели» Баги и непредсказуемость результатов «пользователи»
  • 8. Рассказываю, потому что подгорает :) • CSSO (мейнтейнер) – минификатор CSS • CSSTree (автор) – набор инструментов по работе с CSS, включающий parser, walker, lexer, generator и т.д. 6
  • 10. CSS #практики #методологии #трюки #тонкости #возможности #multitarget... 8
  • 11. Сложности • Большое количество директив, свойств, функций и т.д. • Исключения и особые правила • Белые пятна в спецификациях • CSS меняется • Разная поддержка браузерами • Баги браузеров • Хаки 9
  • 12. Проблемы • К CSS меньше внимания чем к другим веб-технологиям • Низкий уровень знания CSS • Препроцессоры • FCSS (Fantasy CSS из доклада Вадима Макеева) • Много CSS кода в проектах (мегабайты) • Недооценивание масштаба проблем (я оптимист!) 10
  • 13. • Директивы (at-rule) – 40 • Медиа фичи (media feature) – 69 • Псевдо-классы – 125 • Псевдо-элементы – 146 • Свойства – 1150 • Функции – 69 • Единицы измерения (unit) – 30 11 • Цифры включают легаси и вендорные имена • Собрано для словарей CSSTree 
 в рамках проекта real-web-css
  • 14. Без машин не справиться! 12
  • 15. Программы для анализа и трансформации CSS
 #каксейчас #проблемы #вызовы
  • 16. А вы задумывались ... • Как машины видят CSS? • Как понимают его значение? • Как понимают что правильно, а что нет? • Что нужно, чтобы объяснить им как должно быть? • ... 14
  • 18. Rule (правило) 16 .foo, body > .bar:hover { color: red; }
  • 19. Rule (правило) 16 .foo, body > .bar:hover { color: red; } Prelude (прелюдия)
  • 20. Rule (правило) 16 .foo, body > .bar:hover { color: red; } Prelude (прелюдия) Block (блок)
  • 21. Rule (правило) 16 .foo, body > .bar:hover { color: red; } Prelude (прелюдия) Block (блок) Selector (селектор*) * в докладе термин "селектор" ссылается на complex selector
  • 22. Rule (правило) 16 .foo, body > .bar:hover { color: red; } Prelude (прелюдия) Block (блок) Declaration (декларация) Selector (селектор*) * в докладе термин "селектор" ссылается на complex selector
  • 23. At-rule (директива*) 17 @media all, (max-width: 800px) { ... } * перевод из словаря терминов по фронтенду
  • 24. At-rule (директива*) 17 @media all, (max-width: 800px) { ... } At-keyword (ключ директивы*) * перевод из словаря терминов по фронтенду
  • 25. At-rule (директива*) 17 @media all, (max-width: 800px) { ... } Prelude (прелюдия) At-keyword (ключ директивы*) * перевод из словаря терминов по фронтенду
  • 26. At-rule (директива*) 17 @media all, (max-width: 800px) { ... } Prelude (прелюдия) Block (блок) At-keyword (ключ директивы*) * перевод из словаря терминов по фронтенду
  • 29. AST* структура данных 
 для представления исходного кода 20 * Abstract Syntax Tree, тот самый «машинный»
  • 30. 21 .foo { color: red; } { type: "Rule", prelude: ".foo", declarations: [ { type: "Declaration", property: "color", value: "red" } ] } Исходный код AST Строка (набор символов), сложно определить где какая часть Структура (дерево), 
 все разложено по полочкам
  • 31. 22 Код (Строка) РезультатASTParser Walker Generator Lexer Обход узлов AST Применение лексических правил Преобразование
 строки в AST (перевод 
 на «машинный») Обычно новый код (строка) 
 + source map Преобразование
 AST в другое 
 представление (обратное к Parser) Общая схема по работе с кодом
  • 32. Так работают ... • Линтеры (проверяют ошибки) • Минификаторы • Подсказки в IDE/редакторах • Программы форматирования кода • Пре- и пост-процессоры • Autoprefixer и т.д. 23
  • 34. Современные JavaScript парсеры
 (esprima, acorn, babylon, ...)
 используют спецификацию ESTree для формата AST 25
  • 35. Современные CSS парсеры
 (PostCSS, CSSTree, Gonzales PE...) используют каждый свой формат AST, 
 общей спецификации нет 26
  • 36. Какие сложности это вызывает • Нет совместимости между инструментами с разными парсерами • Разработчики парсеров решают одни и те же проблемы • Сложно с именованием типов узлов и их свойств • Открытые вопросы как представлять разные части CSS • Конфликт интересов в формате для разных задач • Не понятно как правильно 27
  • 37. Спецификации CSS 
 не рассматривают формат AST, 
 так как они нацелены на браузеры 28
  • 38. Что получается у меня: 29 Формат AST в CSSTree По прежнему есть открытые вопросы :(
  • 42. Пример 31 width: 100px PostCSS "100px" не разбирает значения CSSTree { type: "Dimension", value: "100", unit: "px" } 1 узел
  • 43. Пример 31 width: 100px PostCSS "100px" не разбирает значения CSSTree { type: "Dimension", value: "100", unit: "px" } 1 узел Gonzales-pe { type: "dimension", content: [{ type: "number", content: "100" }, { type: "ident", content: "px" }] } 3 узла
  • 44. Детальность 32 Меньше Больше • Больше типов узлов • Больше памяти на хранение узлов • Больше времени на обход дерева • Необходим дополнительный разбор • Так как "доразбор" на стороне пользователя: больше зависимостей и шансов сломаться
  • 45. Пример: перевод px в rem 33 // !singlequotes|!doublequotes|!url()|pixelunit var pxRegex = /"[^"]+"|'[^']+'|url([^)]+)|(d*.?d+)px/ig; ast.walkDecls(function (decl, i) { ... decl.value = decl.value.replace(pxRegex, function (m, $1) { // 16px -> 1rem }); }); postcss-pxtorem (PostCSS плагин) (недетальное AST)
  • 46. Та же задача с детальным AST 34 csstree.walk(ast, function (node) { ... if (node.type === 'Dimension' && node.unit === 'px') { // ... вычисление нового значения (newValue) node.value = newValue; node.unit = 'rem'; } }); (как мог бы выглядеть плагин на CSSTree)
  • 47. Пример: подсчет specificity 35 ... attributeRegex = /([[^]]+])/g, idRegex = /(#[^#s+>~.[:]+)/g, classRegex = /(.[^s+>~.[:]+)/g, pseudoElementRegex = /(::[^s+>~.[:]+|:first-line|:first-letter|:before|:after)/gi, pseudoClassWithBracketsRegex = /(:[w-]+([^)]*))/gi, pseudoClassRegex = /(:[^s+>~.[:]+)/g, elementRegex = /([^s+>~.[:]+)/g; ... specificity (1.2M downloads/month, 32 dependants) (не детальное AST)
  • 48. Пример: подсчет specificity 36 ... var A = 0, B = 0, C = 0; simpleSelector.children.each(function walk(node) { switch (node.type) { case 'SelectorList': case 'Selector': node.children.each(walk); break; case 'IdSelector': A++; break; case 'ClassSelector': case 'AttributeSelector': B++; break; ... модуль подсчета specificity в CSSO (57 SLOC) (детальное AST)
  • 49. Детальность AST • Нужный уровень детальности зависит от задачи 
 (например, если обрабатываются только селекторы, 
 не нужно разбирать значения деклараций) • Уровень детализации зависит от парсера • В некоторых парсерах можно управлять уровнем детализации 37
  • 50. Несколько примеров • PostCSS
 Не разбирает (оставляет строкой): прелюдии у директив и правил (selector list), значения деклараций. Детализация не настраивается • CSSTree
 Не разбирает значения custom properties, но можно включить настройкой парсера. Можно отключить разбор прелюдий и значений деклараций • Gonzales PE
 Самой большой уровень детализации. Детализация не настраивается 38
  • 51. Детальность в CSSTree 39 csstree.parse('@example 1 2;'); { "type": "Atrule", "prelude": { "type": "AtrulePrelude", "children": [ { "type": "Number", "value": "1" }, { "type": "WhiteSpace", "value": " " }, { "type": "Number", "value": "2" } ] }, "block": null }
  • 52. Детальность в CSSTree 40 csstree.parse('@example 1 2;', { parseAtrulePrelude: false }); { "type": "Atrule", "prelude": { "type": "Raw", "value": "1 2" }, "block": null }
  • 53. Паритет CSSTree с PostCSS 41 csstree.parse(css, { positions: true, parseAtrulePrelude: false, parseRulePrelude: false, parseValue: false });
  • 55. CSS is hard • at-rules @media, @supports, @font-face, … • необязательные кавычки url(…), [name=value], … • сложные функции calc(), var(), attr(), … • экранирование • bad-url, bad-string… • … 43
  • 56. 44 #31 + 2 { content: "hello world"; background: url(p(4).jpg); } Экранирование drafts.csswg.org/cssom/#the-css.escape()-method В идентификаторах можно использовать любые символы, если экранировать; в браузерах есть метод для этого – CSS.escape() CSS.escape('1 + 2') === '31 + 2'
  • 57. 45 #31 + 2 { content: "hello world"; background: url(p(4).jpg); } Экранирование www.w3.org/TR/CSS22/grammar.html#grammar Можно экранировать перевод строки в строках, 
 как в JavaScript
  • 58. 46 #31 +2 { content: "hello world"; background: url(p(4).jpg); } Экранирование www.w3.org/TR/CSS22/grammar.html#grammar Можно экранировать специальные символы 
 в url()
  • 60. 48 @supports (display: flex) { .simple { display: flex; } } @supports
  • 61. 49 @supports (display: flex) { .simple { display: flex; } } @supports Декларация
  • 62. 50 @supports (display: flex) { .simple { display: flex; } } @supports Декларация Тоже декларация
  • 63. 51 @supports (background: top calc(25% + 2px) !important) { … } @supports С точки зрения спецификаций разрешается все, 
 что можно в декларации, даже !important www.w3.org/TR/css3-conditional/#at-supports
  • 64. CSS Syntax Module Level 3 Когда возникает ошибка в CSS, парсер постепенно восстанавливается, выкидывая минимальное количество контента перед возвращением к разбору в обычном режиме. Это связано с тем, что ошибки не всегда являются ошибками – новый синтаксис выглядит как ошибка для старых парсеров, и это полезно для добавления нового синтаксиса в язык ... 52 § 2.2. Error Handling
  • 65. Парсеры CSS толерантные к ошибкам • CSSTree – толерантный к ошибкам согласно спецификации • PostCSS – толерантен к ошибкам, если используется postcss-safe-parser вместо стандартного парсера. Соответствие спецификации не известно • Это все варианты, что я знаю... 53 * парсеры написанные на JavaScript
  • 67. Ключевое • Нет общего формата AST для CSS • Уровень детализации AST может быть разный • Детальное AST может требовать больше ресурсов, 
 но удобнее для анализа и трансформации • Парсинг CSS в AST сложная задача, много нюансов • CSS парсер должен быть толерантным к ошибкам 55
  • 68. Формат AST и его свойства,
 определяют что и как 
 машины могут делать с CSS 56
  • 70. Обход осуществляет walker, обходит все узлы дерева и вызывает функцию обработчик 58
  • 72. Сложности: декларация 60 @supports (display: flex) { .foo { font-family: "Open Sans"; } } @font-face { font-family: "Open Sans"; }
  • 73. Сложности: декларация 61 @supports (display: flex) { .foo { font-family: "Open Sans"; } } @font-face { font-family: "Open Sans"; } В CSSTree это все декларации (тип узла Declaration): • Декларации внутри @supports обычно обходить не нужно, их приходится игнорировать (а если нужны?) • Внутри @font-face на самом деле не декларация, а дескриптор (decscriptor); для них, например, нельзя применять !important (будет считать ошибкой и браузер проигнорирует дескриптор)
  • 74. Сложности: селекторы 62 @page :first { ... } @keyframes name { from { ... } 25%, 75% { ... } to { ... } } .foo { ... }
  • 75. Сложности: селекторы 63 @page :first { ... } @keyframes name { from { ... } 25%, 75% { ... } to { ... } } .foo { ... } В CSSTree это все селекторы (тип узла SelectorList): • Но обходить селекторы в @page обычно не нужно; да и по спеке это <page-selector-list> • Внутри @keyframes это не обычные селекторы – <keyframe-selector>; а блок <keyframe-block>, хотя внутри все те же декларации • Все это подталкивает к новым типам узлов, усложнению парсера и волкера
  • 76. Поиск «правильного» формата AST 
 и правил обхода – 
 сложный процесс проб и ошибок 64
  • 78. Давайте найдем 
 все значения цвета? 66
  • 79. Цвет это ... • HexColor • rgb(), rgba(), hls(), hlsa() • named colors • deprecated system colors • vendor named colors • ... • CSS Color Module Level 4 • изменения HexColor, rgb(a)/hls(a) • новое: hwb(), lab(), lch(), color(), color-mod(), device-cmyk() 67
  • 80. В целом, можно победить – ведь ищем один узел... если бы не семантика 68
  • 81. Поиск цвета 69 selector { font: 10px arial black; animation-name: red; whatever: green; width: blue; color: superpurple; } Сколько значений цвета?
  • 82. Поиск цвета 70 selector { font: 10px arial black; animation-name: red; whatever: green; width: blue; color: superpurple; } Ни одного! Часть имени шрифта
 "arial black" Имя анимации Неизвестное свойство В width нельзя указывать цвет Нет такого цвета
  • 83. Повышаем ставки – давайте найдем имена анимаций 71 Типичная задача для удаления не используемых @keyframes
  • 84. Поиск имени анимации 72 Что является именем анимации? selector { animation: infinite forwards normal forwards; animation: reverse normal forwards; animation: "reverse" normal forwards; animation: reverse rotate normal; animation: "reverse" normal rotate; }
  • 85. Поиск имени анимации 73 selector { animation: infinite forwards normal forwards; animation: reverse normal forwards; animation: "reverse" normal forwards; animation: reverse rotate normal; animation: "reverse" normal rotate; } Сдавайтесь! Это нетривиальная задача Нет времени объяснять (с) 
 тут могут помочь только машины, об этом дальше
  • 86. Короче, чтобы решать такие задачи нужно понимать лексическое значение 74
  • 88. 76 background: top 100% url(..) no-repeat #008800; Identifier Url Identifier HexColorPercentage AST – абстрактные узлы
  • 89. 77 background: top 100% url(..) no-repeat #008800; Лексическое значение
  • 90. 77 background: top 100% url(..) no-repeat #008800; background-position background-image background-repeat background-color Лексическое значение
  • 91. Как вы поняли что означает
 та или иная часть значения? 78
  • 92. А как должна понять машина? 79
  • 95. Грамматика
 CSS Values and Units Module похоже на RegExp, но немного проще 81 drafts.csswg.org/css-values/#value-defs
  • 96. Шаг первый Идея, которая поменяла мир (немного)
  • 97. Идея! • Собрать синтаксисы в словарь • Разобрать • Научиться мапить на AST • ... • PROFIT!!! 83
  • 98. В 2016м нашелся готовый словарь Mozilla Template:CSSData 84 Таблицы описания свойств из спецификаций в формате JSON; использовалось для генерации страниц developer.mozilla.org
  • 99. Реализовал разбор грамматики, загрузил словари, построил граф зависимостей и тут... 85
  • 100. CSSData был составлен людьми, и использовался для генерации страниц для людей (developer.mozilla.org) 86 😱 О – открытие
  • 101. Хьюстон, у нас проблемы! • Ошибки в синтаксисе (нельзя разобрать) • Некоторые синтаксисы ссылались 
 на несуществующие определения • ... • Люди не замечали это годами... 87
  • 102. Я погуглил, пофиксил, 
 часть законтрибьютил в CSSData 
 (через bugtracker, sic!) 88
  • 103. Забегая вперед • Mozilla Template:CSSData – был служебным шаблоном в недрах MDN • 20 сентября 2016 – дискуссия в багтреке CSSTree относительно словарей • Призвали ребят из MDN • Пропушили их разместить CSSData на github • 19 октября 2016 появился репозиторий mdn/data • Запушил большую часть фиксов из CSSTree, добавил JSON Schema • 22 июня 2017 ребята из MDN опубликовали пакет mdn-data 1.0 на npm • 🎉 89
  • 104. Словарь mdn/data (CSSData) стал пригодным для машин 90 🤖
  • 105. До CSSTree никто не парсил синтаксисы из спек, авторы спецификаций (пока) не автоматизируют проверку 91 О – открытие #2
  • 106. Исправлены ошибки и неточности 
 не только в словаре, но и в спецификациях 92
  • 107. 93 background-image: image-set( "foo.png" 1x, "foo-2x.png" 2x, "foo-print.png" 600dpi ); Поддерживается в Chrome и Safari
  • 108. 94 background-image: image-set( "foo.png" 1x, "foo-2x.png" 2x, "foo-print.png" 600dpi ); Поддерживается в Chrome и Safari WTF?!
  • 109. Clarification `Nx` as <resolution> • Пример нельзя было провалидировать • Не нашел в спецификациях об этом • Создал тикет 
 https://github.com/w3c/csswg-drafts/issues/461 • В CSS Working Group обсудили вопрос • Внесены изменения CSS Values and Units Module Level 4 • Роботы победили! 🤖 95
  • 111. Спецификации не идеальны,
 каждый может помочь сделать их лучше 97
  • 112. Возможное будущее: спецификации адаптированы для машин 98 Сегодня: спецификации написаны людьми для людей
  • 113. Шаг второй Валидация и побочные продукты
  • 114. Сразу не получилось полноценно матчить AST узлы на синтаксисы, но получилось валидировать 100
  • 119. Плагины/пакеты • csstree-validator – npm пакет + консольная команда • stylelint-csstree-validator – плагин для stylelint • gulp-csstree – плагин для gulp • SublimeLinter-contrib-csstree – плагин для Sublime Text • vscode-csstree – плагин для VS Code • atom-plugin – плагин для Atom 105 Огромное спасибо Сергею Мелюкову за его вклад и поддержку!
  • 120. Шаг третий Кто ищет – тот найдет
  • 121. Доработка матчинга – 
 новые возможности 107
  • 122. Вспомним пример ... 108 Теперь CSSTree так видит значение 🤘
  • 124. Узнать у CSSTree лексический тип 110 csstree.lexer .matchDeclaration(this.declaration) .isType(node, 'color') Используется в CSSO при минификации значений цвета
  • 127. Поиск с CSSTree 113 // найти все цвета csstree.lexer.matchAllFragments(ast, 'Type', 'color') // ... имена анимаций csstree.lexer.matchAllFragments(ast, 'Type', 'keyframes-name') // ... имена шрифтов csstree.lexer.matchAllFragments(ast, 'Type', 'family-name')
  • 129. Чтобы добавить новые свойства и синтаксисы – не нужно менять код, 
 достаточно обновить словарь 115 Возможность экспериментировать с новыми синтаксисами,
 создавать свои синтаксисы
  • 130. Решение других задач • Разворачивание и свертка shorthand-свойств
 (например, background <-> background-*) • Мапинг значения на initial value • Применение не только для значений деклараций • Исправить проблемы для сложных случаев • ... 116
  • 131. Почему стоит начать изучать грамматику 
 CSS Values and Units Module уже сегодня 117 CSS Properties and Values API Level 1 Позволит задавать свой синтаксис 
 для ваших Custom properties
  • 133. Ключевое • Появился инструмент для работы с грамматикой 
 CSS Values and Units Module, которая может стать прикладной • Приведен в порядок словарь mdn/data (теперь для машин) • Можно искать фрагменты значений по лексическому типу • Несколько действительно полезных инструментов – информационных и прикладных (пощупайте!) • Новые возможности для ваших идей 119
  • 135. Дальнейшее совершенствование инструментов не возможно без словарей для машин 121
  • 136. Словари • mdn/data – описание свойств (таблицы из спек), директив, селекторов и т.д. • mdn/browser-compat-data – поддержка разных возможностей (JS/CSS/API) браузерами • known-css-properties – список известных свойств • caniuse – поддержка браузерами некоторых частей CSS 122
  • 137. CSS свойств •mdn/data – 367 •Alexa Top 250 – 483 •Известных свойств – 1150 Что можно сделать: • найти неописанное свойство • нагуглить описание • сделать PR с описанием в JSON
  • 141. • Всё сложно • Много нерешенный вопросов в обработке CSS • Инструменты совершенствуются и переходят на новый уровень • Новые возможности • Словари наше всё • Вы можете помочь! 127