CSS Reset Moderno con @layer: Qué Cambia en reseter.css 3 y Cómo Instalarlo

reseter.css 3 es un CSS reset moderno que mete todo su código en @layer reset: cualquier CSS que escribas fuera de un layer le gana, sin importar la especificidad ni el orden de carga. Ese cambio corrige el error más común de los resets escritos a mano, y llega junto con propiedades lógicas, un build con Lightning CSS y varios cambios visuales que conviene revisar antes de actualizar.

:white_check_mark: yoDEV Tested · 15 de octubre de 2026 Instalamos reseter.css 2.1.0 y 3.0.1 desde npm y los comparamos en Chromium 141 sin interfaz contra un reset escrito a mano, en tres escenarios de orden de carga y de layers. Los resultados que reportamos como nuestros salen de esa prueba.

¿Qué es un CSS reset moderno?

Un CSS reset elimina los estilos que cada navegador aplica por defecto (márgenes, sangría de listas, fuentes de los formularios, imágenes en línea) para que partas de una base predecible. Un modern CSS reset va más allá: no lo pone todo a cero. Conserva los valores razonables (los encabezados mantienen sus márgenes, las listas su sangría), aplica box-sizing: border-box a todos los elementos, usa propiedades lógicas para funcionar también en diseños de derecha a izquierda y está pensado para que tus estilos siempre ganen.

Ese último punto es donde fallan casi todos. Un reset debería ser el CSS más débil de la página. En la práctica, los resets escritos a mano suelen usar selectores más fuertes que los estilos de los componentes que vienen después.

¿Reset CSS o Normalize.css: cuál usar?

Normalize.css no borra los estilos del navegador: los iguala entre navegadores y conserva los que son útiles. Un reset parte de una base más limpia y decide él mismo los valores por defecto. reseter.css 3 se ubica en un punto intermedio: quita márgenes y rellenos con el selector universal, pero los devuelve con valores tipo navegador en encabezados y listas.

La documentación oficial de reseter.css incluye una tabla comparativa. Según esa tabla, reseter.css apunta a los navegadores con más de 3 por ciento de uso global y Normalize.css a las últimas tres versiones de cada navegador. Además, reseter.css publica una versión minificada lista para usar, mientras que con Normalize.css tienes que minificarla tú.

¿Qué cambia @layer en la especificidad CSS de un reset?

Con las capas de cascada (cascade layers, @layer) decides qué grupo de estilos gana antes de que entre en juego la especificidad CSS. Los estilos que no están en ningún layer le ganan a todos los que sí lo están. Como el reset vive en @layer reset y el CSS de tu aplicación no tiene layer, tu aplicación gana, use el selector que use cada lado.

Probamos el error clásico. Un reset escrito a mano suele tener algo así:

button, input[type='submit'] { padding: 0 }

Y después tu componente dice:

.btn { padding: 12px }

Escenario <button class="btn"> <input type="submit" class="btn">
Reset escrito a mano + .btn 12px 0px
reseter.css 3 + .btn 12px 12px
reseter.css 3 + .btn, con tu CSS cargado antes 12px 12px

Con el reset escrito a mano, el botón de envío se queda con padding: 0 porque input[type='submit'] tiene especificidad (0,1,1) y .btn solo (0,1,0). Con reseter.css 3 decide primero el layer, así que la competencia de especificidad nunca ocurre.

La tercera fila es la verdadera novedad frente a la versión 2. reseter.css 2.1.0 ya envolvía casi todos sus selectores en :where(), que deja la especificidad en cero, así que rara vez le ganaba a tus componentes. Lo que no podía garantizar era el orden de carga. Una regla de especificidad cero en tu aplicación (por ejemplo :where(.stack) > * + * { margin-block-start: 24px }) cargada antes del reset daba 0px con la 2.1.0 y 24px con la 3.0.1. Con layers, deja de importar en qué orden tu bundler inyecta el CSS.

¿Qué regla queda fuera del layer?

Hay una regla que se deja sin layer a propósito:

:where(dialog):not([open]), [hidden]:not([hidden="until-found" i]) { display: none; }

Gracias a ella, el atributo hidden sigue funcionando aunque una clase defina display. En nuestra prueba, .card { display: flex } sobre un <div class="card" hidden> siguió oculto con reseter.css 3 y quedó visible con el reset escrito a mano. Las notas de la versión no lo mencionan, pero es la decisión correcta.

¿Cómo se instala reseter.css?

Puedes instalarlo con npm o pnpm, o cargarlo desde un CDN. Al momento de publicar esta nota, la última versión es la 3.0.1, publicada el 11 de octubre de 2026, y la guía oficial fija todos los comandos a esa versión:

npm install reseter.css@3.0.1
# o
pnpm add reseter.css@3.0.1

Con un bundler, importa primero el reset y después tus estilos:

import "reseter.css";
import "./app.css";

Sin bundler, usa el CDN:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reseter.css@3.0.1/dist/index.min.css">
<link rel="stylesheet" href="/styles.css">

La guía de inicio repite ese mismo patrón de dos líneas para React, Vue, Svelte, SvelteKit, Next.js, Nuxt, Astro, Remix, Angular, Laravel, Django, Rails, WordPress y Eleventy.

¿Cuánto pesa reseter.css?

Según el changelog del propio proyecto para la 3.0.1, dist/index.min.css pesa 951 bytes con compresión Brotli. Nosotros medimos 1.178 bytes con gzip para el build completo y 377 bytes para el build mini. Si te preocupa el CSS que bloquea el primer render, también te puede servir Critical 9: cómo extraer el CSS crítico sin navegador.

¿reseter.css completo o mini?

Usa el build completo, salvo que una librería de UI ya le dé estilo a tus controles de formulario. En ese caso usa el mini (import "reseter.css/mini"), y carga solo uno de los dos, como indica la documentación. El mini deja fuera formularios, enlaces y diálogos, y además tiene otras diferencias que medimos:

Qué Completo Mini
Peso de fuente de h2 700 400 (normal)
Margen entre párrafos (p + p) 16px 0
Borde de inputs de texto 1px solid el del navegador
Fuente de los controles pila system-ui la del navegador
textarea resize vertical both

La que más sorprende es el peso de los encabezados: con el mini, todos los encabezados quedan con peso normal.

¿Cómo usar reseter.css con frameworks que usan @layer?

Si tu framework o tu sistema de diseño pone sus estilos base dentro de un layer, declara el orden de los layers antes que cualquier otra cosa. Los layers se ordenan según la primera vez que se declaran, y el que se declara después gana. Si el @layer base de tu framework se declara primero y reseter.css se importa después, el reset le gana a tus estilos base.

Lo reprodujimos: con @layer base { h2 { margin-block: 0 } } declarado antes de importar reseter.css, el h2 conservó 19,92px de margen. Una sola línea al principio lo resolvió:

@layer reset, base;

Con esa declaración, el margen del h2 pasó a 0, como se esperaba. Las notas de la versión advierten que los frameworks con layers pueden necesitar atención al orden de las capas. Al 15 de octubre de 2026, la guía de inicio oficial no explica cómo hacerlo.

¿Qué se rompe al actualizar de reseter.css 2 a 3?

La 3 es una versión mayor según semver, y los cambios visuales son reales. Estos son los valores computados que cambiaron entre la 2.1.0 y la 3.0.1 en Chromium:

Área Elemento 2.1.0 3.0.1
Encabezados margen superior de h2 0 19.92px
Encabezados text-wrap de h1–h4 auto balance
Listas padding-inline-start de ul 0 40px
Listas viñetas de ul[role="list"] disc none
Formularios estilo de borde de botones solid outset (el del navegador)
Formularios fuente de input/button/select Arial pila system-ui
Formularios resize de textarea both vertical
Media display de img, svg inline block
Media max-width de img none 100%
Raíz text-size-adjust de html auto none

Hay cuatro áreas que necesitan revisión visual: encabezados (recuperan sus márgenes), listas (recuperan su sangría), formularios (fuente nueva y bordes de botón por defecto) y media (las imágenes pasan a ser bloques, lo que puede romper íconos en línea).

Por debajo también cambia el código. Ya no hay fuentes Sass, el CSS publicado se genera con Lightning CSS y el repositorio pasó a pnpm. Las propiedades ahora son lógicas (margin-block, padding-inline-start, max-inline-size) en lugar de físicas. Si importabas rutas internas del paquete, usa solo las que aparecen en el campo exports de package.json. La documentación recomienda import "reseter.css" y reseter.css/mini.

¿Qué hace text-size-adjust: none?

Desactiva el agrandamiento de texto que aplican los navegadores móviles a las páginas que no fueron diseñadas para pantallas pequeñas. Según MDN, un sitio realmente responsive no necesita ese agrandamiento, y desactivarlo no impide que el usuario haga zoom. Si tu sitio todavía tiene diseños que no son responsive, revisa cómo se ven en un teléfono después de actualizar.


¿Y tú? ¿Qué regla de tu reset o de tus estilos base te ha dado más problemas al pelear contra los estilos de un componente?

¿Qué reset de CSS usas hoy?
  • Uno propio, escrito a mano
  • Normalize.css o similar
  • El que trae mi framework
  • Prefiero otra opción (cuéntanos cuál)
0 votantes

Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.

Relacionado: Panda CSS 2.0: El Compilador Reescrito en Rust y Cómo Migrar sin Romper tu Build