Последние годы CSS взорвался новинками! 💥 Среди них — фичи, которые меняют подход к вёрстке и уже поддерживаются всеми современными браузерами.

Эта шпаргалка — наш топ CSS-инструментов, которые стоит внедрить в продакшн-код в 2025.

Читайте, тестируйте, делитесь лайфхаками! 🔥

Container Queries

Контейнерные запросы включают две отдельные функции: запросы размера (size queries) и запросы стилей (style queries). Мы планируем использовать только запросы размера, которые имеют широкую поддержку, в отличие от запросов стилей.

Проблема:

Мы используем media query, чтобы показать отличную версию компонента на мобильном устройстве по сравнению с десктопом.

Но современный веб-дизайн мало имеет отношения к области просмотра или размеру экрана. Речь идет о размере родительского контейнера.

Нам хочется делать fluid-компоненты, которые меняют свои размеры в зависимости от родительского контейнера, а не ширины экрана.

С помощью CSS Container Queries мы можем решить вышеописанную проблему и сделать компонент fluid. Это значит, что мы можем поместить компонент в узкий родительский контейнер, и он превратится в сложенную версию, или поместить его в широкий контейнер, и он превратится в горизонтальную версию.

🔗 Версии браузеров, поддерживающих Container Queries

:has

Проблема:

Для понимания :has важно помнить, что CSS применяет стили каскадом, который идет слева направо. Последний элемент в объявлении стилизуется.

Например, по локатору main article strong { ... } будут стилизованы только элементы strong.

А что, если мы хотим стилизовать main при условии, что strong существует в HTML?

<main>
  <article>
    <p>Some text</p>
    <strong>My strong text</strong>
    <p>Some text</p>
  </article>
</main>

Для этого используется :has, который проверит наличие элемента:

main:has(strong) {
  /* change main style */
}

Также можно имитировать логические операторы, такие как && и ||, для проверки нескольких условий.

Например, если в main есть p и есть strong (&&):

main:has(p):has(strong) {
  color: red;
}

Если main имеет p или имеет strong (||):

main:has(p, strong) {
  color: red;
}

Но это ещё не всё: :has в сочетании с селекторами CSS, такими как +, ~, >, или другими псевдоселекторами, такими как :nth-child() или :not(), открывает новые возможности.

Пример отрицательной проверки:

main:not(:has(strong)) {
  /* change main style */
}

🔗 Версии браузеров, поддерживающих функцию :has()

:is() и :where()

Проблема:

Когда нам требуется объединить несколько селекторов в одно правило, приходится писать длинные локаторы.

Для упрощения кода есть два псевдокласса: :is() и :where(). Рассмотрим примеры:

/* Без :is() */
header h1,
main h1,
footer h1 {
  color: red;
}

/* С :is() */
:is(header, main, footer) h1 {
  color: red;
}
/* Без :where() */
nav a:hover,
.sidebar a:hover {
  color: blue;
}

/* С :where() */
:where(nav, .sidebar) a:hover {
  color: blue;
}
  • :is() — группирует селекторы без потери специфичности.
  • :where() — так же группирует селекторы, но позволяет легко их переписать.

Специфичность:

  • :is() — равна специфичности самого конкретного селектора в списке. Например, :is(.class, #id) будет иметь специфичность как #id.
  • :where() — всегда имеет нулевую специфичность.

🔗 Версии браузеров, поддерживающих :is()
🔗 Версии браузеров, поддерживающих :where()

CSS Comparison Functions

Проблема:

Нам нужен размер шрифта 16px на мобильных и 24px на десктопе. А между ними — 10 медиа-запросов, чтобы плавно увеличивать. И так для каждого свойства: отступы, гриды, паддинги во флексах.

Для решения этой проблемы появились CSS Comparison Functions: min(), max(), clamp().

Они автоматически рассчитывают промежуточные значения без кучи медиа-запросов:

.title {
  /* От 16px (на экранах ≤ 320px) до 24px (на экранах ≥ 1200px) */
  font-size: clamp(16px, 4vw + 0.5rem, 24px);
}

Как это работает:

  • clamp(min, ideal, max) — подбирает значение между min и max, пропорционально изменяя ideal (например, 4vw + 0.5rem).
  • min() и max() — выбирают минимальное/максимальное значение из списка.

Если вам интересно подробнее посмотреть, как это работает, посетите сайт Utopia, на котором есть простые в использовании инструменты для создания функций сравнения. Вы можете напрямую ввести значения, заданные дизайнером, и получить clamp()-код в виде CSS-переменных.

🔗 Версии браузеров, поддерживающих CSS Comparison Functions

Logical Properties

Проблема:

Многие CSS-свойства используют физические направления для установки значений: margin-top, padding-right, border-left.

Эти свойства не учитывают переключение направления чтения с помощью свойств direction, text-orientation, writing-mode, что используется в некоторых языках, например, арабском, иврите и т.д.

Например, отступ, расположенный слева от текста, останется слева, даже если направление чтения текста будет изменено. Логические свойства устанавливают значения по осям X (inline) и Y (block), что позволяет избежать этой проблемы.

Наиболее распространенные замены:

Физическое свойство Логический аналог
height / width block-size / inline-size
max-width / min-width max-inline-size / min-inline-size
max-height / min-height max-block-size / min-block-size
margin-left / margin-right margin-inline-start / margin-inline-end
padding-top / padding-bottom padding-block-start / padding-block-end
top / bottom inset-block-start / inset-block-end
left / right inset-inline-start / inset-inline-end

🔗 Версии браузеров, поддерживающих Logical Properties

Subgrid

Проблема:

Subgrid в CSS решает проблему выравнивания вложенных сеток. Допустим, у нас есть карточка товара, которая должна растягиваться на 3 колонки основной сетки. Внутри неё есть изображение, заголовок, описание и цена. Без Subgrid их пришлось бы выравнивать вручную, и при изменении основной сетки всё «поехало» бы.

body {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 4;
}

Subgrid избавляет от ручного пересчёта размеров и гарантирует, что вложенные элементы всегда синхронны с основной сеткой. Больше никаких кривых отступов!

🔗 Версии браузеров, поддерживающих Subgrid

Маленькие фичи, но заметные

  • Flexbox gap
    gap упрощает создание промежутков между элементами. Работает так же, как в Grid, и теперь поддерживается во Flexbox.

  • Динамическая единица viewport height — dvh
    Учитывает адресную строку и пользовательский интерфейс браузера, в отличие от vh, который этого не делал.

  • Media Queries Range Syntax
    Позволяет использовать операторы математического сравнения: >, <, >=, <= в медиа-запросах.
    Пример: @media (width <= 1140px) { ... }