Ir directamente al contenido de esta página

La función calc() en CSS3

Tanto la nueva versión de Firefox como la de Explorer cuentan con un interesante soporte de CSS3. La lista de propiedades a nuestra disposición es muy amplia, pero en esta entrada de lo que voy a hablar es de calc(), una función que permite definir valores de longitud por medio de expresiones aritméticas.

Lo que dice la especificación

La última definición de la función calc() se recoge en CSS3 Values and Units: 3.7.4. The calc function, un boceto del W3C del 19 de septiembre de 2006. Básicamente lo que permite es sustituir el valor fijo de cualquier dimensión que podamos aplicar a una propiedad por la expresión de un cálculo de dimensiones, por ejemplo, una suma. De la misma forma que ahora escribimos width:25em, la función permite asignar valores como width:calc(25em + 12em).

A algunos les recordará a las propiedades dinámicas de Explorer, pero la principal diferencia es que la función calc() no permite extraer valores computados de ningún elemento, sólo trabajar con valores específicos.

A la hora de emplear calc(), conviene tener en cuenta algunos puntos:

¿Y para qué nos vale?

Antes he escrito que podemos definir valores como width:calc(25em + 12em), lo que podría parecer un poco absurdo frente a, simplemente, width:37em. Ciertamente en este caso lo sería porque las unidades coinciden, pero si estamos asignando un ancho ¿cuánto es, por ejemplo, 37 ems más 5 píxeles?, ¿y 75 por ciento menos 10 píxeles? Ahí es donde calc() nos puede ayudar. Y, como siempre, vamos a verlo con un ejemplo práctico.

Supongamos que quiero crear un formulario con un diseño fluido, y quiero que algunos campos del mismo ocupen todo el ancho disponible. Asigno, por tanto, un width de 100% a los input y al textarea. Sobre el relleno inicial que he aplicado al formulario, los bordes de estos campos deben quedar a 20 píxeles de distancia por cada lado. Sin embargo, cuando aplico a esos mismos campos un relleno de 2 píxeles y un borde de 1, el total de 6 píxeles se añade al ancho total que ya ocupaban, con lo que la distancia al borde derecho del formulario deja de ser la misma que por el lado izquierdo. Para corregir, por el método tradicional lo que hago es ajustar entonces el ancho total a 99.2%.

Además, hay dos campos que quiero que ocupen la mitad del espacio, y que aparezcan paralelos, así que los floto, y de nuevo tengo que ajustar el ancho por aproximación, esta vez a 47.5%. El resultado es más o menos éste:

El formulario, a una resolución de 1280×1024; los campos están alineados a derecha e izquierda

A simple vista, pienso para mis adentros «misión cumplida». Sin embargo, como he comentado, se trata de un diseño fluido, por lo que el valor computado de los anchos cambia según el tamaño de la ventana. Al variar éste —además de cierta inconsistencia de alineación— llega un momento en que los campos flotados ocupan más píxeles de los disponibles, y el del correo electrónico «se me cae» debajo del de nombre:

Lo que le ocurre al mismo formulario a 1024×768

¿Cómo es eso? Pues porque como el ancho que he asignado es un porcentaje, el cálculo de la dimensión correspondiente en píxeles puede resultar en una cantidad con decimales; como no puede haber fracciones de píxeles en un tamaño computado, los navegadores redondean. Si la suma del ancho —redondeado— de los input, más sus rellenos y bordes, más un pequeño margen que he incluido para separarlos es igual o menor que el ancho computado del formulario, se mantienen uno junto al otro. Pero si con el redondeo esta suma supera ese espacio, el segundo flotado debe situarse debajo del primero puesto que, según la especificación, los elementos flotados no puede superponerse.

Y aquí es donde entra calc().

Para el segundo formulario de ejemplo, defino las siguientes reglas:


/* Ancho de los elementos que contienen los campos de nombre y correo */ 

#f02 .n,#f02 .c{
  width:-moz-calc(50% - 10px);
  width:calc(50% - 10px);
}

/* Ancho de los los campos del formulario */

#n02,#c02,#a02,#m02{
  width:-moz-calc(100% - 6px);
  width:calc(100% - 6px);
}
 

Lo que estoy diciendo al navegador que sobre la mitad del ancho computado del formulario reste 10 píxeles —un margen que dejo entre ambos—, y que tal cantidad es la longitud de los elementos que he flotado; como el cálculo se hace sobre el valor de píxeles ya redondeado, la suma total nunca puede ser superior al espacio efectivo disponible, y por eso el segundo elemento nunca se posicionará debajo del primero.

En el caso de los anchos de los campos, lo que estoy asignando es la cantidad resultante de restar 6 píxeles —la suma del padding derecho e izquierdo más el ancho del borde a cada lado— al espacio total que pueda ocupar el campo, que es 100%.

Un detalle: aunque no está indicado de forma explícita en la especificación, he comprobado que si elimino los espacios alrededor de los signos aritméticos, los navegadores no interpretan el valor:


/* Así funciona */

width:-moz-calc(50% - 10px);
width:calc(50% - 10px);

/* Así no */

width:-moz-calc(50%-10px);
width:calc(50%-10px);
 

Como ya he apuntado, calc() de momento sólo tiene soporte en Firefox 4 y Explorer 9, pero dada su utilidad estoy deseando que se haga más extenso.

Bonus: otra solución para el problema de nuestro formulario

Como siempre me gusta dar otra solución posible a un problema planteado, como extra incluyo aquí un remedio alternativo al problema del formulario.

Es de sobra conocido que muchos de los problemas de incompatibilidad de diseño que provocaba Explorer 6 se basaban en que su modelo de caja era sustractivo, mientras que el modelo del W3C era aditivo. Supongamos que, como en el caso que he indicado arriba, a un elemento le asigno un ancho, un relleno y un borde. Tenemos que:

Microsoft corrigió este modelo en las versiones posteriores de su navegador, pero muchos diseñadores y desarrolladores han coincidido en que esta aproximación puede ser más intuitiva y, sobre todo, útil. En mi ejemplo anterior, en realidad, lo que he hecho por medio de calc() ha sido reproducir ese comportamiento.

Así, en una decisión salomónica, el W3C ha decidido incluir en CSS3 una propiedad que permita elegir el modelo de caja que se prefiera. Esta propiedad es box-sizing, y sus valores son:

Asignando el segundo valor a los elementos flotados y a los campos del formulario, puedo estar seguro de que sus tamaños serán consistentes independientemente del ancho de la ventana.

De momento, esta propiedad hay que aplicarla de la siguiente manera:


-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
box-sizing:border-box;
 

Y en cuanto a su soporte, en el tercer formulario de ejemplo indico las versiones de navegadores más antiguas que he podido comprobar, aunque si alguien puede aportar más datos, agradezco cualquier comentario.

Esta entrada se publicó el 11 de abril de 2011, se archivó en CSS, y fue etiquetada como . Autor: Saúl González Fernández. Hay 1 comentario ›.

Comentarios

  1. Tadira dice:

    Genial :)

¿Algún comentario?

* Los campos con un asterisco son necesarios

Últimos proyectos

© Digital Icon, S.L., 2007 – 2012