Una guía completa de calc () en CSS | Programar Plus

CSS tiene un especial calc() función para hacer matemáticas básicas. En esta guía, cubriremos casi todo lo que hay que saber sobre esta función tan útil.

He aquí un ejemplo:

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

En esta guía, cubriremos casi todo lo que hay que saber sobre esta función tan útil.

calc() es por valores

El único lugar donde puede usar el calc() la función está en valores. Vea estos ejemplos en los que establecemos el valor de varias propiedades diferentes.

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

También podría usarse solo para una parte de una propiedad, por ejemplo:

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

¡Incluso puede ser parte de otra función que forme parte de una propiedad! Por ejemplo, aquí tienes calc() utilizado dentro de las paradas de color de un degradado

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

calc() es para longitudes y otras cosas numéricas

Observe que todos los ejemplos anteriores se basan esencialmente en números. Llegaremos a algunas de las advertencias sobre cómo se pueden usar los números (porque a veces no se necesita una unidad), pero esto es para matemáticas numéricas, no cadenas ni nada por el estilo.

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

Sin embargo, hay muchas longitudes de CSS, y todas se pueden usar con calc():

  • px
  • %
  • em
  • movimiento rápido del ojo
  • en
  • mm
  • cm
  • pt
  • ordenador personal
  • ex
  • ch
  • vh
  • vw
  • vmin
  • vmax

Los números sin unidades también son aceptables. Por ejemplo line-height: calc(1.2 * 1.2); así como ángulos como transform: rotate(calc(10deg * 5));.

Tampoco puedes realizar ningún cálculo y sigue siendo válido:

.el {
  /* Little weird but OK */
  width: calc(20px);
}

No en las consultas de medios

Cuándo calc() se utiliza correctamente (unidades de longitud utilizadas como valor de una propiedad), lamentablemente, calc() no funcionará cuando se aplique a consultas de medios.

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

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

Sería genial algún día porque podrías hacer consultas de medios mutuamente excluyentes de una manera bastante lógica (como la anterior).

Unidades de mezcla 🎉

Esta es quizás la característica más valiosa de calc()! Casi todos los ejemplos anteriores ya han hecho esto, pero solo para señalarlo, aquí está mezclando diferentes unidades:

/* Percentage units being mixed with pixel units */
width: calc(100% - 20px);

Eso es decir: tan ancho como es el elemento, menos 20 píxeles.

Literalmente, no hay forma de precalcular ese valor solo en píxeles en una situación de ancho fluido. En otras palabras, no puede preprocesar calc() con algo como Sass como un intento de completar un polyfill. No es que lo necesite, ya que la compatibilidad con el navegador está bien. Pero el punto es que tiene que hacerse en el navegador (en “tiempo de ejecución”) cuando se mezclan unidades de esta manera, que es la mayor parte del valor de calc().

Aquí hay algunos otros ejemplos de unidades de mezcla:

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

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

Es probable que se puedan preprocesar, ya que mezclan unidades que no son relativas a nada que se determine en tiempo de ejecución.

Comparación con las matemáticas del preprocesador

Acabamos de cubrir que no puede preprocesar las cosas más útiles que calc() puede hacer. Pero hay una pizca de superposición. Por ejemplo, Sass tiene las matemáticas integradas, por lo que puede hacer cosas como:

$padding: 1rem;

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

Incluso las matemáticas con unidades funcionan allí, sumando valores de la misma unidad o multiplicando por números sin unidades. Pero no puede mezclar unidades y tiene limitaciones similares a calc() (por ejemplo, multiplicar y dividir debe ser con números sin unidades).

Muestra las matemáticas

Incluso si no está utilizando una función que solo es posible con calc(), se puede utilizar para “mostrar su trabajo” dentro de CSS. Por ejemplo, digamos que necesita calcular exactamente 1/7 del ancho de un elemento …

.el {
  /* This is easier to understand */
  width: calc(100% / 7);

  /* Than this is */
  width: 14.2857142857%;
}

Eso podría resultar en algún tipo de API CSS de creación propia como:

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

Los operadores matemáticos de calc()

Tienes +, -, *, y /. Pero difieren en la forma en que debe usarlos.

Suma (+) y resta (-) requieren que ambos números sean longitudes

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

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

Los valores no válidos invalidan toda la declaración individual.

División (/) requiere que el segundo número no tenga unidades

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

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

  /* Invalid 👎 (can't divide by 0) */
  margin: calc(30px / 0);
}

Multiplicación

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

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

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

requiere que uno de los números no tenga unidades

El espacio en blanco importa Bueno, lo hace por adición ysustracción

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

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

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

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

. calc(5vw - -5px)Los números negativos están bien (p. Ej.

), pero ese es un ejemplo de dónde el espacio en blanco no solo es necesario, sino que también es útil. + Tab Atkins me dice que la razón del espacio requerido alrededor - y 2px-3px en realidad se debe a problemas de análisis. No puedo decir que lo entienda completamente, pero, por ejemplo, + se analiza como el número “2” y la unidad “px-3px”, que no le está haciendo ningún bien a nadie, y la -- tiene otros problemas, como ser “consumido por la sintaxis numérica”. Habría adivinado que el espacio en blanco habría tenido que ver con el

sintaxis de propiedades personalizadas, ¡pero no!

La multiplicación y la división no necesitan espacios en blanco alrededor de los operadores. Pero creo que un buen consejo general es incluir el espacio para la legibilidad y la memoria muscular para los otros operadores.

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

El espacio en blanco alrededor de los exteriores no importa. Incluso puede hacer saltos de línea si lo desea: calc() Sin embargo, tenga cuidado con esto: no hay espacios entre

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

y el par de apertura. calc(calc());

Anidamiento calc() Puedes, pero nunca es necesario. Es lo mismo que usar un paréntesis adicional sin el

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

parte. Por ejemplo: calc() No los necesitas dentro

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

porque los parens trabajan solos:

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

Y en este caso, el “orden de operaciones” nos ayuda incluso sin los paréntesis. Es decir, la división y la multiplicación ocurren primero (antes de la suma y la resta), por lo que los paréntesis no son necesarios en absoluto. Podría escribirse así:

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

  /* Is very different from this */
  width: calc((100% + 2rem) / 2);
}

Pero siéntase libre de usar el parens si cree que le agrega claridad. Si el orden de las operaciones no funciona a su favor (por ejemplo, realmente necesita hacer la suma o la resta primero), necesitará parens. calc() Propiedades personalizadas de CSS y

🎉 calc() Aparte de la asombrosa habilidad de calc() para mezclar unidades, lo siguiente más asombroso de

html {
  --spacing: 10px;
}

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

lo está usando con propiedades personalizadas. Las propiedades personalizadas pueden tener valores que luego use en un cálculo:

Estoy seguro de que puede imaginar una configuración de CSS en la que se realiza una gran cantidad de configuraciones en la parte superior al establecer un montón de propiedades personalizadas de CSS y luego dejar que el resto de CSS las use según sea necesario. calc() Las propiedades personalizadas también pueden hacer referencia entre sí. Aquí hay un ejemplo en el que se utilizan algunas matemáticas (tenga en cuenta la falta de un calc()función al principio) y luego se aplicó. (En última instancia, tiene que estar dentro de un

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

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

.) calc() Puede que no le guste, ya que necesita recordar el

dónde usa la propiedad entonces, pero es posible y potencialmente interesante desde una perspectiva de legibilidad.

<div style="--index: 1;"> https://css-tricks.com/... </div>
<div style="--index: 2;"> https://css-tricks.com/... </div>
<div style="--index: 3;"> https://css-tricks.com/... </div>
div {
  /* Index value comes from the HTML (with a fallback) */
  animation-delay: calc(var(--index, 1) * 0.2s);
}

Las propiedades personalizadas pueden provenir del HTML, que a veces es algo bastante interesante y útil. (Vea cómo Splitting.js agrega índices a palabras / caracteres como ejemplo).

Agregar unidades más tarde

html {
  --importantNumber: 2;
}

.el {
  /* Number stays 2, but it has a unit now */
  padding: calc(var(--importantNumber) * 1rem);
}

En caso de que se encuentre en una situación en la que sea más fácil almacenar números sin unidades o hacer cálculos matemáticos con números sin unidades con anticipación, siempre puede esperar hasta que aplique el número para sumar la unidad multiplicando por 1 y la unidad.

Jugando con los colores calc()El formato de color como RGB y HSL tiene números con los que puede meterse

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

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

. Por ejemplo, establecer algunos valores HSL base y luego alterarlos formando un sistema de su propia creación (ejemplo):

No puedes combinar calc () y attr () attr() El

<div data-color="red">https://css-tricks.com/...</div>
div {
  /* Nope */
  color: attr(data-color);
}

La función en CSS parece atractiva, como si pudiera extraer valores de atributo de HTML y usarlos. Pero… attr() Desafortunadamente, no hay “tipos” en juego aquí, así que lo único content es para son cadenas junto con el

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

propiedad. Eso significa que esto funciona:

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

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

Menciono esto porque podría ser tentador intentar extraer un número de esa manera para usarlo en un cálculo, como:

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

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

Afortunadamente, no importa mucho porque las propiedades personalizadas en el HTML son igual de útiles o más.

Herramientas del navegador calc() Browser DevTools tenderá a mostrarle las

tal como lo creó en la hoja de estilo.

Firefox DevTools – Reglas

Si necesita averiguar el valor calculado, hay una pestaña Computado (en todas las DevTools del navegador, al menos en las que yo conozco) que se lo mostrará.

Chrome DevTools – Computado

Soporte del navegador

Estos datos de soporte del navegador son de Caniuse, que tiene más detalles. Un número indica que el navegador admite la función en esa versión y posteriores.

Escritorio Cromo Firefox ES DECIR Borde
Safari 19 * 4 * 11 12

6 *

Móvil / Tableta Android Chrome Android Firefox Androide
Safari de iOS 96 94 96

6.0-6.1 * calc()Si realmente necesitabas un soporte muy antiguo (por ejemplo, IE 8 o Firefox 3.6), el truco habitual es agregar otra propiedad o valor antes del que usa

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

: calc() Hay bastantes problemas conocidos para

  • también, pero todos son para navegadores antiguos. ¿Puedo usar … enumera 13 de ellos? Aquí hay un puñado: calc() Firefox <59 no es compatible color: hsl(calc(60 * 2), 100%, 50%)en funciones de color. Ejemplo:
  • . box-shadow IE 9-11 no representará el calc() propiedad cuando
  • se utiliza para cualquiera de los valores. width: calc() No es compatible con IE 9-11 ni con Edge

en las celdas de la tabla.

Fiesta de caso de uso calc() Pregunté a algunos desarrolladores de CSS cuándo usaron por última vez

para que podamos probar aquí cómo lo usan otros en su trabajo diario. .full-bleed { width: 100vw; margin-left: calc(50% - 50vw); } Lo usé para crear una clase de utilidad completa: calc() yo diria

está en mi top 3 de CSS.

Lo usé para hacer espacio para un pie de página pegajoso. font-size Lo usé para establecer un tipo de tipo fluido / tipografía dinámica … una calculada font-sizebasado en mínimos, máximos y una tasa de cambio de las unidades de la ventana gráfica. No solo el line-height , pero

también. calc() Si estas usando rem como parte de una situación de tipo fluido que involucra unidades de ventana gráfica y demás, asegúrese de incluir una unidad que utilice em o

para que el usuario aún tenga cierto control sobre cómo subir o bajar esa fuente al acercar o alejar la imagen según sea necesario. .margin { width: calc( (100vw - var(--content-width)) / 2); }

Una que realmente me gusta es tener una propiedad personalizada de “ancho de contenido” y luego usarla para crear el espacio que necesito, como los márgenes:

.drop-cap { --drop-cap-lines: 3; font-size: calc(1em * var(--drop-cap-lines) * var(--body-line-height)); }

Lo usé para crear un componente de capitalización cruzada entre navegadores. Aquí hay una parte:

Lo usé para hacer que algunas imágenes desborden su contenedor en la página de un artículo. vwLo usé para colocar una visualización correctamente en la página combinándolo con relleno yvh /

unidades. background-positionLo uso para superar las limitaciones en 0.75em , pero especialmente limitaciones en la colocación de paradas de color en degradados. Como “detente

menos del fondo ”.

  • Otros engaños
  • Una cuadrícula de dos que se divide en una sola columna sin consulta de medios
  • Un componente héroe con una relación de aspecto
  • Aplicación de colores de alto contraste clip-path

Ayuda con las coordenadas de un porcentaje