Попробуй спросить десятерых фронтендеров, как правильнее всего подключать иконки в современный веб-интерфейс, и ты получишь десять разных, одинаково раздраженных ответов.
Инлайн-SVG? Он раздувает HTML-разметку мегабайтами повторяющихся тегов <path>, засоряет DOM-дерево и не кэшируется браузером. SVG-спрайты? Требуют архаичных конструкций <svg><use href="#icon"/></svg> и создают проблемы с изолированной стилизацией. Иконочные шрифты (icon fonts)? Ломаются при сбое сети и заставляют экранные дикторы для незрячих читать служебные символы Юникода как бессмысленный шум.
Известный исследователь веб-стандартов Ли Веру (Lea Verou) опубликовала программную статью и библиотеку @nudeui/icons, предложив изящную методологию: перенести управление иконочной системой целиком на уровень CSS.
Токены дизайна и маскирование через mask-image
В основе подхода лежит стандартизированное свойство mask-image (уже вошедшее в Baseline всех современных браузеров) в сочетании с токенизацией через CSS Custom Properties.
Вся векторная графика убирается из разметки и объявляется один раз в виде глобальных токенов в блоке :root. Компоненты интерфейса не содержат тегов SVG — иконка формируется псевдоэлементом ::before, цвет которого заливается нативным currentColor, а контур вырезается CSS-маской:
/* 1. Глобальная регистрация иконочных токенов */
:root {
--icon-trash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 6h18m-2 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E");
--icon-edit: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7'/%3E%3C/svg%3E");
}
/* 2. Базовый класс кнопки */
.btn-icon {
display: inline-flex;
align-items: center;
gap: 0.5em;
}
.btn-icon::before {
content: "";
display: inline-block;
width: 1em;
height: 1em;
background-color: currentColor;
-webkit-mask: var(--icon) no-repeat center / contain;
mask: var(--icon) no-repeat center / contain;
}
/* 3. Назначение конкретной иконки */
.btn-delete {
--icon: var(--icon-trash);
}
В результате разметка кнопки в HTML выглядит безупречно лаконично:
<!-- Чистый HTML без единого тега SVG внутри кнопки -->
<button class="btn-icon btn-delete">Удалить запись</button>
Масштабирование, темы и Container Style Queries
Что дает этот подход в реальной дизайн-системе?
- Автоматическое наследование цвета: иконка залита
currentColor. Меняется цвет кнопки при наведении, фокусе или переключении на темную тему — иконка мгновенно принимает тот же оттенок без дополнительных правил. - Пропорциональное масштабирование: размер зафиксирован в относительных единицах
1em. Увеличиваешь шрифт заголовка — иконка гармонично увеличивается вместе с текстом. - Реактивность через Style Queries: используя современные контейнерные запросы стилей (
@container style(--variant: warning)), можно динамически подменять иконку внутри карточки в зависимости от темы или состояния родителя без манипуляций с DOM в JavaScript. Тонкости таких стилистических запросов мы изучали в статье Определение перекрытия элементов средствами чистого CSS: якорное позиционирование и Style Queries.
Чек-лист доступности (a11y) при использовании CSS-иконок
- Кнопки с иконками без видимого текста снабжены атрибутом
aria-label="Описание действия" - Псевдоэлементы
::beforeс масками не содержат текста в свойствеcontentво избежание озвучки скринридерами - Проверено визуальное отображение в высококонтрастном режиме Windows High Contrast
Методология Ли Веру наглядно доказывает: возможности современного CSS позволяют убрать из HTML тонны инфраструктурного мусора, вернув верстке былую элегантность.
