AUDIT LOG
История обработки
Каждый вызов модели, версия промпта, время и полный ответ.
0 шагов
Цикл AI ещё не запускался.
Извлечённый текст источника12325 символов
# CSS в 2026 году: где JavaScript уже не обязателен
Когда работаешь с такими масштабными продуктами, как мы делаем в VK, быстро начинаешь ценить код, который можно не писать. Особенно если речь о небольших сценариях: открыть поповер, анимировать появление блока или подстроить поле под контент. Ещё недавно для таких задач мы почти автоматически тянулись к JavaScript. Но за последние два года CSS сильно расширил свои возможности для задач, связанных с интерфейсом.
Я Максим Кузнецов, занимаюсь оптимизацией производительности и улучшением стабильности веб-версий ВКонтакте. В этой статье расскажу, что уже можно использовать как альтернативу JS, что стоит попробовать аккуратно, а за чем пока лучше просто следить.
## Что уже полезно в реальных проектах
Начнём с возможностей, которые чаще всего влияют на повседневную разработку: состояние DOM, формы, всплывающие элементы и анимации. Это не самые новые фичи, но именно они чаще всего помогают работать уже без использования JavaScript.
### :has(): стилизация контейнера по состоянию вложенных элементов
Поддержка: Chrome, Safari, Firefox
:has() далеко не новая тема, разговоры про него идут давно, и во многих проектах он уже активно используется. Но именно сейчас он стал восприниматься как полноценный рабочий инструмент.
:has() решает одну из старых проблем CSS: как изменить стиль родителя, если внутри него есть элемент в определённом состоянии.
Раньше для этого часто использовали JS. Например, если внутри блока выбран checkbox, скрипт добавлял класс на родительский элемент. Если выбор снимался, класс удалялся. В итоге появлялась вспомогательная логика, которая отвечала только за визуальное состояние.
С :has() такой сценарий можно описать сразу в CSS:
Ещё несколько типичных примеров:
:has() хорошо подходит для локального визуального состояния: выбранный checkbox, невалидное поле, фокус внутри карточки, активный элемент внутри контейнера, наличие определённого дочернего элемента.
В нашем коде такие сценарии уже встречаются, и это хороший пример того, как CSS забирает на себя не бизнес-логику, а именно визуальную часть поведения. Если состояние нужно для данных, аналитики, маршрутизации или бизнес-правил, оно остаётся в JS. Но если класс раньше добавлялся только ради оформления, :has() в этом плане часто оказывается проще.
### field-sizing: авторазмер полей без помощи JavaScript
Поддержка: Chrome и Safari — есть, Firefox — ещё нет
Авторазмер полей формы долго оставался задачей, которую обычно решали через JavaScript. Для textarea приходилось подписываться на input, читать высоту содержимого, сбрасывать текущее значение высоты и выставлять новое. Для input использовали похожие обходные решения: скрытые элементы, измерение текста или дополнительные обёртки.
field-sizing закрывает часть этих сценариев на уровне CSS. При значении content поле может подстраиваться под введённое значение.
Это полезно для инлайн-редактирования, небольших форм и интерфейсов, где размер поля должен зависеть от содержимого.
При этом свойство не отменяет нормальную работу с ограничениями. Для реального интерфейса всё равно нужно задать минимальный и максимальный размер, проверить переносы, длинные значения, мобильную клавиатуру и доступность.
Вывод простой: если поле должно просто подстраиваться под контент, для этого уже не всегда нужен отдельный скрипт.
### Popover API: всплывающие элементы без лишнего кода
Всплывающие элементы долго требовали большого количества JavaScript. Popover API забирает часть этого базового поведения на себя.
Для простых меню, тултипов и небольших поповеров это снижает объём кода, потому что базовое открытие и закрытие можно описать декларативно.
Конечно, в сложных компонентах JS всё равно может понадобиться — например, для сложного управления состоянием, вложенных сценариев. Но для базового поведения теперь есть нативная основа, и это уже меняет подход к таким компонентам.
### CSS Anchor Positioning: позиционирование относительно якоря
Поддержка: Chrome и Safari — есть, Firefox — нет
Тултипы, меню и превью обычно должны появляться рядом с конкретным элементом: кнопкой, аватаром, полем ввода. Раньше для этого часто считали координаты через JS, следили за прокруткой, изменением размеров окна и выходом элемента за границы экрана.
CSS Anchor Positioning позволяет связать всплывающий элемент с якорем и описать позицию декларативно.
Главная идея здесь не в том, что все утилитарные методы уже завтра станут не нужны. Идея в том, что для части сценариев браузер уже начинает закрывать то, что раньше писали вручную.
### @starting-style: анимация появления без промежуточного состояния
Когда элемент впервые появляется в DOM или переходит из display: none в видимое состояние, браузер не всегда знает, от какого значения запускать переход. Поэтому в интерфейсах часто заводят промежуточные состояния: mounted, visible, closing, таймеры и ручное удаление элемента после анимации.
@starting-style позволяет задать начальное состояние для такого перехода.
Это особенно полезно для dialog, popover, меню и элементов, которые появляются после изменения атрибута или состояния отображения.
### transition-behavior: переходы для дискретных свойств
Некоторые CSS-свойства не анимируются плавно. Например, display не имеет промежуточных значений, так как элемент либо отображается, либо нет.
transition-behavior: allow-discrete позволяет включить переходы для дискретных свойств и аккуратнее описывать открытие и закрытие элементов.
В связке с @starting-style это помогает описывать появление и скрытие поповеров, диалогов и меню без дополнительного слоя состояний в JS.
### Scroll-driven animations: анимации на основе прокрутки
Анимации, завязанные на прокрутку, долго делали через обработчики scroll: вычисляли позицию элемента, обновляли CSS-переменные, синхронизировали прогресс и следили за производительностью.
Сейчас часть таких задач можно описать через CSS Scroll-driven animations: scroll-timeline, view-timeline, animation-timeline.
Типовые сценарии:
— индикатор прогресса чтения— появление блока при попадании в область видимости— декоративные scroll-эффекты— анимация, завязанная на положение контейнера прокрутки
Это не замена всем scroll-сценариям. Если прокрутка влияет на данные, сбор аналитики, состояние приложения или иную побочную логику, JavaScript остаётся незаменимым. Но если задача визуальная, CSS-вариант следует рассмотреть первым.
## Новые и экспериментальные возможности
Теперь перейдём к возможностям, которые интересны, но требуют большей осторожности; часть из них пока доступна не везде, часть лучше использовать как постепенное улучшение, а другая часть показывает, куда в целом развивается CSS.
Все возможности из этого раздела перед внедрением нужно отдельно проверять по целевым браузерам.
### sibling-index() и sibling-count(): позиция элемента без ручной передачи индекса
Поддержка: только Chrome
В повторяющихся элементах, например списках или повседневных сетках, часто нужно знать позицию элемента: для задержки анимации, расчёта смещения, распределения элементов или декоративного эффекта.
До появления новых функций обычно использовали один из трёх подходов:
— прописывали несколько правил через :nth-child()— передавали индекс через CSS-переменную из шаблона— считали позицию через JavaScript
sibling-index() возвращает номер текущего элемента среди соседей, а sibling-count() — общее количество соседних элементов.
Ещё один пример — распределение элементов по ширине:
Это особенно полезно для декоративных списков, каскадных анимаций и компонентов, где визуальное поведение зависит от порядка элементов.
### if(): условные значения внутри CSS-свойств
if() добавляет в CSS возможность выбирать значение свойства по условию. Это не заменяет медиазапросы, @supports или состояние приложения, но позволяет держать часть локальной логики рядом со свойством.
media() внутри if() проверяет условия среды, например ширину экрана или тип устройства ввода. А @supports внутри if() проверяет поддержку конкретного CSS-свойства или значения.
Например, можно выбрать размер кнопки в зависимости от типа устройства ввода:
Здесь media(any-pointer: fine) означает: если у пользователя точное устройство ввода, например мышь или трекпад, можно сделать кнопку компактнее. В остальных случаях оставляем более крупный размер.
Можно опираться на ширину вьюпорта:
Можно проверять поддержку возможности браузером:
А можно выбирать значение на основе другого CSS-свойства:
Главная польза if() не в том, что CSS превращается в язык программирования. Польза в локализации условий, иными словами, связанная логика остаётся рядом с тем свойством, на которое влияет.
Для боевого кода всё равно нужны запасные значения и проверка через @supports.
### @function: переиспользуемые вычисления в CSS
@function позволяет описывать собственные CSS-функции и переиспользовать вычисления без препроцессора.
Пример — функция для сетки:
Это направление особенно интересно для команд, которые до сих пор держат препроцессор только ради функций или миксинов.
### interest-delay: задержка открытия и закрытия для hover-сценариев
Выпадающие элементы часто открываются слишком резко. Пользователь наводит курсор на кнопку, элемент сразу появляется, затем исчезает, если курсор не успел перейти на всплывающую область. В таких сценариях раньше обычно добавляли задержку через JavaScript.
interest-delay позволяет задавать задержку для interest-сценариев декларативно.
Это может быть полезно для подсказок, hover-карточек, предпросмотров и элементов, которые не должны открываться или закрываться мгновенно.
## Декоративные и нишевые возможности
Здесь я собрал фичи для более точной настройки интерфейса (цвета, нестандартные формы и курсор ввода). Они не меняют общий подход к приложению, но могут быть полезны в конкретных местах.
### contrast-color(): автоматический контраст для простых случаев
Поддержка: только Safari
contrast-color() принимает цвет и возвращает контрастный к нему цвет. В текущей модели функция выбирает между чёрным и белым в зависимости от того, какой вариант лучше читается на переданном фоне.
Но contrast-color() нельзя считать заменой дизайн-системе и проверкам доступности. Функция выбирает только между чёрным и белым, а не подбирает цвет из палитры продукта. Абсолютный чёрный и абсолютный белый не всегда подходят визуально. А автоматический выбор контраста не отменяет дизайн-токены, тесты и ручную проверку цветовых пар.
### border-shape: декоративные формы без части ограничений clip-path
Поддержка: слабая
Здесь поддержка хуже всего, поэтому пока это скорее возможность, за развитием которой стоит следить, а не брать в основу интерфейса.
clip-path давно используют для нестандартных форм. Но у него есть ограничение: он обрезает не только сам элемент, но и декоративные эффекты. Например, box-shadow может исчезнуть вместе с областью, которую срезал clip-path.
Один из распространённых обходов — filter: drop-shadow(). Но это отдельный приём со своими ограничениями по качеству отрисовки и производительности.
border-shape решает похожую задачу иначе: задаёт форму границы и позволяет сохранить декоративные свойства.
Свойство поддерживает знакомые функции форм:
Но пока border-shape лучше внедрять как прогрессивное улучшение: если браузер не поддерживает свойство, интерфейс должен оставаться нормальным.
### caret-shape: форма текстовой каретки
В CSS давно есть caret-color, который задаёт цвет текстовой каретки. caret-shape добавляет ещё один уровень настройки — форму курсора ввода.
Доступны три базовых значения:
Это нишевая возможность. В обычных формах лучше не менять каретку без причины: пользователи ожидают стандартное поведение поля ввода. Но для редакторов кода, терминальных интерфейсов, обучающих сред и специальных полей свойство может быть полезным. caret-shape позволяет аккуратнее настроить детали интерфейса там, где форма курсора действительно важна.
## Что в итоге?
CSS не стал (и не должен был стать) заменой JavaScript. Но они начали лучше дополнять друг друга: JS остаётся там, где нужна логика приложения, а CSS всё чаще закрывает задачи, которые действительно должен закрывать.
- css
- без javascript
- разработка сайтов
- веб-разработка
- js
- html
- javascript
- фронтенд
- frontend
- Блог компании VK
- CSS
- Веб-разработка
- Интерфейсы
- JavaScript