HTML и CSS в 2025–2026 без SCSS: :has(), Container Queries, Nesting, @layer и нативные модалки
Подробный разбор современных возможностей HTML и CSS в 2025–2026: dialog, inert, :has(), container queries, CSS nesting, @layer, dvh/svh. С примерами и пометками поддержки браузеров — что уже можно тащить в прод.
Современный HTML и CSS в 2025–2026: что реально использовать без SCSS и без боли
Если коротко и честно: SCSS больше не нужен в большинстве проектов.
HTML и CSS за последние годы дозрели:
- появились вложенность,
- нормальное управление каскадом,
- адаптивность на уровне компонентов,
- мощные селекторы,
- нативные модалки и поповеры.
В 2025–2026 можно писать чистый CSS, не теряя удобства и контроля.
Разбираем всё по порядку — что использовать, как и с какой поддержкой браузеров.
HTML: нативные возможности, которые заменяют JS
HTML снова становится инструментом, а не контейнером под React.
<dialog> — нативные модальные окна
Пример
<button onclick="modal.showModal()">Открыть</button>
<dialog id="modal">
<h2>Заголовок</h2>
<p>Контент модального окна</p>
<button onclick="modal.close()">Закрыть</button>
</dialog>
Почему это важно
- фокус ловится автоматически
- блокируется фон
- Esc работает из коробки
- никакого JS-кода на управление состоянием
Поддержка браузеров
- Google Chrome — ✅
- Microsoft Edge — ✅
- Mozilla Firefox — ✅
- Apple Safari — ⚠️ (есть, но бывают баги с фокусом)
Вывод
- ✔ Можно использовать в блогах, админках, статических сайтах
- ⚠️ Для Safari — тестировать
inert — блокировка фона без JS
<div inert>
<!-- сюда нельзя кликнуть и сфокусироваться -->
</div>
Работает идеально вместе с <dialog>.
Поддержка
- Chrome / Edge / Firefox / Safari — ✅
Popover API — подсказки и меню нативно
<button popovertarget="help">?</button>
<div id="help" popover>Подсказка</div>
Поддержка
- Chrome / Edge — ✅
- Firefox — ⚠️ (включается постепенно)
- Safari — ❌
Вывод
Использовать только как progressive enhancement. Обязательно иметь fallback.
CSS в 2025–2026: можно без SCSS
Вот здесь начинается самое интересное.
CSS Nesting — нативная вложенность
.card {
padding: 1rem;
&__title {
font-weight: 600;
}
&:hover {
background: #111;
}
}
Поддержка
- Chrome — ✅
- Firefox — ✅
- Safari 17+ — ✅
Что это даёт
- SCSS-вложенность больше не нужна
- код читается логично
- меньше сборки и зависимостей
:has() — селектор родителя (революция)
.card:has(img) {
padding-top: 0;
}
.form:has(input:invalid) {
border-color: red;
}
Поддержка
- Chrome — ✅
- Firefox — ✅
- Safari — ✅
Почему это важно
Теперь можно:
- реагировать на вложенные элементы
- убирать JS-хаки
- делать умные компоненты на CSS
👉 Одна из самых мощных CSS-фич за десятилетие.
Container Queries — адаптивность компонентов
Пример
.card {
container-type: inline-size;
}
@container (min-width: 420px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
Поддержка
- Chrome — ✅
- Firefox — ✅
- Safari — ✅
Почему это лучше media queries
- компонент адаптируется сам
- не зависит от размера экрана
- идеально для компонентного подхода, CMS, современных фреймворков
@layer — контроль каскада
@layer reset, base, components, utilities;
@layer base {
body {
font-family: system-ui;
}
}
@layer components {
.btn {
padding: 0.75rem 1rem;
}
}
Поддержка
- Все современные браузеры — ✅
Почему это важно
- больше нет войн специфичности
- удобно сочетать свой CSS и utility-фреймворки
- архитектура CSS становится предсказуемой
Современные единицы высоты: dvh, svh, lvh
min-height: 100dvh;
Что решает
- мобильные адресные строки
- прыгающие layout’ы
- баги
100vh
Поддержка
- Chrome / Firefox / Safari — ✅
👉 100vh можно считать устаревшим.
:where() и :is() — управление специфичностью
:where(h1, h2, h3) {
margin-block: 0.5em;
}
:where()— 0 специфичность:is()— берёт максимальную
Использовать для:
- reset’ов
- базовых стилей
- безопасных селекторов
Современный CSS-стек без SCSS
Минимум (рекомендую)
- HTML (семантика, dialog, inert)
- CSS (nesting, :has, container queries)
- PostCSS + Autoprefixer
- Design tokens через
:root
Пример токенов
:root {
--space-sm: 0.5rem;
--space-md: 1rem;
--radius-md: 12px;
--clr-bg: #0b0d10;
}
Поддержка браузеров — кратко
| Фича | Chrome | Firefox | Safari |
|---|---|---|---|
| CSS Nesting | ✅ | ✅ | ✅ |
| :has() | ✅ | ✅ | ✅ |
| Container Queries | ✅ | ✅ | ✅ |
| dialog | ✅ | ✅ | ⚠️ |
| Popover API | ✅ | ⚠️ | ❌ |
| dvh / svh | ✅ | ✅ | ✅ |
| @layer | ✅ | ✅ | ✅ |
Практические примеры
Пример 1: Модальное окно с <dialog>
<button id="openModal" type="button">Открыть модалку</button>
<dialog id="demoDialog">
<h3>Нативный dialog</h3>
<p>Работает без библиотек. Esc закрывает. Фокус внутри.</p>
<menu>
<button id="closeModal" type="button">Закрыть</button>
</menu>
</dialog>
<script>
const dialog = document.getElementById("demoDialog");
const openBtn = document.getElementById("openModal");
const closeBtn = document.getElementById("closeModal");
openBtn.addEventListener("click", () => dialog.showModal());
closeBtn.addEventListener("click", () => dialog.close());
// Закрытие по клику на backdrop
dialog.addEventListener("click", (e) => {
const rect = dialog.getBoundingClientRect();
const clickInDialog =
rect.top <= e.clientY &&
e.clientY <= rect.top + rect.height &&
rect.left <= e.clientX &&
e.clientX <= rect.left + rect.width;
if (!clickInDialog) dialog.close();
});
</script>
<style>
dialog {
padding: 1rem 1.25rem;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 14px;
background: #0b0d10;
color: #e8eaf0;
max-width: 520px;
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.55);
backdrop-filter: blur(6px);
}
button {
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.14);
background: rgba(255, 255, 255, 0.06);
color: #e8eaf0;
padding: 0.6rem 0.9rem;
cursor: pointer;
}
menu {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
padding: 0;
margin: 1rem 0 0;
}
</style>
Как это работает
dialog.showModal()открывает модалку в модальном режиме (фон недоступен).dialog.close()закрывает.::backdrop— стилизация затемнения.- Обработчик
clickсравнивает координаты клика с границами окна и закрывает по клику вне прямоугольника.
Пример 2: Container Queries в действии
<div class="wrap">
<div class="pane narrow">
<h4>Контейнер узкий</h4>
<article class="card">
<div class="media"></div>
<div class="content">
<div class="title">Card title</div>
<p>При узком контейнере — вертикальная компоновка.</p>
</div>
</article>
</div>
<div class="pane wide">
<h4>Контейнер широкий</h4>
<article class="card">
<div class="media"></div>
<div class="content">
<div class="title">Card title</div>
<p>При широком контейнере — сетка: медиа слева, текст справа.</p>
</div>
</article>
</div>
</div>
<style>
.wrap {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
/* Для десктопа показываем рядом */
@media (min-width: 900px) {
.wrap {
grid-template-columns: 1fr 1fr;
}
}
.pane {
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
padding: 1rem;
background: rgba(255, 255, 255, 0.03);
/* ВАЖНО: объявляем контейнер */
container-type: inline-size;
}
.pane h4 {
margin: 0 0 0.75rem;
font-size: 0.95rem;
opacity: 0.85;
}
.card {
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: #0b0d10;
color: #e8eaf0;
overflow: hidden;
display: grid;
grid-template-columns: 1fr; /* базово — колонка */
}
.media {
height: 140px;
background: linear-gradient(
135deg,
rgba(0, 180, 255, 0.35),
rgba(160, 110, 255, 0.25)
);
}
.content {
padding: 0.9rem 1rem 1rem;
}
.title {
font-weight: 650;
margin-bottom: 0.35rem;
}
/* Container Query: реагируем на ширину контейнера, а не окна */
@container (min-width: 480px) {
.card {
grid-template-columns: 180px 1fr;
align-items: stretch;
}
.media {
height: auto; /* теперь высота определяется карточкой */
min-height: 100%;
}
}
/* И чуть более "богатый" режим */
@container (min-width: 620px) {
.card {
grid-template-columns: 220px 1fr;
}
}
</style>
Как это работает
container-type: inline-size;делает элемент контейнером, на который можно ориентироваться.@container (min-width: 480px)— переключает layout когда контейнер стал шире, даже если окно не менялось.- Это идеально для компонентного подхода: карточка адаптируется в сайдбаре, сетке, модалке — везде.
Главный вывод
В 2025–2026:
- SCSS не нужен по умолчанию
- HTML снова решает задачи
- CSS стал мощным и зрелым
- JS — для логики, а не для вёрстки
Меньше сборки. Меньше зависимостей. Больше предсказуемости.
Поддержка браузеров (на практике):
dialog— Chrome/Edge/Firefox ✅, Safari ⚠️ (проверяй на реальных устройствах)- Container Queries — Chrome/Edge/Firefox/Safari ✅
- CSS Nesting — Chrome/Firefox/Safari 17+ ✅
:has()— все современные браузеры ✅



Комментарии