Hermano estructural de Most CSS Resets Solve the Wrong Problem misma distinción, diferente capa.
También disponible en Inglés
El problema
Un sitio en producción se despliega. El sistema de diseño reconstruye la tipografía, el espaciado y los estados mediante clases de utilidad. El QA visual aprueba en escritorio. El QA visual aprueba en móvil. La maquetación parece intencional, meditada, correcta.
Entonces alguien presiona la tecla Tab.
Nada se resalta. Ningún contorno marca el enlace, el botón o el campo de formulario bajo el control del teclado. La interfaz sigue funcionando: un usuario de teclado aún puede enviar el formulario, seguir el enlace, abrir el menú. Simplemente no puede ver dónde está mientras lo hace.
Nadie señaló esto en la revisión. No es un error en el sentido convencional: nada falló, nada se renderizó de forma incorrecta. Es un comportamiento predeterminado del navegador que dejó de existir en silencio, y nadie lo reemplazó.
Por qué existe el problema
Los navegadores generalmente proporcionan un indicador de foco renderizado para los elementos interactivos enfocados mediante el teclado. No es decoración. Existe para que alguien que se desplaza por una página sin ratón pueda rastrear su propia posición: la navegación por teclado sin un indicador visible es navegación sin mapa.
Algunos resets amplios de CSS eliminan esto al limpiar los estilos predeterminados del navegador en un solo movimiento, lo cual es la premisa misma de un reset. Eso es legítimo: los navegadores difieren en márgenes, rellenos, marcadores de lista y apariencia de controles de formulario, y un reset permite que todos comiencen desde el mismo lienzo en blanco.
El problema comienza cuando el mismo selector amplio que elimina la inconsistencia cosmética también elimina el comportamiento funcional, sin que nada en la sintaxis señale la diferencia.
El primer principio
La cascada no distingue entre un comportamiento predeterminado cosmético y uno funcional. Solo conoce especificidad, orden de origen y procedencia. *:focus { outline: none; } es exactamente tan válido, tan fácil de escribir y tan invisible en un diff como * { margin: 0; }. El navegador lo aplica sin quejarse, porque no tiene concepto de "este importaba más".
La serie sobre CSS denominó esta misma forma de problema como normalización frente a opinión: corregir un desacuerdo real entre navegadores frente a codificar una preferencia no documentada. La versión de HTML de esa separación opera en un eje diferente: decoración frente a affordance.
Decoración es una elección visual que el navegador tomó ante la ausencia de una por parte del autor: marcadores de lista predeterminados, tamaños de encabezado predeterminados, apariencia de controles de formulario. No tiene peso funcional. Eliminarla no cuesta nada.
Affordance es una señal que comunica un estado o permite la interacción: la indicación de foco, el cursor de puntero en un elemento clickable, la apariencia deshabilitada en un control inerte. Tiene peso funcional, sea o no visualmente elaborada.
El QA visual comprueba la apariencia. No comprueba la ausencia de una señal que nunca se diseñó para verse excepto en el momento en que alguien la necesita: en el caso de la indicación de foco, solo al navegar con el teclado. Un revisor que hace clic en un sitio de pruebas con el ratón nunca activa la condición que revela el problema. El proceso de QA no falló. Nunca estuvo orientado a la pregunta que importaba.
Demostración del principio
Compara dos versiones del mismo botón, estilizadas de forma idéntica para un usuario de ratón:
/* 1. Decoración eliminada */
button {
margin: 0;
padding: 0.5rem 1rem;
border: none;
background: none;
}
/* 2. Decoración eliminada; affordance de foco eliminado */
button:focus {
outline: none;
}
La diferencia de una sola línea entre ambas es invisible para un ratón e invisible en un diff visual. Solo aparece en el momento en que alguien navega con Tab hacia el botón y busca dónde está. La primera versión todavía se lo indica. La segunda se ha quedado en silencio.
Detectar esto no requiere herramientas exóticas. Requiere preguntar, línea por línea, qué hacía realmente cada comportamiento predeterminado eliminado antes de decidir que es seguro quitarlo.
El punto de dolor
Esto no es una hipótesis. Un sitio en producción atravesó exactamente esta secuencia: un reset amplio, una reconstrucción basada en utilidades para tipografía, espaciado y estados, una revisión completa de QA visual en escritorio y móvil, y un *:focus { outline: none; } enviado a producción sin ningún reemplazo en todo el sistema.
Los usuarios de ratón vieron una interfaz pulida. Los usuarios de teclado no vieron nada en el momento exacto en que necesitaban ver algo. El reset no solo eliminó un estilo visual. Eliminó una pieza del estado de la interfaz como efecto secundario de limpiar algo no relacionado; no fue una decisión que alguien haya tomado a propósito.
Los Apuntes desde el pase del sábado reconstruyen una pequeña interfaz de tres formas: comportamientos predeterminados del navegador sin reset, un reset nuclear ajustado para verse idéntico y un reset controlado que restaura el comportamiento de foco a propósito. Las dos primeras se ven iguales para un ratón. Solo el teclado las diferencia.
La lección general
Esto no trata realmente sobre resets de CSS. Trata sobre la diferencia entre eliminar algo y entender qué estaba proporcionando. Cada plataforma incluye un comportamiento predeterminado que nadie pidió y del que todos se benefician hasta que desaparece.
El fallo no está en eliminar comportamientos predeterminados: los sistemas se vuelven más simples y más intencionales cuando alguien asume la propiedad explícita de lo que solía ser implícito. El fallo es eliminar un comportamiento predeterminado sin saber qué hacía, porque la eliminación fue fácil y el coste permaneció invisible hasta que alguien tropezó con él.
Vale la pena preguntar, la próxima vez que se incluya un reset en un nuevo proyecto: qué líneas están corrigiendo una brecha real entre navegadores y cuáles están decidiendo en silencio qué se le permite comunicar a la interfaz.
Top comments (0)