3 puntos por GN⁺ 2023-12-03 | 1 comentarios | Compartir por WhatsApp
  • Al implementar funcionalidades web, conviene revisar primero las tecnologías menos potentes en el orden HTML, CSS y JavaScript, ya que eso ayuda a reducir fallas de carga y problemas de accesibilidad
  • JavaScript puede controlar directamente el comportamiento del navegador, pero por los recursos adicionales que requiere y la posibilidad de errores, es fácil que los usuarios de teclado y de tecnologías de asistencia queden excluidos
  • Funciones que antes requerían JavaScript, como interruptores con checkbox, datalist, input type="color", details/summary y dialog, ahora en gran parte ya pueden lograrse con funcionalidades nativas de HTML/CSS
  • Las capacidades declarativas de HTML y CSS permiten que el navegador se encargue del comportamiento nativo, las preferencias del usuario y la accesibilidad, ofreciendo mejores valores predeterminados
  • Aunque una implementación conocida en JavaScript siga funcionando, conviene revisar periódicamente las alternativas modernas en HTML/CSS y, al hacer cambios, acompañarlos con pruebas de accesibilidad

La regla del menor poder

  • La regla del menor poder es un principio de desarrollo web que indica elegir el lenguaje menos potente capaz de cumplir el objetivo
  • En la web, normalmente se aplica considerando primero HTML antes que CSS, y CSS antes que JavaScript
  • JavaScript es la más versátil de las tres tecnologías, pero también la más pesada
    • Puede romperse
    • Puede fallar al cargar
    • Requiere recursos adicionales para descargarse, analizarse y ejecutarse
    • Es fácil excluir a usuarios de teclado y a usuarios de tecnologías de asistencia
  • HTML y CSS funcionan de forma declarativa, a diferencia del JavaScript imperativo
    • El desarrollador le dice al navegador qué quiere, y el navegador decide cómo implementarlo
    • El navegador puede elegir una forma de procesamiento más eficiente
  • Cuando el navegador se encarga de las funciones de HTML/CSS, puede haber ventajas en rendimiento, comportamiento nativo, respuesta a las preferencias del usuario y accesibilidad
    • Aun así, la accesibilidad no siempre queda garantizada automáticamente

Funciones que antes requerían JavaScript

  • Los fabricantes de navegadores y quienes escriben las especificaciones han ido trasladando a CSS y HTML funciones que hasta hace unos años requerían JavaScript
  • Como la web mantiene la compatibilidad hacia atrás, una forma de implementación que aprendiste una vez suele quedarse en tu caja de herramientas y reutilizarse una y otra vez
  • Aunque creas que cierta función necesita JavaScript, vale la pena comprobar de vez en cuando si todavía es así, porque eso puede ayudarte a crear sitios web mejores

Interruptores personalizados con checkbox

  • Un interruptor personalizado puede implementarse con un checkbox nativo y CSS, en lugar de usar un div, un controlador onclick y estado interno
  • Si colocas un <input type="checkbox"> dentro de un <label>, el navegador conecta ambos
    • Hacer clic en cualquier parte de la etiqueta activa o desactiva el checkbox
    • No hace falta un controlador onclick aparte
  • appearance: none detiene el renderizado predeterminado de los controles de formulario del navegador y permite estilizarlo manualmente
    • El propio input puede decorarse como fondo del interruptor
    • ::before puede usarse como el punto interno que se mueve al alternar
  • La pseudoclase :checked permite cambiar el color de fondo y la posición de ::before según el estado marcado
  • Para usuarios de teclado, hace falta un indicador de foco
    • No es buena idea ocultar el foco con outline: none
    • :focus-visible permite mostrar un anillo de foco agradable solo durante la interacción con teclado
    • outline-offset permite ajustar el contorno de foco hacia afuera o hacia adentro del elemento
  • input:focus { outline-color: transparent; } hace transparente el contorno en condiciones normales, pero en modo de alto contraste puede volver a mostrarse con el color elegido por el usuario
  • Puedes ver más sobre el modo de colores forzados en forced colors explained

Autocompletado nativo con datalist

  • datalist es una función de sugerencias automáticas integrada en el navegador que muestra una lista de opciones mientras el usuario escribe
  • La estructura es simple
    • Se coloca un id y varios option dentro del elemento datalist
    • Se conecta con el atributo list del input
  • Cuando el usuario escribe, el navegador muestra un menú desplegable y filtra automáticamente las opciones según el contenido ingresado
  • Como sigue siendo un campo de entrada normal, también se puede escribir directamente un valor que no esté en la lista
  • Después de seleccionar el campo, se puede recorrer la lista con las teclas de flecha o hacer clic en el ícono desplegable que agrega el navegador para ver todas las opciones

Selector de color nativo con input type="color"

  • Con una sola línea, <input type="color"> permite usar el selector de color nativo del navegador
  • Puede reemplazar muchas interfaces en canvas y sliders hechas con JavaScript
  • En navegadores Chromium, el selector de color nativo permite elegir colores no solo dentro del sitio, sino en cualquier parte de la pantalla
  • Como no todos los usuarios pueden usar el selector de color del navegador, conviene ofrecer también otra forma de elegir el color, por ejemplo mediante una entrada de texto común

Acordeones con details y summary

  • Los elementos details y summary ofrecen un acordeón nativo del navegador para contraer y expandir contenido
  • El comportamiento básico es simple
    • El contenido dentro de details, excepto summary, queda oculto
    • Cuando el usuario hace clic en summary, se muestra el resto del contenido
  • El atributo open define el estado inicialmente abierto
    • No es un valor fijo después de la interacción; si el usuario abre o cierra, el estado cambia
  • summary::marker permite estilizar el marcador triangular predeterminado
    • Su contenido puede cambiarse por emoji u otros elementos
    • Se pueden ajustar el color de fondo, la imagen de fondo, el tamaño de fuente, etc.
    • Muchas propiedades CSS no funcionan, y hay limitaciones para estilos como colocarlo en una posición completamente distinta
  • En Safari se necesita el pseudoelemento ::-webkit-details-marker
  • Cambiar el contenido del marcador puede afectar la forma en que las tecnologías de asistencia anuncian el acordeón, así que puedes consultar details/summary inconsistencies
  • summary es clicable, pero por defecto no muestra un cursor tipo puntero como un enlace ni parece un botón, por lo que conviene agregar estados hover y focus para dejar claro que se puede pulsar

Modales con dialog

  • alert(), prompt() y confirm() permiten avisar algo al usuario o pedir confirmación, pero bloquean el hilo principal y son difíciles de estilizar para ajustarlos al diseño
  • Si construyes tu propio diálogo, manejar la accesibilidad se vuelve complejo
    • Hay que mantener el foco dentro del diálogo
    • Hay que indicar que es modal
    • Hay que evitar que el usuario salga accidentalmente
    • Puede entrar en conflicto con widgets que usan un z-index muy alto
  • El elemento dialog del navegador ofrece diálogos nativos
  • Actualmente todavía se necesita JavaScript para abrir un diálogo
    • Se está trabajando en cambios para abrirlo sin JavaScript, pero todavía no están completamente especificados ni implementados
    • Se puede abrir con la función showModal()
  • dialog se abre en la top layer
    • La top layer es una capa nueva separada del HTML
    • Los elementos en esta capa siempre se muestran por encima, sin importar el z-index ni el anidamiento de contextos de apilamiento
    • Para entender el concepto, puedes consultar Top layer en MDN
  • dialog no ofrece una interfaz de cierre predeterminada, así que hay que agregarla manualmente
    • Si se envía un form method="dialog", el navegador cierra el diálogo
    • Si a dos botones de envío se les da un value distinto, puede usarse como un diálogo de confirmación
    • En el evento close, puedes leer dialog.returnValue para saber qué botón pulsó el usuario
    • Los datos adicionales del formulario pueden leerse con FormData
  • dialog::backdrop es la capa entre el diálogo y el resto de la página
    • Puedes oscurecer o desenfocar el fondo para dirigir la atención del usuario al diálogo
    • Como el navegador se encarga de su colocación, no hace falta gestionar manualmente el scroll, los elementos fijos ni los cambios de tamaño de la ventana

Funciones posibles con menos JavaScript

  • Hay más funciones en las que se puede reducir el uso de JavaScript
    • Scroll suave nativo con scroll-behavior: smooth
      • con la condición de usarlo solo cuando prefers-reduced-motion: no preference se cumpla
    • Carruseles nativos con scroll-snap
    • Elementos “in-view” con position: sticky
    • Container queries
  • También hay funciones que llegarán más adelante
    • Animaciones basadas en scroll
    • Diseños Masonry con grid-template-rows: masonry sin masonry.js
    • Un select completamente estilizable mediante el nuevo elemento selectlist
    • El selector :has(), que puede reducir una categoría de código de selección en JavaScript
  • Puedes ver más sobre esto en la charla Stop Using JavaScript for That: Moving Features from JS to CSS and HTML.
  • Al cambiar una implementación ya probada por una forma nueva, especialmente, hay que probar la accesibilidad para no dejar a nadie fuera

1 comentarios

 
GN⁺ 2023-12-03
Comentarios de Hacker News
  • Lo que falta en este artículo es que la razón para usar JavaScript en estos casos es que ofrece mejor compatibilidad.
    El JavaScript nuevo se puede transpilar, pero hacer polyfill de funciones faltantes de CSS o HTML es mucho más difícil y, en algunos casos, imposible. Además, esos polyfills al final también usan JavaScript.
    Incluso en MDN hay muchas advertencias de probar a fondo appearance, incluso appearance: none. Si solo das soporte a navegadores modernos puede importar menos, pero las versiones antiguas de Safari siguen circulando más tiempo de lo que uno cree.
    datalist no hace absolutamente nada en Firefox Android, y para mí solo aparece como un campo de entrada sin siquiera sugerencias.
    El selector de color es genial, pero extremadamente no estándar, lo cual es fatal para la mayoría de los negocios. No es solo que los diseñadores se quejen: soporte al cliente también tiene más dificultades para ayudar a los usuarios. Chromium incluso permite tomar un color de la página o elegir uno arbitrario, pero Firefox Android solo ofrece algo como arcoíris, gris, blanco y negro.
    El propio artículo también reconoce las inconsistencias de details y dialog. Ojalá algún día dejen de usarse los navegadores que no soportan estas funciones, o que no las soportan de forma consistente entre sí, pero por ahora creo que estos elementos solo se usarán en proyectos personales donde se pueda controlar por completo qué navegadores se soportan.

    • Me cuesta estar de acuerdo con que el selector de color sea no estándar.
      En iPhone, al tocar el botón aparece el selector de color nativo real del sistema. Es el mismo control que proporciona el OS y que se ve en varias apps, y lo prefiero muchísimo más que uno hecho a medida.
    • Que la compatibilidad sea mejor solo es cierto si se asume que todos los usuarios deben usar JavaScript.
      Prefiero muchísimo más la web sin JavaScript, y además afecta la batería de la laptop por horas. Algunos sitios no son compatibles con esto y solo renderizan una página en blanco, o se quejan de que necesitan JavaScript para mostrar texto.
      En cambio Amazon incluso tiene una réplica de su sitio de e-commerce sin JavaScript, lo que demuestra que algo así de enorme es posible sin JavaScript.
    • El elemento dialog ya tiene una cobertura de soporte bastante amplia, y los polyfills para ese pequeño porcentaje de usuarios que usan Firefox o Safari de 2021 también son bastante aceptables.
      Si vas a crear un modal, lo recomiendo mucho; las mejoras de accesibilidad son excelentes.
    • Que soporte al cliente tenga más dificultades para ayudar a los usuarios es un punto importante.
      En mi trabajo anterior discutimos activamente este problema y decidimos usar una implementación en JS en lugar de cosas como datalist. En particular probamos datalist, pero los resultados eran tan inconsistentes que tuvimos que descartarlo.
      Al final, por las inconsistencias entre navegadores, incluso terminamos dejando de dar soporte a todo lo que no fuera Chrome.
    • No. JavaScript falla por completo cuando falla, y el contenido en sí desaparece.
      Los ejemplos en HTML pueden verse mal en navegadores antiguos, pero el contenido real sigue ahí. Con JS simplemente no hay nada. Rompe por completo la accesibilidad.
      Con HTML, un lector de pantalla al menos puede leerlo, pero el contenido generado con JS lo impide. Cuando JS no puede ejecutar JS, ningún polyfill ni otro JS puede rescatar a JS. Tiene que “funcionar” desde el principio para ser aceptable en accesibilidad, y en ese caso el argumento original deja de tener sentido.
  • No conocía Datalist, pero al menos en Chrome Android no parece funcionar correctamente.
    Las opciones sí aparecen en el área del teclado donde salen las sugerencias de autocompletado: https://imgur.com/a/Ecb4503
    Es la primera vez que veo algo así en un control de formulario de una UI web móvil, y no lo había visto salvo cuando una app de autocompletado de contraseñas usa el mismo espacio.
    No está mal. Es mucho mejor que desplazarse torpemente por un dropdown personalizado en JS hecho a medias, pero no estoy seguro de que un usuario común vaya a descubrir cómo usarlo. Por eso creo que en móvil, en la práctica, no tiene mucho futuro.
    En Firefox Android ni siquiera está soportado: https://caniuse.com/?search=datalist

    • Fabricantes de navegadores, ¿no podrían permitir un poco de estilizado en los dropdowns de datalist?
      Referencia: https://adrianroselli.com/2023/06/under-engineered-comboboxe...
    • Esta es la razón por la que este tipo de soluciones tarda tanto en adoptarse ampliamente.
      JavaScript está bastante bien estandarizado, pero HTML y CSS lo están menos en comparación.
    • Me pregunto si agregar autocomplete="off" al elemento input cambia el comportamiento.
      De todos modos, es necesario para usar datalist correctamente. Si no, el historial de selección de valores se añade a la lista desplegable. Lo observé en Chromium.
      Además, en algunas situaciones, como cuando hay un valor predeterminado establecido, datalist todavía necesita JS. Dejé documentados workarounds y notas de comportamientos particulares por navegador en el código del nuevo sitio web de LibreOffice: https://git.libreoffice.org/infra/libreofficeorg/+/835a5cc59...
      La buena noticia es que un desarrollador de Firefox planea revisar mejoras al comportamiento de datalist, así que quizá sea posible mostrar la lista con un solo clic.
    • ¿Miraste arriba del teclado?
      En mi caso, las opciones aparecen en el área sobre el teclado donde normalmente se muestran sugerencias de palabras.
    • Que las opciones de datalist aparezcan dentro del teclado es un cambio de los últimos meses.
      Antes era “normal”, pero parece que alguien quiso cambiarlo solo por cambiarlo.
  • Usar desplazamiento suave nativo con scroll-behavior: smooth debería hacerse, por favor, solo de forma limitada
    En más casos de los que uno cree no es una buena idea, y suele tener efectos secundarios no deseados
    Dicen que se puede crear un carrusel nativo con scroll-snap, pero los carruseles siguen siendo una mala idea, así que el ámbito legítimo de uso de scroll-snap es extremadamente limitado
    Las páginas que usan animaciones basadas en el scroll por lo general mejoran si se les quita eso

    • El punto de este artículo no es indicar qué elementos de diseño usar, sino mostrar cómo implementar esos diseños de una forma más amigable para el usuario
      El desplazamiento suave es un buen ejemplo. La API nativa permite que el usuario lo interrumpa cuando quiera. La mayoría de las implementaciones en JS se traban horriblemente y hacen sufrir al usuario
      Puedes criticar todo lo que quieras las decisiones de diseño, pero si no presentas razones reales para decir que “los carruseles siguen siendo malos”, es difícil esperar que te hagan caso
    • Yo también odio los carruseles
      Pero la página de inicio de Amazon usa carruseles de forma muy visible, y tengo entendido que Amazon prueba sin piedad variantes de su página de inicio con A/B testing. Entonces es posible que los carruseles hayan salido bien en las pruebas, y es ambiguo decir que realmente son “malos” en algún sentido universal u objetivo
    • ¿Por qué el desplazamiento suave nativo no es una buena idea en la mayoría de los casos?
      Normalmente, justo después de implementar anclas al estilo de una tabla de contenidos, al menos suelo agregarlo
    • De todos modos, para esas cosas no hace falta JavaScript
  • Sorprende que en 2023 todavía estemos peleando por los formularios y la UX general donde el usuario ingresa datos
    Basta ver los comentarios sobre datalist y los selectores de color; no entiendo por qué esto todavía no es un área resuelta
    Antes hubo un intento de resolverlo de una vez con XForms, pero no se implementó en los navegadores
    En cambio, casi todos los frameworks de componentes CSS/JS ofrecen cada uno su propio conjunto limitado de elementos de formulario con semánticas distintas

    • Como resultado de rechazar las tecnologías XML, la web quedó condenada a reimplementar eternamente versiones pésimas de lo que XML ofrecía
      Parece que nos pasaremos la vida implementando a mano controles básicos de UI
    • Ya está resuelto. Mételo en React y sigue con tu vida
      Que “no está resuelto” solo parece así porque algunas personas, por su extraña obsesión con evitar JavaScript, intentan encajar a la fuerza alternativas a medio cocinar
    • ¿Qué significa que los formularios estén “resueltos”?
      Si te quedas con tecnología aburrida y básica, ya están resueltos. Pero si insistes en resolverlos otra vez con React, luego otra vez con React hooks, y así infinitamente, entonces pasan a no estar resueltos
    • Por CSRF hay algunas cosas que una persona sí puede hacer, pero nosotros no
      La intención no es algo que pueda determinarse programáticamente, así que en ciertas situaciones no podemos tener funciones elegantes
      En el último formulario complejo en el que trabajé, tuve que hacer que un evento de clic provocara el envío del formulario de forma bastante directa para que el navegador lo permitiera
    • Los formularios no están resueltos porque alguien, en algún lugar, quiere enviar cosas distintas con formularios
      Nunca pedí una forma de enviar colores a través de una página web
  • Si usas details en lugar de JavaScript, Ctrl+F puede buscar dentro y abrirlo
    Un acordeón hecho con JavaScript no puede abrirse así

    • Con hidden="until-found" eso también es posible en acordeones basados en JS u otro contenido oculto, pero lamentablemente por ahora solo está en navegadores basados en Chromium: https://developer.chrome.com/articles/hidden-until-found/
    • ¿Hay otra forma de ocultar algo y al mismo tiempo permitir que se busque?
    • Me acaba de pasar un problema parecido mientras revisaba un documento
  • Estoy de acuerdo con la mayoría, pero no he usado lo suficiente dialog como para opinar, y creo que datalist no es una opción válida si no es para herramientas internas
    Es feo, tiene capacidades limitadas y no se le puede aplicar estilo. Ese es el problema de la mayoría de los argumentos de “simplemente usa lo incorporado”. Lo mismo pasa con el date picker
    No solo los valores predeterminados son malos, sino que tampoco puedes cambiarlos aunque quieras. Si te topas con una de las muchas paredes al cambiar el estilo o el comportamiento, por ejemplo querer que la semana empiece en lunes, no puedes. Entonces la opción suele ser una biblioteca de reemplazo completa usando JS
    Estoy a favor de usar opciones más ligeras y coincido con la jerarquía HTML > CSS > JS, pero para tener una UI agradable y todas las funciones que quieres, a veces JS es la única respuesta

    • Mientras implementaba un cuadro de sugerencias de búsqueda, pensé que datalist podría servir
      Funcionaba bien hasta el momento en que quise mostrar opciones que no empezaran estrictamente con lo escrito. Por ejemplo, si hay un error tipográfico en la entrada, no se muestra ninguna opción
      Como no había forma de forzar que se mostraran todos los elementos, terminé eligiendo una lista ordenada
    • Siempre vale la pena recordar que extender el marcado semántico incorporado con JS es un enfoque orientado al futuro
      Cuando empecé en desarrollo web, los cambios tardaban hasta 10 años. IE6 también nos tenía atrapados a todos, pero el w3c de entonces tampoco tenía mucho poder. Ahora los cambios son rápidos
      El año que viene, tal vez sea posible dar estilo a datalist sin prefijos en los tres navegadores principales, pero si estás atado a una solución JS personalizada, el negocio no pagará el costo de reconstruirla
      Si extiendes funciones nativas con JS, cuando el soporte sea suficiente podrás quitar el JS a bajo costo. Usa ahora los controles nativos donde sean aceptables y aplica JS como si fuera un polyfill
    • La mayoría de las personalizaciones que suelen proponerse para el día de inicio de la semana o para input[type=date] es mejor que no estén bajo control del desarrollador
      El calendario apropiado que se muestra debería depender del locale. La plataforma del usuario ya tiene la capacidad de configurarlo y mostrarlo de la forma que es más probable que el usuario pueda usar eficazmente
      El selector de fecha de la plataforma es mejor que alguna cosa rara hecha a mano
  • Ese botón de alternar está buenísimo
    Parece que los desarrolladores frontend de memes se están enojando con este artículo, pero el punto central es correcto. ¿Por qué se hacen tantos sitios absurdos con JS? Si la gente siguiera un solo estándar como HTML, todo podría ser consistente, y cosas como la accesibilidad o la traducción también serían fáciles de ajustar
    Hoy en día entras a un sitio y, como cargan todo dinámicamente en una sola página, ni siquiera funciona el botón de atrás

    • Aunque la gente siguiera un solo estándar como HTML, los fabricantes de navegadores tendrían que implementarlo de forma consistente
      Y sigue existiendo el problema de “esperar a que la gente actualice”, en el que pueden pasar años desde que se introduce una función nueva hasta que tenga soporte lo bastante amplio como para ser útil
      En general estoy de acuerdo en que hay muchas implementaciones malas y artilugios complejos en JavaScript. Hay bastantes soluciones estandarizadas para mantener la función de volver atrás incluso con contenido dinámico, y tengo entendido que los frameworks web populares las soportan por defecto
    • ¿De verdad se están enojando?
      Leí los comentarios principales, pero no veo mucho que pueda llamarse enojo; solo veo gente planteando puntos válidos sobre el soporte de los navegadores
  • Es un paso en la dirección correcta, pero CSS también es otra herramienta que los “artistes” de los que hablaba Philip Greenspun usan indebidamente para crear páginas difíciles de leer
    No soy partidario de Gemini, pero básicamente todos los aspectos del layout y la tipografía deberían volver al navegador y quedar bajo control del usuario. Los diseñadores han demostrado una y otra vez que no se puede confiar en ellos para eso

  • Me gusta la intención, el switch está genial y summary/details también son útiles a veces
    Pero el elemento datalist casi nunca es una opción realista para algo que vaya más allá de un juguete o prototipo

  • Mis cosas favoritas de “CSS alcanza sin JS” son los drawers de barra lateral y los carruseles
    La biblioteca de componentes TailwindCSS llamada DaisyUI también tiene componentes listos para usar
    https://daisyui.com/components/drawer/
    https://daisyui.com/components/carousel/

    • ¿Cómo se anuncia el drawer a un lector de pantalla?
      El drawer y el resto del contenido que aparece en la página deben anunciarse, y junto al control debería estar el estado aria-expanded
      Sigue siendo una pregunta real. Tal vez haya una forma, o tal vez los desarrolladores colectivamente piensen que no es importante. Aunque los auditores no estarían de acuerdo
    • Cuando veo frameworks así, al principio siempre me entusiasman, pero como todos los otros frameworks que he probado, DaisyUI también tiene varios problemas en iOS Safari y otros navegadores
      Creo que los autores de estos frameworks subestiman muchísimo cuántas pruebas hacen falta para que realmente funcionen en todos los navegadores
      Con tantos componentes y, además, la posibilidad de usar temas, tampoco es seguro que se puedan corregir sin romper temas y aplicaciones existentes
    • Es la primera vez que veo “Snap to [start|center|end]” en components/carousel/
      ¿Qué diablos es snap y cómo funciona? Mi pantalla no responde a clics con el dedo
      No creo que un modo de interacción desconocido sea una buena base para recomendar una biblioteca de elementos de UI