Programando en CSS¶
Hasta hace no mucho tiempo, CSS era considerado un lenguaje de diseño web, pero no un lenguaje de programación, en el sentido de que no admitía estructuras típicas de lenguajes de programación, como el uso de variables o estructuras condicionales como if. Esta limitación era realmente importante porque, a la hora de establecer distintas opciones de diseño según las condiciones que se determinaran, era necesario acudir a herramientas externas como Sass o LESS, que permitían generar un archivo CSS u otro en base a ciertos parámetros que se facilitaban.
Sin embargo, en los últimos años el propio lenguaje CSS se ha ido dotando de ciertas estructuras de programación que permiten flexibilizar mucho las opciones de diseño. Veremos en este documento algunas de estas opciones.
1. Uso de variables¶
Una de las principales novedades que ha incorporado CSS en este último tiempo son las custom properties, que permiten asignar valores a propiedades, para usarlos más adelante en el código CSS. De este modo, si queremos cambiar este valor, sólo debemos modificarlo en su asignación inicial, y automáticamente se propaga por todo el documento.
Las variables se declaran definiendo una propiedad que comience con un doble guión --
. Es habitual definirlas en un bloque CSS llamado :root
, pseudoclase que alude a la raíz del documento, aunque pueden definirse también en cualquier otra parte. Para referenciar luego a esa variable en cualquier parte del documento hacemos uso de la instrucción var
.
:root
{
--color-fondo-principal: red;
}
...
#contenedor
{
background-color: var(--color-fondo-principal);
}
Si declaramos una variable dentro de un contenedor específico, la variable sólo tendrá valor dentro de dicho contenedor (es decir, podemos utilizarla para aplicarla a cualquiera de sus hijos). Fuera de él no existirá, y si intentamos usarla tendremos un valor vacío. Para evitar este problema, podemos pasar un segundo valor a la instrucción var
que indique qué valor por defecto aplicar si no encuentra el original.
Por ejemplo, dado este documento:
<div class="padre">
<div class="hijo">Hijo 1</div>
<div class="hijo">Hijo 2</div>
</div>
<div class="hijo">Hijo 3</div>
Vamos a definir sobre él los siguientes estilos:
.padre
{
--color-fondo: black;
}
.hijo {
background: var(--color-fondo, blue);
}
Esto provoca que:
- Los hijos 1 y 2, que están dentro del contenedor padre, tendrán color de fondo negro
- El hijo 3, que queda fuera del contenedor padre, no encuentra esa variable
--color-fondo
, y se le asigna un color alternativo azul.
2. Reglas¶
Ya hemos visto en algún documento anterior el uso de las media-queries para definir comportamientos CSS dependiendo de ciertas condiciones de pantalla. El término @media
es una at-rule (regla de arroba), y corresponde a un conjunto de directivas especiales de CSS para indicar ciertos comportamientos. Veremos ahora algunas de las más habituales.
2.1. Soporte: @supports¶
La regla @supports
permite aplicar estilos si el sistema (navegador) soporta o no ciertas propiedades. Por ejemplo, estos estilos se aplicarían si el navegador no acepta Flexbox:
@supports not(display:flex) { ... }
Podemos enlazar condiciones con and
y or
. Por ejemplo, estos estilos se aplicarán si el navegador no soporta grid pero sí flex:
@supports not(display:grid) and (display:flex) { ... }
2.2. Capas: @layer¶
La regla @layer
define una capa de cascada, es decir, agrupa código CSS en una capa para luego unirlo con el resto. Con esta regla conseguimos alterar el orden en que se aplican los estilos en el CSS, ya que no sólo va a depender de cuándo los definimos en el documento, sino también del orden en que apliquemos las capas que creamos.
Esto es particularmente útil cuando tenemos estilos en varios ficheros CSS que interfieren unos con otros. El orden en que se aplican depende del orden en que se cargan los CSS:
/* estilos1.css */
h1 { color: red; }
/* estilos2.css */
h1 { color: blue; }
Si cargamos primero estilos1.css
y luego estilos2.css
, todos los encabezados de nivel 1 tendrán color azul, que fue el último que se cargó.
Para evitar perder el control sobre la cascada, podemos agrupar los estilos en capas. Los pasos son los siguientes:
- Primero declaramos el orden de las capas que vamos a aplicar. El orden en que definamos las capas aquí será el orden de prioridad de los estilos que se definan.
/* Los etilos de capa3 prevalecerán sobre el resto en caso de conflicto */
@layer capa1, capa2, capa3
- Después definimos los estilos o reglas que añadimos en cada capa:
@layer capa1
{
h1 { color: blue; }
}
@layer capa2
{
h1 { color: red; }
}
@layer capa3
{
h1 { color: green; }
}
...
2.3. Importaciones: @import¶
La regla @import
se coloca siempre al inicio de los documentos CSS, y permite importar reglas desde otras hojas de estilo, para así separar el diseño en varias páginas y cargar en cada una los componentes que se requieran.
En su sintaxis básica sólo debemos indicar la URL del documento CSS a importar. Por ejemplo:
@import "estilos2.css";
/* Alternativamente */
@import url("estilos2.css");
Sin embargo, podemos añadir algunos elementos adicionales para ajustar más algunos aspectos de la carga:
- Por ejemplo, podemos combinarlo con media queries para definir en qué casos cargar ese documento
/* Cargamos grid.css para ver web en pantallas con anchura mínima de 768 px */
@import url("grid.css") screen and (min-width: 768px);
/* Cargamos print.css en visualización para impresión */
@import "print.css" print;
- También podemos limitar la carga a los casos en que el navegador acepte alguna propiedad, usando la regla
supports
vista antes
/* Cargamos el CSS si el navegador soporta Flexbox */
@import url("estilos2.css") supports (display:flex);
- Podemos también combinarlo con la regla
layers
/* Cargamos el CSS en la capa1 */
@import url("estilos.css") layer(capa1);
3. Condiciones con if¶
Desde hace muy poco tiempo, se ha añadido a CSS la posibilidad de comprobar ciertas condiciones con una cláusula if
similar a la de los lenguajes de programación convencionales. Sin embargo, es una instrucción bastante nueva que puede que no tenga compatibilidad con el navegador que queramos utilizar. Puedes consultar aquí su documentación oficial y la compatibilidad actual con los navegadores.
Aquí vemos un ejemplo de uso, donde aplicamos un fondo con un color de degradado u otro dependiendo del valor de la variable --estilo
. Para ello usamos la también función experimental style
(con soporte limitado también, por ahora), que permite comprobar si el valor de una variable es el que estamos buscando.
:root
{
--estilo: hielo;
}
div
{
background-image: if(
style(--estilo: hielo): linear-gradient(#caf0f8, white, #caf0f8);
style(--estilo: fuego): linear-gradient(#ffc971, white, #ffc971);
else: none;
)
}
Lo que hace el ejemplo es poner un degradado lineal u otro en el div dependiendo del valor de la variable --estilo
. En caso de que no tenga ninguno de los dos valores que interesan (hielo o fuego) no se le da ninguna imagen de fondo.
4. Algunas funciones útiles¶
CSS también pone a nuestra disposición algunas funciones útiles que podemos emplear en nuestras hojas. La mayoría de ellas son matemáticas:
calc
: permite realizar un cálculo matemáticomin
ymax
: devuelven el mínimo o máximo de una expresión o secuencia de valoressin
,cos
,tan
: calculan el seno, coseno y tangente de un ángulo dadopow
: calcula una potenciasqrt
: calcula una raíz cuadradaabs
: calcula un valor absolutoattr
: devuelve el contendido de un attributo- ...
Aquí vemos algunos ejemplos de uso:
div.especial
{
width: calc(400px + 1em);
height: min(20px + 2em, 25%, 12vh);
}
div.especial2
{
width: round(161.17px, 0.1px); /* Devuelve 161.2px */
}
a:after
{
content: ' - URL: ' attr(href);
color: red;
}