Что делает calc()
calc() выполняет арифметику внутри значения CSS и может смешивать единицы, размер которых известен только при раскладке. Классический случай: «вся ширина минус боковая панель фиксированной ширины»:
100% известен только после раскладки страницы, а 180px фиксирован, поэтому ни одна единица не выразила бы это сама. calc() вычисляет: в превью шириной 800px строка шириной 784px, и основной колонке достается 604px, а строка под раскладкой выводит настоящие числа. Сегодня эту раскладку без вычислений сделали бы flexbox или grid, но такое же вычитание встречается повсюду: высота минус шапка, ширина минус промежуток.
Правила синтаксиса
width: calc(100% - 2rem); /* + and - need spaces on both sides */
width: calc(100% / 3); /* divide by a plain number */
margin: calc(var(--space) * 2); /* multiply by a plain number */
height: calc(100vh - (64px + 1rem)); /* parentheses group */
| Правило | Валидно | Невалидно |
|---|---|---|
Пробелы вокруг + и - | calc(100% - 20px) | calc(100%-20px) |
*: хотя бы с одной стороны простое число | calc(2 * 1rem) | calc(2px * 3px) |
/: длину делят на простое число | calc(100% / 3) | width: calc(300px / 3px) (не длина) |
| Единицы должны быть совместимы | calc(1rem + 10px) | calc(1rem + 2s) |
Правило пробелов существует потому, что 100% -20px читалось бы как два отдельных значения, второе из которых отрицательное число. Когда calc() невалиден, все объявление отбрасывается, и элемент сохраняет значение из более ранних правил.
Попробуйте выражение
Введите любое выражение для ширины блока. Браузер покажет, валидно ли оно и какую ширину дало:
Попробуйте 100%-200px (невалидно, нет пробелов), 100% / 3, 50% + 4rem, 2 * 120px, 200px * 2px (невалидно) и (100% - 40px) / 2.
calc() с CSS-переменными
Переменные и calc() хорошо работают вместе: храните базовое значение один раз и выводите из него остальные. Переменная без единиц становится длиной, если умножить ее на одну единицу:
Измените --space на 12px или --cols на 4, и все производные значения последуют за ними. Объявление и область видимости переменных разобраны на странице про переменные CSS.
Типичные применения
| Задача | calc() |
|---|---|
| Заполнить пространство рядом с элементом фиксированной ширины | width: calc(100% - 240px) |
| Секция под фиксированной шапкой | min-height: calc(100vh - 64px) |
| Половина ширины минус половина промежутка | width: calc(50% - 8px) |
| Центрировать абсолютно позиционированный блок 100px | left: calc(50% - 50px) |
| Размер шрифта, который немного растет с экраном | font-size: calc(1rem + 0.5vw) |
| Превратить числовую переменную в длину | calc(var(--n) * 1px) |
| Отрицательное значение переменной | calc(var(--space) * -1) |
Для значения, которое должно оставаться в пределах, используйте clamp(): она принимает те же вычисления в аргументах без записи calc().
Где работает calc()
Везде, где допустимы длина, проценты, число, угол или время: width, margin, padding, top, font-size, line-height, размеры дорожек grid, transition-delay и углы внутри transform. calc() можно вкладывать, и вложенный calc() равнозначен обычным скобкам.
Хороший пример это углы. У каждой риски ниже свой --i (от 0 до 11), и одно правило превращает его в угол через calc(var(--i) * 30deg):
Риска 3 получает rotate(90deg), который Chrome показывает как матрицу matrix(0, 1, -1, 0, 0, 0): четверть оборота. left: calc(50% - 2px) центрирует каждую риску, вычитая половину ее собственной ширины 4px.
Частые ошибки
- Нет пробелов вокруг
-или+.calc(100%-20px)невалидно и игнорируется. - Умножение двух длин.
calc(10px * 2px)в CSS не имеет смысла. Одна сторона*должна быть простым числом. - calc() для процентной высоты без высоты у родителя.
calc(100% - 20px)дляheight, как иheight: 100%, требует родителя с заданной высотой. - calc() там, где справился бы flexbox или grid.
width: calc(33.333% - 10px)для колонок хрупко;display: grid; grid-template-columns: repeat(3, 1fr); gap: 15pxобходится без вычислений. - Ожидание сообщения об ошибке. Браузер не предупреждает о невалидном calc(). Проверьте элемент в инструментах разработчика: невалидное объявление показано зачеркнутым.
Часто задаваемые вопросы
Что делает calc() в CSS?
Вычисляет значение из выражения с +, -, * и / и может смешивать единицы, которые браузер узнает только при раскладке. width: calc(100% - 200px) это полная ширина родителя минус 200px, какой бы ни была ширина родителя.
Почему не работает calc()?
Самая частая причина: нет пробелов. Вокруг + и - должны быть пробелы с обеих сторон, поэтому calc(100%-20px) невалидно. Другие причины: умножение двух длин (10px * 2px) или деление на длину, что не дает длины. Невалидный calc() делает невалидным все объявление, и браузер его игнорирует.
Можно ли использовать CSS-переменные в calc()?
Да. calc(var(--gap) * 2) удваивает переменную, а calc(var(--columns) * 1px) превращает число без единиц в пиксели. Сначала подставляется значение переменной, а затем выполняется вычисление.
Нужны ли пробелы вокруг * и / в calc()?
Нет. Пробелы обязательны только вокруг + и -, потому что без них -20px читалось бы как отрицательное число. Пробелы вокруг * и / необязательны, но писать их везде проще всего запомнить.
Чем calc() отличается от clamp()?
calc() вычисляет одно значение из выражения. clamp(MIN, VAL, MAX) удерживает значение между двумя пределами. Они сочетаются: каждый аргумент clamp() уже может содержать вычисления в стиле calc, например clamp(1rem, 1rem + 2vw, 3rem).