CSS Cálculo de la especificidad del selector


Ejemplo

Cada selector de CSS individual tiene su propio valor de especificidad. Cada selector en una secuencia aumenta la especificidad general de la secuencia. Los selectores se clasifican en uno de tres grupos de especificidad diferentes: A , B y c . Cuando múltiples secuencias de selección seleccionan un elemento dado, el navegador utiliza los estilos aplicados por la secuencia con la mayor especificidad general.

Grupo Compuesto de Ejemplos
UNA selectores de identificación #foo
segundo selectores de clase
selectores de atributos
pseudo-clases
.bar
[title] , [colspan="2"]
:hover :nth-child(2)
do selectores de tipo
pseudo-elementos
div , li
::before , ::first-letter

El grupo A es el más específico, seguido del grupo B y , finalmente, el grupo c .

El selector universal ( * ) y los combinadores (como > y ~ ) no tienen especificidad.

Ejemplo 1: Especificidad de varias secuencias de selección

#foo #baz {}      /* a=2, b=0, c=0 */

#foo.bar {}       /* a=1, b=1, c=0 */

#foo {}           /* a=1, b=0, c=0 */

.bar:hover {}     /* a=0, b=2, c=0 */

div.bar {}        /* a=0, b=1, c=1 */

:hover {}         /* a=0, b=1, c=0 */

[title] {}        /* a=0, b=1, c=0 */

.bar {}           /* a=0, b=1, c=0 */

div ul + li {}    /* a=0, b=0, c=3 */

p::after {}       /* a=0, b=0, c=2 */

*::before {}      /* a=0, b=0, c=1 */

::before {}       /* a=0, b=0, c=1 */

div {}            /* a=0, b=0, c=1 */

* {}              /* a=0, b=0, c=0 */

Ejemplo 2: Cómo se usa la especificidad por el navegador

Imagina la siguiente implementación de CSS:

#foo {
  color: blue;
}

.bar {
  color: red;
  background: black;
}

Aquí tenemos un selector de ID que declara el color como azul , y un selector de clase que declara el color como rojo y el background como negro .

Un elemento con un ID de #foo y una clase de .bar será seleccionado por ambas declaraciones. Los selectores de ID tienen una especificidad de Grupo A y los selectores de clase tienen una especificidad de Grupo B. Un selector de ID supera cualquier número de selectores de clase. Por eso, color:blue; desde el selector #foo y el background:black; Desde el selector .bar se aplicará al elemento. La mayor especificidad del selector de ID hará que el navegador ignore la .bar de color del selector .bar .

Ahora imagine una implementación diferente de CSS:

.bar {
  color: red;
  background: black;
}

.baz {
  background: white;
}

Aquí tenemos dos selectores de clase; uno de los cuales declara el color como rojo y el background como negro , y el otro declara el background como blanco .

Un elemento con ambas clases .bar y .baz se verá afectado por estas dos declaraciones, sin embargo, el problema que tenemos ahora es que tanto .bar como .baz tienen una especificidad idéntica al Grupo B. La naturaleza en cascada de CSS resuelve esto por nosotros: como .baz se define después de .bar , nuestro elemento termina con el color rojo de .bar pero el background blanco de .baz .

Ejemplo 3: Cómo manipular la especificidad.

El último fragmento del Ejemplo 2 anterior se puede manipular para garantizar que se .bar la declaración de color del selector de clase .bar lugar de la del selector de clase .baz .

.bar {}        /* a=0, b=1, c=0 */
.baz {}        /* a=0, b=1, c=0 */

La forma más común de lograr esto sería averiguar qué otros selectores se pueden aplicar a la secuencia del selector .bar . Por ejemplo, si el .bar clase sólo se aplicó nunca a span elementos, podríamos modificar el .bar selector para span.bar . Esto le daría una nueva especificidad para el Grupo C , que anularía la falta del mismo .baz selector:

span.bar {}    /* a=0, b=1, c=1 */
.baz {}        /* a=0, b=1, c=0 */

Sin embargo, es posible que no siempre sea posible encontrar otro selector común que se comparta entre cualquier elemento que use la clase .bar . Debido a esto, CSS nos permite duplicar los selectores para aumentar la especificidad. En lugar de solo .bar , podemos usar .bar.bar en .bar.bar lugar (Ver La gramática de los selectores, Recomendación W3C ). Esto aún selecciona cualquier elemento con una clase de .bar , pero ahora tiene el doble de especificidad de Grupo B :

.bar.bar {}    /* a=0, b=2, c=0 */
.baz {}        /* a=0, b=1, c=0 */

Declaraciones de estilo !important y en línea.

Se considera que la !important en una declaración de estilo y los estilos declarados por el atributo de style HTML tienen una mayor especificidad que cualquier selector. Si existen, la declaración de estilo que afectan anulará otras declaraciones independientemente de su especificidad. Es decir, a menos que tenga más de una declaración que contenga un indicador !important para la misma propiedad que se aplica al mismo elemento. Luego, las reglas de especificidad normales se aplicarán a esas propiedades en referencia entre sí.

Debido a que anulan completamente la especificidad, el uso de !important está mal visto en la mayoría de los casos de uso. Uno debería usarlo lo menos posible. Para mantener el código CSS eficiente y mantenible a largo plazo, casi siempre es mejor aumentar la especificidad del selector circundante que utilizarlo !important

Una de esas raras excepciones en las que lo !important no está mal visto, es cuando se implementan clases auxiliares genéricas como una .hidden o .background-yellow que se supone que siempre anulan una o más propiedades donde sea que se encuentren. E incluso entonces, necesitas saber lo que estás haciendo. Lo último que desea, al escribir CSS mantenible, es tener !important todo su CSS.

Una nota final

Un error común acerca de la especificidad de CSS es que los valores de los grupos A , B y c deben combinarse entre sí ( a=1, b=5, c=1 => 151). Este no es el caso. Si este fuera el caso, tener 20 de un selector de grupo B o c sería suficiente para anular un solo selector de grupo A o B , respectivamente. Los tres grupos deben considerarse como niveles individuales de especificidad. La especificidad no puede ser representada por un solo valor.

Al crear su hoja de estilo CSS, debe mantener la menor especificidad posible. Si necesita hacer que la especificidad sea un poco más alta para sobrescribir otro método, hágalo más alto pero lo más bajo posible para hacerlo más alto. No deberías tener un selector como este:

body.page header.container nav div#main-nav li a {}

Esto hace que los cambios futuros sean más difíciles y contaminan esa página css.


Puedes calcular la especificidad de tu selector aquí