Especificidad en CSS: Qué es y cómo funciona

¡Hola gente bonita!👋

En este articulo voy a explicar a detalle la especificidad, una parte clave de la cascada. La especificidad es una de las cuatro etapas distintas de la cascada, que se trató en mi articulo anterior.

Para entender por qué tus estilos CSS no se están aplicando a un elemento, primero debes tener una comprensión básica de la Especificidad en CSS.

Es muy fácil poner el valor !important a tus estilos CSS, pero esto hace que tu CSS se descontrole rápidamente.

Entendiendo cómo se aplican los estilos, puedes asegurarte de que los estilos que quieres que se apliquen se muestren.

Es más fácil cambiar rápidamente un estilo cuando se sabe exactamente qué selector da estilo a ese elemento específico. Además, probablemente te encontrarás escribiendo menos código CSS en general, lo que ayudará a su mantenimiento.

¿Qué es la especificidad?

La especificidad en CSS es un grupo de reglas aplicadas a los selectores CSS para determinar qué estilo se aplica a un elemento. Cuanto más específico sea un selector, mayor será su valor en puntos y más probable será que esté presente en el estilo del elemento.

La documentación oficial de la MDN describe la especificidad de la siguiente manera:

La especificidad es la manera mediante la cual los navegadores deciden qué valores de una propiedad CSS son más relevantes para un elemento y, por lo tanto, serán aplicados

Esto significa que la especificidad de CSS es un conjunto de reglas usadas por los navegadores para determinar cuál de los estilos definidos por el desarrollador se aplicará a un elemento específico. Para que un estilo se aplique a un elemento en particular, el desarrollador tiene que cumplir con las reglas, de modo que el navegador sepa cómo aplicar el estilo.

El navegador evalúa la especificidad en dos partes:

  1. Los estilos aplicados en línea en el HTML (Inline Styles).
  2. Los estilos aplicados mediante un selector (Especificidad del selector).

Jerarquía de la especificidad

Piense en la especificidad como un score/rank que determina qué declaraciones de estilo se aplican finalmente a un elemento.

La especificidad utiliza un sistema de ponderación o puntuación.

Cada tipo de selector recibe puntos que indican su especificidad, y se suman los puntos de todos los selectores que hayas utilizado. para calcular la especificidad total del selector.

Cada selector tiene su lugar en la jerarquía de especificidad. Hay cuatro categorías que definen el nivel de especificidad de un selector.

Puntuación de cada tipo de selector

Antes de comenzar, debes conocer primero cuales son los tipos de selectores en CSS, estos se dividen en varias categorías. Un ejemplo son las pseudoclases que vas a poder encontrar muchas de ellas, sin embargo, te recomiendo que solo aprendas las mas importantes.

La cantidad de especificidad de un selector se mide usando cuatro valores diferentes separados por coma que tienen diferente peso y pueden describirse como millares, centenas, decenas y unidades (cuatro dígitos individuales dispuestos en cuatro columnas):

*Selector Universal

El selector con menor peso ( y menos valor ) es el selector universal, que en CSS se define de la siguiente forma:

* {
  box-sizing: border-box;
}

Este selector comúnmente se utiliza para aplicar la propiedad box-sizing: border-box a todos los elementos. Si quieres saber más sobre esta propiedad, te invito a leer mi articulo completo⤵️

Este selector en CSS tiene un valor de 0-0-0-0, eso quiere decir que cualquier otro selector cuyo valor sea 1-0-0-0, 0-1-0-0 o incluso 0-0-0-1 tendrá mayor peso que el y lo reescribirá. Esto lo podemos comprobar con el siguiente ejemplo:

<p>Lupita Code</p>
* {
  font-size: 1rem;
}

p {
font-size: 3rem;
}

¿Qué tamaño de fuente se va aplicar al elemento <p>?

El selector universal * tiene un peso de 0-0-0-0 mientras que el selector con un elemento HTML ( en este caso un <p> ) tiene un peso de 0-0-0-1, al ser un valor mayor que el anterior, su peso es mayor y CSS entiende que su especificidad también es mayor y gana sobre el anterior selector a pesar de estar declarado en primer lugar en la hoja de estilos.

</> Elementos y ::pseudoelementos

Los selectores de tipo o de etiqueta: <p>, <div>,<main> etc.
Tiene un valor de 0-0-0-1

<header>
  <h1><span>Welcome</span> to my youtube channel</h1>
</header>
header h1 span {
    text-transform: lowercase;
}
span {
  text-transform:uppercase;
}

El elemento <span> solamente tiene un peso de 0-0-0-1 pero también tenemos en la primera regla 3 etiquetas HTML que tienen un peso total de 0-0-0-3, ¿Por que 3? 🤔 la respuesta es que el 3 es la cantidad de elementos HTML declarados, por lo que todo el texto estará en minúsculas a pesar de que el <span> tenga mayúscula.

Por lo tanto si agregas 5 Selectores de elementos anidados, el peso será de 0-0-0-5.
Recuerda que mayor peso en la especificidad será el ganador 🏆.

Lo mismo pasa con los pseudo-elementos tienen un valor de 0-0-0-1. Los pseudo-elementos más usados son ::after y ::before.

.clases, atributos[...] y :pseudoclases

El selector de clase tiene mayor peso (o especificidad) que los selectores de tipo o elementos HTML y que el selector universal, seguiremos con el ejemplo anterior pero ahora con una clase llamada title en la etiqueta <span>:

<header>
  <h1><span class="title">Welcome</span> to my youtube channel</h1>
</header>
header h1 span {
    text-transform: lowercase;
}
.title {
  text-transform:uppercase;
}

Ahora el texto del elemento <span> si estará en mayúscula y todo lo demás estará en minúscula, esto sucede porque las clases tienen un peso de 0-0-1-0 mientras que el selector de 3 elementos será de 0-0-0-3.

Existen otros selectores que tienen el mismo peso de 0-0-1-0 que son los selectores de atributo y las pseudo-clases. Existen muchas pseudo-clases un ejemplo son las pseudo-clases child, si no la conoces te comparto un cheatsheet que publique en mi Twitter:

Selector de id

Este es de los selectores más específicos en este caso el ID tendrá un peso de 0-1-0-0.

Esto significa que un selector de ID tiene una mayor especificidad que un selector de clase. De hecho, un único ID tiene una mayor
especificidad que un selector con cualquier número de clases. Del mismo modo, un selector de clases tiene una mayor especificidad
que un selector de etiquetas (también llamado selector de tipos).

<header id="header" class="header"> Lupita Code </header>
#header {
  background-color: rebeccapurple;

.header {
   background-color: khaki;
}

El valor que se va aplicar al elemento <header> es el color rebeccapurple ya que el id tiene un valor de 0-1-0-0, mientras que la clase tiene un valor de 0-0-1-0.

Estilos en línea

Los estilos inline añadidos a un elemento HTML siempre sobrescriben a cualquier estilo escrito en hojas de estilo externas o una etiqueta <style>, por lo que se puede decir que tienen la mayor especificidad. Los estilos en línea no tienen selector porque se aplican directamente al elemento al que se dirigen.

<li>
  <a href="/specials" class="featured" 
style="background-color: orange;"> 
     Specials
 </a>
</li>

Los estilos en línea tienen un valor de 1-0-0-0.

Para anular los estilos inline, tendrás que añadir un !important a la declaración de la hoja de estilos externa. Si los estilos en línea están marcados como !important, entonces nada puede anularlos.

Es preferible que todos tus estilos estén en una hoja de estilos externa. Utilizar !important es solo para casos desesperados y NO se recomienda usarlo ya que si comienzas a agregar !important en varios lugares de tus hojas de estilos te será más complicado debuggear o reescribir algún elemento. Aunque existen ciertos casos especiales en los que si puedes usarlo pero si eres principiante recomiendo NO utilizar !important a menos que sepas lo que estas haciendo.

🙄 ¿Qué tiene que ver !important con la especificidad?

En la tabla anterior que te presente al inicio de este articulo, mencione que !important gana a todos, es decir le gana a la especificidad.

Cuando se emplea !important en una declaración de estilo, esta declaración reescribirá cualquier estilo antes aplicado, esta palabra clave para el navegador es de prioridad muy alta. Aunque técnicamente !important no tiene nada que ver con especificidad, interactúa directamente con esta.

Es posible que te encuentres con situaciones al utilizar frameworks CSS, como Bootstrap, en las que no puedes utilizar la especificidad CSS para anular los estilos nativos. En estos casos, el uso de !important no se considera una mala práctica.

Excepciones

  • El selector universal (*), los combinadores (+, >, ~, etc ) y la pseudo-clase de negación :not() no tienen efecto sobre la especificidad. (Sin embargo, los selectores declarados dentro de :not() si lo tienen). Por ejemplo:
div.outer p {
  color:orange;
}
div:not(.outer) p {
  color: lime;
}
<div class="outer">
  <p>Esto está en el outer div.</p>
  <div class="inner">
    <p>Este texto está en el inner div.</p>
  </div>
</div>

Como puedes observar la pseudo-clase de negación :not() no es considerada una pseudo-clase para el cálculo de la especificidad. Pero los selectores colocados dentro de ella en este ejemplo la clase .outer, si cuentan en la especificidad.

Diferentes tipos de selectores, diferente especificidad

Cuando usamos diferentes tipos de selectores combinados (por ejemplo,body #content .data img:hover{}) el navegador contará el número de ids, pseudo-clases y pseudo-elementos y asignará un valor de especificidad a la regla, para compararla con las demás y decidir cuál usar. Por ejemplo:

VSCODE al rescate

Te preguntaras si tienes que hacer estos cálculos siempre para saber que tan específicos son tus selectores, por fortuna no tienes que hacer estos cálculos manualmente, gracias al editor de código vscode podemos saber la especificidad de los selectores.

Lo único que tienes que hacer es posicionar el cursor sobre tus selectores en la hoja de estilos y vscode automaticamente te da la especificidad:

Metodología BEM (Block Element Modifier)

El CSS puede convertirse rápidamente en algo desordenado cuando no nos detenemos a pensar en una arquitectura para nuestras hojas de estilo, y en su lugar colocamos una gran cantidad de selectores sin pensar en la especificidad.

Una forma de combatir el CSS desordenado, y asegurar que tus reglas de especificidad se aplican como es debido, es adoptar una metodología. BEM es una de las metodologías de CSS más utilizadas. No vamos a profundizar ahora en las metodologías o arquitecturas, pero pueden ayudarte a garantizar que tus estilos no se anulen entre sí.

Hay un montón de arquitecturas y metodologías que ayudan a lidiar con la especificidad para escribir un CSS escalable y mantenible.
Realmente no importa qué arquitectura o metodología elija tu equipo, lo importante es tener una que todos sigan para evitar problemas.

Al aprovechar al máximo la especificidad de CSS, te aseguras de que tu código esté organizado y de que tus selectores no entren en conflicto unos con otros.

Si quieres aprender sobre la metodología BEM en mi cuenta de Twitter compartí un repositorio donde podrás encontrar una colección de recursos sobre esta metodología:

Conclusión

Los navegadores utilizan la especificidad para decidir que reglas CSS aplicar a los elementos.

🔎 Recursos:

📚 Libros de CSS consultados para este tema:

  1. CSS in Depth
  2. CSS The Missing Manual
  3. CSS The Definitive Guide

Gracias por leer🦸🏻‍♀️
Mis redes sociales donde comparto notas de código:

45