calc()

Время чтения: меньше 5 мин

Кратко

Секция статьи "Кратко"

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

Пример

Секция статьи "Пример"

Частая ситуация: в вёрстке три колонки, ширина каждой из которых должна быть ровно третью от 100%. 100% / 3 = 33.3333333333...%. Раньше мы допускали неточность и указывали ширину как 33%. Теперь можно использовать calc() и пусть браузер сам считает.

При отрисовке страницы браузер сам высчитает и подставит значение:

        
          
          .selector {  width: calc(100% / 3);}
          .selector {
  width: calc(100% / 3);
}

        
        
          
        
      

Но лучше не перегружать браузер расчётами. На каждую операцию он тратит некую долю секунды и часть оперативной памяти. Если расчётов будет много, то это потенциально повлияет на скорость загрузки страницы. Используйте calc() с умом.

Как пишется

Секция статьи "Как пишется"

В круглых скобках мы можем писать любые математические операции с любыми единицами измерения, доступными в вебе (%, px, rem, em, vw, vh, vmin и т.д.). Доступны четыре стандартных операнда:

  • + — сложение
  • - — вычитание
  • / — деление
  • * — умножение

Операторы сложения и вычитания обязательно с двух сторон должны отбиваться пробелом. Иначе браузер воспримет их как часть числа. Хоть операторы деления и умножения не требуют такой строгости к себе, но принято и их тоже отбивать пробелами для удобства чтения.

Хорошо 👍

        
          
          .selector {  width: calc(100% - 2rem);}
          .selector {
  width: calc(100% - 2rem);
}

        
        
          
        
      

Плохо 👎

        
          
          .selector {  width: calc(100% -2rem);}
          .selector {
  width: calc(100% -2rem);
}

        
        
          
        
      

Внутри скобок может быть больше одного вычисления, можно группировать операции при помощи скобок. Всё как в настоящем языке программирования 😺 Но не стоит увлекаться, чем короче вычисление, тем проще потом его прочитать и понять что там вообще происходит.

Для каких свойств можно указать calc() в качестве значения? Для любых, значением которых должна быть цифра! Причём если свойство предполагает составное значение, то можно указать функцию как часть этого значения:

        
          
          .selector {  margin: calc(5vh / 4) 20px;  transition: transform calc(0.5s + 120ms);}
          .selector {
  margin: calc(5vh / 4) 20px;
  transition: transform calc(0.5s + 120ms);
}

        
        
          
        
      

Внутри круглых скобок можно складывать только числовые значения. Нельзя сложить число со строкой, хотя в полноценных языках программирования, типа JavaScript, такой трюк с лёгкостью бы удался.

Ещё одно неудачное место для этой функции — медиавыражения. Вот такая запись считается не валидной:

        
          
          @media (min-width: calc(465px + 1vw)) {  ...;}
          @media (min-width: calc(465px + 1vw)) {
  ...;
}

        
        
          
        
      

Хотя бы у одной из цифр внутри скобок нужно указать единицу измерения, иначе браузер не сможет понять, от чего же вести вычисление.

Как это понять

Секция статьи "Как это понять"

Во время отрисовки (рендеринга) страницы браузер заглядывает в CSS и производит все вычисления из функций calc(), подставляя на их место итоговое значение. Исходя из этих значений и отрисовываются стили элементов.

Подсказки

Секция статьи "Подсказки"

💡 Очень удобно (и часто приходится) использовать, когда из одной величины в относительных единицах надо вычесть другую величину в абсолютных единицах. Самостоятельно это никак не посчитать, а браузеру раз плюнуть. Например, каким будет результат такого вычисления?

        
          
          .selector {  height: calc(100vh - 34px);}
          .selector {
  height: calc(100vh - 34px);
}

        
        
          
        
      

На практике

Секция статьи "На практике"

Алёна Батицкая

Секция статьи "Алёна Батицкая"

🛠 Возьмём тот же пример с тремя колонками из начала статьи. Пусть у каждой из колонок будет внешний отступ по 40px с каждой из сторон. Если зададим свойства в лоб, то ничего не выйдет, последний блок падает на новую строку.

        
          
          <div class="parent">  <div class="child">    <h2>Газеты</h2>  </div>  <div class="child">    <h2>Заводы</h2>  </div>  <div class="child">    <h2>Пароходы</h2>  </div></div>
          <div class="parent">
  <div class="child">
    <h2>Газеты</h2>
  </div>
  <div class="child">
    <h2>Заводы</h2>
  </div>
  <div class="child">
    <h2>Пароходы</h2>
  </div>
</div>

        
        
          
        
      
        
          
          .child {  display: inline-block;  width: 33.3%;  margin-left: 40px;  margin-right: 40px;}
          .child {
  display: inline-block;
  width: 33.3%;
  margin-left: 40px;
  margin-right: 40px;
}

        
        
          
        
      
Открыть демо в новой вкладке

Можно использовать флексбокс. Избежим падения, но получим проблему сужения блоков чтобы уместиться в ряд. Как всего этого избежать? Высчитывать размер блоков с учётом этих боковых отступов!

        
          
          .child {  display: inline-block;  width: calc(33.3% - 80px);  margin-left: 40px;  margin-right: 40px;}
          .child {
  display: inline-block;
  width: calc(33.3% - 80px);
  margin-left: 40px;
  margin-right: 40px;
}

        
        
          
        
      
Открыть демо в новой вкладке