AbacoUna característica muy interesante introducida en CSS3 es la posibilidad de asignar valores a propiedades CSS utilizando cálculos, de forma que en lugar de utilizar valores constantes coo siempre, se utilicen valores dinámicos que varíen en función de ciertas condiciones.

Para ello se ha diseñado la función calc de CSS3.

Es una función específica para trabajar con valores numéricos (generalmente dimensiones) y que nos permite realizar operaciones matemáticas muy sencillas. Los operadores que permite utilizar son solamente la suma (+), la resta (-), la multiplicación (*) y la división (/).

Su principal característica, y para lo que vamos a usarlo realmente la mayor parte de las veces, es que gracias a calc podemos mezclar unidades de medida, incluso relativas y absolutas, en los valores de las propiedades CSS.

Por ejemplo: ¿cómo centrarías un elemento dentro de otro de modo que el centro de ambos quede superpuesto? (es decir, un centrado perfecto).

Si tenemos estos dos elementos:

   1: <div id="contenedor">
   2:     <div id="caja"></div>
   3: </div>

con estos estilos asignados:

   1: <style type="text/css">
   2:     #contenedor {
   3:         position:relative;
   4:         width: 500px;
   5:         height:500px;
   6:         border: 1px solid black;
   7:     }
   8:     #caja {
   9:         width: 100px;
  10:         height: 100px;
  11:         background-color:red;
  12:     }
  13: </style>

¿cómo haríamos para centrar “caja” dentro de “contenedor”?

El primer impulso sería definir una clase llamada “centrada” y asignárselo a “caja”, de modo que le asignemos un posicionamiento absoluto a la caja de la siguiente manera:

   1: .centrada {
   2:     position:absolute;
   3:     left:50%;
   4:     top:50%;
   5: }

El problema es que esto centrará la equina superior izquierda de la caja en el contenedor, obteniendo el siguiente resultado:

calc_1_mal

Como vemos no está centrada como querríamos.

Existen maneras de conseguir el efecto deseado usando subterfugios, como por ejemplo poniendo la mitad del lado de la caja como margen negativo, pero, gracias a calc podemos conseguirlo de manera muy sencilla de la siguiente forma:

   1: .centrada {
   2:     position:absolute;
   3:     left:calc(50% - 50px);
   4:     top:calc(50% - 50px);
   5: }

Con calc le indicamos que lo queremos meter en la mitad, como antes, pero restándole la mitad del lado de la caja (mide 100px, así que le restamos 50px). Listo, ahora obtenemos el resultado deseado, que es este:

calc_2_bien

Existen muchas aplicaciones para esta funcionalidad, y seguro que le encuentras una rápidamente. Por ejemplo:

  • Para centrar fácilmente elementos, como acabamos de ver.
  • Para que los elementos se adapten en ancho y alto al contenedor restándole el tamaño de ciertos elementos (por ejemplo una cabecera)
  • Para hacer que todos los campos de un formulario se adapten al ancho de éste (sea cual sea) dejando al mismo tiempo cierto margen
  • Para posicionar imágenes de fondo con mayor precisión
  • Para conseguir elementos divididos fácilmente para repartirse el espacio y con una separación entre ellos, sin tener que andar calculando porcentajes o anchos fijos, ni cambiar el modelo de renderizado de caja.
  • Muchas aplicaciones más.

Por ejemplo, para conseguir lo que dice el último ejemplo (cajas divididas en un espacio sin cálculos complejos de porcentajes), considera que tenemos la siguiente estructura de elementos:

   1: <div id="contenedor">
   2:     <div id="col1"></div>
   3:     <div id="col2"></div>
   4:     <div id="col3"></div>
   5: </div>

Lo que queremos es que las tres cajas se repartan el espacio disponible en el contenedor (que puede ser relativo y cambiar con el tiempo) de modo que ocupen respectivamente el 25%, 25% y 50% del espacio disponible.

Esto es muy fácil de conseguir porque basta con asignar esos porcentajes al ancho de cada columna. La dificultad viene si además queremos que haya una cierta separación entre ellas y los bordes, de manera que queden de la siguiente manera:

calc_3_separacionColumnas

En este caso las he separado 1.5em de los bordes y entre sí. Lo que quiero es poder especificar esos porcentajes (25%, 25% y 50%) de manera sencilla y no tener que volverme loco cambiando los porcentajes a otros con decimales o andar haciendo números para calcularlos de manera absoluta. Es más, quiero que la caja contenedora tenga un ancho relativo y pueda variar automáticamente el conjunto si cambio las dimensiones de la ventana del navegador.

Con calc es muy sencillo de conseguir y este sería el CSS necesario:

   1: #contenedor {
   2:     width: 80%;
   3:     height:300px;
   4:     border: 1px solid black;
   5:     overflow:auto;
   6: }
   7: #col1 {
   8:     float:left;
   9:     width: calc(25% - 3em);
  10:     height: 100%;
  11:     margin-left: 1.5em;
  12:     margin-right: 1.5em;
  13:     background-color:red;
  14: }
  15: #col2 {
  16:     float:left;
  17:     width: calc(25% - 1.5em);
  18:     height: 100%;
  19:     margin-right: 1.5em;
  20:     background-color:blue;
  21: }
  22: #col3 {
  23:     float:left;
  24:     width: calc(50% - 1.5em);
  25:     height: 100%;
  26:     margin-right: 1.5em;
  27:     background-color:green;
  28: }

Fíjate en como calculo el ancho usando los porcentajes que quería utilizar y simplemente restándoles los espacios en blanco de más que tienen cada uno. Dado que hay cuatro separaciones de 1.5em (las dos entre los tres bloques más las dos de los laterales), tengo que restarle a uno de ellos de los extremos el doble de espacio para que entren bien. En este caso se la resto al primero, por eso tiene 3em en el cálculo.

Soporte de navegadores y algunas cosas a tener en cuenta

Esta característica es de CSS3 por lo que es relativamente moderna. Aún así hace ya algunos años que está soportada por la mayoría de los navegadores, por lo que si vamos a soportar navegadores que tengan solo unos pocos años podemos hacerlo con bastante confianza. Está soportada a partir de Internet Explorer 9, Chrome 29, Firefox 23 y Safari 6. También se soporta en las versiones móviles de los navegadores: en iOS desde la versión 6.0 y en Windows Phone desde la 8.0. En Android solamente en la nueva versión Kit Kat 4.4, así que cuidado con esto si es importante que funciones en móviles o tablets con el sistema operativo de Google.

Además hay que tener en cuenta un par de cosas adicionales:

  • Es obligatorio poner espacios a ambos lados de los operadores “+” y “-“. Si escribes por ejemplo esto: calc(100%-10px); se interpretará como una expresión no válida y se considerará un 0, por lo que puedes volverte loco para saber qué está pasando. La expresión correcta sería esta: calc(100% - 10px);(fíjate en los espacios). Esto es así para evitar problemas con valores negativos de unidades. No existe ese problema en el caso de la multiplicación y la división, pero por coherencia yo trataría de usar los espacios también ahí.
  • Si divides entre 0 se produce un error y el elemento ni siquiera se renderizará. Así que mucho ojo con despistarnos con esto.

Este post está basado en material extraído de mi curso online de HTML(5) y CSS(3) en campusMVP. Si quieres aprender de verdad este tema y tenerme como tutor para contestar tus dudas empieza hoy mismo.

He dejado los dos ejemplos anteriores en este archivo ZIP (1 KB) por si quieres probarlos sin tener que escribir.

¡Espero que te sea útil!

Escrito por un humano, no por una IA