calc()

Настоящая математика внутри CSS! Что может быть безумнее удобнее?

Время чтения: меньше 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);
}

        
        
          
        
      

На практике

Скопировано

Алёна Батицкая советует

Скопировано

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

        
          
          <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;
}

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