CSS mind – Telegram
Channel created
Channel photo updated
Привет! Меня зовут София, я CSS-инженер.
В этот канал я нерегулярно и неравномерно пишу конспекты разделов спецификаций W3C и не только.
Автор канала - @ariarzer
CSS mind pinned «Привет! Меня зовут София, я CSS-инженер. В этот канал я нерегулярно и неравномерно пишу конспекты разделов спецификаций W3C и не только. Автор канала - @ariarzer»
О терминологии селекторов

Термин «селектор» может относиться к простому селектору, составному селектору, сложному селектору или списку селекторов.

Простой селектор - это отдельное условие для элемента. Селектор типа, универсальный селектор, селектор атрибутов, селектор класса, селектор идентификатора или псевдокласс - это простой селектор. Он представлен как <simple-selector> в грамматике селекторов.

Составной селектор - это последовательность простых селекторов, не разделенных комбинатором, и представляет собой набор одновременных условий для одного элемента. Если он содержит селектор типа или универсальный селектор, этот селектор должен быть первым в последовательности. В последовательности разрешен только один селектор типа или универсальный селектор. Составной селектор представлен как <compound-selector> в грамматике селекторов. Считается, что данный элемент соответствует составному селектору, если он соответствует всем простым селекторам в составном селекторе.

Комбинатор - это условие взаимосвязи между двумя составными селекторами. Комбинаторы в селекторах уровня 4 включают: комбинатор потомков (пробел), комбинатор прямых потомков (U+003E, >), комбинатор следующего элемента (U+002B, +) и комбинатор последующих элементов (U+007E, ~). Говорят, что два заданных элемента соответствуют комбинатору, если условие взаимосвязи между этими элементами истинно.

Сложный селектор - это последовательность из одного или нескольких составных селекторов, разделенных комбинаторами. Он представляет собой набор одновременных условий для набора элементов в определенных отношениях, описываемых его комбинаторами. Сложные селекторы представлены <complex-selector> в грамматике селекторов. Считается, что данный элемент соответствует сложному селектору, когда существует список элементов, каждый из которых соответствует соответствующему составному селектору в сложном селекторе, с каждой парой последовательные элементы в списке, соответствующих комбинатору между соответствующими составными селекторами, причем последний элемент является данным элементом.

Список селекторов - это список простых, составных или сложных селекторов, разделенных запятыми. Это также называется просто списком селекторов, когда тип не важен или указан в окружающем тексте; если тип важен и не указан, по умолчанию используется список сложных селекторов. Списки селекторов представоены <* - selector-list> в грамматике. Считается, что данный элемент соответствует списку селекторов, если он соответствует любому (по крайней мере, одному ) селекторов в этом списке селекторов.

#selectors
Псевдоклассы

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

Синтаксис псевдокласса состоит из ":" (U + 003A COLON), за которым следует имя псевдокласса в качестве идентификатора CSS, и, в случае функционального псевдокласса, пара круглых скобок, содержащих свои аргументы.

Например: valid - это обычный псевдокласс, а lang () - это функциональный псевдокласс.

Как и все ключевые слова CSS, имена псевдоклассов не чувствительны к регистру. Запрещается использовать пробелы между двоеточием и именем псевдокласса, а также, как обычно для синтаксиса CSS, между именем функционального псевдокласса и его открывающими скобками (которые, таким образом, образуют `<function-token>`). Также, как обычно, разрешены пробелы вокруг аргументов внутри скобок функционального псевдокласса, если для конкретного псевдокласса не указано иное.

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

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

#selectors #pseudo_class
О тонкостях парсинга списка селекторов

Список селекторов, разделенных запятыми, представляет собой объединение всех элементов, выбранных каждым из отдельных селекторов этого списка. Например, когда несколько селекторов собержат одни и те же декларации, они могут быть сгруппированы в список, разделенный запятыми. Перед запятой и/или после нее может быть пробел или перенос строки.

h1 { font-family: sans-serif }
h2 { font-family: sans-serif }
h3 { font-family: sans-serif }

/* то же самое что: */

h1, h2, h3 { font-family: sans-serif }


НО! Это работает только пока все селекторы в списке валидны. Как только один них ошибочен, дропается весь список.

h1 { font-family: sans-serif } /* работает */
h2.. { font-family: sans-serif } /* НЕ работает */
h3 { font-family: sans-serif } /* работает */

/* НЕ то же самое что: */

h1, h2.., h3 { font-family: sans-serif } /* НЕ работает*/


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

input[type=range]::-webkit-slider-runnable-track {
background-color: orange;
}

input[type=range]::-moz-range-track {
background-color: orange;
}


Если же написать их в списке, то, признав второй селектор невалидным, хром дропнет весь список и декларации внутри ни к чему не будут применены:

input[type=range]::-webkit-slider-runnable-track,
input[type=range]::-moz-range-track {
background-color: orange;
}


#selectors
Дополнение к "О тонкостях парсинга списка селекторов"

Пусть и запоздало, но о будущей обратной совместимости все-таки подумали.

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

Поэтому новые фукнциональные псевдоклассы используют не <selector-list>, который при парсинге дропается если один из селекторов невалидный, а новую продукцию <forgiving-selector-list>.

Эта продукция анализирует каждый селектор в списке индивидуально, игнорируя те, которые не удалось проанализировать. Синтаксически это эквивалентно <any-value>?.

#selectors
Функциональные псевдоклассы is() и where()

Псевдокласс match-any :is() - это функциональный псевдокласс, принимающий <forgiving-selector-list> в качестве единственного аргумента.
Он сопостовляется с любым селектором из переданного списка, но его специфичность равна наибольшей среди элементов списка. Поясним на примере.

С первого взгляда можно подумать что это просто синтаксический сахар :is(.a, .b) .c === .a .c, .b .c. Однако :is(#id, .b) .c !== #id .c, .b .c.

То есть вот в такой ситуации цвет будет красный:

<div class="a">Lorem</div>
<style>
:is(#id, .a) {color: red;}
.a {color: blue;}
</style>


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

Иллюстрируем тем же примером, цвет будет синий:

<div class="a">Lorem</div>
<style>
:where(#id, .a) {color: red;}
.a {color: blue;}
</style>


Оба псевдокласса поддерживаются в FireFox начиная c 78 версии и в Safari c 14.

#selectors #pseudo_class #function_pseudo_class
Псевдоэлементы

Подобно тому, как псевдоклассы представляют дополнительную информацию о состоянии, не представленную непосредственно в DOM, псевдоэлемент представляет элемент, не присутствующий непосредственно в DOM.

Синтаксис псевдоэлемента: “::” (два символа U+003A COLON), за которым следует имя псевдоэлемента в качестве идентификатора. Имена псевдоэлементов не чувствительны к регистру. Запрещается использовать пробелы между двумя двоеточиями или между двоеточиями и именем.
Поскольку CSS уровня 1 и уровня 2 объединяют псевдоэлементы и псевдоклассы, разрешая синтаксис с одним двоеточием для обоих, юзер-агенты также должны принимать предыдущую нотацию с одним двоеточием для псевдоэлементов уровней 1 и 2 (::before , ::after, ::first-line и ::first-letter). Эта нотация не допускается ни для каких других псевдоэлементов и оставлена только для обратной совместимости.

Псевдоэлементы не существуют независимо в дереве: они всегда привязаны к другому элементу на странице, называемому их исходным элементом. Синтаксически псевдоэлемент следует сразу за составным селектором, представляющим его исходный элемент. Если этот составной селектор опущен, предполагается, что это универсальный селектор *.
Например, в селекторе div a::before элементы a, соответствующие селектору, являются исходными элементами для прикрепленных к ним псевдоэлементов ::before.

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

#selectors #pseudo_elements

Источник: https://drafts.csswg.org/selectors-4/#pseudo-elements
У меня теперь есть блог и в нем есть первая статья.

Про процесс вычисления значения css-свойства.

https://ariarzer.dev/css-value-processing.html

P.S. Что в телеграм по формату не лезет будет теперь там.
Не тыкать в пользователя ошибками, пока он ничего не сделал

Показать пользвателю ошибку позволяет псевдокласс :invalid. Он соответствует инпустам, значение которых не валидно.

В этом примере инпут, если он пустой, будет иметь класный фон:

<input required type="text">
<style>
:invalid {
background-color: red;
}
</style>


Так при первом заходе пользователя на страницу поле будет уже подсвечено красным цветом. А он даже не прочитал что надо вводить и вообще что это за сайт. Неприятно.

Решение: в новом черновике спецификации селекторов описан класс :user-invalid. Он соответствует тем полям, с которыми пользователь провзаимодействовал + срабатывает также после нажатия на button[type="submin"] или input[type="submin"].

В этом примере поле подсветится красным только когда пользователь что-то в него введет, удалит и уберет фокус, или после нажания на кнопку отправки формы:

<form action="">
<label>
Text
<input required type="text">
</label>
<button type="submin">Submit</button>
</form>
<style>
input:user-invalid {
background-color: red;
}
</style>


Прежде чем вы попытались опробовать этот пример в деле: сейчас это так НЕ работает. Поддержки селектора нет почти нигде. Только частично за префиксом в FireFox под другим именем. Подробнее на MDN про :-moz-ui-invalid.

#selectors #pseudo_class

Источник: https://drafts.csswg.org/selectors-4/#user-pseudos
Пару дней назад вышел первый рабочий черновик спецификации CSS Cascading and Inheritance 5 уровня.

Главное обновление - директива @ layer.

Написала о текущем ее состоянии и добавила пару примеров зачем оно может быть надо, если дойдет до браузеров :
https://ariarzer.dev/css-cascade-layer.html
Несколько слов про calc()

Рассмотрим пример:

<div></div>
<style>
div {
height: calc(-14px);
}
</style>


Подробно поведение браузера можно посмотреть в этом пэне. Здесь же ограничимся информацией о том, что эта декларации валидная и Used value высота для блока будет 0px.

Почему отрицательное значение может быть валидно для высоты?
Потому что calc() наследуется в вычисленном не до конца виде.

Computed value - это значение, которое вложенные блоки наследуют как inherit. На этом этапе значения в относительных единицах (em, ex, vh, vw, но не проценты) приводятся к пикселям. Это утверждение относится и к значениям, содержащим calc() или другие функции.

Например:

height: calc(50% - 25px); /* => CV=calc(50% - 25px) */
height: calc(100px - 5em); /* => CV=calc(50px) */


Рассмотрим пример с вложенными блоками, объясняющий зачем это нужно:

<div class="a"> // 100px
<div class="b"> // 60px
<div class="c"> // 20px
<div class="d"></div> //0px
</div>
</div>
</div>
<style>
.a { height: 100px; }
.b { height: calc(100% - 40px); } /* => CV=calc(100% - 50px) */
.c { height: inherit; } /* => CV=calc(100% - 50px) */
.d { height: inherit; } /* => CV=calc(100% - 50px) */
</style>


Для каждого блока выражение вычисляется заново и для блока .d вычисление наследованного выражение дает отрицательное значение. НО! Во время вычисления used value для функий проводится Range Checking.

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

Однако значение свойства все же должно быть ограничено диапазоном, разрешенным в целевом контексте.

Range Checking выполняется на этапе computed value, если это возможно (то есть если выражение не содержит процентов и возможно вычисление для пикселей), и на этапе used value во всех остальных случаях.

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

#css_functions

Источник: https://www.w3.org/TR/css-values-4/#calc-range
Для описания css-функций в статье использовала сочетание синтаксиса JSDoc, VDS и css-переменных.

Думаю, это можно назвать css-doc.

В сравнении с VDS и текстовым описанием в спецификации получилось гораздо более наглядно.

https://css-live.ru/css/css-colors.html
О color-mix() на март 2021

На прошлой неделе CSSWG рассмотрела несколько ишью о функции color-mix(), поэтому считаю нужным написать о ней подробнее.

Эта функция принимает два значения <color> и возвращает результат их смешивания в заданной пропорции в заданном цветовом пространстве.

Грамматика функции, указанная в спецификации:

color-mix() = color-mix( in <colorspace> , [ <color> && <percentage>? ]#{2})

Более наглядно:

/*
* @param {<colorspace>} --colorspace Цветовое пространство
* @param {<color>} --color1 Первый цвет
* @param {<percentage>} [--p1: 50%] Доля первого цвета
* @param {<color>} --color2 Второй цвет
* @param {<percentage>} [--p2: 50%] Доля второго цвета
*/
color: color-mix(in var(--colorspace), var(--color1) var(-p1), var(--color2) var(-p2))


Проценты нормализуются следующим образом:
1. Пусть p1 будет первым процентом, а p2 - вторым.
2. Если оба процента опущены, каждое из них по умолчанию равно 50% (равное сочетание двух цветов).
3. В противном случае, если p2 опущен, он становится 100% - p1
4. В противном случае, если p1 опущен, он становится 100% - p2
5. Если сумма процентов равна нулю поведение пока не определено
6. Если оба значение опредоставлены, но не дают в сумме 100%, они масштабируются соответствующим образом, чтобы они в сумме составляли 100%. Это означает, что p1 = p1 / (p1 + p2), а p2 = p2 / (p1 + p2).

После нормализации обоих значений результат получается по следующему алгоритму:
1. Оба цвета преобразуются в указанное цветовое пространство. Если заданное цветовое пространство имеет меньшую гамму, чем та, в которой задан цвет, который должен быть настроен, будет выполнено отображение гаммы.
2. Затем цвета интерполируются в указанном цветовом пространстве. Результатом смешивания является указанное процентное соотношение цвета по мере перехода от второго цвета к первому.

Для больше наглядности разберем пример:

color-mix(in lch, peru 40%, lightgoldenrod)

1. peru: lch(62.253% 54.011 63.677)
2. lightgoldenrod: lch(91.374% 31.415 98.821)
3. смешение светлоты: 62.253 * 40/100 + 91.374 * (100-40)/100 = 79.7256
4. смешение количества цвета: 54.011 * 40/100 + 31.415 * (100-40)/100 = 40.4534
5. смешение тона: 63.677 * 40/100 + 98.821 * (100-40)/100 = 84.7634
6. результат: lch(79.7256% 40.4534 84.7634)
Обновление рабочего черновика слоёв

На встрече 17 марта принято решение об обновлении рабочего черновика css-cascade-5.
Коротко о главном.

Синтаксиис импорта в слой
5681

Из-за синтаксических конфликтов с объявлением пустого слоя синтакис импорта решено поменять. Новый синтаксис импорта в слой:

@import [ <url> | <string> ] layer | layer (<layer-ident>)

Например:

@import url("links.css") layer(myLayer);

Ключевое слово revert-layer
5681

Если cascaded value свойства является ключевое слово revert-layer, то оно откатывается до уровня ниже, так что specified value вычисляется так, как если бы правила не были указаны в текущем слое для этого свойства в этом элементе.

Если в том же каскадном источнике нет объявлений с более низким приоритетом, чем значение revert-layer, каскадное значение вернется к предыдущему источнику, как и для ключевого слова revert.

Например, в этом примере кнопка будет красной:

@layer common {
button { color: red; }
}

@layer components {
button {
color: blue;
}
button {
color: revert-layer;
}
}


А здесь синей:

@layer common {
button { color: red; }
}

@layer components {
.class {
color: blue;
}
button {
color: revert-layer;
}
}


P.S. Статья про слои тоже обновлена.
У меня теперь есть RSS на сайте, так что посты из этого канала скоро можно будет читать и там тоже.

ariarzer.dev/rss.xml

P.S. Не верьте feedly, там три статьи, он просто еще не обновился.