Saltar al contenido
Development

El contorno estaba bien, la caja alrededor de la cual se dibujaba no

Por Victor Da Luz
sveltecssaccessibilitydev-loggreenhouse

Un arreglo anterior en Greenhouse había agregado gestión programática del foco: al abrir el tablero kanban, el explorador de la bóveda, o al volver al panel principal, el foco se mueve al encabezado de esa vista para que quienes usan teclado o lector de pantalla sepan de verdad dónde aterrizaron. Buena idea. Después, una captura de pruebas manuales no relacionadas mostró un grueso contorno verde envolviendo permanentemente el encabezado “Board”, no un sutil anillo de foco de teclado, sino una píldora gigante que abarcaba todo el encabezado, visible todo el tiempo.

Mi primer instinto fue asumir que WebKit estaba haciendo algo raro con :focus-visible en un foco disparado por script sin ningún evento de teclado detrás, hay antecedentes reales de que eso es delicado entre navegadores. Así que fui a verificarlo de la misma manera que verifico todo lo demás últimamente: manejar la app compilada real a través de el arnés de WebDriver y revisar. Y no se reprodujo. document.activeElement era correctamente el encabezado. heading.matches(':focus-visible') devolvía false.

Eso era más interesante que el error original. Profundicé un nivel más y le pregunté directamente a la página si creía tener el foco: document.hasFocus(), false. La ventana lanzada por WebDriver nunca se convirtió en la ventana activa real a nivel de sistema operativo. Nada en mis clics automatizados le dijo nunca a macOS “trae esto al frente como lo haría una persona real”. Y WebKit, con razón, no pinta anillos de foco en documentos que no cree que tienen el foco. Mi herramienta de verificación no podía ver el error, no porque el error fuera falso, sino porque la herramienta estructuralmente no puede poner una ventana en el estado del que depende el error.

Así que el problema del contorno era real, solo que no se podía reproducir por automatización, tuve que compilar el binario de depuración simple (sin automatización), lanzarlo como una ventana normal, y revisarlo a simple vista. Y una vez que lo hice, la forma del error era obvia: el encabezado que recibía el foco TAMBIÉN era un elemento flex con flex: 1, estirado para llenar la fila del encabezado (porque en un par de otras vistas, esa misma propiedad flex hace un trabajo real, empujar un botón final hasta el borde). El contorno se estaba dibujando exactamente bien. Solo estaba delineando la caja equivocada: todo el espacio estirado del encabezado en vez de las tres palabras de texto que había adentro.

El arreglo no tocó el layout para nada. Envolví el texto del encabezado en un span interno, dejé el contorno fuera del elemento exterior, y apunté el estilo de :focus-visible al span interno en su lugar:

h2:focus-visible { outline: none; }
h2:focus-visible .heading-text { outline: 2px solid var(--focus-ring); outline-offset: 4px; }

Un span es en línea por defecto, así que se ajusta a su propio contenido sin importar lo que el elemento padre esté haciendo con el layout. El encabezado sigue cumpliendo su función (empujar ese botón final hacia la derecha), el objetivo del foco no se movió, y el anillo ahora abraza tres palabras en vez de toda una fila de encabezado.

Un caso no encajaba en ese patrón para nada: la vista principal del panel enfoca toda su grilla de contenido, no un solo encabezado, al salir de una subvista, no hay ningún “texto” al cual reducir un contorno, porque la región ES lo que recibió el foco. Primero intenté ajustar ahí el mismo contorno de caja (moviendo el offset hacia adentro unos píxeles) y no ayudó ni un poco a esa escala, un rectángulo gigante unos píxeles más chico sigue siendo un rectángulo gigante. Lo que en realidad funcionó fue descartar el modelo de caja por completo para ese caso y usar en su lugar una fina línea de acento interior solo a lo largo del borde superior. Problema distinto, forma de arreglo distinta, intentar reusar el truco de “achicar la caja” donde no había caja que achicar fue la jugada equivocada.

Documenté tanto la limitación de hasFocus() en WebDriver como el truco del span interno para acotar el contorno en la base de conocimiento, para no tener que volver a deducir ninguno de los dos la próxima vez.

Lecturas relacionadas

Development

Un anillo de foco que no debía estar a máxima intensidad

Una línea verde brillante debajo de la barra superior en cada inicio, un intento de captura de pantalla que terminó mostrando las ventanas equivocadas, y una muestra de color que probó las matemáticas del color pero no la respuesta.

Leer
Development

Cuando el texto importante es el que desaparece

Una tarjeta de kanban con una etiqueta de etapa, un chip de abandono, una insignia Disponible, y sin nombre. Flexbox no sabe que "achicarse con gracia" y "achicarse hasta nada" son resultados distintos.

Leer