Как стать автором
Обновить
3160.62
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

«Безумный» CSS квиз от гика

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров3.1K


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


Сразу скажу, что вопросы в нём только отчасти имеют практический смысл. На практике навряд ли вы столкнётесь с ними. Но это так задумано! Я специально хочу сделать всё, чтобы вы не ответили на вопросы! Поэтому, пожалуйста, не воспринимайте квиз серьёзно. Просто весело проведём время.


Конечно, я оставлю своё решение для каждого вопроса. Будет классно, если вы тоже добавите своё в комментариях. Я тоже хочу учиться. Давайте вместе увидим, каким может быть CSS.


Так, вы готовы? Давайте посмотрим, что я вам подготовил.


▍ Задача №1


Есть абстрактный элемент с классом .awesome-block. Я хотел установить ему фон с помощью background-color. Но, находясь в приподнятом настроении, добавил значение 10px.


:root {
  --\*: 10px;
}

.awesome-block {
  background-color: tomato;
  background-color: var(--\*); /* какое здесь будет значение в devTools? */
}

Сработает ли этот код? Если да, какое значение вычислят браузеры для свойства background-color?

Ответ

Сначала разберёмся с пользовательским свойством --\*. Может показаться, что оно написано с нарушением синтаксиса. Это не так.


Как говорится в спецификации, название пользовательского свойства — это специальный CSS-идентификатор <dashed-ident>, начинающийся с --. Одновременно к нему применимы правила синтаксиса CSS-идентификатора <ident>, описанного в стандарте CSS Syntax Module Level 3. По правилам мы можем использовать символы [a-zA-Z0-9], дефис -, подчёркивание _ и другие ASCII-символы, если их экранировать.


Получается, что ошибки нет. Для свойства background-color браузеры передадут значение 10px.


:root {
  --\*: 10px;
}

.awesome-block {
  background-color: tomato;
  background-color: var(--\*); /* здесь значение 10px */
}

Мы получили ситуацию, когда после замены пользовательского свойства получается некорректное значение для свойства background-color. Браузеры это понимают и не могут позволить такому произойти. Они некорректное значение заменят корректным.


Здесь стандартами описаны два сценария. Они зависят от типа свойства. Если оно не позволяет наследовать значение, используется начальное (initial) значение. Если значение можно получить в результате алгоритма наследования, то так и произойдёт.


В нашем примере используется свойство background-color. Оно не является наследуемым. По этой причине вместо некорректного значения 10px подставляется начальное значение, т. е. transparent.


:root {
  --\*: 10px;
}

.awesome-block {
  background-color: tomato;
  background-color: var(--\*); /* в итоге здесь значение transparent */
}

Правильный ответ — Код корректный. Браузеры вычислят значение transparent.


▍ Задача №2


Сидел я как-то вечером и думал: «Можно ли добавить обводку к родительскому элементу, когда пользователь сфокусировался на определённом дочернем элементе при помощи клавиатуры?». В итоге я придумал одно решение. Вам нужно его повторить.


В задаче мы будем использовать следующую разметку:


<body>
  <div class="awesome-block">
    <a href="#0" class="no-call-outline">ссылка не вызывает обводку</a>
    <a href="#0" class="call-outline">ссылка вызывает обводку</a>		
  </div>
</body>

Вам нужно написать селектор, который сработает только на элементе с классом .call-outline, когда пользователь сфокусировался при помощи клавиатуры, и добавить свойство outline со значением 3px solid darkolivegreen к элементу с классом .awesome-block.


Если пользователь сфокусировался на элемент с классом .no-call-outline, стили не должны быть добавлены. Также нужно учесть, что если по элементу кликнули мышкой, то стили не должны применяться.


Я оставляю изображения итогового результата. Думаю, так вам будет проще.



Ответ

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


Всё было бы хорошо, но нет. Данный код будет срабатывать на любом интерактивном элементе. А нам нужно только на том, у которого установлен класс .call-outline.


Следующий способ отследить попадание фокуса на дочернем элементе основан на использовании псевдо-класса :has. Мы буквально скажем, что если на элементе сфокусировались, то применяй стили.


.awesome-block:has(.call-outline:focus) {
  outline: 3px solid darkolivegreen;
}

Это почти правильное решение. Поскольку в условии задачи сказано, что нужно отлавливать момент фокусировки только при помощи клавиатуры, то псевдо-класс :focus не подходит. Тут нужен псевдо-класс :focus-visible.


.awesome-block:has(.call-outline:focus-visible) {
  outline: 3px solid darkolivegreen;
}

Так выглядит мой правильный вариант.


▍ Задача №3


Представим, что у нас есть элемент с классом .awesome-block.


<body>
  <div class="awesome-block"></div>		
</body>

Он создаёт грид-контейнер с сеткой из шести колонок и четырёх строк.


.awesome-block {
  box-sizing: border-box;
  min-height: 100dvh;
  border: 1px solid currentColor;

  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(4, 1fr);

  position: relative;
}

У него также есть дочерний псевдо-элемент ::before. Он растягивается на всю ширину и высоту родительского элемента с помощью свойства inset.


.awesome-block::before {
  content: "";
  background-color: darkolivegreen;

  position: absolute;
  inset: 0;
}

У меня к вам вопрос. Если для псевдо-элемента ::before добавить свойства grid-column и grid-row, продолжит ли он растягиваться на всю ширину и высоту родительского элемента с классом .awesome-block?


.awesome-block::before {
  content: "";
  background-color: darkolivegreen;

  grid-column: 2 / span 2;
  grid-row: 2 / span 2;

  position: absolute;
  inset: 0;
}
Ответ

Для правильного ответа нужно вспомнить, какая задача у свойств grid-column и grid-row. Она заключается в указании номеров линий, по которым браузеры рассчитают положение дочерних элементов. Другими словами, этими свойствами мы очерчиваем контур, где будет расположен элемент.


В моём примере строка grid-column: 2 / span 2 приведёт к тому, что элемент будет отображаться, начиная от второй линии, отвечающей за колонки, и заканчиваться через две линии. Строка grid-row: 2 / span 2 делает то же самое, только по направлению строк.


После создания контура браузеры начинают использовать его для расчёта координат для свойств top, right, bottom, right и inset, если у грид-контейнера установлено свойство position со значением relative.


В нашем примере это условие соблюдается, и по этой причине псевдо-элемент ::before перестаёт растягиваться по размерам родительского элемента .awesome-block и начинает это делать по созданному свойствами grid-column и grid-row контуру.



В итоге правильный ответ — псевдо-элемент ::before перестаёт растягиваться по родительскому элементу с классом .awesome-block.


▍ Задача №4


Напоследок я подготовил творческое задание. Мы будем рисовать на CSS флаг Индонезии. Я уже подготовил разметку:


<body>
  <div class="indonesia">
    <div class="indonesia__group"></div>
    <div class="indonesia__group"></div>
  </div>
</body>

У флага будет ширина шестьсот пикселей, а высота — четыреста пикселей. Цвета я уже тоже задал.


.indonesia {
  width: 600px;
  height: 400px;
  border: 2px solid;
}

.indonesia__group:first-child {
  background-color: #f70000;
}

.indonesia__group:nth-child(2) {
  background-color: #fff;
}

Какие есть способы сделать равные две полоски, расположенные друг под другом? Важно учесть, что если высота элемента с классом .indonesia поменяется, то высота полос динамически подстроится под новое значение.

Ответ

Первый способ будет основан на использовании свойства flex-grow.


.indonesia {
  display: flex;
  flex-direction: column;
}

.indonesia__group {
  flex-grow: 1;
}

Главная задача свойства flex-grow — это растянуть элемент по основной оси. Его значение указывает, в какой пропорции нужно распределять свободное пространство, по которому браузеры будут тянуть элемент.


Поскольку полосы во флаге Индонезии одинаковые, то и пространство должно равномерно растянуться. Это означает, что у элементов с классом .indonesia__group должно быть одинаковое значение для свойства flex-grow. Я выбрал 1.


Второй способ ещё проще, чем первый. Мы просто объявим свойство display со значением grid для элемента с классом .indonesia.


.indonesia {
  display: grid; /* ещё можно inline-grid */
}

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


В третьем способе мы будем работать со свойством inset.


.indonesia {
  position: relative;
}

.indonesia__group {
  position: absolute;
  inset-inline: 0;
}

.indonesia__group:first-child {
  inset-block: 0 50%;
}

.indonesia__group:nth-child(2) {
  inset-block: 50% 0;
}

Свойство inset — это краткая альтернативна для свойств top, right, bottom и left. Если мы устанавливаем значение 0, то получаем такое значение сразу со всех сторон. А это приводит к тому, что элемент со свойством position и значением absolute занимает всю ширину и высоту родительского элемента с нестатическим значением для свойства position. Напомню, что это все значения, кроме static.


Только нам нужно, чтобы первая полоса по высоте занимала пятьдесят процентов. Соответственно нам нужно сделать отступ снизу для первого элемента с классом .indonesia__group, и сверху для второго элемента. Поэтому я использую значение 50%.


▍ Заключение


В этой статье мы рассмотрели вопросы, касающиеся следующих тем:


  • какие правила синтаксиса есть у пользовательских CSS свойств;
  • что делают браузеры, если после замены пользовательского CSS свойства получилось некорректное значение;
  • наши новые возможности отслеживать дочерние элементы при разных состояниях с помощью псевдо-класса :has;
  • ограничение псевдо-класса :focus-within по сравнению с псевдо-классом :has;
  • разницу между псевдо-классами :focus-visible и :focus;
  • что меняется при позиционировании элементов со свойством position и значением absolute внутри грид-контейнера, если для него ещё добавили свойства grid-column и grid-row;
  • свойство дочерних элементов равномерно растягиваться на всю ширину и высоту родительского элемента;
  • свойство inset является краткой альтернативой для свойств top, right, bottom и left;
  • значение 0, установленное для свойств top, right, bottom и left приводит к тому, что элемент c position: absolute начинает занимать всё пространство родительского элемента, если у него установлено любое значение для свойства position, кроме static.

Также, пожалуйста, напишите в комментариях, какие вопросы или задачки спросили бы вы. Буду ждать их. Спасибо за чтение!


P.S. Помогаю больше узнать про CSS в своём ТГ-канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.


© 2024 ООО «МТ ФИНАНС»


Telegram-канал со скидками, розыгрышами призов и новостями IT 💻
Теги:
Хабы:
+28
Комментарии3

Публикации

Информация

Сайт
ruvds.com
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия
Представитель
ruvds