Kodokon kodokon.com

CSS-переменные и функции calc/clamp

Освой пользовательские свойства, то, как они разрешаются во время выполнения внутри каскада, и функции calc() и clamp() для плавных, адаптивных интерфейсов.

10 мин · 3 вопросов

Открыть этот урок в Kodokon

Пользовательские свойства - это не переменные препроцессора. Переменная Sass подставляется на этапе компиляции; свойство --brand разрешается во время выполнения, участвует в каскаде, наследуется как любое другое свойство и может быть изменено медиазапросом, классом или из JavaScript через setProperty(). Именно это делает возможными динамические темы, тёмный режим без перекомпиляции и обмен данными между CSS и JS без повторного рендеринга.

CSS
:root {
  --brand: #6c5ce7;
  --spacing: 8px;
}

.card {
  color: var(--brand);
  padding: calc(var(--spacing) * 2);
  border-color: var(--accent, currentColor);
}
Объявление, чтение и запасные значения

Второй аргумент var() - это запасное значение, которое используется только тогда, когда свойство не определено. Классическая ловушка: если --accent равно 12px и ты подставляешь его в color, запасное значение не сработает. Объявление становится невалидным на этапе вычисления значения (computed-value time): свойство откатывается к своему унаследованному или начальному значению, а не к предыдущему объявлению, как это было бы при обычной синтаксической ошибке.

Правило @property снимает два серьёзных ограничения: оно задаёт переменной тип (а значит, и валидацию) и делает её анимируемой, ведь движок теперь умеет интерполировать между двумя типизированными значениями, а не считает переменную непрозрачной строкой.

CSS
@property --progress {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

.gauge {
  background: conic-gradient(
    var(--brand) var(--progress),
    #e5e7eb 0
  );
  transition: --progress 0.4s ease-out;
}

.gauge.is-full {
  --progress: 100%;
}
Типизированная анимируемая переменная через @property

Что до математики, calc() позволяет смешивать единицы (calc(100% - 2rem)), что невозможно в препроцессоре, потому что результат зависит от контекста отрисовки. clamp(min, ideal, max) - это синтаксический сахар для max(min, min(ideal, max)), и для плавной типографики он лучше стопки контрольных точек: идеальное значение, часто выраженное в vw или cqi, свободно скользит между двумя границами.

CSS
:root {
  --fluid-title: clamp(
    1.5rem,
    1rem + 2.5vw,
    3rem
  );
}

h1 {
  font-size: var(--fluid-title);
  max-width: clamp(20ch, 60%, 65ch);
}
Плавная типографика без медиазапроса

Проверка знаний

Убедись, что запомнил ключевые моменты этого урока.

  1. Что произойдёт, если color: var(--gap) вычисляется, когда --gap равно 12px?
    • Объявление игнорируется, и применяется предыдущее правило color
    • Объявление становится невалидным на этапе вычисления значения, и color разрешается как unset
    • Браузер преобразует 12px в цвет, близкий к чёрному
    • В консоль выбрасывается ошибка, и таблица стилей отклоняется
  2. Чему в точности эквивалентно clamp(1rem, 2.5vw, 2rem)?
    • max(1rem, min(2.5vw, 2rem))
    • min(1rem, max(2.5vw, 2rem))
    • calc(1rem + 2.5vw + 2rem)
  3. В чём главное преимущество @property перед обычным пользовательским свойством?
    • Оно делает переменную доступной из JavaScript
    • Оно позволяет использовать переменную внутри calc()
    • Оно задаёт переменной тип, что, в частности, делает её интерполируемой в анимациях
    • Оно заставляет переменную наследоваться во всём документе