Мои любимые вопросы о CSS с ответами. Версия 2023 года

hf_k493dccgdqre2swyqa-b8jhg.png


В 2020 году я поделился списком моих любимых вопросов о CSS, который стал довольно популярным, судя по просмотрам. Спустя 3 года CSS изменился, и я решил дополнить список, добавив вопросы про гриды, пользовательские свойства (CSS-переменные), новые селекторы и свойства.

Работая над вопросами, мне хотелось помочь вам в изучении новых возможностей CSS и тех моментов, которые многие разработчики упускают, судя по моей практике. Также вы можете использовать их, если проводите интервью. Я буду только рад этому. А теперь давайте начнём.

▍ Какая специфичность следующего правила?

:is(#container, .content, main) {
  color: red;
}


Ответ

Принцип работы псевдокласса :is() заключается в том, что браузеры выбирают наиболее специфичный селектор из переданных. В нашем случае передан селектор #container, у которого специфичность 0,1,0,0. Она же будет использоваться для всего правила.


▍ Верно ли, что браузеры вычислят значение red для свойства color?


  текст элемента












.label {
  color: red;
}

:where(#label) {
  color: blue;
}


Ответ

Верно. Поскольку псевдокласс :where() имеет специфичность 0, то в нашем примере более специфичным будет правило с селектором .label. Соответственно, браузеры возьмут значение для свойства color из него.


▍ Перепишите следующий код так, чтобы свойства применялись при клике на кнопку, но не применялись, когда на неё сфокусировались при помощи клавиатуры.

.button {
  outline: none;
  color: red;
}


Ответ
Для определения способа фокусировки на кнопке я буду использовать псевдокласс :focus-visible, который срабатывает, когда пользователь сфокусировался на интерактивном элементе при помощи клавиатуры.

В задаче требуется не применять свойства, поэтому нужно использовать инверсию, т. е псевдокласс :not(), а также добавить псевдокласс :focus, чтобы стили срабатывали после клика по кнопке.

.button:focus:not(:focus-visible) {
  outline: none;
  color: red;
}


▍ Какое вычисленное значение для свойства display у псевдоэлементов ::before и ::after?


.parent {
  display: inline-grid;
}

.parent::before {
  content: "";
  display: inline;	
}

.parent::after {
  content: "";
  display: flex;
}


Ответ
После объявления значений grid или inline-grid для элемента браузеры сделают проверку значения для свойства display его дочерних элементов. Если у них будет значение inline, inline-block, inline-flex, inline-grid или inline-table, то оно трансформируется в блочный аналог, а именно inline, inline-block в block, inline-flex в flex, inline-grid в grid и inline-table в table.

В нашем примере у псевдоэлемента ::before установлено значение inline, поэтому оно преобразуется в block, а для псевдоэлемента ::after значение flex будет сохранено.

.parent {
  display: inline-grid;
}

.parent::before {
  content: "";
  display: inline; /* здесь будет display: block */		
}

.parent::after {
  content: "";
  display: flex; /* здесь будет display: flex */
}


▍ Как по умолчанию отображаются дочерние элементы внутри родительского с display: grid или display: inline-grid?


Ответ

После объявления display: grid или display: inline-grid для родителя его дочерние элементы начинают отображаться в столбец.


▍ Чему равняется вычисленное значение для свойства width и height у элементов .child?


  
элемент №1
элемент №2
.parent {
  display: grid;
  width: 1000px;
  height: 400px;
}


Ответ
В нашем примере используется display: grid. В этом случае свойство width будет эквивалентно свойству width родительского элемента, т.е будет 1000px. В свою очередь, вычисление свойства height зависит от количества элементов.

Если внутри грид-контейнера один элемент, то свойство height будет таким же, как у родителя. Если несколько элементов, то свойство height распределяется между элементами. В примере у всех дочерних элементов не объявлено свойство height, поэтому у них одинаковая высота, следовательно, нужно разделить 400px на 2, и мы получим 200px.


▍ Верно ли, что внешние отступы у первого и последнего элемента p выходят за границы родительского элемента?

body {
  display: grid;
}

p {
  margin-top: 1em;
  margin-bottom: 1em;
}


Ответ

После объявления display: grid внешние отступы у первого и последнего элемента перестают выходить за пределы родительского элемента. Соответственно, правильный ответ — неверно.


▍ Если добавить display: grid к элементу, будут ли схлопываться внешние отступы у его дочерних элементов?


Ответ

Внутри грид-контейнера внешние отступы между элементами суммируются, а не схлопываются.


▍ Псевдоэлемент ::before располагается по центру по горизонтали и по вертикали. Да или нет?

.box {
  display: inline-grid;
  width: 200px;
  height: 200px;
}

.box::before {
  content: "";
  width: 15px;
  height: 15px;
  margin: auto;
}


Ответ

Да, псевдоэлемент ::before располагается по центру по горизонтали и по вертикали, потому что внутри грид-контейнера автоматические внешние отступы распределяются равномерно по обеим осям.


▍ В следующем примере для свойства padding будет установлено значение 0. Правда или ложь?

:root {    
  --padding-vertical-start: 30px;
  --padding-horizontal-end: 40px;
  --padding-vertical-end: 50px;
}

.box {
  padding: var(--padding-vertical-start) 
	       var(--padding-horizontal-end) 
	       var(--padding-vertical-end) 
	       var(--padding-horizontal-start);
}


Ответ
Когда мы используем пользовательские CSS-свойства в краткой форме записи обычного свойства, мы должны определить все значения, требуемые таким свойством, потому что браузеры без этого не смогут правильно соотнести значения.

В примере со свойством padding из-за того, что не хватает одного значения, браузеры не знают, к какой стороне относят переданные значения 30px, 40px и 50px, поэтому вычисленное значение для всех сторон будет 0, соответственно, правильный ответ — правда.


▍ Какое вычисленное значение будет у свойства font-size и background-color у элемента p?

body {
  --font-size: purple;
  --background-color: 20px;
	
  font-size: 10px;
  background-color: green;
}

p {
  --font-size: inherit;
  --background-color: inherit;
	
  font-size: var(--font-size, 50px);
  background-color: var(--background-color, red);
}


Ответ
При использовании ключевого слова inherit для пользовательских свойств нужно помнить, что они наследуют значение только между собой, и поэтому пользовательские свойства --font-size и --background-color унаследуют значения purple и 20px.
body {
  --font-size: purple;
  --background-color: 20px;
	
  font-size: 10px;
  background-color: green;
}

p {
  --font-size: inherit; /* здесь значение purple */
  --background-color: inherit; /* здесь значение 20px */
	
  font-size: var(--font-size, 50px);
  background-color: var(--background-color, red);
}

Далее эти значения используются для свойств font-size и background-color, поэтому значения по умолчанию 50px и red будут проигнорированы. После этого браузеры должны вместо функции var() подставить значение пользовательского свойства. Перед тем как это сделать, они проверят, является ли значение корректным для свойства, для которого происходит замена.

В нашем случае значения некорректны, потому что значение purple должно быть подставлено для свойства font-size, а значение 20px для свойства background-color. Но ошибки здесь не будет! В этом случае есть алгоритм, согласно которому браузеры подставят корректное значение.

Для этого они анализируют свойство, для значения которого происходит замена. Если оно наследуемое, то значение будет вычислено в результате наследования, если нет, то будет использоваться начальное значение (initial).

В нашем примере свойство font-size наследуемое, поэтому значение для элемента p будет 10px, которое наследуется от свойства font-size элемента body, а свойство background-color ненаследуемое, поэтому будет использоваться начальное значение, а именно transparent.

body {
  --font-size: purple;
  --background-color: 20px;
	
  font-size: 10px;
  background-color: green;
}

p {
  --font-size: inherit; 
  --background-color: inherit; 
	
  font-size: var(--font-size, 50px); /* здесь получается font-size: 10px */
  background-color: var(--background-color, red); /* здесь получается background-color: transparent */
}


▍ Почему для элемента p браузеры вычислят значение green для свойства background-color?

body {
  background-color: green;
}

p {
  --background-color: inherit;
  background-color: var(--background-color, inherit);
}


Ответ
Поскольку для элемента body не определено пользовательское свойство --background-color, то наследовать значение с помощью ключевого слова inherit неоткуда. Так что значение для пользовательского свойства --background-color будет не определено.

Соответственно, браузеры подставят значение по умолчанию inherit, а с помощью него передадут значение green по алгоритму наследования.


▍ Каким свойством можно сократить количество определённых свойств для псевдоэлемента ::before до трёх?

.parent {
  position: relative;
}

.parent::before {
  content: "";
  width: 100%;
  height: 100%;
  
  position: absolute;
  top: 0;
  left: 0;
}


Ответ
Разобьём задачу на этапы. Поскольку используется position: absolute, то можно альтернативно установить размеры с помощью свойств top, right, bottom и left.
.parent {
  position: relative;
}

.parent::before {
  content: "";
  
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

Теперь сократим их в одно свойство inset.
.parent {
  position: relative;
}

.parent::before {
  content: ""; 
  position: absolute;
  inset: 0;
}


▍ Перепишите следующий код так, чтобы определение значений для свойств margin и padding было без использования 0

.box {
  margin: 0 20px 0 40px;
  padding: 30px 0 15px;
}


Ответ
Здесь мы можем использовать логические свойства margin-block, margin-inline, padding-block и padding-inline. Важно помнить, что первым значением устанавливается значение сначала (сверху и слева), а вторым — значение с конца (снизу и справа).
.box {
  margin-inline: 40px 20px;
  padding-block: 30px 15px;
}


▍ Как с помощью свойства gap можно сократить следующий код до одного правила?

ul {
  display: flex;
}

li:not(:last-child) {
  margin-right: 15px;
}


Ответ
Для того, чтобы установить отступы между элементами внутри элемента с display: flex, кроме свойства margin, мы можем использовать свойство gap.
ul {
  display: flex;
  gap: 15px;
}


▍ Как с помощью свойства isolation расположить псевдоэлемент ::after позади текста, чтобы он не перекрывался фоном элемента .parent?


  
текст элемента
.parent {
  background-color: purple;
}

.container {
  position: relative;
}

.container::after {
  content: "";
  background-color: green;
  
  position: absolute;
  inset: 0;
  z-index: -1;
}


Ответ
Когда используется отрицательное значение для свойства z-index, то мы должны помнить, относительно какого контекста наложения (stacking context) будет расчёт положения. Поскольку в коде не создаётся новый контекст, то будет использоваться корневой, то есть элемент html. Поэтому псевдоэлемент ::after с отрицательным z-index будет позади элемента .parent.

Чтобы отобразить его позади текста элемента .container, нужно сделать этот элемент новым контекстом с помощью свойства isolation, для которого задать значение isolate.

.parent {
  background-color: purple;
}

.container {
  position: relative;
  isolation: isolate;
}

.container::after {
  content: "";
  background-color: green;
  
  position: absolute;
  inset: 0;
  z-index: -1;
}


▍ Вместо заключения


Мне интересно прочитать, какие темы о CSS, по вашему мнению, я упустил. Или, возможно, у вас есть свой список любимых вопросов. Так что, пожалуйста, делитесь. Я нацелен написать третью версию через 3 года! Ваша помощь будет очень кстати. Спасибо.

Выиграй телескоп и другие призы в космическом квизе от RUVDS. Поехали?

© Habrahabr.ru