Skip to content

Modern Web Guidance: el contexto de plataforma web que le falta a tu agente

Modern Web Guidance: el contexto de plataforma web que le falta a tu agente
13 min read

Si usás un agente para escribir frontend, seguramente te pasó esto: le pedís un modal y te arma un div con position: fixed, un overlay a mano, un listener de keydown para el Escape y un focus trap copiado de algún lado. Funciona. Pero hace años que existe <dialog>, que trae todo eso resuelto por el navegador, con la accesibilidad incluida.

El modelo sabe programar, pero aprendió de una web donde casi todo el código publicado es de antes de que existieran (o se pudieran usar) las APIs que hoy conviene usar. Tampoco tiene idea de qué soporta cada navegador hoy, ni de los bugs puntuales que hacen que una feature "soportada" no funcione igual en todos lados.

Para eso Chrome armó Modern Web Guidance, que ayer llegó a la 1.0. Lo estuve probando en este mismo blog, así que va un repaso de qué es, cómo funciona por dentro y qué cosas tener en cuenta.

Qué es

Es un skill para agentes de código (Claude Code, Codex, Copilot CLI, Gemini CLI, Cursor, Antigravity y varios más) más un CLI que ese skill invoca. El skill en sí es corto: un SKILL.md que le dice al agente "antes de escribir HTML, CSS o JS de cliente, buscá si hay una guía para lo que vas a hacer". La guía la trae el CLI.

Lo publica el equipo de Chrome, pero con la 1.0 pasó a ser un esfuerzo compartido con Firefox, Edge y MDN. El código es Apache 2.0 y las guías son CC-BY 4.0, con partes derivadas de MDN y de las specs.

Hoy son unas 200 guías organizadas por área: ui-behaviors, forms, css, performance, accessibility, security, pwa, built-in-ai, webmcp, etc. Cada una cubre un caso de uso concreto ("animar un dialog al abrir y cerrar", "priorizar la imagen del LCP", "validar un input después de que el usuario interactuó") y hay algunas guías generales por disciplina (html, css, accessibility, performance).

Cómo funciona por dentro

El flujo que le pide el skill al agente son dos comandos. Primero buscar, con una query corta y orientada a la acción:

npx -y modern-web-guidance@latest search "animate dialog open and close"

La búsqueda corre local (embeddings offline más BM25) y devuelve un JSON con ids y descripciones:

[
  {
    "id": "animate-to-from-top-layer",
    "description": "Animate elements such as dialogs, popovers, and tooltips as they're entering/exiting the top layer."
  },
  {
    "id": "declarative-dialog-popover-control",
    "description": "Toggle the visibility of a dialog or popover from a button without writing JavaScript."
  },
  {
    "id": "light-dismiss-a-dialog",
    "description": "Create a modal dialog that can be closed via light dismiss (i.e. clicking or tapping outside of the dialog)"
  }
]

El agente lee las descripciones, elige y pide la guía completa:

npx -y modern-web-guidance@latest retrieve "animate-to-from-top-layer"

La guía es un markdown escrito para que lo lea un modelo, con la implementación, una lista de reglas MANDATORY / DO NOT y una sección de fallbacks con datos de Baseline al día.

Por ejemplo, la de animar elementos del top layer arranca con lo que uno esperaría (@starting-style, transition-behavior: allow-discrete, transicionar overlay) y después baja a reglas bastante específicas, como esta:

dialog,
[popover] {
  opacity: 0;
  transition-property: opacity, transform, display, overlay;
  transition-duration: 0.3s;
  /* Separado del shorthand: si va adentro de `transition`,
     los navegadores viejos descartan la declaración entera */
  transition-behavior: allow-discrete;
}

Más abajo aparece algo que yo tampoco sabía: Firefox 129+ parsea transition-behavior: allow-discrete y CSS.supports() devuelve true, pero no transiciona display de verdad (bug 1882408): el dialog desaparece de golpe al cerrarse. La guía explica cómo detectarlo con un elemento de prueba en lugar de confiar en CSS.supports(), y cómo hacer la animación de salida con un data-closing y getAnimations() antes de llamar a .close() donde no hay soporte.

La API el modelo probablemente ya la conoce. Lo que no tiene es el estado real de soporte y este tipo de bugs, que cambian de un release a otro.

Baseline como política del proyecto

Cada guía trae el estado de Baseline de las features que usa. Si no le decís nada, el agente asume Baseline Widely available: lo que esté disponible en todos los navegadores principales hace más de 30 meses se usa directo, y para el resto tiene que aplicar el fallback que indica la guía.

Lo podés ajustar desde el CLAUDE.md o AGENTS.md del proyecto:

**Browser Support:** Baseline 2024. Allow Newly Available features
if feature-detected with graceful degradation, but only adopt custom
fallback code that adds <= 20 lines and no external dependencies.

Esto sirve aunque no uses el skill. Muchos equipos nunca escriben su política de soporte, y después cada PR tiene su discusión de "¿esto anda en Safari?" sin un criterio en común.

Hay dos niveles más, apagados por defecto: las features volátiles (implementadas en un solo motor o con menos de tres meses en estable) y las que están en origin trial. Las podés encontrar con search, pero retrieve no te las da hasta que lo habilitás explícitamente:

npx modern-web-guidance@latest set-allow-volatile-features
npx modern-web-guidance@latest set-allow-origin-trials

Eso queda guardado en un .mwgrc en la raíz del proyecto. Me parece bien que sea opt-in, no quiero que el agente me meta en producción una API que todavía está detrás de un flag.

Instalación

La forma recomendada es el instalador del propio CLI, que además se encarga de las actualizaciones:

npx modern-web-guidance@latest install
# y para pasar de la preview a la 1.0
npx modern-web-guidance@latest update

También está en los marketplaces de plugins de la mayoría de los agentes. En Claude Code:

claude plugin install modern-web-guidance@claude-plugins-official

O con el instalador genérico de skills, que es lo que usé acá:

npx skills add GoogleChrome/modern-web-guidance

Ojo con esta última: copia el skill a .agents/skills/, crea un symlink en .claude/skills/ y deja un skills-lock.json con un hash, pero no se actualiza sola. La doc lo dice: la mayoría de las opciones que no son el CLI no tienen actualizaciones automáticas.

Modernizar código existente

La novedad grande de la 1.0 es legacy-scan, un análisis estático que busca patrones viejos en HTML, CSS, JS y package.json:

npx modern-web-guidance@latest legacy-scan . --json

Cada hallazgo viene con un criterio keepWhen / dropWhen para que el agente decida si es un falso positivo (un fallback a propósito, código de terceros, algo que se parece pero no es) antes de tocar nada. El propio skill aclara que el scan cubre más o menos un 20% de las guías, las que tienen reglas deterministas. El resto depende de que el agente busque la guía correcta mientras trabaja.

Lo que encontró en este blog

Lo corrí sobre el código de este sitio (Next.js con export estático) y el legacy-scan devolvió cero hallazgos. Revisó 35 reglas y ninguna matcheó, lo cual habla más del alcance del scan que del sitio. Lo útil apareció cuando le pedí al agente que recorriera los componentes buscando guías para cada cosa que el sitio hace (header, carrusel de imágenes, paginación, filtro de idioma, embeds).

Ahí sí salieron cosas, casi todas de reduced motion:

  • Las ondas animadas del home corren en loop infinito aunque el usuario tenga activado reduced motion. Nada de @media (prefers-reduced-motion).
  • html { scroll-behavior: smooth } aplicado a todo el mundo, y lo mismo con los scrollTo({ behavior: 'smooth' }) del botón de volver arriba y de la paginación.
  • Los botones del filtro de idioma no exponen cuál está activo (aria-pressed) y la página actual de la paginación no tiene aria-current="page".
  • Los iframes de YouTube y SlideShare de posts viejos cargan sin loading="lazy".

La guía distingue dos estrategias: si con _reduced motion la animación no tiene que existir, va dentro de no-preference; si solo cambian sus parámetros, se ajusta dentro de reduce. El scroll suave cae en el primer caso. Con las ondas probé lo mismo primero, pero quedaban las cuatro capas alineadas y parecía una sola onda. Pausarlas conserva el desfase que les dan los animation-delay negativos, y no se mueven:

html {
  @media (prefers-reduced-motion: no-preference) {
    scroll-behavior: smooth;
  }
}

.parallax > use {
  animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite;

  @media (prefers-reduced-motion: reduce) {
    animation-play-state: paused;
  }
}

Un detalle que me había pasado por alto: un window.scrollTo({ top: 0, behavior: 'smooth' }) explícito ignora el scroll-behavior del CSS, así que gatear el CSS no alcanza. Sacándole el behavior toma lo que diga el CSS, y listo.

Nada grave, todo chico, y justamente el tipo de cosa que se escapa en una review. También me sirvió para confirmar lo que ya estaba bien (prioridad de la imagen del LCP, content-visibility en lo que está abajo del fold, view transitions con reduced motion) y para descartar con argumento alguna idea: la guía de prefetch dice explícitamente que no conviene usar speculation rules en una SPA, y con el router de Next las navegaciones internas son client-side.

Los números

Los evals son de lo más prolijo del proyecto. Cada guía tiene un script de Playwright que valida la implementación en un navegador real (por ejemplo, que se respete prefers-reduced-motion donde corresponde), calibrado contra una implementación correcta que tiene que pasar al 100% y una rota a propósito que tiene que fallar al 100%. Después corren la misma tarea con y sin la guía, varias veces por semana, con Claude Code, Codex y Antigravity. Todo eso es público en el dashboard de evals y en el repo de fuentes.

Las últimas corridas que vi andan por +28 a +36 puntos porcentuales de mejora: Claude Code pasa de 57% a 88%, Codex de 54% a 82%. La doc habla de un promedio de 37 puntos.

Dos aclaraciones. Primero, son evals propios: las tareas y los criterios de "bien hecho" los define el mismo equipo que escribe las guías, así que en parte miden qué tan bien el agente sigue sus recomendaciones. Dicho eso, los graders verifican comportamiento (roles, foco, teclado) y no nombres de variables, y el benchmark es open source, así que se puede auditar. Segundo, el anuncio trae casos de empresas (Policybazaar, WeTV, note, MetaMask) con números del tipo "90% menos bugs". Son testimonios de lanzamiento: interesantes, pero no son un estudio.

El caso que más me gustó es el de MetaMask, porque es el más fácil de replicar: lo corren como bot de review en cada PR con un prompt de tres líneas. En cinco semanas revisó unos 480 PRs, comentó en 64 y los ingenieros arreglaron 43 hallazgos, mayormente de accesibilidad, semántica HTML y formularios. Cosas que un linter no agarra.

Cosas a tener en cuenta

Corre @latest en cada consulta. El skill invoca npx -y modern-web-guidance@latest para cada search y retrieve. Eso implica red (en un sandbox sin salida a internet no anda, aunque hay un --offline) y que cada vez estás ejecutando la última versión publicada de un paquete de npm. Es de Google y el riesgo es bajo, pero si tu política de supply chain es estricta, vale saberlo y considerar fijar la versión.

Telemetría. Por defecto manda datos anónimos: conteo de instalaciones, qué agente lo llama, qué guías se piden y las queries de búsqueda que arma el agente (no tus prompts). Se apaga con DISABLE_TELEMETRY=1. Si trabajás en algo confidencial, las queries pueden decir más de lo que parece ("passkey login flow for "), aunque el skill le pide al agente que no ponga nombres de producto ni de componentes.

Tokens. Las guías no son chicas: la de animar el top layer pesa unos 11 KB y las generales (accessibility, html) arriba de 5.000 tokens. Si el agente trae tres o cuatro por tarea, se nota en el contexto. A cambio, se ahorra varias vueltas de "esto no anda en Safari".

El skill es insistente. La descripción dice "MANDATORY: Execute FIRST for all HTML/CSS and clientside JS tasks", y además le pide al agente que cierre cada respuesta con una sección explicando qué guías usó. Para tareas de UI está bien. Para un cambio de una línea en un componente puede ser ruido.

No reemplaza correr el código. La guía te dice cómo hacerlo bien, pero no verifica que haya quedado bien en tu app. Por eso Chrome lo empuja junto con Chrome DevTools para agentes: uno pone el conocimiento, el otro mide (un trace con CPU throttling para ver si un long task bajó de 50 ms, un screen recording para ver si la animación quedó bien, el árbol de accesibilidad).

Cierre

Los modelos ya escriben código que funciona. Lo que les falta es saber qué feature usar, desde cuándo se puede usar sin fallback y dónde están los bugs, y eso cambia cada mes, mucho más rápido de lo que se reentrena un modelo. Modern Web Guidance apunta a eso, y por lo que vi en este blog, cumple.

Lo que haría hoy: instalarlo con el CLI (por las actualizaciones), escribir la política de Baseline en el CLAUDE.md o AGENTS.md aunque no uses el skill, y correr un legacy-scan sobre el proyecto para ver qué aparece. Y si tenés un repo con mucho frontend y PRs de varias personas, probar el enfoque de MetaMask como bot de review, que es donde más rinde un criterio consistente.

Lo que espero ahora es que el legacy-scan crezca. Hoy cubre una quinta parte de las guías, y el plan es pasar a auditorías donde el agente razone sobre el código en lugar de buscar patrones. Para proyectos que ya existen, que son la mayoría, eso es lo que más va a servir.

Comentarios

Comentá con tu cuenta de GitHub.

Cargando comentarios…


Related Posts