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

от автора

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

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

  • мой подход к написанию стилей для динамической сетки без использования БЭМ-модификаторов;
  • как я перестал писать свойство 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *