Функции в CSS
Перед чтением: функции в коде — общая модель имени, аргументов и вызова; в CSS те же скобки (), но семантика делится на значения свойств и селекторы.
Две семьи "функций"
В CSS слово "функция" встречается в двух разных местах. Синтаксис похож (имя(аргументы)), роль разная.
| Семья | Где пишется | Примеры | Результат |
|---|---|---|---|
| Функции значений | Внутри значения свойства | calc(), var(), rgb(), clamp() | Число, цвет, длина, угол, градиент и т.д. |
| Функциональные псевдоклассы | В селекторе | :is(), :where(), :has(), :not() | Уточнение, какие элементы попадут под правило |
Код ITЗагрузка примера кода…
Подробнее про :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() | Светлая/тёмная пара в одном объявлении (где поддерживается) |
Play ITЗагрузка интерактивного демо…
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 — кастомная отрисовка фона |
Фильтры, трансформации, анимация
Готовые @keyframes и transition с построчным разбором — CSS-анимации — готовые эффекты. Ниже — синтаксис функций в связке с transform и animation.
Код ITЗагрузка примера кода…
| Группа | Примеры |
|---|---|
| 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):
Код ITЗагрузка примера кода…
Здесь :where() снижает вес селектора, :has() отсекает вложенные списки, cubic-bezier() задаёт ритм анимации — три разных "функции", одна задача.
Разбор и осторожность с производительностью :has() — в Селекторы :is, :where и :has.
Как сделать "свою" логику
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
Код ITЗагрузка примера кода…
Связка с доступностью и медиа-настройками.
Форма без 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, справочник.