El podcast del CSS: 003: Especificidad
Supongamos que estás trabajando con el siguiente código HTML y CSS:
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
Aquí hay dos reglas que segmentan el mismo elemento. Cada regla contiene una declaración que intenta establecer el color del botón: una intenta colorear el botón de rojo y la otra de azul. ¿Qué declaración se aplica al elemento?
Comprender el algoritmo de especificidad de CSS es clave para entender cómo CSS decide entre declaraciones en conflicto.
La especificidad es una de las etapas distintas de la cascada, que se abordó en el último módulo, sobre la cascada.
Puntuación de especificidad
Cada regla de selector dentro de un origen obtiene una puntuación. Puedes pensar en la especificidad como una puntuación total, y cada tipo de selector obtiene puntos para esa puntuación. Las declaraciones de reglas con la especificidad más alta ganan.
Con la especificidad en un proyecto real, el acto de equilibrio es asegurarse de que las reglas de CSS que esperas que se apliquen, se apliquen realmente, mientras que, en general, se mantienen las puntuaciones bajas para evitar la complejidad. La especificidad solo debe ser tan alta como la necesitemos, en lugar de intentar obtener la especificidad más alta posible. En el futuro, es posible que se deba aplicar un CSS más importante. Si buscas la especificidad más alta, harás que ese trabajo sea difícil.
La especificidad no es un número decimal, sino una tríada que consta de tres componentes: A, B y C.
A: Especificidad similar a un IDB: Especificidad similar a una claseC: Especificidad similar a un elemento
A menudo, se representa con la notación (A,B,C). Por ejemplo: (1,0,2).
También se usa comúnmente la notación alternativa A-B-C.
Cómo comparar especificidades
Las especificidades se comparan comparando los tres componentes en orden: la especificidad con un valor A más grande es más específica; si los dos valores A están empatados, la especificidad con un valor B más grande es más específica; si los dos valores B también están empatados, la especificidad con un valor C más grande es más específica; si todos los valores están empatados, las dos especificidades son iguales.
Por ejemplo, (1,0,0) se considera una especificidad más alta que (0,4,3)
porque el valor A en (1,0,0) (que es 1)
es mayor que el valor A de (0,4,3) (que es 0).
Los selectores influyen en la especificidad
Cada parte de la tríada de especificidad comienza con un valor de 0,
por lo que la especificidad predeterminada es (0,0,0).
Cada parte de un selector aumenta la especificidad que, según el tipo de selector, incrementa el valor de A, B o C.
Selector universal
Un selector universal (*)
**no agrega especificidad**, lo que deja su valor en la especificidad inicial de (0,0,0).
* {
color: red;
}
Selector de elementos o pseudo-elementos
Un selector de elementos (tipo)
o pseudo-elementos
agrega especificidad similar a un elemento , que incrementa el componente C en 1.
Los siguientes ejemplos tienen una especificidad general de (0,0,1).
Selector de tipo
div {
color: red;
}
Selector de pseudo-elementos
::selection {
color: red;
}
Selector de clase, pseudo-clase o atributo
Un selector de clase,
pseudo-clase o
atributo agrega especificidad similar a una clase
que incrementa el componente B en 1.
Los siguientes ejemplos tienen una especificidad de (0,1,0).
Selector de clase
.my-class {
color: red;
}
Selector de pseudo-clase
:hover {
color: red;
}
Selector de atributos
[href='#'] {
color: red;
}
Selector de ID
Un selector de ID
agrega especificidad similar a un ID que incrementa el componente A en 1,
siempre que uses un selector de ID (#myID) y no un selector de atributos ([id="myID"]).
En el siguiente ejemplo, la especificidad es (1,0,0).
#myID {
color: red;
}
Otros selectores
CSS tiene muchos selectores. No todos agregan especificidad.
Por ejemplo, la :not() pseudo-clase
en sí no agrega nada al cálculo de especificidad.
La especificidad de la pseudo-clase :not() se reemplaza por la especificidad del selector más específico en su argumento de selectores separados por comas, lo que proporciona la misma especificidad que si se hubiera escrito :not(:is(argument)).
div:not(.my-class) {
color: red;
}
La pseudo-clase :is()
tampoco se agrega al cálculo de especificidad. Al igual que :not(), toma la especificidad de su argumento más específico.
:is(h1, h2, h3) {
color: blue;
}
Esta muestra tiene una especificidad de (0,0,1) porque solo tiene un tipo de selector (type).
Con la adición de un id, la especificidad aumenta a (1,0,0).
:is(h1, h2, h3, #my-heading) {
color: blue;
}
La :where() pseudo-clase
es diferente. Sin importar la especificidad de cualquiera de sus argumentos, siempre tiene una especificidad de (0,0,0).
:where(h1, h2, h3, #my-heading) {
color: blue;
}
Los estilos de baja especificidad aplicados con :where() te permiten anular estos estilos con selectores básicos más adelante en tu hoja de estilo:
:where(#my-content) {
color: red;
}
p {
color: blue;
}
Aunque :where() tiene un id en su lista de argumentos, solo tiene una especificidad de (0, 0, 0), por lo que el selector p básico lo anula y el texto será blue.
Verifica tus conocimientos
Pon a prueba tus conocimientos sobre la puntuación de especificidad
¿Cuál es la especificidad de a[href=/learn/css/%22#%22%5D%3C%2Fcode>?
(0,0,1)a vale (0,0,1), pero el [href=/learn/css/%22#%22%5D%3C%2Fcode> vale (0,1,0).(0,1,0)a vale (0,0,1), pero el [href=/learn/css/%22#%22%5D%3C%2Fcode> vale (0,1,0).(0,1,1)a vale (0,0,1) y el [href=/learn/css/%22#%22%5D%3C%2Fcode> vale (0,1,0), lo que da una especificidad total de (0,1,1).Factores que no afectan la especificidad
Existen algunas ideas equivocadas comunes sobre los siguientes factores que afectan la especificidad.
Atributos de estilo intercalado
El CSS aplicado directamente al atributo style de un elemento,
no afecta la especificidad, ya que es un paso diferente en la cascada
que se evalúa antes de la especificidad.
<div style="color: red"></div>
Para anular esta declaración desde una hoja de estilo, debes recurrir a obtener la declaración en un paso anterior de la cascada.
Por ejemplo, puedes agregar !important para que forme parte de el origen !important creado.
Declaraciones !important
Un !important al final de una declaración de CSS no afecta la especificidad
pero coloca la declaración en un origen diferente,
es decir, creado !important.
En el siguiente ejemplo, la especificidad de .my-class no es relevante para que gane la declaración !important.
.my-class {
color: red !important;
color: white;
}
Cuando dos declaraciones son !important, la especificidad vuelve a entrar en juego, ya que el paso de origen de la cascada aún no pudo determinar el ganador.
.branding {
color: blue !important;
}
button {
color: red !important;
}
Especificidad en contexto
Cuando se usa un selector complejo o compuesto, cada parte de ese selector se suma a la especificidad. Considera este ejemplo de HTML:
<a class="my-class another-class" href="#">A link</a>
Este vínculo tiene dos clases.
La regla del siguiente CSS tiene una especificidad de (0,0,1):
a {
color: red;
}
Si haces referencia a una de las clases en el selector,
ahora tiene una especificidad de (0,1,1):
a.my-class {
color: green;
}
Agrega la otra clase al selector,
ahora tiene una especificidad de (0,2,1):
a.my-class.another-class {
color: rebeccapurple;
}
Agrega el href atributo al selector,
ahora tiene una especificidad de (0,3,1):
a.my-class.another-class[href] {
color: goldenrod;
}
Por último,agrega una :hover pseudo-clase a todo eso,
el selector termina con una especificidad de (0,4,1):
a.my-class.another-class[href]:hover {
color: lightgrey;
}
Verifica tus conocimientos
Pon a prueba tus conocimientos sobre la puntuación de especificidad
¿Cuál de los siguientes selectores tiene una especificidad de (0,2,1)?
article > section(0,0,2).article.card.dark(0,2,1).article:hover a[href](0,0,1)), un selector de atributos (que vale (0,1,0)) y un selector de clase (que vale (0,1,0)). Esto hace que este selector tenga una especificidad total de (0,2,2).Aumentar la especificidad de forma pragmática
Supongamos que tienes un CSS como el siguiente:
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Con un HTML como este:
<button class="my-button" onclick="alert('hello')">Click me</button>
El botón tiene un fondo gris,
porque el segundo selector tiene una especificidad de (0,1,1).
Esto se debe a que tiene un selector de tipo (button), que es (0,0,1) y un selector de atributos ([onclick]), que es (0,1,0).
La regla anterior, .my-button, es igual a (0,1,0) porque tiene un selector de clase, que es una especificidad más baja que (0,1,1).
Si deseas impulsar esta regla, puedes repetir el selector de clase de la siguiente manera:
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Ahora, el botón tendrá un fondo azul, porque el nuevo selector obtiene una especificidad (0,2,0).
Un empate en la especificidad vuelve al siguiente paso de la cascada
Continuando con el ejemplo del botón por ahora, cambia el CSS a lo siguiente:
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
El botón tiene un fondo gris, porque ambos selectores tienen una especificidad idéntica de (0,1,0).
Si cambias las reglas en el orden de origen, el botón se volverá azul.
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
Esto se debe a que ambos selectores tienen la misma especificidad. En este caso, la cascada vuelve al paso del orden de aparición.