Функции в CSS
Перед чтением: функции в коде — общая модель имени, аргументов и вызова; в CSS те же скобки (), но семантика делится на значения свойств и селекторы.
Две семьи «функций»
В CSS слово «функция» встречается в двух разных местах. Синтаксис похож (имя(аргументы)), роль разная.
| Семья | Где пишется | Примеры | Результат |
|---|---|---|---|
| Функции значений | Внутри значения свойства | calc(), var(), rgb(), clamp() | Число, цвет, длина, угол, градиент и т.д. |
| Функциональные псевдоклассы | В селекторе | :is(), :where(), :has(), :not() | Уточнение, какие элементы попадут под правило |
/* функция значения — вычисляет ширину */
.card {
width: min(100%, 24rem);
padding: calc(var(--space) * 2);
color: color-mix(in oklch, var(--brand) 80%, white);
}
/* функция в селекторе — выбирает элементы */
.card:has(img) {
grid-template-columns: 120px 1fr;
}
:where(h1, h2, h3) {
line-height: 1.2;
}
Подробнее про :is(), :where(), :has() — в отдельной главе Селекторы :is, :where и :has. Ниже — обе семьи в одном обзоре с упором на вызов, встроенный набор и способы «своих» вычислений.
Полный перечень в табличном виде — в справочнике CSS.
Как объявлять и вызывать
Встроенные функции значений
Объявлять их в CSS нельзя — они заданы спецификацией. Вызывают прямо в значении свойства:
.sidebar {
width: clamp(12rem, 20vw, 18rem);
gap: calc(1rem + 2px);
background: linear-gradient(180deg, #1e293b, #0f172a);
filter: blur(0);
transition-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
}
Общий синтаксис:
имя-функции( аргумент1 [, аргумент2 …] )
- Имя без двоеточия в начале (
calc,var,rgb). - Аргументы разделяются запятой (в
calc()для+и-вокруг операндов часто нужны пробелы). - Вложенность разрешена:
calc(min(100%, 400px) - 1rem).
Функциональные псевдоклассы
Пишутся в селекторе, с двоеточием:
:where(.btn, button) { … }
form:has(:invalid) { … }
Их тоже нельзя «объявить» в таблице стилей — только вызывать с готовыми селекторами внутри скобок.
Свои вычисления — что доступно
| Подход | Что это | «Своя функция»? |
|---|---|---|
Custom properties --x + var() | Именованное значение, подстановка в каскаде | Именованный параметр, вызов через var(--x) |
@property | Тип и начальное значение переменной | Строгая переменная, анимация чисел/цветов |
| Препроцессор (Sass, Less) | @function → компиляция в CSS | Да, но только на этапе сборки |
| CSS Houdini | paint(), @function (черновик) | Ограниченно, в основном Chromium |
| PostCSS-плагин | Подстановка на сборке | Любая логика, которую напишет плагин |
В чистом CSS нет аналога function myFn(a, b) { return a + b; } для произвольных значений (кроме экспериментов и Houdini). Паттерн «своя функция» — это композиция var() + calc() / color-mix() и дизайн-токены на :root.
См. Переменные в CSS и раздел про @property там же.
Математические функции
Используются для адаптивных размеров, сеток и отступов без медиазапросов на каждый пиксель.
calc()
Складывает, вычитает, умножает и делит совместимые единицы (px, %, rem, vw, var() и др.).
.hero {
/* 50% минус половина gap в flex-сетке */
width: calc(50% - 0.5rem);
min-height: calc(100vh - var(--header-height));
}
Правила:
- После
+и-нужны пробелы с обеих сторон. *и/могут обходиться без пробелов у числа:calc(100% / 3).- Внутри
calc()можно вызыватьmin(),max(),clamp().
min(), max(), clamp()
.fluid-type {
/* не меньше 1rem, не больше 2.5rem, между ними — 4vw */
font-size: clamp(1rem, 2vw + 0.5rem, 2.5rem);
}
.dialog {
width: min(90vw, 32rem);
max-height: max(40vh, 20rem);
}
clamp(MIN, VAL, MAX) эквивалентно max(MIN, min(VAL, MAX)).
round(), mod(), rem() (CSS Values Level 4)
Округление и остаток от деления для сеток без «дробных пикселей»:
.tiles {
--cols: 3;
width: round(down, 100%, calc(100% / var(--cols)));
}
Поддержка в браузерах растёт; для продакшена проверяйте caniuse.
Тригонометрия и гипотенуза
sin(), cos(), tan(), asin(), acos(), atan(), atan2(), hypot(), pow(), sqrt(), log(), exp() — для анимаций по кругу, диаграмм, offset-path:
.orbit-dot {
offset-path: path("M 50 50");
offset-distance: calc(sin(45deg) * 100%);
}
Цветовые функции
| Функция | Назначение |
|---|---|
rgb(), hsl(), hwb() | Классические модели; современный синтаксис без запятых: rgb(255 0 0 / 0.5) |
lab(), lch(), oklab(), oklch() | Перцептивно равномерные пространства |
color() | Произвольное цветовое пространство, например display-p3 |
color-mix() | Смесь цветов в заданном цветовом пространстве |
light-dark() | Светлая/тёмная пара в одном объявлении (где поддерживается) |
color-mix() — смешивание без препроцессора
color-mix() позволяет смешивать два (и в новых браузерах — больше) цвета в любом цветовом пространстве. Оттенки, затемнения и динамические палитры можно строить прямо в CSS через var() — без Sass/Less и без ручного подбора hex.
Базовый синтаксис:
color-mix(in <colorspace>, <color1> [<percentage>], <color2> [<percentage>])
Если проценты не указаны, цвета смешиваются 50/50.
Полярные пространства (hsl, lch, oklch) — удобны, когда важен оттенок:
color-mix(in hsl, hsl(200 50% 80%), coral);
color-mix(in hsl, hsl(200 50% 80%) 20%, coral 80%);
Прямоугольные (srgb, lab, oklab) — предсказуемое смешение по каналам:
color-mix(in srgb, plum, #123456);
color-mix(in lab, plum 60%, #123456 50%);
Интерполяция оттенка — в lch/hsl можно задать, как «обходить» цветовой круг:
color-mix(in lch increasing hue, hsl(200deg 50% 80%), coral);
color-mix(in lch longer hue, hsl(200deg 50% 80%) 44%, coral 16%);
Несколько цветов (где поддерживается):
color-mix(in oklab, teal, olive, blue);
color-mix(in oklab, teal 20%, olive 30%, blue 50%);
Типичные задачи на токенах:
:root {
--brand: oklch(0.55 0.15 250);
--surface: color-mix(in oklch, var(--brand) 12%, white);
--text-on-brand: color-mix(in srgb, var(--brand) 90%, black);
--brand-hover: color-mix(in oklch, var(--brand) 85%, black);
}
.badge {
background: light-dark(#f1f5f9, #1e293b);
}
| Задача | Пример |
|---|---|
| Осветлить фон | color-mix(in oklch, var(--brand) 15%, white) |
| Затемнить hover | color-mix(in oklch, var(--brand) 80%, black) |
| Полупрозрачная обводка | color-mix(in srgb, var(--brand) 40%, transparent) |
Палитра из одного --brand | серия --brand-100 … --brand-900 через разные доли white/black |
Для UI чаще берут oklch или oklab — смесь выглядит равномернее, чем в srgb. Для точного совпадения с legacy-hex иногда достаточно srgb.
color-contrast() и color-adjust() — из черновиков Color Level 5; перед использованием смотрите поддержку.
Раскладка, формы и фигуры
Grid и Flex
.grid-auto {
grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
gap: fit-content(2rem);
}
| Функция | Роль |
|---|---|
repeat() | Повтор трека repeat(3, 1fr) или repeat(auto-fit, …) |
minmax() | Диапазон размера трека |
fit-content() | «По содержимому», но с потолком |
aspect-ratio и размеры
.video-wrap {
aspect-ratio: 16 / 9;
width: min(100%, 960px);
}
Изображения, градиенты, маски
.banner {
background-image:
linear-gradient(135deg, transparent 40%, rgba(0, 0, 0, 0.4)),
url("/img/hero.webp");
mask-image: radial-gradient(circle at center, #000 60%, transparent 100%);
}
.icon {
background: conic-gradient(from 0deg, #3b82f6, #8b5cf6, #3b82f6);
}
| Функция | Примечание |
|---|---|
url() | Файл, data-URI, фрагмент SVG |
image-set() | Набор источников под плотность экрана |
cross-fade() | Плавная смена двух изображений |
paint() | Houdini — кастомная отрисовка фона |
Фильтры, трансформации, анимация
.modal-backdrop {
backdrop-filter: blur(8px) brightness(0.9);
}
.card:hover {
transform: translateY(-4px) rotate(1deg);
filter: drop-shadow(0 8px 16px rgb(0 0 0 / 0.12));
}
.spinner {
animation: spin 1s linear infinite;
animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
}
@keyframes steps-demo {
from {
opacity: 1;
}
to {
opacity: 0.5;
}
}
.stepped {
animation-timing-function: steps(4, end);
}
| Группа | Примеры |
|---|---|
| Transform | translate(), rotate(), scale(), matrix(), translate3d() |
| Filter | blur(), brightness(), contrast(), grayscale() |
| Easing | cubic-bezier(), steps(), linear() (набор точек в Level 2) |
var(), env(), attr()
var() — вызов custom property
:root {
--space: 0.5rem;
--radius: calc(var(--space) * 2);
}
.button {
padding: var(--space) calc(var(--space) * 3);
border-radius: var(--radius, 6px); /* fallback */
}
Второй аргумент var(--name, fallback) обязателен, если переменная может отсутствовать. Fallback может быть другим var().
env() — системное окружение
.app-bar {
padding-top: env(safe-area-inset-top, 0px);
padding-bottom: env(keyboard-inset-height, 0px);
}
attr() — данные из HTML
Сегодня надёжно в content и счётчиках; в значениях длины/цвета — по мере внедрения Typed OM:
[data-label]::before {
content: attr(data-label);
}
/* будущее / ограниченная поддержка */
.thumb {
width: attr(data-width px, 64px);
}
Счётчики, шрифты, прочее
body {
counter-reset: section;
}
h2::before {
counter-increment: section;
content: counters(section, ".") ". ";
}
.code {
font-family: ui-monospace, monospace;
font-feature-settings: "liga" 0;
}
| Функция | Где |
|---|---|
counter(), counters() | Нумерация разделов, оглавление |
symbols() | Маркеры списков из символов |
local() | Локальный шрифт в @font-face |
Функции в селекторах — кратко
Они не возвращают значение — фильтруют дерево DOM.
| Псевдокласс | Специфичность | Типичная задача |
|---|---|---|
:is(a, b) | Как у самого «тяжёлого» аргумента | Сократить длинный список селекторов |
:where(a, b) | 0 | Базовые стили дизайн-системы, легко перебить классом |
:has(S) | Как у :has + внутренние селекторы | Стили родителя по потомкам и соседям |
:not(S) | Как у :not + аргумент | Исключения |
Комбинация из реального UI (индикатор «печатает» у последнего узла markdown):
@keyframes pulse-dot {
50% {
opacity: 0.5;
}
}
/* последний «лист» контента в блоке со статусом running */
.aui-md[data-status="running"]:empty::after,
.aui-md[data-status="running"] > :where(:not(ol):not(ul):not(pre)):last-child::after,
.aui-md[data-status="running"] > pre:last-child code::after,
.aui-md[data-status="running"] :where(ol, ul):last-child > li:last-child:not(:has(> li))::after {
content: "\25cf";
margin-left: 0.25rem;
animation: pulse-dot 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
font-family: ui-sans-serif, system-ui, sans-serif;
}
Здесь :where() снижает вес селектора, :has() отсекает вложенные списки, cubic-bezier() задаёт ритм анимации — три разных «функции», одна задача.
Разбор и осторожность с производительностью :has() — в 114.md.
Как сделать «свою» логику
1. Токены и композиция (основной путь)
:root {
--space-unit: 4px;
--space-md: calc(var(--space-unit) * 4);
--space-lg: calc(var(--space-unit) * 6);
--focus-ring: 0 0 0 3px color-mix(in srgb, var(--brand) 40%, transparent);
}
.focusable:focus-visible {
box-shadow: var(--focus-ring);
}
Меняете --space-unit — пересчитывается вся шкала.
2. @property — типизированная переменная
@property --progress {
syntax: "<percentage>";
inherits: false;
initial-value: 0%;
}
.bar::before {
width: var(--progress);
transition: --progress 0.3s ease;
}
Позволяет анимировать custom properties там, где браузер понимает зарегистрированный тип.
3. Sass — настоящая @function
@function space($n) {
@return $n * 4px;
}
.card {
padding: space(3); /* → 12px после компиляции */
}
В браузер уходит уже обычный CSS без @function.
4. Houdini — paint() и черновик @function
// registerPaint в отдельном worklet-файле
CSS.paintWorklet.addModule("checkerboard.js");
.cell {
background: paint(checkerboard);
}
Модуль CSS Functions описывает @function для выражений в самом CSS; на момент написания статьи это эксперимент, а не база для продакшена.
Практические сценарии
Адаптивная типографика без десятка брейкпоинтов
html {
font-size: clamp(15px, 0.9rem + 0.35vw, 18px);
}
h1 {
font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem);
}
Тема через color-mix и prefers-color-scheme
:root {
--bg: #f8fafc;
--fg: #0f172a;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f172a;
--fg: #e2e8f0;
}
}
.card {
background: color-mix(in oklch, var(--bg) 92%, var(--fg));
color: var(--fg);
}
Связка с доступностью и медиа-настройками.
Форма без JS-классов на обёртке
fieldset:has(:user-invalid) {
border-color: #b91c1c;
}
fieldset:has(:user-valid) legend {
color: #15803d;
}
Сброс типографики в @layer
@layer base {
:where(h1, h2, h3, p) {
margin-block: 0 0.5em;
}
}
Сочетание с каскадом и @layer.
Карточка с превью только при наличии картинки
.product:has(img) {
display: grid;
grid-template-columns: 96px 1fr;
gap: 1rem;
}
Шпаргалка по категориям
| Категория | Вызов в значении | Вызов в селекторе |
|---|---|---|
| Числа и размеры | calc, min, max, clamp, round | — |
| Цвет | rgb, hsl, oklch, color-mix | — |
| Сетка | repeat, minmax, fit-content | — |
| Картинки | url, linear-gradient, image-set | — |
| Движение | cubic-bezier, steps | — |
| Переменные | var, env, attr | — |
| Логика выбора | — | :is, :where, :has, :not |
Частые ошибки
| Симптом | Причина | Что сделать |
|---|---|---|
calc() игнорируется | Нет пробелов у + / - | calc(100% - 1rem) |
var() пустой | Опечатка в --name или область видимости | DevTools → Computed → custom properties |
Перебить :where() не выходит | Конфликт с !important или порядком слоёв | Проверить @layer и источник |
Тормоза при :has() | Слишком широкий контекст (body:has(...)) | Сузить до компонента .list:has(.active) |
| «Функция» из Sass не в браузере | Забыли сборку | Смотреть скомпилированный CSS |
Краткий итог
Функции значений вызываются в свойствах (calc(), var(), color-mix() и десятки других) и возвращают конкретное значение для движка стилей. Функциональные псевдоклассы (:is, :where, :has, :not) работают в селекторах и решают, к кому применить правило. Свои вычисления в стандартном CSS строят из custom properties, @property, иногда препроцессора или Houdini; произвольных myFunc() в чистом CSS пока нет. Для углубления — переменные, селекторы :is/:where/:has, справочник.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). В CSS тег используется как селектор по типу, например p { color: black; }. Тег используется для подключения внешних ресурсов к HTML-документу. Наиболее распространённое применение — подключение CSS-файлов. CSS custom properties - именованные значения для повторного использования, темизации и централизованного управления стилями. Контентная боксовая модель в CSS - как width и height задают размер контентной области и взаимодействуют с отступами и границами. Мы разберём различные примеры типовых элементов интерфейса, в формате HTML и CSS. Можете добавлять и экспериментировать - для удобства, в HTML-части будет создаваться элемент, а в CSS - стиль. Группировка селекторов без дублирования, нулевая специфичность :where и условный родитель :has. Порядок применения стилей через @layer — сброс, база, компоненты, утилиты без гонки специфичности. margin-inline, padding-block, writing-mode и вложенная сетка subgrid для выравнивания с родителем. prefers-reduced-motion, prefers-contrast, forced-colors и связка с семантикой HTML. Сводные таблицы — что использовать, чего избегать и на что смотреть осторожно в повседневной вёрстке, включая мобильные экраны. Flexbox - одноосевая раскладка с распределением пространства и выравниванием дочерних элементов в контейнере. Как работает CSS, как читать единицы измерения и планировать размещение.CSS
Подключение и организация CSS-кода
Переменные в CSS
Блочная модель и механизм каскадирования
Типовые элементы интерфейса
Селекторы :is, :where и :has
Каскадные слои @layer
Логические свойства CSS и subgrid
Доступность и пользовательские настройки в CSS
Практические рекомендации по CSS
Flexbox и CSS Grid
Основные стили в CSS