Calculadora de Especificidad CSS

Calcula la especificidad CSS de cualquier selector. Desglose por colores, comparación múltiple, soporta :is, :not, :has, :where según W3C.

Selectores CSS (uno por línea)
Un selector por línea. Las reglas separadas por comas cuentan como una sola línea.
Referencia de Especificidad
ComponenteEjemplosPeso
a IDs#header, #main(1, 0, 0)
b Clases / Atributos / Pseudo-clases.btn, [type="text"], :hover, :nth-child(2)(0, 1, 0)
c Tipos / Pseudo-elementosdiv, p, ::before, ::placeholder(0, 0, 1)
*, :where(...), +, >, ~(0, 0, 0)
:is(A, B), :not(A), :has(A)max del argumento

Calculadora de Especificidad CSS — Analiza Selectores, Calcula (a, b, c)

Pega cualquier selector CSS — simple o compuesto, con combinadores, pseudo-clases, pseudo-elementos, o los modernos :is/:not/:where/:has — y la calculadora devuelve la tripla de especificidad W3C. El desglose muestra a qué componente contribuye cada token, y una vista de comparación clasifica múltiples selectores para que veas de un vistazo qué regla gana la cascada.

¿Qué es la especificidad CSS en un párrafo?

Cuando dos reglas CSS intentan establecer la misma propiedad en el mismo elemento, el navegador necesita un desempate. El primer criterio es *origen e importancia* (user-agent < autor < usuario, luego !important invierte eso). Después, *especificidad*: cada selector recibe un peso, expresado como tres números — (a, b, c) — y la tupla mayor gana, comparando de izquierda a derecha.

Los tres slots cuentan:

- **a** — número de selectores de ID (`#foo`)
- **b** — número de selectores de clase (`.bar`), de atributo (`[type=text]`), y pseudo-clases (`:hover`)
- **c** — número de selectores de tipo (`div`) y pseudo-elementos (`::before`)

Un selector como `#nav .item a:hover` tiene un ID, dos entradas clase/pseudo-clase, y un tipo — especificidad (1, 2, 1). Gana a `.menu .item a:focus` (0, 3, 1) porque el primer slot vence sin importar cuán altos sean los siguientes.

¿Cómo afectan `:is()`, `:not()`, y `:has()` a la especificidad?

Los tres aportan la *máxima* especificidad de sus argumentos, no cero, no la suma.

Ejemplo:

```
:is(.btn, #primary) { color: red; }
```

La especificidad la determina `#primary` (1, 0, 0), no `.btn` (0, 1, 0). El token completo `:is(...)` aporta (1, 0, 0).

La misma regla aplica a `:not(...)` y `:has(...)` — toman el selector más pesado dentro de los paréntesis. Por eso `:not(#admin)` es un selector pesado a pesar de parecer inocente; su especificidad es (1, 0, 0) por sí solo.

Este comportamiento se define en CSS Selectors Level 4. El `:not()` más antiguo (Level 3, forma de selector simple único) seguía la misma regla, así que la mayoría de los navegadores siempre han coincidido.

¿Y `:where(...)`?

`:where(...)` es la válvula de escape: aporta **especificidad cero** sin importar lo que contenga.

```
:where(#header, .nav, h1) { color: blue; }
```

Especificidad = (0, 0, 0). Esto es intencional. `:where()` permite escribir un estilo base que comparten varios selectores agrupados sin bloquear futuras anulaciones — cualquier cosa que apunte a los mismos elementos con aunque sea una clase ganará.

Un patrón común es envolver reglas reset o por defecto en `:where(...)` para que tengan efectivamente cero peso de especificidad, mientras los estilos de componentes autorados quedan libres de anularlas con selectores normales. Se añadió en CSS Selectors Level 4 (2018) y se entregó en todos los navegadores evergreen para 2021.

¿Por qué a veces veo `(a, b, c, d)` con cuatro slots?

Artículos antiguos añaden un cuarto slot al principio para **estilo inline** (el atributo `style="..."`), dando (1, 0, 0, 0) para cualquier declaración inline. W3C la quitó de la tupla formal de especificidad porque el estilo inline es una capa de origen separada — gana todas las decisiones de cascada a nivel de autor antes de que la especificidad siquiera se compare.

En la práctica:

1. Las declaraciones `!important` ganan (capa de origen).
2. El estilo inline gana a cualquier selector sin `!important`.
3. Los selectores luego se clasifican por (a, b, c) — IDs, clases/attrs/pseudo-clases, tipos/pseudo-elementos.
4. Si la especificidad empata, gana la regla declarada al último en orden de fuente.

Esta calculadora sigue la convención moderna de tres slots. Si comparas con un tutorial más viejo, padea mentalmente con un 0 al inicio — `(0, 1, 2, 1)` y `(1, 2, 1)` describen el mismo selector.

¿El selector universal `*` o los combinadores añaden especificidad?

No. Nada de lo siguiente aporta especificidad:

- `*` (selector universal)
- ` ` (combinador descendiente, escrito como espacio en blanco)
- `>` (combinador hijo)
- `+` (combinador hermano adyacente)
- `~` (combinador hermano general)
- `||` (combinador de columna, para tablas — Level 4)

Un selector como `* > * + *` tiene especificidad (0, 0, 0) — tres universales y dos combinadores, todos sin peso. Los combinadores describen *relaciones*, no qué se selecciona, así que no añaden peso.

Por eso `body > main p` (0, 0, 3) empata con `h1 ~ h2 ~ p` (0, 0, 3) — mismos tres selectores de tipo, combinadores distintos, misma especificidad. La cascada decide entonces por orden de fuente.

¿Cuál es la diferencia entre pseudo-clases y pseudo-elementos?

**Pseudo-clases** describen un estado de un elemento:

- `:hover`, `:focus`, `:active`, `:checked`, `:disabled`
- `:nth-child(2)`, `:nth-of-type(odd)`, `:first-child`
- `:lang(en)`, `:dir(rtl)`, `:state(custom)`

Aportan al slot **b** — mismo peso que un selector de clase.

**Pseudo-elementos** describen una sub-parte virtual de un elemento:

- `::before`, `::after`, `::first-line`, `::first-letter`
- `::placeholder`, `::marker`, `::backdrop`, `::selection`

Aportan al slot **c** — mismo peso que un selector de tipo.

La diferencia sintáctica es un solo dos puntos (`:hover`) vs doble dos puntos (`::before`). CSS2 usaba un solo dos puntos para los cuatro pseudo-elementos más antiguos (`:before`, `:after`, `:first-line`, `:first-letter`) — esta calculadora acepta ambas formas y clasifica esos cuatro como pseudo-elementos en cualquier caso.

¿Cómo bajo la especificidad cuando estoy en guerra con otra hoja de estilos?

Varias técnicas de menor a mayor severidad:

1. **Usa `:where()`** — envuelve las partes pesadas de tu selector en `:where()` para que no aporten nada. `:where(.legacy) .button` → (0, 1, 0) en vez de (0, 2, 0). Ideal para hojas reset.
2. **Quita IDs de los selectores** — refactoriza `#nav .item` a `.nav .item` si el markup lo permite. Los IDs son el único contribuyente más pesado.
3. **Usa una sola clase** — los selectores planos como `.btn-primary` ganan porque empatan en (0, 1, 0) contra la mayoría de estilos autorados, dejando que el orden de fuente decida.
4. **Duplica una clase** — `.btn.btn` (0, 2, 0) es un hack conocido para subir especificidad *sin* necesitar IDs.
5. **Usa cascade layers** — `@layer base, components, utilities;` te deja controlar qué archivo gana sin importar la especificidad. La capa declarada después gana, punto.
6. **Usa `!important`** — último recurso. Funciona pero crea una cadena frágil de guerras de anulación.

La estrategia moderna es: minimizar especificidad en CSS de componentes (clases únicas), envolver reglas legacy/reset en `:where()`, y usar cascade layers para la división tooling/utility.

¿Es privada y offline esta calculadora?

Sí. Todo se calcula localmente en el navegador con unos cientos de líneas de JavaScript:

- El parser de selectores está escrito a mano, sin llamar a ningún motor CSS externo.
- Sin telemetría, sin analíticas para los cálculos en sí.
- El botón Ejemplos llena el textarea con cadenas integradas; nada se descarga.
- La página comparte los assets normales del sitio (Bootstrap CSS, íconos) pero ninguna API de terceros se contacta para la matemática de especificidad real.

Puedes verificar abriendo DevTools → Red y mirando mientras escribes o pulsas Calcular — no debería dispararse ninguna petición. Esto también significa que la calculadora funciona offline una vez cargada la página, útil si auditas una hoja de estilos en un vuelo o con poca señal.

Características Principales

  • Tupla (a, b, c) correcta según W3C para cualquier selector CSS
  • Desglose por colores resaltando qué token aporta a cada slot
  • Vista de comparación multi-selector, ordenada por especificidad descendente
  • Manejo correcto de :is(), :not(), :has() — máxima especificidad del argumento
  • :where(...) reconocido como especificidad cero
  • Pseudo-elementos (::before, ::after, ::first-line) clasificados aparte de pseudo-clases
  • Pseudo-elementos CSS2 con un solo dos puntos (:before, :after) aceptados
  • Selector universal * y combinadores (>, +, ~, espacio) correctamente con peso cero
  • Selectores de atributo, incluyendo [attr=value] y [attr^=value]
  • Pseudo-clases funcionales :nth-child(), :nth-of-type(), :lang(), :dir()
  • Preset Ejemplos carga 10 selectores representativos para comparación instantánea
  • Detección de empates — resalta selectores con misma especificidad
  • JavaScript puro, sin motor CSS externo
  • Funciona offline tras la primera carga
  • 100% del lado del cliente — tus selectores se quedan en tu navegador