CSS: guia completo da função calc ()

CSS possui uma função especial calc()usada para realizar cálculos simples. Aqui está um exemplo de seu uso:

.main-content {
  /*  80px  100vh */
  height: calc(100vh - 80px);
}

Aquicalc() você pode experimentar o código CSS em que é usado . O autor do artigo, cuja tradução estamos publicando hoje, quer falar sobre tudo o que vale a pena conhecer sobre essa função muito útil.





Função Calc () e valores de propriedade CSS


O único lugar em que você pode usar a função calc()é com valores de propriedade CSS. Veja os exemplos a seguir, nos quais, usando esta função, definimos os valores de várias propriedades.

.el {
  font-size: calc(3vw + 2px);
  width:     calc(100% - 20px);
  height:    calc(100vh - 20px);
  padding:   calc(1vw + 5px);
}

A função calc()também pode ser usada para definir qualquer parte separada da propriedade:

.el {
  margin: 10px calc(2vw + 5px);
  border-radius: 15px calc(15px / 3) 4px 2px;
  transition: transform calc(1s - 120ms);
}

Essa função pode até fazer parte de outra função responsável por formar parte de uma determinada propriedade! Por exemplo, aqui é calc()usado para ajustar a posição da mudança de cor gradiente:

.el {
  background: #1E88E5 linear-gradient(
    to bottom,
    #1E88E5,
    #1E88E5 calc(50% - 10px),
    #3949AB calc(50% + 10px),
    #3949AB
  );
}

A função calc () é uma ferramenta para trabalhar com propriedades numéricas.


Observe que em todos os exemplos acima, usamos a função calc()ao trabalhar com propriedades numéricas. Também falaremos sobre alguns recursos do trabalho com propriedades numéricas (eles estão associados ao fato de que, às vezes, o uso de unidades de medida não é necessário). Agora, observamos que essa função foi projetada para executar operações com números, e não com strings ou com outra coisa.

.el {
  /* ! */
  counter-reset: calc("My " + "counter");
}
.el::before {
  /* ! */
  content: calc("Candyman " * 3);
}

Há muitas unidades de medida que podem ser usados em CSS para especificar o tamanho dos elementos e suas partes: px, %, em, rem, in, mm, cm, pt, pc, ex, ch, vh, vw, vmin, vmax. Todas essas unidades podem ser usadas com a função calc().

Esta função também pode trabalhar com números usados ​​sem especificar unidades:

line-height: calc(1.2 * 1.2);

Também pode ser usado para calcular ângulos:

transform: rotate(calc(10deg * 5));

Essa função também pode ser usada nos casos em que nenhum cálculo é realizado na expressão passada para ela:

.el {
  /*   ,    */
  width: calc(20px);
}

Calc () não pode ser usado em consultas de mídia


Embora essa função tenha sido projetada para definir valores de propriedade CSS, infelizmente não funciona em consultas de mídia:

@media (max-width: 40rem) {
  /* 40rem   */
}

/*  ! */
@media (min-width: calc(40rem + 1px)) {
  /* ,  40rem */
}

Se uma vez que essas construções forem viáveis, isso será muito bom, pois permitirá a criação de consultas de mídia mutuamente exclusivas que parecerão muito lógicas (por exemplo, as mostradas acima).

Usando unidades diferentes em uma expressão


A admissibilidade de usar diferentes unidades de medida em uma expressão é provavelmente a oportunidade mais valiosa calc(). Semelhante é usado em quase todos os exemplos acima. Aqui, apenas para chamar sua atenção, outro exemplo que mostra o uso de diferentes unidades de medida:

/*      */
width: calc(100% - 20px);

Esta expressão é a seguinte: "A largura é igual à largura do elemento do qual 20 pixels são subtraídos."

Em uma situação em que a largura do elemento pode mudar, é completamente impossível calcular antecipadamente o valor desejado, usando apenas indicadores expressos em pixels. Em outras palavras, você não pode pré-processar calc()usando algo como Sass e tentar obter algo como polyfill. Sim, isso não é necessário, pois os navegadores suportamcalc() muito bem . O ponto aqui é que esses cálculos, nos quais os valores expressos em diferentes unidades são misturadas, devem ser executados no navegador (durante a "execução" da página). Ou seja, a capacidade de realizar esses cálculos é o principal valor .calc()

Aqui estão mais alguns exemplos do uso de valores expressos em diferentes unidades:

transform: rotate(calc(1turn + 45deg));

animation-delay: calc(1s + 15ms);

Provavelmente, você pode pré-processar essas expressões, porque elas misturam valores cujas unidades não estão relacionadas a nada que é determinado enquanto a página está em execução no navegador.

Comparação de calc () com cálculos de pré-processador


Acabamos de dizer que o recurso mais útil calc()não é passível de pré-processamento. Mas o pré-processamento fornece ao desenvolvedor alguns recursos que correspondem aos recursos calc(). Por exemplo, ao usar o Sass, você também pode calcular os valores da propriedade:

$padding: 1rem;

.el[data-padding="extra"] {
  padding: $padding + 2rem; //  3rem;
  margin-bottom: $padding * 2; //  2rem; 
}

Aqui, podem ser feitos cálculos indicando as unidades de medida, aqui você pode adicionar as quantidades expressas nas mesmas unidades de medida, você pode multiplicar certos valores por valores cujas unidades não são indicadas. Mas não é possível realizar cálculos com valores expressos em diferentes unidades de medida. Restrições semelhantes a restrições são impostas a esses cálculos calc()(por exemplo, os números pelos quais algo é multiplicado ou dividido devem ser valores sem unidades).

Divulgar o significado dos valores numéricos usados ​​no CSS


Mesmo que você não aproveite as oportunidades que são possíveis apenas com ajuda calc(), esta função pode ser usada para revelar o significado dos valores usados ​​no CSS. Suponha que você queira que o valor de uma propriedade seja exatamente 1/7 da largura do elemento:

.el {
  /*   , */
  width: calc(100% / 7);

  /*   */
  width: 14.2857142857%;
}

Essa abordagem pode ser útil em algo como um tipo de CSS-API com estilo próprio:

[data-columns="7"] .col { width: calc(100% / 7); }
[data-columns="6"] .col { width: calc(100% / 6); }
[data-columns="5"] .col { width: calc(100% / 5); }
[data-columns="4"] .col { width: calc(100% / 4); }
[data-columns="3"] .col { width: calc(100% / 3); }
[data-columns="2"] .col { width: calc(100% / 2); }

Operadores matemáticos da função calc ()


A expressão a ser avaliada com a ajuda calc()dos operadores que você pode usar +, -, *e /. Mas em sua aplicação, existem alguns recursos.

Ao adicionar ( +) e subtrair ( -), você deve usar os valores com as unidades especificadas

.el {
  /*  */
  margin: calc(10px + 10px);

  /*  */
  margin: calc(10px + 5);
}

Observe que o uso de valores incorretos leva ao fato de que um anúncio específico também se torna incorreto.

Ao dividir ( /), é necessário que a unidade de medida não seja indicada no segundo número

.el {
  /*  */
  margin: calc(30px / 3);

  /*  */
  margin: calc(30px / 10px);

  /*  (   ) */
  margin: calc(30px / 0);
}

Ao multiplicar ( *), um dos números não deve ter uma unidade de medida:

.el {
  /*  */
  margin: calc(10px * 3);

  /*  */
  margin: calc(3 * 10px);

  /*  */
  margin: calc(30px * 3px);
}

A importância dos espaços


Os espaços usados ​​nas expressões são importantes nas operações de adição e subtração:

.el {
  /*  */
  font-size: calc(3vw + 2px);

  /*  */
  font-size: calc(3vw+2px);

  /*  */
  font-size: calc(3vw - 2px);

  /*  */
  font-size: calc(3vw-2px);
}

Aqui é bem possível usar números negativos (por exemplo, em um construto como calc(5vw — -5px)), mas este é um exemplo de uma situação em que os espaços não são apenas necessários, mas também úteis em termos de clareza de expressões.

Tab Atkins me disse que a razão pela qual os operadores de adição e subtração devem ser separados por espaços é, de fato, as peculiaridades de analisar expressões. Não posso dizer que entendi completamente isso, mas, por exemplo, o analisador processa a expressão 2px-3pxcomo um número 2com uma unidade de medidapx-3px. E ninguém precisará de uma unidade de medida tão estranha. A análise de expressões com o operador de adição tem seus próprios problemas. Por exemplo, um analisador pode considerar esse operador como parte da sintaxe usada para descrever números. Eu pensei que era necessário um espaço para lidar corretamente com a sintaxe das propriedades personalizadas ( --), mas esse não é o caso.

Ao multiplicar e dividir espaços ao redor dos operadores, não é necessário. Mas acredito que você pode recomendar o uso de espaços com esses operadores para aumentar a legibilidade do código e para não esquecer os espaços e ao inserir expressões que usam adição e subtração.

Os espaços que separam colchetes calc()de uma expressão não desempenham nenhum papel. A expressão, se desejar, pode até ser selecionada movendo-se para uma nova linha:

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

É verdade que você deve ter cuidado aqui. Não calcdeve haver espaços entre o nome da função ( ) e o primeiro colchete de abertura:

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

Construções aninhadas: calc (calc ())


Ao trabalhar com uma função calc(), você pode usar construções aninhadas, mas isso não é realmente necessário. É semelhante ao uso de colchetes sem calc:

.el {
  width: calc(
    calc(100% / 3)
    -
    calc(1rem * 2)
  );
}

Não faz sentido criar construções aninhadas a partir de funções calc(), pois o mesmo pode ser reescrito usando apenas colchetes:

.el {
  width: calc(
   (100% / 3)
    -
   (1rem * 2)
  );
}

Além disso, os parênteses não são necessários neste exemplo, pois as regras para determinar a prioridade dos operadores são aplicadas ao calcular as expressões apresentadas aqui. A divisão e multiplicação são realizadas antes da adição e subtração. Como resultado, o código pode ser reescrito assim:

.el {
  width: calc(100% / 3 - 1rem * 2);
}

Porém, no caso de parecer que os colchetes adicionais tornam o código mais claro, eles podem ser usados. Além disso, se sem parênteses, com base apenas na prioridade dos operadores, a expressão será calculada incorretamente, essa expressão precisará de parênteses:

.el {
  /* ,   , */
  width: calc(100% + 2rem / 2);

  /*     ,    */
  width: calc((100% + 2rem) / 2);
}

Propriedades CSS personalizadas e calc ()


Já aprendemos sobre um dos grandes recursos calc(), sobre cálculos que usam valores com unidades diferentes. Outro recurso interessante dessa função é como ela pode ser aplicada com propriedades CSS personalizadas. Propriedades personalizadas podem receber valores que podem ser usados ​​nos cálculos:

html {
  --spacing: 10px;
}

.module {
  padding: calc(var(--spacing) * 2);
}

Tenho certeza de que é fácil imaginar um conjunto de estilos CSS em que muitas configurações são feitas em um só lugar, definindo valores para propriedades CSS personalizadas. Esses valores serão usados ​​em todo o código CSS.

Além disso, as propriedades personalizadas podem se referir uma à outra (observe que não é calc()usada aqui). Os valores obtidos podem ser usados ​​para definir os valores de outras propriedades CSS (mas aqui você calc()não pode prescindir).

html {
  --spacing: 10px;
  --spacing-L: var(--spacing) * 2;
  --spacing-XL: var(--spacing) * 3;
}

.module[data-spacing="XL"] {
  padding: calc(var(--spacing-XL));
}

Para alguns, isso pode não parecer muito conveniente, pois ao acessar uma propriedade personalizada, você precisa se lembrar calc(). Mas acho isso interessante em termos de legibilidade do código.

A origem das propriedades customizadas pode ser o código HTML. Às vezes isso pode ser extremamente útil. Por exemplo, no Splitting.js, os índices são adicionados às palavras e símbolos.

<div style="--index: 1;"> ... </div>
<div style="--index: 2;"> ... </div>
<div style="--index: 3;"> ... </div>
div {
  /*     HTML (   ) */
  animation-delay: calc(var(--index, 1) * 0.2s);
}

Atribuindo unidades a propriedades personalizadas após declarar essas propriedades


Suponha que estamos em uma situação em que faz sentido escrever um número sem unidades de medida em uma propriedade customizada ou em uma situação em que esse número seja conveniente, antes do uso real, de alguma forma converter sem usar unidades. Nesses casos, é possível atribuir um valor a uma propriedade customizada sem especificar unidades. Quando for necessário converter esse número em um novo, expresso em determinadas unidades de medida, ele poderá ser multiplicado, 1indicando as unidades de medida desejadas:

html {
  --importantNumber: 2;
}

.el {
  /*    ,  ,        */
  padding: calc(var(--importantNumber) * 1rem);
}

Trabalhar com flores


Ao descrever cores usando formatos como RGB e HSL, os números são usados. Esses números podem ser trabalhados calc(). Por exemplo, você pode definir alguns valores básicos de HSL e alterá-los conforme necessário ( aqui está um exemplo):

html {
  --H: 100;
  --S: 100%;
  --L: 50%;
}

.el {
  background: hsl(
    calc(var(--H) + 20),
    calc(var(--S) - 10%),
    calc(var(--L) + 30%)
  )
}

Você não pode combinar calc () e attr ()


A função CSS attr()pode parecer bastante atraente. E a verdade: você pega o valor do atributo do HTML e depois o usa. Mas…

<div data-color="red">...</div>
div {
  /*    */
  color: attr(data-color);
}

Infelizmente, esta função não entende os "tipos" de valores. Como resultado, attr()é adequado apenas para trabalhar com seqüências de caracteres e para definir propriedades CSS usando-a content. Ou seja, esse design acaba funcionando bastante:

div::before {
  content: attr(data-color);
}

Eu disse isso aqui porque alguém pode tentar extrair um attr()determinado número do código HTML e usá-lo nos cálculos:

<div class="grid" data-columns="7" data-gap="2">...</div>
.grid {
  display: grid;

  /*         */
  grid-template-columns: repeat(attr(data-columns), 1fr);
  grid-gap: calc(1rem * attr(data-gap));
}

No entanto, o bom é que isso realmente não importa, pois as propriedades personalizadas em HTML são ótimas para resolver esses problemas:

<div class="grid" style="--columns: 7; --gap: 2rem;">...</div>
.grid {
  display: grid;

  /* ! */
  grid-template-columns: repeat(var(--columns), 1fr);
  grid-gap: calc(var(--gap));
}

Ferramentas do navegador


As ferramentas do desenvolvedor do navegador geralmente exibem expressões com as calc()mesmas descritas no código-fonte CSS.


Guia Ferramentas do desenvolvedor do Firefox, guia Regras

Se você precisar descobrir o que a função calcularácalc(), consulte a guiaComputed(essa guia pode ser encontrada nas ferramentas de desenvolvedor de todos os navegadores que eu conheço). Lá, o valor calculado será mostradocalc().


Guia Computado das Ferramentas para Desenvolvedor do Chrome

Suporte do navegador


Aqui você pode descobrir sobre calc()o suporte ao navegador para o recurso . Se falamos de navegadores modernos, o nível de suporte calc()é superior a 97%. Se você precisar oferecer suporte a navegadores bastante antigos (como IE 8 ou Firefox 3.6), eles geralmente fazem o seguinte: adicione calc()a mesma propriedade antes da propriedade para calcular o valor definido em um formato que os navegadores antigos entendem:

.el {
  width: 92%; /*   */
  width: calc(100% - 2rem);
}

A função calc()tem muitos problemas conhecidos, mas apenas navegadores antigos sofrem com eles. Em Caniuse pode encontrar uma descrição de 13 desses problemas. Aqui estão alguns deles:

  • O navegador Firefox abaixo da versão 59 não suporta calc()as funções usadas para definir a cor. Por exemplo: color: hsl(calc(60 * 2), 100%, 50%).
  • O IE 9-11 não renderizará a sombra especificada pela propriedade box-shadowse for usada para determinar qualquer um dos valores calc().
  • O IE 9-11 e o Edge não suportam o design de exibição width: calc()quando aplicados às células da tabela.

Exemplos de vida


Perguntei a vários desenvolvedores de CSS sobre quando eles usaram a função pela última vez calc(). Suas respostas foram uma pequena seleção que ajudará todos a aprender sobre como outros programadores usam calc()em seu trabalho diário.

  • Eu usei calc()para criar a classe auxiliar para as áreas de gestão: .full-bleed { width: 100vw; margin-left: calc(50% — 50vw); }. Posso dizer que ele calc()está entre meus 3 principais recursos CSS mais úteis.
  • Eu usei essa função para alocar espaço para um "rodapé" fixo da página.
  • calc() . , font-size, . font-sizecalc() line-height. ( , calc() , , , rem em. , ).
  • , . . — : .margin { width: calc( (100vw — var(--content-width)) / 2); }.
  • calc() - , . : .drop-cap { --drop-cap-lines: 3; font-size: calc(1em * var(--drop-cap-lines) * var(--body-line-height)); }.
  • , .
  • , padding vw/vh.
  • Eu aplico calc()para contornar restrições background-position. Isto é especialmente verdade para restrições no ajuste de posições de mudança de cor em gradientes. Por exemplo, isso pode ser descrito da seguinte maneira: "posicione a posição da mudança de cor, sem atingir 0.75ema parte inferior".



Queridos leitores! Você usa CSS calc()?

All Articles