Хабр, привет! Я снова пришёл к вам со статьёй, где показываю мои любимые техники вёрстки. Моя цель — поделиться опытом с вами. Я использую не только трюки известных экспертов, есть лично мои придумки. Но, пожалуйста, относитесь к этому контенту, как к просто альтернативному мнению. Мои техники не являются единственными правильными решениями.
Сегодня мы рассмотрим:
- подходы при стилизации элементов для вёрстки текста;
- какая может быть проблема с радиокнопками в вашем проекте;
- как задать размеры с использованием функций
min()
иmax()
; - CSS-наследование и свойство
line-height
; - для чего делать подсказки в имени класса.
Давайте посмотрим, что я вам подготовил.
▍ Способы стилизации текста
Кажется, стилизация текста довольна простая задача. Написал всякие font-size
и line-height
и дело готово. Только есть пару нюансов.
В принципе у нас есть два вида текста. Разделяются они по способу добавления на страницу. К первому случаю относится текст, добавленный разработчиком при вёрстке макета. Например, текст на сайте Нижегородской области.
Второй тип текста добавляется редактором сайта через редактор. Обычно это новостные страницы или страницы с документами.
В первом случае, кажется, нет никаких нюансов. Добавил класс и написал стили для заголовков и абзацев. А вот во втором случае он есть. Многие редакторы не позволяют добавлять класс. После редактирования текста в редакторе, в коде будут просто элементы. Такие, как <p>
, <ul>
, <h2>
и т. п.
Столкнувшись с этой проблемой, я начал гуглить, что же можно делать. Нашёл два подхода. Первый подход основан на сложном селекторе с классом и селектором типа. Пример можно найти на Хабре.
.article-formatted-body ol,
.article-formatted-body ul {
padding-inline-start: 32px;
}
.article-formatted-body h2 {
font-size: 1.25rem;
line-height: 1.625rem;
}
.article-formatted-body p {
margin: 0;
padding: 0;
}
В данном подходе создаётся специальный класс .article-formatted-body
. Он не даёт случиться утечке стилей, чтобы они не стали применяться к таким же элементам в других частях приложения.
Второй способ основан на селекторе :not([class])
.
:is(ul, ol):not([class]) {
margin-block: 2rem 0;
}
h2:not([class]) {
font-size: 1.25rem;
line-height: 1.625rem;
}
p:not([class]) {
margin-block: 2rem 0;
}
Для реализации этой идеи существует правило. Атрибут class
добавляется только для элементов, доступных для редактирования разработчиками. Элементы, редактируемые через редактор, должны быть без атрибута. В этом случае селектор :not([class])
сработает отлично.
Мне лично больше нравится второй подход. Во-первых, не надо придумывать имя класса. Во-вторых, код выглядит более структурировано. В-третьих, я люблю встроенные возможности CSS.
Но это всё личные предпочтения. А что выбираете вы? И как вы поступаете в таких задач? Напишите, пожалуйста, в комментариях.
▍ Подружим радиокнопки и режим высокой контрастности в Windows
Я посмотрел много популярных решений кастомных радиокнопок на Codepen. У них у всех есть общая проблема. Они используют свойство background-color
для установки цвета точки при активном состоянии. Взгляните на псевдоэлемент ::before
.
.toggle {
appearance: none;
margin: 0;
width: 1rem;
height: 1rem;
border: 1px solid #242424;
border-radius: 50%;
display: grid;
place-items: center;
}
.toggle[type="radio"]::before {
content: "";
width: 0.5rem;
height: 0.5rem;
background-color: #242424;
border-radius: 50%;
opacity: 0;
position: absolute;
scale: 0;
}
.toggle[type="radio"]:checked::before {
opacity: 1;
scale: 1;
}
Почему я говорю, что есть проблема. Давайте посмотрим на радиокнопки в режиме высокой контрастности в Windows.
Скажите теперь, какой из элементов активный. Не знаете? Вот, в этом заключается проблема. На деле активный первый.
<body>
<div class="custom-radio-button">
<input id="rb-1" class="toggle custom-radio-button__input" type="radio" name="radio" checked>
<label for="rb-1" class="custom-radio-button__label">Вариант №1</label>
</div>
<div class="custom-radio-button">
<input id="rb-2" class="toggle custom-radio-button__input" type="radio" name="radio">
<label for="rb-2" class="custom-radio-button__label">Вариант №2</label>
</div>
</body>
Почему так получилось? Дело в том, что в режиме высокой контрастности браузеры подставляют значение transparent
для свойства background
. Это изменить нельзя. Так, что наше значение пропадёт.
Правда, я нашёл решение. Достаточно точку сделать с помощью свойства border
.
.toggle[type="radio"]::before {
content: "";
border: 0.25rem solid #242424;
/* оставшиеся CSS */
}
Теперь радиокнопки отлично работают. Думаю, теперь вы знаете, что поправить в своём проекте. Надеюсь, вы это сделаете.
▍ Функции min()
и max()
помогают мне установить максимальный или минимальный размер у элемента
Периодически нам приходится ограничивать размеры элементов. Например, указывать ширину, но она не должна быть больше какого-то значения. Такая задача решается с помощью свойств width
и max-width
:
.container {
width: 100%;
max-width: 75rem;
}
Это надёжный фрагмент кода, проверенный временем. Лично я предпочитаю другой способ. Можно сократить код до одной строки. Для этого подходит математическая функция min()
.
.container {
width: min(100%, 75rem);
}
Весь трюк заключается в том, что данная функция позволяет браузеру выбрать наименьшее значение из представленных аргументов. В моём примере их два — 100%
и 75rem
. Далее браузеры рассчитывают итоговое значение для каждого аргумента в пикселях и сравнивают между собой. В итоге мы получим значение 100%
, пока оно не станет больше значения 75rem
.
Круто ещё то, что есть функция max()
. С помощью неё я могу указать минимальный размер элемента. Например, ширину.
.container {
width: max(100%, 75rem);
}
Принцип тот же самый. Единственная разница в том, что браузеры выбирают максимальное значение.
▍ Моя самая обидная ошибка со свойством line-height
Я должен признаться. Раньше я постоянно встречал свойство line-height
, определённое для элемента <body>
. Отключая его в DevTools, я думал: «Зачем оно здесь?». Ленившись поискать ответ, забивал.
А моё недоумение было следствием моей привычки. Я для каждого типа элемента определял свойство line-height
.
p {
line-height: 1.5;
}
ul {
line-height: 1.5;
}
Скорее всего, вы знаете о том, что свойство line-height
является наследуемым. И уже догадались, что я зря дублировал значение.
Я узнал об этом случайно. Мне попались CSS советы с типичным названием «CSS Protips». В этом списке был раздел, в котором написано: «Вам не нужно отдельно добавлять line-height
для каждого элемента <p>
, <h*>
и других. Вместо этого добавьте свойство к элементу <body>
».
body {
line-height: 1.5;
}
И всё. У меня щёлкнуло в голове. С тех пор объявляю всегда.
▍ Рассказываем о назначении класса с помощью его имени
Я фанат БЭМа с 2013 года. Мне нравится идея использовать библиотеку универсальных компонентов. Только у меня всегда был затык. В проектах с большим количеством кода сложно ориентироваться в нём. Приходится тратить очень много времени на осмысление нужного фрагмента кода. По этой причине мне нравится делать подсказки в названии CSS класса.
Саму идею я где-то встретил много лет назад. Не вспомню, где конкретно. Поэтому пошёл за примером к знакомым. Они прислали мне несколько. Одним из них был АБЭМ. Суть заключается в соединении БЭМа и принципов атомарного дизайна (Atomic Design).
Мы не будем подробно разбирать данную философию. Нам достаточно знать, что весь дизайн делится на организмы, молекулы и атомы. АБЭМ вносит специальные обозначения для них в имена классов.
Так, классы-организмы начинаются с o-
, классы-молекулы с m-
, классы-атомы с a-
.
.o-accordion {
/* здесь свойства */
}
.m-revealer {
/* здесь свойства */
}
.a-control {
/* здесь свойства */
}
Я не фанат этой идеи. Да, если честно, мне нравится изобретать свой велосипед. Так что АБЭМ натолкнул меня на идею: «А почему бы в названии класса не показать цель компонента?». Так у меня появились обозначения uia-
и ra-
.
<body class="page">
<header class="page__banner">
<div class="page__container">
<h1 class="page__cv-heading uia-heading ra-heading">
<span>Catherine Starobor-Strakhova</span>
<span class="page__cv-role">Full stack game UX/UI designer with strong visual development</span>
</h1>
<a href="#0" class="page__cv-download ra-link uia-control">
<span class="uia-control__group">Download CV</span>
</a>
</div>
</header>
</body>
В коде есть универсальные компоненты uia-heading
и uia-control
. Они используются в разных проектах. Я отношу их к интерфейсным компонентам, поэтому называю User Interface Atoms или кратко — uia-
.
Кроме них есть компоненты для сброса браузерных стилей у заголовков и у ссылок, а именно ra-heading
и ra-link
. Они являются Reset Atoms, соответственно, у них обозначение — ra-
.
Такая вот идея. При большом количестве кода она меня выручала. Надеюсь, вам она зайдёт.
▍ Заключение
Давайте подведём итог. В этой статье мы рассмотрели:
- как селектор
:not([class])
помогает при стилизации текста; - пользу свойства
border
при реализации кастомных радиокнопок; - сокращённую форму установки минимальных и максимальных размеров;
- установку свойства
line-height
без дублирования значения в нескольких местах; - подсказки в именах классов, сообщающие их назначение.
Оставлю ссылки на все выпуски:
Спасибо за чтение!
P.S. Помогаю больше узнать про CSS в своём ТГ-канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.
Telegram-канал со скидками, розыгрышами призов и новостями IT ?
Комментарии (12)
p07a1330
13.08.2024 12:19+2▍ Функции
min()
иmax()
помогают мне установить максимальный или минимальный размер у элементаПериодически нам приходится ограничивать размеры элементов. Например, указывать ширину, но она не должна быть больше какого-то значения. Такая задача решается с помощью свойств
width
иmax-width
:Это не магия
Это 10 минут чтения документации
Как бы в такой статье не ожидаешь пересказ стандартных функций из докиvanxant
13.08.2024 12:19+1Да в современном css примерно всё - это пересказ стандартных функций из доки. Прошли времена, когда приходилось использовать text-indent для сокрытия элементов, теги <ins> и <del> как единственные с поведением inline-block в IE, и padding-bottom в процентах при нулевой высоте вместо aspect-ratio.
Лично для меня использование функций min и max это небольшое открытие. При том что в каких-нибудь гридах я использую их постоянно, но блин, перенести идею на обычные div-ы не догадался.
Baigildin
13.08.2024 12:19Для реализации этой идеи существует правило. Атрибут
class
добавляется только для элементов, доступных для редактирования разработчиками. Элементы, редактируемые через редактор, должны быть без атрибута. В этом случае селектор:not([class])
сработает отлично.То есть стили применятся для всех элементов без атрибута class? А если изначально например в body было задано стили для p, то его перезапишет? В первом случае же применится для элементов внутри специального класса. Или я неправильно понял?
melnik909 Автор
13.08.2024 12:19Указываю элемент, например
h2
, к нему добавляю:not([class])
и получается так:h2:not([class]) { font-size: 1.25rem; line-height: 1.625rem; }
В HTML элемент будет без атрибута
class
.Source
13.08.2024 12:19Придётся везде дописывать этот суффикс и надеяться не получить случайно сайд-эффектов от того, что где-то ещё есть элементы без классов.
А общий класс можно просто вынести за скобки и всё будет структурировано:
.article-formatted-body { ol, ul { padding-inline-start: 32px; } h2 { font-size: 1.25rem; line-height: 1.625rem; } p { margin: 0; padding: 0; } }
director-rentv
13.08.2024 12:19Какой-нибудь магией, конечно, и не пахнет, но все равно спасибо за очередное напоминание о режиме высокой контрастности и его нюансах.
А в дополнение к min/max также стоит рассмотреть и clamp
melnik909 Автор
13.08.2024 12:19+1Подскажите, пожалуйста, практический кейс, кроме указания размера шрифта
Haze27
Префиксы у аторманых селекторов o-* и т.д. выглядят так, будто мы вернулись в эру именования переменных с префиксами типов (https://en.wikipedia.org/wiki/Hungarian_notation)