Функция calc()

Функция calc() позволяет вычислять значение CSS-свойства прямо в коде, причём можно смешивать РАЗНЫЕ единицы измерения в одной формуле - например, проценты и пиксели. Без calc() так не получится: "50% минус 8 пикселей" в принципе нельзя записать одним обычным числом, потому что проценты и пиксели измеряют разное.

Попробуй прямо сейчас: подвигай ползунок. Одна переменная --gap меняется - а сразу три РАЗНЫХ формулы (умножить на 3, умножить на 6, использовать как есть) пересчитываются одновременно на трёх разных элементах. Никаких перезагрузок - браузер вычисляет всё заново в реальном времени.

Синтаксис calc() и смешивание единиц

Внутри calc() работают четыре обычных математических оператора: сложение, вычитание, умножение и деление. Главная сила функции - в том, что она умеет складывать и вычитать значения в РАЗНЫХ единицах измерения: width: calc(50% - 40px); означает "ширина родителя минус 40 пикселей", и браузер честно считает это на лету при каждом изменении размера окна. Для умножения и деления одно из чисел обязательно должно быть просто числом без единиц: calc(2em * 5) - можно, а calc(2em * 5px) - нет, потому что "пиксели умножить на пиксели" не имеет физического смысла для размера.

.hero { height: calc(100vh - 60px); } - высота экрана минус высота шапки, классический пример на реальных проектах.

.hero { height: 100vh - 60px; } без calc() - это просто невалидное значение, вычислений без обёртки calc() в обычном CSS не бывает.

Пробелы вокруг + и - обязательны

У операторов + и - есть жёсткое требование из спецификации: с ОБЕИХ сторон обязательно должен быть пробел. Без пробела браузер не может понять, что перед ним - оператор вычитания или знак отрицательного числа. calc(50% - 8px) - это "проценты, потом минус, потом 8 пикселей", а calc(50% -8px) без пробела перед минусом браузер разбирает как "проценты, а следом сразу отрицательная длина" - что вообще не является допустимым выражением. В результате ЛОМАЕТСЯ ВСЁ правило целиком, а не просто "минус 8px" пропадает: свойство откатывается к значению по умолчанию, будто calc() там вообще не было. Для * и / пробелы не обязательны, но для единообразия их всё равно принято ставить.

width: calc(50% - 8px); - пробелы есть с обеих сторон минуса, работает правильно.

width: calc(50% -8px); - пробела перед минусом нет, всё выражение невалидно, свойство width вернётся к обычному поведению по умолчанию.

calc() и переменные вместе

Настоящая мощь раскрывается, когда calc() объединяют с CSS-переменными из прошлого урока. Там одна переменная меняла сразу несколько элементов через var() напрямую - здесь то же самое, но с математикой: calc(var(--gap) * 3) и calc(var(--gap) * 6) могут использовать одну и ту же переменную для получения РАЗНЫХ, но связанных между собой размеров. Изменится переменная - пересчитаются сразу обе формулы, потому что и переменные, и calc() живут в браузере в реальном времени, а не только на этапе сборки проекта.

:root { --unit: 8px; } .a { margin: calc(var(--unit) * 2); } .b { padding: calc(var(--unit) * 3); } - меняешь --unit один раз, пересчитываются оба отступа с сохранением пропорции.

.a { margin: 16px; } .b { padding: 24px; } без переменной и calc() - если понадобится изменить масштаб всех отступов сразу, придётся вручную искать и менять каждое число по отдельности.

Из истории Первым поддержку calc() получил Chrome 19 в 2012 году, следом подтянулись Firefox 4 и Safari 6. Но Internet Explorer 9-11 поддерживали её лишь частично, и на практике это ещё долго оставалось источником багов при попытке использовать более сложные вложенные выражения. Статус "широко доступно" во всех актуальных браузерах calc() получила только в июле 2015 года - то есть на первый взгляд простая функция добиралась до надёжной кросс-браузерной поддержки около трёх лет.

Частые ошибки новичков

ОшибкаЧто происходитКак исправить
Пишут calc(50% -8px) без пробела перед минусом Всё выражение становится невалидным, свойство откатывается к значению по умолчанию Всегда ставить пробелы с обеих сторон + и -
Пытаются умножить или разделить два значения с единицами calc(2em * 5px) невалиден - непонятно, что такое "пиксели в квадрате" для размера Для * и / одно из значений должно быть простым числом без единиц
Не пробуют смешивать разные единицы там, где это и есть решение задачи Вместо простого calc(100vh - 60px) городят сложные обходные конструкции Использовать calc() именно там, где нужно вычесть/сложить разные единицы измерения
Забывают, что % внутри calc() всё ещё считается от родителя как обычный процент Ожидают одно значение, получают другое из-за незнания, от чего именно считается % Проверять, от какого именно родителя или направления считается % внутри calc()

Шпаргалка

Что нужноКак сделать
Сложение/вычитание разных единицcalc(100% - 40px), пробелы вокруг + и - обязательны
Умножение/делениеcalc(var(--x) * 3) - один из множителей должен быть числом
Экран минус шапкаcalc(100vh - 60px)
calc() + переменнаяcalc(var(--gap) * 2) - пересчитывается на лету при смене переменной
Частая ошибкаcalc(50% -8px) без пробела - ломает всё выражение целиком

Коротко: отвечаем на вопросы

Можно ли смешивать разные единицы измерения в calc(), например проценты и пиксели?

Да, это и есть главная причина использовать calc() - обычный CSS не умеет складывать или вычитать значения в разных единицах напрямую, а calc(50% - 40px) браузер вычисляет сам, каждый раз пересчитывая процент от актуального размера родителя.

Почему у плюса и минуса в calc() обязательно должны быть пробелы с обеих сторон?

Без пробела браузер не может отличить оператор вычитания от знака отрицательного числа: calc(50% -8px) разбирается как "проценты, а следом отдельная отрицательная длина" - невалидное выражение, из-за которого откатывается всё правило целиком, а не только вычитание.

Можно ли использовать CSS-переменную внутри calc()?

Да, и это одна из самых полезных комбинаций: calc(var(--gap) * 3) пересчитывается заново каждый раз, когда меняется значение переменной --gap, даже если это происходит уже после загрузки страницы через JavaScript.

Категория
css
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×