Присаживайся, наливай кофе. Давай поговорим о будущем CSS-модулей
Помнишь то прекрасное чувство, когда ты впервые запустил CSS-модули на реальном проекте? Классы больше не улетают в глобальный скоуп, верстка не ломается из-за того, что коллега в соседнем компоненте назвал класс точно так же, и можно наконец-то расслабиться. CSS-модули стали стандартом де-факто для компонентного подхода, будь то React, Vue или Solid.
Но веб не стоит на месте. На дворе 2026 год, и то, что раньше требовало сложных конфигураций Webpack или Vite, сегодня переосмысляется на уровне стандартов. Давай разберем, как эволюционирует модульный CSS, как избавиться от старых костылей и писать чистый, производительный код, который не устареет через пару месяцев.
Как мы страдали раньше: костыли, препроцессоры и тонны JS
Долгое время изоляция стилей была настоящей головной болью. Мы придумывали сложные методологии вроде БЭМ, строили километровые имена классов в духе .block__elem--modifier и надеялись, что никто не забудет эти правила. Если проект разрасталлся, поддерживать это становилось невыносимо.
Затем пришла эпоха CSS-in-JS (привет, Styled Components). Мы радовались динамическим стилям прямо в JavaScript, но платили за это производительностью: браузер тратил драгоценные миллисекунды на парсинг стилей на клиенте, а бандл раздувался от лишней JS-логики.
Классические CSS-модули спасли ситуацию, но тянули за собой другие проблемы. Нам приходилось настраивать сложные загрузчики (css-loader), генерировать нечитаемые хеши классов вроде ._button_18z9g_1, из-за которых отладка в DevTools превращалась в ад, и использовать SASS/LESS просто для того, чтобы писать вложенные селекторы.
Как делать правильно в 2026 году: нативные технологии на службе модулей
В 2026 году мы наконец-то пришли к синергии нативных стандартов браузера и инструментов сборки. Больше не нужно тащить тяжелые препроцессоры ради базовых вещей. Современные CSS-модули стали невероятно легкими и мощными благодаря двум ключевым технологиям:
- Нативный CSS Nesting. Забудь про SASS. Браузеры теперь прекрасно понимают вложенность из коробки. Это делает код модулей чистым и читаемым без лишней компиляции. Если ты все еще сомневаешься, стоит ли отказываться от старых инструментов, рекомендую почитать статью Зачем использовать CSS Nesting вместо SASS и LESS.
- Каскадные слои (@layer). Главная проблема CSS-модулей раньше — сложность переопределения стилей снаружи компонента. Теперь мы можем упаковать весь модуль в отдельный слой спецификации. О том, как это работает на практике, читай в статье Как использовать CSS @layer для управления специфичностью без боли.
- Import Attributes. В спецификациях закрепляется нативный импорт CSS-документов прямо в JavaScript (модули CSS-скриптов). Браузер сам парсит файл стилей и отдает его как готовый объект
CSSStyleSheet.
Давай посмотрим, как выглядит элегантный компонент сегодня. Никакого визуального мусора, только чистая структура и современные фичи CSS.
Готовый сниппет кода: современный компонент
Вот пример того, как выглядит стильный и изолированный компонент карточки товара с использованием современных CSS-модулей, нативного nesting и каскадных слоев.
/* Card.module.css */
@layer components {
.card {
--card-bg: #ffffff;
--card-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
background: var(--card-bg);
border-radius: 16px;
padding: 24px;
box-shadow: var(--card-shadow);
transition: transform 0.2s ease;
/* Нативная вложенность без препроцессоров */
&:hover {
transform: translateY(-4px);
}
.title {
font-size: 1.25rem;
color: #1a1a1a;
margin-bottom: 8px;
}
.button {
background: #0076ff;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
&:active {
background: #0056b3;
}
}
}
}
А теперь импортируем и применяем это в нашем JS/React компоненте. Сборщик автоматически свяжет локальные имена классов с уникальными хешами, но при этом сохранит читаемость в DOM.
// Card.jsx
import React from 'react';
import styles from './Card.module.css';
export function Card({ title, description }) {
return (
<div className={styles.card}>
<h3 className={styles.title}>{title}</h3>
<p>{description}</p>
<button className={styles.button}>Подробнее</button>
</div>
);
}
Частая ошибка новичков: злоупотребление :global и «протекание» стилей
Когда разработчики только переходят на CSS-модули, они часто сталкиваются с ситуацией, когда нужно стилизовать дочерний сторонний компонент (например, из библиотеки UI-компонентов). И тут начинается самое страшное: бездумное использование псевдокласса :global.
Писать вот так — это выстрел в ногу:
/* ТАК ДЕЛАТЬ НЕ НАДО */
.myCard {
:global(.ant-btn) {
background: red; /* Стили потекут по всему проекту! */
}
}
Почему это плохо? Обертка :global внутри локального класса часто компилируется так, что затрагивает глобальные селекторы сильнее, чем ты планировал. Стоит твоему компоненту появиться на странице, как все кнопки в интерфейсе внезапно станут красными.
Как правильно? Используй CSS-переменные для темизации дочерних компонентов или изолируй внешние стили строго внутри контекста конкретного родителя, не выходя за рамки локального дерева селекторов. Передавай кастомные классы через пропсы, но не ломай глобальную область видимости.
Держи свои стили в чистоте, пользуйся современными фичами платформы и пиши код, который приятно поддерживать!
🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!