Ir directamente al contenido de esta página

codexexempla.org

Herencia y cascada de CSS 2.1

Tabla de contenidos

  1. Introducción
  2. Herencia
  3. Cascada
    1. Importancia
    2. Especificidad
    3. Orden

Introducción

En la sección sobre selectores y pseudoselectores he indicado los diferentes métodos para aplicar propiedades de estilo a uno o varios elementos. No obstante, el aspecto final que presentará cada elemento no depende sólo de las declaraciones individuales que se han especificado para él, sino que intervienen dos mecanismos de CSS:

Además, hemos de tener en cuenta que son varios los orígenes de las hojas de estilo que se aplican a cualquier documento:

Vamos a ver en detalle todos estos conceptos.

Herencia

Como ya vimos en la parte del curso dedicada a los selectores avanzados, podemos representar un documento XHTML como un árbol genealógico:

Un ejemplo de árbol de documento

Pues bien, algunas propiedades de CSS se propagan por los descendientes de un elemento. Pensemos, por ejemplo, en la fuente de un documento. Si cada una de las propiedades que tienen que ver con las fuentes de un elemento no fuesen heredables, habría que especificarlas para todos y cada uno de los elementos que empleásemos, lo que supondría crear decenas de reglas con las mismas propiedades. Para un documento tan simple como el esquematizado en la imagen anterior, habría que definir:


    h1{font:1em/1.5 Verdana,Helvetica,sans-serif;}    
    p{font:1em/1.5 Verdana,Helvetica,sans-serif;}    
    blockquote{font:1em/1.5 Verdana,Helvetica,sans-serif;}
    cite{font:1em/1.5 Verdana,Helvetica,sans-serif;}
            

Y si pensamos que por lo general no vamos a crear documentos tan simples, ni aislados, para todo un sitio deberíamos definir la fuente para cada estado de vínculo, cada encabezado, cada strong, em, i… Decididamente, podría acabar con la paciencia de cualquiera.

Afortunadamente, gracias a la herencia, las regla anteriores —y las hipotéticas para todos y cada uno de los elementos posibles— se pueden resumir así:


    body{font:1em/1.5 Verdana,Helvetica,sans-serif;}    
            

Afortunadamente también, hay propiedades que no se heredan. Veamos esta página de ejemplo creada sobre el árbol anterior, y luego ésta, en la que se heredan todas las propiedades. Como se ve, estaríamos en la misma situación que antes: deberíamos restablecer los valores de cualquier propiedad en cualquier descendiente. Ese sería el único argumento de verdad válido para volver a las tablas y a font.

La moraleja es que hay que saberse de memoria qué propiedades se heredan y cuáles no, y aprovechar las primeras para simplificar nuestras hojas de estilo.

Cascada

La herencia es un mecanismo básico que hay que tener en mente al trabajar con CSS, pero el más importante es la cascada. La cascada responde a una pregunta crucial: ¿qué ocurre si dos reglas diferentes asignan la misma propiedad al mismo elemento? Supongamos el siguiente estilo:


    p{color:lime;}
    body p{color:purple;}        
            

Ambas reglas se aplican a los mismos elementos, en la medida en que no puede haber —al menos en un código válido— un párrafo fuera del cuerpo de un documento. ¿Cómo se dirimen sus diferencias? ¿El texto aparecerá en verde lima, o púrpura? Ahí es donde entra la cascada.

Si atendemos a lo que dice la especificación de CSS 2.1 al respecto (inglés), a cada regla aplicada a cualquier elemento se le asigna un «peso», y al final las reglas más pesadas son las que prevalecen.

Tal vez sería más preciso decir que el peso se asigna a cada declaración, puesto que en una regla como


    h1{color:#000;border-bottom:1px solid #CCC;}
                

se asignan pesos descomponiendo previamente la regla en tantas como declaraciones contenga. Además, las propiedades de conjunto también se analizan en sus componentes por separado, por lo que la regla anterior, desde el punto de vista de la cascada, es


    h1{color:#000;}
    h1{border-bottom-width:1px;}
    h1{border-bottom-style:solid;}
    h1{border-bottom-color:#CCC;}
                

Así, el peso se asigna de la siguiente manera:

  1. Se listan todas las reglas —descompuestas como he dicho antes— que se asignan a cada elemento.
  2. Se clasifican por importancia: cuanto más importantes, mayor es su peso.
  3. Dentro de los dos grupos resultantes —el de las que cuentan con importancia explícita y las que no—, se ordenan por especificidad: a mayor especificidad, mayor peso.
  4. Por último, a igualdadad de especificidad se comprueba el orden en la hoja de estilo: las reglas posteriores ganan más peso.

Y ya está. Ahora sólo hay que saber que saber qué es eso de la importancia, la especificidad y el orden.

Importancia

Es posible que una declaración sea lo bastante crítica en un estilo como para que no se quiera que deje de aplicarse independientemente de lo que pueda especificar otra hoja de estilo, o la herencia, o cualquier otra regla. Para ello existe !important, que explicita la importancia de esa declaración, y que se debe incluir antes del punto y coma final para que surta efecto.

Si volvemos a nuestro ejemplo de los párrafos y lo modificamos:


    p{color:lime !important;}
    body p{color:purple;}        
            

aunque en circunstancias normales el texto de los párrafos sería púrpura, el !important hará que se vean verde lima, un color que personalmente aborrezco.

Una pequeña nota sobre las hojas de estilo de usuario y agente. En general, las declaraciones de la hoja del autor anulan las del usuario y las del agente, pero el !important en la hoja del usuario anula el !important de un autor si entran en conflicto.

Especificidad

La regla de la importancia queda clara, pero ¿qué ocurre si dos declaraciones tienen la misma importancia, bien porque ambas cuenten con !important, bien porque ambas carezcan de él? Bueno, pues se mira cómo son de específicas.

La especificidad de una declaración se puede representar como cuatro valores separados por comas, que son:

  1. El numero de estilos en línea aplicados al elemento, a través del atributo style en el marcado.
  2. El número de selectores de la regla de estilo que son un id.
  3. El número de selectores que son un class, un selector de atributo o una pseudoclase.
  4. El número de selectores que son un elemento o un pseudoelemento.

Veamos unos ejemplos:


    p{ … }                                     /* 0,0,0,1 */
    body p{ … }                                /* 0,0,0,2 */
    .intro{ … }                                /* 0,0,1,0 */
    p.intro{ … }                               /* 0,0,1,1 */
    #contenido{ … }                            /* 0,1,0,0 */
    #contenido p{ … }                          /* 0,1,0,1 */
    div#contenido p{ … }                       /* 0,1,0,2 */
    div#contenido p.intro{ … }                 /* 0,1,1,2 */
    body div#contenido p.intro{ … }            /* 0,1,1,3 */
    body div#contenido p.intro:hover{ … }      /* 0,1,2,3 */
    body div#contenido p.intro:first-line{ … } /* 0,1,1,4 */
            

Cuando se tienen todos estos valores, cualquiera de ellos otorga más peso que los posteriores, es decir, que un solo id otorga más peso que cualquier número de clases, y una sola clase más peso que cualquier número de elementos. De la misma forma, si se tiene el mismo peso para uno de los valores, son los demás los que determinan el peso total.

Comparemos ahora pares de declaraciones para ver esto más claro.


    p{color:lime;}        /* 0,0,0,1 */
    body p{color:purple;} /* 0,0,0,2 */
            

Los párrafos serían púrpuras, porque su selector cuenta con más elementos.


    p.intro{color:lime;}  /* 0,0,1,1 */
    body p{color:purple;} /* 0,0,0,2 */
            

Un párrafo con class="intro" sería verde lima, porque una sola clase pesa más que dos elementos.


    p.intro{color:lime;}        /* 0,0,1,1 */
    body p.intro{color:purple;} /* 0,0,1,2 */
            

Ahora el mismo párrafo sería púrpura, porque hay el mismo número de clases pero la segunda regla tiene más elementos.


    #resumen{color:lime;}                    /* 0,1,0,0 */
    body div.destacado p.info{color:purple;} /* 0,0,2,3 */
            

Un párrafo con id="resumen" class="info" anidado en un div con class="destacado" sería lima, porque un solo id pesa más que cualquier cantidad de clases y elementos.


    #info li a[title]:hover{color:lime;}   /* 0,1,2,1 */
    #info a.v_externo:hover{color:purple;} /* 0,1,2,0 */
            

En caso de conflicto de estas dos reglas, el vínculo sería verde lima, puesto que a igualdad de identificadores y clases/selectores de atributo/pseudoclases, es el modesto li el que aporta más peso.

Alguien se preguntará: «¿y el primer número, que siempre es cero en los ejemplos?». Pues ese valor no depende de las declaraciones de la hoja de estilo aplicada al documento, sino del atributo style que aparezca en su marcado. Si tenemos en nuestro XHTML


    <h1 style="color:#FFF;background:#000;">Encabezado</h1>
            

el encabezado será blanco sobre fondo negro, por muchos identificadores, selectores, clases y elementos que empleemos en una regla, puesto que su especificidad será 1,…,…,…, y tendrá el mayor peso posible.

Por último, si alguien combina las taras de ser desarrollador web y fanático de La Guerra de las Galaxias, le alegrará saber que Andy Clarke creó un gráfico explicativo con personajes del Imperio para ilustrar la especificidad de CSS (inglés).

Con lo dicho hasta ahora es suficiente para comprender la especificidad, pero quiero señalar algunos detalles que suelen plantear dudas cuando se estudia por primera vez este aspecto de CSS:

  • Las propiedades heredadas no tienen valor alguno en relación con la especificidad.
  • El selector universal o comodín (*) tiene un valor de 0, por lo que por ejemplo div p y * div p tendrían la misma especificidad.
  • Los combinadores de selectores no afectan a la especificidad, por lo que ésta sería la misma tanto para div p como para div>p.

Orden

Bien, ya sabemos que la importancia y la especificidad afectan de una manera crítica al peso de una declaración, pero si nos encontramos estas reglas:


    body p.destacado{color:lime !important;}
    html body .destacado{color:purple !important;}        
            

¿de qué color será el párrafo destacado? Su importancia, como se ve, es la misma, y su especificidad, idéntica —0,0,1,2—. Pues será de color púrpura, porque a igualdad de importancia y especificidad, una regla que aparezca posteriormente en la hoja de estilo gana mayor peso.

El orden no tiene mayor misterio. Con respecto a él, sólo hay que apuntar que si por algún motivo a una página concreta se le añade en la cabecera el elemento style, es recomendable que se incluya después de cualquier link a una hoja externa, para asegurarse de que las reglas del documento se aplicarán en caso de que alguna de las incluídas en el archivo .css tenga la misma importancia y la misma especificidad:


    <head>
        <title>Título del codumento</title>
        <link rel="stylesheet" type="text/css"
                href="estilo_vinculado.css" />
        <style type="text/css">
          /* 
             Las reglas adicionales incluídas en 
             este bloque contarán con un peso mayor 
             que las de estilo_vinculado.css, lo
             que nos asegurará que se apliquen las 
             excepciones que queramos incluir
          */
        </style>
    </head>
            

Con esto termina esta sección dedicada a la herencia y la cascada.

Notas

  1. Éste es el motivo por el que algunos autores recomiendan crear una hoja de estilo de «reinicio» que elimine la del agente de usuario, y que así no altere el estilo del autor. Eric A. Meyer recomienda ésta (inglés), aunque yo personalmente me siento un poco reacio a sobrecargar mi CSS con tantas reglas. Me suelo conformar con eliminar las propiedades que me parecen más inconvenientes, a saber, márgenes, rellenos y bordes. Para ello simplemente comienzo cada hoja de estilo con esta regla: *{padding:0;margin:0;border:0;}. Volver

Contacto

En virtud de la Ley Orgánica 15/1999 de Protección de Datos de Carácter Personal le informo de que los datos que proporcione no serán empleados para otro fin que el de responder a su mensaje. En especial, me comprometo a no cederlos a terceros ni a emplearlos para enviar información no solicitada.

Del blog de Digital Icon