Una guía completa para calc() en CSS
- calc()es para valores
- calc()es para longitudes y otras cosas numéricas
- No a las consultas de los medios
- ¿Unidades de mezcla?
- Comparación con las matemáticas del preprocesador
- mostrar las matemáticas
- Los operadores matemáticos decalc()
- Anidacióncalc(calc());
- Propiedades personalizadas de CSS y calc()?
- Herramientas del navegador
- Soporte del navegador
- Fiesta de casos de uso
- Otros engaños
CSS tiene una calc()
función especial para realizar operaciones 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 para valores
El único lugar donde puedes usar la calc()
función es en valores. Vea estos ejemplos en los que configuramos el valor para 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 forma parte de una propiedad! Por ejemplo, aquí se calc()
usa 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 necesitas 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 utilizar con calc()
:
- píxeles
- %
- ellos
- movimiento del ojo rapido
- es
- milímetros
- cm
- pt
- ordenador personal
- ex
- ch
- vh
- VW
- vmin
- vmáx
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 a las consultas de los medios
Cuando calc()
se usa correctamente (unidades de longitud utilizadas como valor para una propiedad), lamentablemente calc()
no funcionará cuando se aplica a consultas de medios.
@media (max-width: 40rem) { /* Narrower or exactly 40rem */}/* Nope! */@media (min-width: calc(40rem + 1px)) { /* Wider than 40rem */}
Algún día sería genial porque podrías realizar consultas de medios mutuamente excluyentes de una manera bastante lógica (como arriba).
¿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 aclararlo, aquí se mezclan diferentes unidades:
/* Percentage units being mixed with pixel units */width: calc(100% - 20px);
Es decir: Tan ancho como sea el elemento, menos 20 píxeles.
Literalmente, no hay forma de calcular previamente ese valor solo en píxeles en una situación de ancho fluido. En otras palabras, no puedes preprocesar calc()
con algo como Sass como un intento de completar un polirelleno. No es que sea necesario, ya que la compatibilidad con el navegador está bien. Pero el punto es que debe hacerse en el navegador (en “tiempo de ejecución”) cuando mezclas 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);
Probablemente podrían preprocesarse, ya que mezclan unidades que no son relativas a nada que se determine en el tiempo de ejecución.
Comparación con las matemáticas del preprocesador
Acabamos de cubrir que no se pueden preprocesar las cosas más útiles que calc()
se pueden hacer. Pero hay una pizca de superposición. Por ejemplo, Sass tiene matemáticas integradas, por lo que puedes 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 se pueden mezclar unidades similares y tiene limitaciones calc()
(por ejemplo, multiplicar y dividir deben realizarse con números sin unidades).
mostrar las matemáticas
Incluso si no estás utilizando una función que solo es posible con calc()
, puedes usarla para “mostrar tu 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 funcionar 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 decalc()
Tienes +
, -
, *
y /
. Pero difieren en cómo se requiere su uso.
La suma ( +
) y la resta ( -
) requieren que ambos números sean largos
.el { /* Valid */ margin: calc(10px + 10px); /* Invalid */ margin: calc(10px + 5);}
Los valores no válidos invalidan toda la declaración individual.
La 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);}
La multiplicación (*) requiere que uno de los números no tenga unidades.
.el { /* Valid */ margin: calc(10px * 3); /* Valid */ margin: calc(3 * 10px); /* Invalid */ margin: calc(30px * 3px);}
El espacio en blanco importa
Bueno, lo hace para la suma y la resta .
.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);}
Los números negativos están bien (p. ej. calc(5vw - -5px)
), pero ese es un ejemplo de dónde el espacio en blanco no sólo es necesario, sino que también es útil.
Tab Atkins me dice que el motivo del espacio requerido +
se -
debe en realidad a problemas de análisis. No puedo decir que lo entiendo completamente, pero, por ejemplo, 2px-3px
se analiza como el número “2” y la unidad “px-3px” que no le hace ningún bien a nadie, y +
tiene otros problemas como ser “consumido por la sintaxis numérica”. ”. Habría adivinado que el espacio en blanco tendría que ver con la --
sintaxis de las 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 espacio para la legibilidad y la memoria muscular de los demás operadores.
Los espacios en blanco alrededor del exterior no importan. Incluso puedes hacer saltos de línea si lo deseas:
.el { /* Valid */ width: calc( 100% / 3 );}
Pero tenga cuidado con esto: no hay espacios entre calc()
el par inicial y el par inicial.
.el { /* Invalid */ width: calc (100% / 3);}
Anidacióncalc(calc());
Puedes pero nunca es necesario. Es lo mismo que usar un par de paréntesis extra sin la calc()
pieza. Por ejemplo:
.el { width: calc( calc(100% / 3) - calc(1rem * 2) );}
No los necesitas adentro calc()
porque los padres trabajan solos:
.el { width: calc( (100% / 3) - (1rem * 2) );}
Y en este caso el “orden de las 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 { width: calc(100% / 3 - 1rem * 2);}
Pero siéntete libre de utilizar los pares si crees que aporta claridad. Si el orden de las operaciones no funciona a su favor (por ejemplo, primero necesita hacer la suma o la resta), necesitará paréntesis.
.el { /* This */ width: calc(100% + 2rem / 2); /* Is very different from this */ width: calc((100% + 2rem) / 2);}
Propiedades personalizadas de CSS y calc()?
Además de la asombrosa capacidad de calc()
mezclar unidades, lo siguiente más sorprendente calc()
es usarlo con propiedades personalizadas. Las propiedades personalizadas pueden tener valores que luego usará en un cálculo:
html { --spacing: 10px;}.module { padding: calc(var(--spacing) * 2);}
Estoy seguro de que puedes imaginar una configuración de CSS en la que se realizan muchas configuraciones en la parte superior estableciendo un montón de propiedades personalizadas de CSS y luego dejando que el resto del CSS las use según sea necesario.
Las propiedades personalizadas también pueden hacer referencia entre sí. A continuación se muestra un ejemplo en el que se utilizan algunas matemáticas (tenga en cuenta la falta de una calc()
función al principio) y luego se aplican. (En última instancia, tiene que estar dentro de un calc()
).
html { --spacing: 10px; --spacing-L: var(--spacing) * 2; --spacing-XL: var(--spacing) * 3;}.module[data-spacing="XL"] { padding: calc(var(--spacing-XL));}
Puede que no le guste, ya que necesita recordar calc()
dónde usa la propiedad en ese momento, pero es posible y potencialmente interesante desde una perspectiva de legibilidad.
Las propiedades personalizadas pueden provenir del HTML, lo cual a veces es algo bastante interesante y útil. (Vea cómo Splitting.js agrega índices a palabras/caracteres como ejemplo).
div ... /divdiv ... /divdiv ... /div
div { /* Index value comes from the HTML (with a fallback) */ animation-delay: calc(var(--index, 1) * 0.2s);}
Agregar unidades más tarde
En caso de que te encuentres en una situación en la que sea más fácil almacenar números sin unidades, o hacer matemáticas con números sin unidades con anticipación, siempre puedes esperar hasta aplicar el número para sumar la unidad multiplicando por 1 y la unidad.
html { --importantNumber: 2;}.el { /* Number stays 2, but it has a unit now */ padding: calc(var(--importantNumber) * 1rem);}
Jugando con los colores
Los formatos de color como RGB y HSL tienen números con los que puedes jugar calc()
. Por ejemplo, establecer algunos valores base de HSL y luego modificarlos formando un sistema de su propia creación (ejemplo):
html { --H: 100; --S: 100%; --L: 50%;}.el { background: hsl( calc(var(--H) + 20), calc(var(--S) - 10%), calc(var(--L) + 30%) )}
No puedes combinar calc() y attr()
La attr()
función en CSS parece atractiva, como si pudieras extraer valores de atributos de HTML y usarlos. Pero…
div data-color="red".../div
div { /* Nope */ color: attr(data-color);}
Desafortunadamente, aquí no hay "tipos" en juego, por lo que lo único attr()
que se necesita son cadenas en conjunto con la content
propiedad. Eso significa que esto funciona:
div::before { content: attr(data-color);}
Menciono esto porque puede resultar tentador intentar extraer un número de esa manera para utilizarlo en un cálculo, como:
div data-columns="7" data-gap="2".../div
.grid { display: grid; /* Neither of these work */ grid-template-columns: repeat(attr(data-columns), 1fr); grid-gap: calc(1rem * attr(data-gap));}
Afortunadamente, no importa mucho porque las propiedades personalizadas en HTML son igual de útiles o más.
div.../div
.grid { display: grid; /* Yep! */ grid-template-columns: repeat(var(--columns), 1fr); grid-gap: calc(var(--gap));}
Browser DevTools le tenderá a mostrarle el contenido calc()
tal como lo creó en la hoja de estilo.
Si necesita calcular el valor calculado, hay una pestaña Calculado (en todas las DevTools del navegador, al menos las que conozco) que se lo mostrará.
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 superiores.
Escritorio
Cromo | Firefox | ES DECIR | Borde | Safari |
---|---|---|---|---|
19* | 4* | 11 | 12 | 6* |
Móvil/Tableta
androidcromo | Android Firefox | Androide | Safari en iOS |
---|---|---|---|
125 | 126 | 125 | 6,0-6,1* |
Si realmente necesita soporte muy atrás (por ejemplo, IE 8 o Firefox 3.6), el truco habitual es agregar otra propiedad o valor antes del que usa calc()
:
.el { width: 92%; /* Fallback */ width: calc(100% - 2rem);}
También hay bastantes problemas conocidos calc()
, pero todos corresponden a navegadores antiguos. ¿Puedo usar… enumera 13 de ellos. Aquí hay algunos:
- Firefox 59 no admite
calc()
funciones de color. Ejemplo:color: hsl(calc(60 * 2), 100%, 50%)
. - IE 9-11 no representará la
box-shadow
propiedad cuandocalc()
se use para cualquiera de los valores. - Ni IE 9-11 ni Edge son compatibles
width: calc()
con las celdas de la tabla.
Fiesta de casos de uso
Le pregunté a algunos desarrolladores de CSS cuándo lo usaron por última vez calc()
para que pudiéramos tener una buena idea de cómo lo usan otros en su trabajo diario.
Lo usé para crear una clase de utilidad completa:
.full-bleed { width: 100vw; margin-left: calc(50% - 50vw); }
diría quecalc()
está entre mis 3 mejores cosas de CSS.
Lo usé para dejar espacio para un pie de página adhesivo.
Lo usé para establecer algún tipo de fluido/tipografía dinámica... un cálculo
font-size
basado en mínimos, máximos y una tasa de cambio de las unidades de la ventana gráfica. No sólo elfont-size
, sinoline-height
también.
Si lo está utilizando calc()
como parte de una situación de tipo fluido que involucra unidades de ventana gráfica y similares, asegúrese de incluir una unidad que use rem
o em
para que el usuario aún tenga cierto control sobre cómo aumentar o disminuir esa fuente al acercarla o alejarla como necesitan para.
Una que realmente me gusta es tener una propiedad personalizada de "ancho de contenido" y luego usarla para crear el espacio que necesito, como márgenes:
.margin { width: calc( (100vw - var(--content-width)) / 2); }
Lo usé para crear un componente de letra capitular para varios navegadores. He aquí una parte de ello:
.drop-cap { --drop-cap-lines: 3; font-size: calc(1em * var(--drop-cap-lines) * var(--body-line-height)); }
Lo usé para hacer que algunas imágenes desbordaran su contenedor en la página de un artículo.
Lo usé para colocar una visualización correctamente en la página combinándola con relleno y
vw
/vh
unidades.
Lo uso para superar limitaciones
background-position
, pero especialmente limitaciones en la colocación de paradas de color en degradados. Como “detenerse0.75em
antes de llegar al fondo”.
Otros engaños
- Una cuadrícula de dos páginas que se divide en una sola columna sin consulta de medios
- Un componente de héroe con una relación de aspecto similar
- Imponer colores de alto contraste
- Ayuda con las coordenadas de un porcentaje.
clip-path
Deja un comentario