
Хабр, привет! Я снова пришёл к вам со статьёй, где показываю мои любимые техники вёрстки. Моя цель — поделиться опытом с вами. Я использую не только трюки известных экспертов, есть лично мои придумки. Но, пожалуйста, относитесь к этому контенту как просто к альтернативному мнению. Мои техники не являются единственными правильными решениями.
Сегодня мы рассмотрим:
- мой подход к написанию стилей для динамической сетки без использования БЭМ-модификаторов;
- как я перестал писать свойство
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
ссылка на оригинал статьи https://habr.com/ru/articles/887542/
Добавить комментарий