От декларации до отображения
Sofi Valitova, CSS-engineer
Валитова София
От декларации
до отображения

:root { color: yellow;}
div { color: 40px;}
.class { color: gold !important;}
#id { color: 1ms;}
@keyframes color {
from { color: fuchsia; }
to { color: tomato; }
}
:has(.class, #id) {
color: purple !important;
}
* { animation: color 2s infinite; }

Поплыли!
Value processing
- Declared value
- Cascaded value
- Specified value
- Computed value
- Used Value
- Actual Value
Declared value
Список всех значений, подходящих этому элементу.
- Селектор
- Условия
- Проверка типа
Declared value
Список всех значений, подходящих этому элементу.
- Селектор
- Условия
- Проверка типа
Селектор
<div class="a">CSS</div>
<style>
#id { /* ... */ }
.a { /* ... */ }
div { /* ... */ }
</style>
Declared value
Сбор всех деклараций свойства, применимых к элементу
- Селектор
- Условия
- Проверка типа
Условия
<div class="a">Safari IOs</div>
<style>
@media (max-width: 600px) {}
@supports (display: flex) {}
@media (min-width: 1200px) {}
</style>
Declared value
Сбор всех деклараций свойства, применимых к элементу
- Селектор
- Условия
- Проверка типа
Проверка типа
<div class="a">CSS</div>
<style>
.a {
height: 12ms;
height: 12em;
}
</style>


Короткие свойства (shorthand) 🦖

Короткие свойства (shorthand) 🦖
background: url('image.svg');
то же самое, что:
background-image: url('image.svg');
background-color: initial;
background-origin: initial;
....

Выбрали декларации
свойство | значение | селектор | место |
border-left-color | red | #abc | cssWritingModes.html:12 |
border-left-style | solid | #id | style.css:14 |
height | 10px | - | style attribute |
color | green | [attr='value'] | style.css:6 |
border-left-color | red | .a | style.css:123 |
Cascading
Style
Sheets
Что такое каскад?
Cascaded value
Каскад принимает неупорядоченный список объявленных значений, сортирует их по приоритету их объявления, и выводит одно значение.
Cascaded value
- Уровни объявления
- Слои
@layer
- Специфичность селекторов
- Порядок объявления
Уровни объявления
Декларации из Transition |
!important декларации user-агента |
!important декларации пользователя |
!important декларации автора (то есть разработчика) |
Animation декларации |
Декларации автора (то есть разработчика) |
Декларации пользователя |
Декларации user-агента |
Уровни объявления
Декларации из Transition | transition |
!important декларации user-агента | ! user-agent |
!important декларации пользователя | ! user |
!important декларации автора (то есть разработчика) | ! author |
Animation декларации | animation |
Декларации автора (то есть разработчика) | author |
Декларации пользователя | user |
Декларации user-агента | user-agent |
Декларации user-агента
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent

Декларации user-агента
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent

Декларации автора
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
.blue {
color: blue;
}
.red {
color: red;
}
Декларации автора
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
.blue {
color: blue;
}
.red {
color: red !important;
}
Декларации анимаций
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
.blue {
color: red;
animation: anim 3s infinite;
}
@keyframes anim {
50% {color: green;}
}
Декларации анимаций
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
.blue {
color: red !important;
animation: anim 3s infinite;
}
@keyframes anim {
50% {color: green;}
}
Декларации переходов
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
.red {
color: red;
transition: color 1s;
}
.green
color: green;
}
Декларации переходов
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
.red {
color: red;
transition: color 1s;
}
.green
color: green !important;
}
Декларации пользователя

Уровни объявления
Декларации из Transition |
!important декларации user-агента |
!important декларации пользователя |
!important декларации автора (то есть разработчика) |
Animation декларации |
Декларации автора (то есть разработчика) |
Декларации пользователя |
Декларации user-агента |
История
Декларации анимаций в 2020
.blue {
color: red !important;
animation: anim 3s infinite;
}
@keyframes anim {
50% {color: green;}
}




Выводы из истории:
Не молчите
о проблеме
Cascaded value
- Уровни объявления
- Слои
@layer
- Специфичность селекторов
- Порядок объявления
Слои @layer
Способ создать уровни объявления внутри стилей автора.
@layer default, components, theme;
@layer default {
button { color: red; }
}
@import url('theme.css') layer(theme); }
@layer components {
button { color: green; }
}
А что, если у нас две декларации на одном уровне?
Две декларации на одном уровне?
<div class="red" id="blue">
CSS
</div>
<style>
#blue { color: blue; }
.red { color: red; }
</style>
Две декларации на одном уровне?
<div class="red" id="blue">
CSS
</div>
<style>
#blue { color: blue !important; }
.red { color: red !important; }
</style>
Здесь нет конфликта селекторов
- transition
- ! user-agent
- ! user
- ! author
- animation
- author
- user
- user-agent
<div class="red" id="blue">
CSS
</div>
<style>
.red { color: red !important; }
#id { color: blue; }
</style>
Коэффициент специфичности
Набор чисел, позволяющий определить приоритет селектора.
- как разряды в числе
- как семантическое версионирование
Коэффициент специфичности
Селектора делятся на 3 уровня:
#id | +1 | 0 | 0 |
.class , :hover ,[name="value"] | 0 | +1 | 0 |
::before , div | 0 | 0 | +1 |
Коэффициент специфичности
Селектора делятся на 3 уровня:
#id | 1 * 100 | 0 * 10 | 0 * 1 | 100 |
.class , :hover ,[name="value"] | 0 * 100 | 1 * 10 | 0 * 1 | 010 |
::before , div | 0 * 100 | 0 * 10 | 1 * 1 | 001 |
Коэффициент специфичности
span | 0 * 100 | 0 * 10 | 1 * 1 | 001 |
.class #id | 1 * 100 | 1 * 10 | 0 * 1 | 110 |
.class #id::before:hover | 1 * 100 | 2 * 10 | 1 * 1 | 121 |
#id [name="value"] | 1 * 100 | 1 * 10 | 0 * 1 | 110 |
Коэффициент специфичности

А минусы где?
Сравним 11 классов и один идентификатор:
#id
= 1 * 10^2
+ 0 * 10^1
+ 0 * 10^0
= 100
.a.b.c.d.e.f.e.r.g.t.h
=
= 0 * 10^2
+ 11 * 10^1
+ 0 * 10^0
= 110
⁕⁕⁕ ⁕⁕
⁕⁕⁕⁕⁕?????
11 классов больше идентификатора???
На самом деле чуть-чуть не так
Используется степень двойки.
1 * 10^2
+ 1 * 10^1
+ 1 * 10^0
1 * 2^24
+ 1 * 2^16
+ 1 * 2^8

Семантическое версионирование
1.0.2
Коэффициент специфичности
селектор | major | minor | patch | результат |
span | 0 | 0 | 1 | 0.0.1 |
.class #id | 1 | 1 | 1 | 1.1.0 |
.class #id::before:hover | 1 | 2 | 1 | 1.2.1 |
#id [name="value"] | 1 | 1 | 0 | 1.1.0 |
Коэффициент специфичности
селектор | major | minor | patch | результат |
#id | 1 | 0 | 0 | 1.0.0 |
.a.b.c.d.e.f.e.r.g.t.h | 0 | 11 | 0 | 0.11.0 |
polypane.app/css-specificity-calculator/


Атрибут style
Считается специфичнее всего для целей этого этапа.
<div id="id" style="color:red">CSS</div>
<style>
#id { color: blue; }
<style>
Порядок объявления
А что, если у нас два селектора одной специфичности?
https://twitter.com/mxstbr/status/1038073603311448064<div class="red blue">CSS</div>
<style>
.blue { color: blue; }
.red { color: red; }
</style>
Порядок объявления
Чем ближе к концу документа, тем приоритетнее
https://twitter.com/mxstbr/status/1038073603311448064<div class="red blue">CSS</div>
<style>
.blue { color: blue; }
.red { color: red; }
</style>
Выбрали одну декларацию
свойство | значение | селектор | место |
height | 100px | #abc | index.html:12 |
height | 10em | #id | style.css:14 |
height | calc(50% - 25px) | - | style="" |
height | 50% | [n='4'] | style.css:6 |
height | 1vh | .a | style.css:123 |
Specified value
А что, если свойство не указали ни мы, ни юзер-агент?
Specified value
А что, если свойство не указали ни мы, ни юзер-агент?
Берем initial value

Теперь у свойства точно есть значение
Computed value
Значение, которое наследуется.
height: 100px; // => 100px
height: inherit // => 100px
font-size: 10px;
height: 5em; // => 50px CV=50px
font-size: 20px;
height: inherit; // => 50px CV=50px
Computed value
- Вычисляются зависимые величины.
height: 100px; // => 100px
height: 50%; // => 50px CV = 50%
height: inherit; // => 25px CV = 50%
Computed value
- Вычисляются зависимые величины. Кроме процентов!
--h: 100px;
height: var(--h); // => 100px CV=100px
--h: 10px;
height: inherit; // => 100px CV=100px
Computed value
- Проценты не вычисляются. Но остальные зависимые величины вычисляются.
- Подставляются переменные.
После этого этапа у нас есть значение, в котором посчитано все, что можно посчитать без отрисовки документа.
Used value
Считаем проценты
height: 50%;
/* CV = 50% */
/* UV = 25px */
Считаем calc()
width: calc(100px - 50%);
/* CV = calc(100px - 50%) */
/* UV = 25px */
Немного про calc()
width: calc(-50px);
width: calc(2s);
width: calc(50% - 50px);
width: 100px; // => 100px
width: calc(50% - 25px); // => UV = 25px
width: inherit; // => -12.5px ???
Range Checking (Проверка диапазона)
Приводим к ближайшему допустимому.

width: 100px; // => 100px
width: calc(50% - 25px); // => UV = 25px
width: inherit; // => 0px
Считаем calc-size()
height: calc-size(auto, size - 50%);
/* CV = calc-size(auto, size - 50%) */
/* UV = 25px */
Справка про calc-size()
calc-size( <calc-size-basis>, <calc-sum> )
- Базис
- Выражение для вычисления
Справка про calc-size()
width: calc-size(max-content, size / 2);
Actual value
Преобразования на основе ограничений среды.
- Округление пикселей до целых.
- Приведение цвета в тот, который может отобразить экран.
Один слайд, чтобы править всеми
- Отбираем декларации
- Выбираем одну
- Наследуем её
- Вычисляем
- Отрисовываем на устройстве
Источники
- Спецификация css-cascade-4
- Про Value Definition Syntax
- Про Value Processing
- Почтовая рассылка www-style
София Валитова из KiskoLabs
- ariarzer@gmail.com
- Twitter – @ariarzer
- Telegram – @ariarzer
- Мой канал про css – @css_mind
- Мой блог про css – ariarzer.dev
Презентация сделана с помощью Shower.