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

Магия CSS на практике: советы по вёрстке от гика. Часть 6

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


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


Сегодня мы рассмотрим:

  • мой подход к написанию стилей для динамической сетки без использования БЭМ-модификаторов;
  • как я перестал писать свойство text-decoration со значением none для элемента <button>;
  • способ для вычисления значения свойства width в зависимости от контента элемента;
  • почему вам стоит удалить все стили с использованием псевдо-класса :focus.

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


▍ Стили для динамической сетки без БЭМ-модификаторов


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


<body>
  <div class="page">
    <main class="page__content"><!-- Здесь основной контент --></main>
  </div>
</body>

.page {
  display: grid;
}

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


Как быть? Лично я делал дополнительный класс БЭМ-модификатора.


<body>
  <div class="page page_ad--yes">
    <main class="page__content"><!-- Здесь основной контент --></main>
    <div class="page__ad"><!-- Здесь реклама --></div>
  </div>
</body>

.page {
  display: grid;
}

.page_ad--yes {
  grid-template-columns: 1fr 30%;
  gap: 1rem;
}

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


Давайте подумаем, когда появляется необходимость добавить новый класс? Когда в макете появляется новый элемент. Так это ведь то, что делает псевдо-класс :has()!


Когда у нас нет элемента, мы можем написать первый вариант стилей, а когда есть — второй. Вот так выглядит обновлённый код моего примера.


.page {
  display: grid;
}

.page:has(.page__ad) {
  grid-template-columns: 1fr 30%;
  gap: 1rem;
}

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


▍ Я больше не использую свойство text-decoration для элемента <button>


Четырнадцать лет вёрстки отложили свой отпечаток на моём психологическом состоянии. Я иногда рассказываю тут о своих загонах. Вот и сегодня расскажу ещё об одном.


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


В общем, в чём проблема. Когда мы создаём универсальный класс для реализации компонента «Кнопка», то мы вынуждены учитывать, что он может применяться сразу и к элементам <a>, и к элементам <button>.


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


В моём универсальном классе я вынужден сбросить эти свойства. В итоге получается, что свойство text-decoration будет сбрасывать подчёркивание у элемента <button>, а свойство border сбросит рамку у элемента <a>.


.uia-control {
  display: inline-flex;
  text-decoration: none;
  border: none;
}

Для меня супер странно писать свойства, зная, что они применятся там, где и близко не нужны. Ведь у элемента <button> нет подчёркивания, а у элемента <a> нет рамки. Зачем тогда я сбрасываю их?


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


.uia-control {
  display: inline-flex;
  /* оставшиеся стили */
}

a.uia-control {
  text-decoration: none;
}

button.uia-control {
  border: none;
}

Для моих личных проектов решение подходило. Но для команд разработки это было сложно. Поскольку я повысил специфичность селектора, это выливалось в проблемы. Было сложно установить новое значение.


.uia-control {
  display: inline-flex;
  /* оставшиеся стили */
}

a.uia-control {
  text-decoration: none;
}

button.uia-control {
  border: none; /* для элемента <button> применится значение none */
}

.uia-control {
  border: 2px solid lightblue; 
}

В общем коллеги намекнули мне, что такой подход не очень. Поэтому я отказался от него и смирился с тем, что свойства используются нелогично.


А потом появились CSS слои. И у меня появилась новая надежда. Я сразу напишу код и объясню, как он работает.


@layer reset {
  .uia-control {
    /* правило А */
    display: inline-flex;
    /* оставшиеся стили */
  }

  a.uia-control {
    text-decoration: none;
  }

  button.uia-control {
    border: none;
  }
}

.uia-control {
  /* правило Б */
  border: 2px solid lightblue; /* значение применится без проблем! */
}

В этом коде я создаю слой reset. В него добавил правила, которые сбрасывают стили. Теперь у селекторов a.uia-control и button.uia-control более высокий приоритет только внутри слоя. То есть у них приоритет над правилом А с селектором .uia-control.


Но у всего слоя меньший приоритет, чем у стилей без слоя. По этой причине правило Б с селектором .uia-control более специфично. Следовательно, свойства из этого правила без проблем применятся.


Таким способом я пишу только нужные для элемента стили. Мне нравится. Да и коллеги вроде заценили.


▍ Значение, позволяющее рассчитать размеры элемента по контенту


В вёрстке периодически приходится менять стандартное поведение элементов. Я часто вижу, что фронтендеры меняют значение свойства display, чтобы браузеры рассчитывали значение свойства width элемента с блочным значением по контенту.


Они используют значения inline-block, inline-flex или inline-grid.


<body>
  <div class="awesome-block">
    <span> Блочный элемент, значение свойства width рассчитано по контенту</span>
  </div>
</body>

.awesome-block {
  display: inline-flex; /* здесь может быть inline-block или inline-grid */
}

Восемь лет назад это был единственный способ. А CSS же развивается. Вот теперь можно не менять значения свойства display. Есть ключевое значение fit-content.


Оно помогает браузерам рассчитать значение для свойств width, height, min-width, min-height, max-width и max-height так, чтобы контент элемента стремился занять всё пространство. Проще говоря, оно рассчитается по контенту.


Это то, что нужно в нашей задаче. Поэтому удаляем свойство display и добавляем свойство width.


.awesome-block {
  width: fit-content;
}

Отображается элемент с голубым фоном. Видно, что ширина элемента рассчитана по тексту внутри элемента

А самое главное, что в этом варианте не меняются стандартные свойства блочных значений. В первом способе с изменением значения свойства display при добавлении ещё одного элемента <div> они выстраиваются в строку. В способе с ключевым словом fit-content элементы отобразятся в столбец.


<body>
  <div class="awesome-block">
    <span> Блочный элемент, значение свойства width рассчитано по контенту</span>
  </div>
  <div class="awesome-block">
    <span> Блочный элемент, значение свойства width рассчитано по контенту</span>
  </div>
</body>

Два элемента отображены друг под другом. Их ширина рассчитана по тексту внутри них

И последний плюс, чисто субъективный. Если мне нужно изменить принцип расчёта значения свойства width, то странно использовать свойство display. Это похоже на хитрый хак. Я понимаю, когда в CSS не было способа это сделать. Сейчас же есть. Поэтому я отдаю предпочтение ключевому слову fit-content.


▍ Псевдо-класс :focus устарел


Однажды у меня возник вопрос: «А зачем сегодня использовать псевдо-класс :focus?» Так-то не за чем. Я лично везде использую псевдо-класс :focus-visible. Единственно, я думал, что он всё ещё существует в стилях браузера. Решил проверить.


Для этого эксперимента я создал разметку с интерактивными элементами <button>, <a> и <input>. Дальше использовал инструменты разработчика. В них есть панелька, где можно включать различные состояния. Она отобразится, если кликнуть на кнопку «:hov».



Мне нужно было выбрать :focus. Раньше в стилях браузера использовалось свойство outline, которое добавляло обводку вокруг элемента. По моей логике, если состояние :focus всё ещё существует, то она должна была появиться. Вот что я увидел в своём эксперименте.


Четыре интерактивных элемента. У них нет обводки. Также отображается панель разработчика. В ней включено состояние фокус

Обводки нет. Я не буду показывать остальные элементы. У них она тоже не появилась. Я проверил демонстрацию в браузерах Google Chrome, Firefox, Edge и Safari. Нет её. Получается, что в какой-то момент стили для псевдо-класса :focus были удалены.


Только если переключаться клавишей Tab, то обводка появляется у элементов. Я попробовал включить псевдо-класс :focus-visible. Она появилась. И даже у всех элементов.


Четыре интерактивных элемента. У первого есть обводка. Также отображается панель разработчика. В ней включено состояние фокус визибл. В панели со стилями появилось правила, которое добавляет обводку

Я всё ещё встречаю фронтендеров, которые по привычке используют псевдо-класс :focus. Коллеги, уже не надо. Удаляем его и заменяем на псевдо-класс :focus-visible.


▍ Заключение


Давайте подведём итог. В этой статье мы рассмотрели:

  • технику вёрстки изменяемой сетки с помощью псевдо-класса :has();
  • метод сброса стилей с использованием CSS слоёв, позволяющий не добавлять ненужные свойства для элементов;
  • ключевое слово fit-content для вычисления значения свойства width в зависимости от контента элемента;
  • псевдо-класс :focus, который больше не нужен в проектах.

Другие статьи из серии можно найти по тегу «sm909_css_tricks».


Спасибо за чтение!


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


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



Telegram-канал со скидками, розыгрышами призов и новостями IT 💻
Теги:
Хабы:
Всего голосов 42: ↑41 и ↓1+61
Комментарии0

Публикации

Информация

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