3 pontos por GN⁺ 2023-12-03 | 1 comentários | Compartilhar no WhatsApp
  • Ao implementar recursos na web, é melhor considerar primeiro as tecnologias menos poderosas na ordem HTML, CSS e JavaScript, pois isso ajuda a reduzir falhas de carregamento e problemas de acessibilidade
  • O JavaScript permite controlar diretamente o comportamento do navegador, mas, por exigir recursos extras e trazer possibilidade de erros, tende a excluir com mais facilidade usuários de teclado e de tecnologias assistivas
  • Recursos que antes exigiam JavaScript, como switches com checkbox, datalist, input type="color", details/summary e dialog, agora podem em grande parte ser feitos com funcionalidades nativas de HTML/CSS
  • Os recursos declarativos de HTML e CSS permitem que o navegador cuide do comportamento nativo, das preferências do usuário e da acessibilidade, oferecendo padrões melhores
  • Mesmo que implementações familiares em JavaScript ainda funcionem, vale revisar periodicamente as alternativas modernas em HTML/CSS e, ao trocar, fazer também testes de acessibilidade

Regra do menor privilégio

  • A regra do menor privilégio é um princípio de desenvolvimento web que diz para escolher a linguagem menos poderosa capaz de cumprir o objetivo
  • Na web, isso normalmente é aplicado considerando primeiro HTML antes de CSS, e CSS antes de JavaScript
  • JavaScript é a mais versátil das três tecnologias, mas também a mais custosa
    • Pode quebrar
    • Pode falhar ao carregar
    • Exige recursos extras para download, parsing e execução
    • Pode excluir com facilidade usuários de teclado e de tecnologias assistivas
  • HTML e CSS funcionam de forma declarativa, ao contrário do JavaScript imperativo
    • O desenvolvedor diz ao navegador o que quer, e o navegador escolhe como implementar
    • O navegador pode escolher uma forma de processamento mais eficiente
  • Quando o navegador lida com recursos de HTML/CSS, isso pode ser vantajoso em desempenho, comportamento nativo, respeito às preferências do usuário e acessibilidade
    • Ainda assim, acessibilidade nem sempre é garantida automaticamente

Recursos que antes exigiam JavaScript

  • Fabricantes de navegadores e autores de especificações vêm migrando para CSS e HTML recursos que até poucos anos atrás exigiam JavaScript
  • A web mantém compatibilidade retroativa, então uma forma de implementação aprendida uma vez tende a permanecer na caixa de ferramentas e ser reutilizada
  • Mesmo que você ache que certo recurso precisa de JavaScript, vale conferir de tempos em tempos se isso ainda é verdade para criar sites melhores

Switch customizado com checkbox

  • Um switch customizado pode ser implementado com um checkbox nativo e CSS, em vez de div, manipulador onclick e estado interno
  • Ao colocar <input type="checkbox"> dentro de um <label>, o navegador associa os dois
    • Clicar em qualquer parte do rótulo alterna o checkbox
    • Não é preciso um manipulador onclick separado
  • appearance: none faz o navegador parar de renderizar o controle de formulário padrão, permitindo estilização manual
    • Dá para estilizar o próprio input como fundo do switch
    • ::before pode ser usado como o ponto interno que alterna
  • A pseudo-classe :checked permite mudar a cor de fundo e a posição do ::before conforme o estado marcado
  • Para usuários de teclado, é preciso indicação de foco
    • Esconder o foco com outline: none não é uma boa prática
    • :focus-visible permite mostrar um anel de foco bonito apenas em interações por teclado
    • Com outline-offset, dá para ajustar o contorno de foco para fora ou para dentro do elemento
  • input:focus { outline-color: transparent; } pode deixar o contorno transparente em situações normais e, em modo de alto contraste, fazê-lo reaparecer na cor escolhida pelo usuário
  • Você pode ver mais sobre modo de cores forçadas em forced colors explained

Autocompletar nativo com datalist

  • datalist é um recurso nativo do navegador de sugestão automática que mostra uma lista de opções enquanto o usuário digita
  • A estrutura é simples
    • Coloque um id e vários option dentro do elemento datalist
    • Conecte-o ao input pelo atributo list
  • Quando o usuário digita, o navegador mostra um dropdown e filtra automaticamente as opções de acordo com o conteúdo inserido
  • Como é um campo de entrada comum, também é possível digitar diretamente um valor que não esteja na lista
  • Depois de selecionar o campo, o usuário pode navegar pela lista com as setas ou clicar no ícone de dropdown adicionado pelo navegador para ver todas as opções

Seletor de cores nativo com input type="color"

  • Com apenas uma linha, <input type="color"> permite usar o seletor de cores nativo do navegador
  • Isso pode substituir muitas interfaces em canvas e sliders feitos com JavaScript
  • O seletor de cores nativo dos navegadores Chromium permite escolher cores não só dentro do site, mas em qualquer lugar da tela
  • Como nem todos os usuários conseguem usar o seletor de cores do navegador, é melhor oferecer junto outra forma de escolher a cor, como uma entrada de texto comum

Acordeão com details e summary

  • Os elementos details e summary oferecem um acordeão nativo do navegador para recolher e expandir conteúdo
  • O comportamento padrão é simples
    • O conteúdo dentro de details, exceto summary, fica oculto
    • Quando o usuário clica em summary, o restante do conteúdo é exibido
  • O atributo open define o estado inicial aberto
    • Ele não é um valor fixo após a interação do usuário; o estado muda conforme o usuário abre e fecha
  • summary::marker permite estilizar o marcador triangular padrão
    • Dá para trocar o conteúdo por emoji etc.
    • Dá para ajustar cor de fundo, imagem de fundo, tamanho da fonte etc.
    • Muitas propriedades CSS não funcionam, e há limitações para estilizações como posicioná-lo em um lugar completamente diferente
  • No Safari, é necessário o pseudo-elemento ::-webkit-details-marker
  • Alterar o conteúdo do marcador pode afetar a forma como tecnologias assistivas anunciam o acordeão, então vale consultar details/summary inconsistencies
  • summary é clicável, mas por padrão não mostra cursor de ponteiro como um link nem parece um botão, então é preciso adicionar estados de hover e focus para deixar claro que pode ser clicado

Modal com dialog

  • alert(), prompt() e confirm() podem avisar ou pedir confirmação ao usuário, mas bloqueiam a thread principal e são difíceis de estilizar para combinar com o design
  • Criar um diálogo manualmente torna a acessibilidade mais complexa
    • É preciso manter o foco dentro do diálogo
    • É preciso informar que ele é modal
    • É preciso impedir que o usuário saia dele por engano
    • Pode haver conflito com widgets que usam z-index muito alto
  • O elemento dialog do navegador fornece um diálogo nativo
  • Atualmente, ainda é preciso JavaScript para abrir o diálogo
    • Já existem mudanças em andamento para abrir sem JavaScript, mas isso ainda não foi totalmente especificado nem implementado
    • É possível abrir o diálogo com a função showModal()
  • dialog abre na top layer
    • A top layer é uma nova camada separada do HTML
    • Elementos nessa camada sempre aparecem por cima, independentemente de z-index e do aninhamento de contextos de empilhamento
    • Para entender o conceito, consulte Top layer na MDN
  • dialog não fornece interface de fechamento por padrão, então é preciso adicionar a sua própria
    • Quando um form method="dialog" é enviado, o navegador fecha o diálogo
    • Se você der value diferentes a dois botões de envio, poderá usá-lo como um diálogo de confirmação
    • No evento close, é possível ler dialog.returnValue para saber o valor do botão pressionado pelo usuário
    • Dados adicionais do formulário podem ser lidos com FormData
  • dialog::backdrop é a camada entre o diálogo e o restante da página
    • Dá para escurecer ou desfocar o fundo e direcionar a atenção do usuário ao diálogo
    • Como o navegador faz o posicionamento, não é preciso lidar manualmente com rolagem, elementos fixos nem redimensionamento da janela

Recursos possíveis com menos JavaScript

  • Há mais recursos em que é possível reduzir o uso de JavaScript
    • Rolagem suave nativa com scroll-behavior: smooth
      • Com a condição de usar isso apenas quando prefers-reduced-motion: no preference for verdadeiro
    • Carrossel nativo com scroll-snap
    • Elementos “in-view” com position: sticky
    • Container queries
  • Também há recursos que ainda vão chegar
    • Animações baseadas em scroll
    • Layout Masonry com grid-template-rows: masonry, sem masonry.js
    • Um select totalmente estilável com o novo elemento selectlist
    • O seletor :has(), que pode reduzir uma categoria de código JavaScript de seleção
  • Você pode ver mais no vídeo da apresentação Stop Using JavaScript for That: Moving Features from JS to CSS and HTML.
  • Ao trocar uma implementação já comprovada por uma abordagem nova, é especialmente importante testar a acessibilidade para não excluir ninguém

1 comentários

 
GN⁺ 2023-12-03
Comentários no Hacker News
  • O que este texto deixa de fora é que a razão para usar JavaScript nesses casos é a melhor compatibilidade
    JavaScript novo pode ser transpilado, mas é muito mais difícil — e, em alguns casos, impossível — aplicar polyfills para recursos ausentes de CSS ou HTML. Além disso, esses polyfills acabam usando JavaScript
    Mesmo no MDN, há muitos avisos para testar cuidadosamente appearance, até mesmo appearance: none. Se você só precisa dar suporte a navegadores modernos, isso pode ser menos importante, mas versões antigas do Safari continuam por aí por mais tempo do que se imagina
    datalist não faz nada no Firefox Android e, para mim, aparece apenas como um campo de entrada sem sequer sugestões
    O seletor de cores é legal, mas é extremamente não padronizado, o que é fatal para a maioria dos negócios. Não são só os designers que reclamam: o suporte ao cliente passa a ter dificuldade para ajudar os usuários. O Chromium até oferece a opção de capturar uma cor da página ou escolher uma cor arbitrária, mas o Firefox Android só dá algo como arco-íris, cinza e preto e branco
    O próprio texto também reconhece as inconsistências de details e dialog. Espero que um dia navegadores que não dão suporte a esses recursos, ou que não os suportam de forma consistente entre si, deixem de ser usados, mas por enquanto esses elementos parecem úteis apenas em projetos paralelos nos quais você consegue controlar totalmente os navegadores suportados

    • Acho difícil concordar que o seletor de cores seja não padronizado
      No iPhone, ao tocar no botão, aparece o seletor de cores nativo real do sistema. É aquele mesmo controle fornecido pelo SO e visto em vários apps, e eu o prefiro muito mais do que algo feito sob medida
    • A ideia de que a compatibilidade é melhor só é verdadeira quando se assume que todos os usuários precisam usar JavaScript
      Prefiro muito mais uma web sem JavaScript, e isso afeta a bateria do notebook em horas. Alguns sites não são compatíveis com isso e renderizam apenas uma página em branco, ou reclamam que precisam de JavaScript para mostrar texto
      Por outro lado, a Amazon também tem uma réplica do site de e-commerce sem JavaScript, mostrando que até algo enorme assim é possível sem JavaScript
    • O elemento dialog agora tem uma cobertura de suporte bastante ampla, e os polyfills para os poucos por cento de usuários que usam Firefox ou Safari da época de 2021 são bons o suficiente
      Se você estiver criando um modal, recomendo muito; as melhorias de acessibilidade são excelentes
    • A dificuldade do suporte ao cliente para ajudar usuários é um ponto grande
      No meu emprego anterior discutimos ativamente esse problema e decidimos usar uma implementação em JS em vez de algo como datalist. Em especial, tentamos datalist, mas os resultados eram tão inconsistentes que tivemos de abandonar
      No fim, por causa das inconsistências entre navegadores, também acabamos deixando de dar suporte a tudo que não fosse Chrome
    • Não. Quando JavaScript falha, ele falha por completo e o próprio conteúdo desaparece
      Nos exemplos em HTML, o visual pode ficar errado em navegadores antigos, mas o conteúdo real continua lá. Com JS, simplesmente não há nada. Isso quebra totalmente a acessibilidade
      Com HTML, um leitor de tela pelo menos consegue ler, mas conteúdo gerado por JS impede isso. Quando o JS não consegue executar JS, nenhum polyfill nem outro JS pode salvar o JS. Ele precisa “funcionar” desde o começo para ser aceitável em acessibilidade e, nesse caso, o argumento original perde o sentido
  • Eu não conhecia Datalist, mas pelo menos no Chrome Android ele não parece funcionar direito
    As opções aparecem na área do teclado onde surgem as sugestões de preenchimento automático: https://imgur.com/a/Ecb4503
    Nunca vi esse tipo de comportamento em controles de formulário de UI web móvel, exceto quando apps de preenchimento automático de senha usam o mesmo espaço
    Não é ruim. É muito melhor do que rolar desajeitadamente por um dropdown JS customizado malfeito, mas não tenho confiança de que um usuário comum vá descobrir como usar isso. Por isso, no mobile, considero praticamente sem futuro
    No Firefox Android, não há suporte nenhum: https://caniuse.com/?search=datalist

    • Fabricantes de navegadores, não dá para permitir um pouco de estilização no dropdown de datalist?
      Referência: https://adrianroselli.com/2023/06/under-engineered-comboboxe...
    • É por isso que soluções desse tipo demoram tanto para se popularizar
      JavaScript é bastante bem padronizado, mas HTML e CSS são relativamente menos
    • Fico curioso para saber se adicionar autocomplete="off" ao elemento input muda o comportamento
      De qualquer forma, isso é necessário para usar datalist corretamente. Caso contrário, o histórico de valores selecionados é anexado à lista do dropdown. Observei isso no Chromium
      Além disso, em certas situações, como quando há um valor padrão definido, datalist ainda precisa de JS. Documentei as soluções de contorno e observações sobre comportamentos específicos de navegadores no código do novo site do LibreOffice: https://git.libreoffice.org/infra/libreofficeorg/+/835a5cc59...
      A boa notícia é que um desenvolvedor do Firefox planeja analisar melhorias no comportamento de datalist, o que talvez permita exibir a lista com apenas um clique
    • Você olhou acima do teclado?
      No meu caso, as opções aparecem na área acima do teclado onde normalmente são mostradas sugestões de palavras
    • As opções de datalist aparecerem dentro do teclado é uma mudança que surgiu nos últimos meses
      Antes era “normal”, mas parece que alguém quis mudar só por mudar
  • Usar rolagem suave nativa com scroll-behavior: smooth deve, por favor, ser feito apenas de forma limitada
    Na maioria dos usos, é uma ideia pior do que parece e costuma ter efeitos colaterais indesejados
    Dizem que dá para criar um carrossel nativo com scroll-snap, mas carrosséis continuam sendo uma má ideia, então o escopo legítimo de uso de scroll-snap é extremamente limitado
    Páginas que usam animações baseadas em rolagem geralmente ficam melhores quando isso é removido

    • O ponto deste texto não é mandar usar algum elemento de design, mas mostrar como implementar esse design de forma mais amigável ao usuário
      A rolagem suave é um bom exemplo. A API nativa permite que o usuário interrompa a qualquer momento. A maioria das implementações em JS é terrivelmente engasgada e faz o usuário sofrer
      Dá para criticar escolhas de design à vontade, mas, se você não apresentar motivos reais para “carrosséis continuam sendo ruins”, é difícil esperar que alguém dê ouvidos
    • Eu também odeio carrosséis
      Mas a homepage da Amazon usa carrosséis de forma bem visível, e pelo que sei a Amazon faz testes A/B implacáveis em variações da homepage. Então é possível que os carrosséis tenham se saído bem nos testes, e fica meio ambíguo dizer que eles são realmente “ruins” em algum sentido universal e objetivo
    • Por que a rolagem suave nativa não é uma boa ideia na maioria dos casos?
      Normalmente, eu pelo menos a adiciono logo depois de implementar âncoras no estilo sumário
    • De qualquer forma, essas coisas de fato não precisam de JavaScript
  • É surpreendente que, em 2023, ainda estejamos brigando por causa de formulários e da UX comum em que o usuário insere dados
    Basta ver os comentários sobre datalist e seletores de cor; não entendo por que isso ainda não é uma área resolvida
    Antigamente houve uma tentativa de resolver tudo isso de uma vez com XForms, mas ela não foi implementada nos navegadores
    Em vez disso, praticamente todo framework de componentes CSS/JS oferece seu próprio conjunto limitado de elementos de formulário com semânticas diferentes

    • O resultado de rejeitar as tecnologias XML foi que a Web ficou condenada a reimplementar eternamente versões ruins do que o XML oferecia
      Parece que vamos passar a vida inteira implementando controles básicos de UI por conta própria
    • Isso já está resolvido. É só colocar no React e seguir a vida
      A impressão de que “não está resolvido” só existe porque algumas pessoas têm uma obsessão estranha em evitar JavaScript e tentam enfiar alternativas meio cruas à força
    • O que quer dizer que formulários foram “resolvidos”?
      Se você vai ficar em tecnologias básicas e sem graça, já está resolvido. Mas, se insistir em resolver de novo com React, depois resolver mais uma vez com React hooks e continuar resolvendo de novo para sempre, então passa a não estar resolvido
    • Por causa de CSRF, há algumas coisas que uma pessoa consegue fazer, mas nós não conseguimos
      Intenção não é algo que possa ser determinado por programa, então, em certas situações, não dá para ter recursos legais
      No último formulário complexo em que trabalhei, tive que fazer com que um evento de clique causasse o envio do formulário de maneira bem direta para que o navegador permitisse
    • Formulários não estão resolvidos porque alguém, em algum lugar, quer enviar coisas diferentes por meio de formulários
      Eu nunca pedi um jeito de enviar cores por uma página web
  • Se você usar details em vez de JavaScript, o Ctrl+F consegue pesquisar dentro dele e abri-lo
    Um acordeão em JavaScript não consegue abrir assim

    • Com hidden="until-found", isso também passa a ser possível em acordeões baseados em JS ou em outros conteúdos ocultos, mas infelizmente por enquanto só existe em navegadores baseados em Chromium: https://developer.chrome.com/articles/hidden-until-found/
    • Existe alguma outra forma de esconder, mas ainda permitir a busca?
    • Acabei de passar por um problema parecido enquanto examinava a documentação
  • Concordo com a maior parte, mas não usei dialog o bastante para ter uma opinião, e acho que datalist não é uma opção válida a menos que seja para ferramentas internas
    É feio, limitado no que permite fazer e também não dá para estilizar. Esse é o problema da maioria dos argumentos de “use simplesmente o que já vem embutido”. O mesmo vale para date picker
    O padrão não é apenas ruim; mesmo que você queira mudá-lo, não consegue. Quando você bate em uma das inúmeras paredes ao tentar mudar o estilo ou o comportamento, por exemplo querendo que a semana comece na segunda-feira, não dá. Aí a opção geralmente é uma biblioteca de substituição completa usando JS
    Sou a favor de usar opções mais leves e também concordo com a hierarquia HTML > CSS > JS, mas, para ter uma UI bonita e todos os recursos desejados, às vezes JS é a única resposta

    • Ao implementar uma caixa de sugestões de busca, pensei que datalist poderia ajudar
      Funcionou bem até o momento em que passei a querer exibir opções que não começam estritamente com o texto digitado. Por exemplo, se houver um erro de digitação na entrada, as opções não aparecem
      Como não havia como forçar a exibição de todos os itens, acabei optando por uma lista ordenada
    • Vale sempre lembrar que estender marcação semântica nativa com JS é uma abordagem voltada para o futuro
      Quando comecei no desenvolvimento web, mudanças levavam até 10 anos. O IE6 também segurava todos nós, mas o w3c também era bem fraco naquela época. Hoje as mudanças são rápidas
      No ano que vem, talvez seja possível estilizar datalist sem prefixos nos três principais navegadores, mas, se você estiver preso a uma solução JS personalizada, o negócio não vai pagar o custo de reconstrução
      Se você estender recursos nativos com JS, poderá remover o JS a baixo custo quando o suporte for suficiente. Use controles nativos agora onde forem aceitáveis e aplique JS como se fosse um polyfill
    • A maioria das personalizações normalmente sugeridas para o dia de início da semana ou para input[type=date] é melhor que o desenvolvedor não controle mesmo
      O calendário adequado a exibir deve ser dependente da localidade. A plataforma do usuário já tem a capacidade de configurar e exibir isso da forma que o usuário tem mais probabilidade de usar com eficiência
      O seletor de data da plataforma é melhor do que alguma coisa estranha feita à mão
  • Aquele botão de alternância é realmente ótimo
    Parece que os desenvolvedores de memes de frontend estão ficando irritados com este texto, mas o ponto central está correto. Por que tantos sites idiotas são feitos com JS? Se as pessoas seguissem apenas um padrão, como HTML, tudo poderia ser consistente, e coisas como acessibilidade ou tradução também poderiam ser atendidas facilmente
    Hoje em dia, quando você entra em um site, até o botão de voltar não funciona, porque tudo é carregado dinamicamente em uma única página

    • Mesmo que as pessoas sigam um único padrão, como HTML, os fabricantes de navegadores precisam implementá-lo de forma consistente
      E ainda existe o problema de “esperar as pessoas atualizarem”, em que, depois que um novo recurso é introduzido, pode levar anos até que ele tenha suporte amplo o suficiente para ser útil
      No geral, concordo que há muitas implementações ruins e engenhocas complexas em JavaScript. Existem várias soluções padronizadas para manter a funcionalidade de voltar mesmo com conteúdo dinâmico, e, pelo que sei, frameworks web populares oferecem suporte a isso por padrão
    • Eles estão mesmo indignados?
      Li os comentários no topo, mas não vi muita coisa que eu chamaria de indignação; só pessoas levantando pontos válidos sobre suporte dos navegadores
  • É um passo na direção certa, mas CSS também é outra ferramenta que os “artistes” de Philip Greenspun abusam para criar páginas difíceis de ler
    Não sou defensor do Gemini, mas basicamente todos os aspectos de layout e tipografia deveriam voltar para o navegador e ficar sob controle do usuário. Designers já demonstraram infinitas vezes que não dá para confiar isso a eles

  • Gosto da intenção, o switch é bacana, e summary/details também são úteis às vezes
    Mas o elemento datalist quase nunca é uma opção realista para usos além de brinquedos ou protótipos

  • As coisas que eu gosto de fazer “só com CSS, sem JS” são drawers de barra lateral e carrosséis
    A DaisyUI, uma biblioteca de componentes TailwindCSS, também tem componentes prontos para uso
    https://daisyui.com/components/drawer/
    https://daisyui.com/components/carousel/

    • Como você anuncia o drawer para um leitor de tela?
      O drawer e outros conteúdos que aparecem na página precisam ser anunciados, e deve haver um estado aria-expanded ao lado do controle
      Ainda é uma pergunta de verdade. Talvez exista um jeito, ou talvez os desenvolvedores coletivamente achem que isso não é importante. Auditores não concordariam
    • Quando vejo frameworks assim, sempre fico animado no começo, mas, como todos os outros frameworks que testei, a DaisyUI também tem vários problemas no iOS Safari e em outros navegadores
      Acho que os autores desses frameworks subestimam muito a quantidade de testes necessária para fazer tudo realmente funcionar entre navegadores
      Com tantos componentes e, além disso, a possibilidade de temas, é difícil garantir que será possível corrigir sem quebrar temas e aplicações existentes
    • Vi pela primeira vez o “Snap to [start|center|end]” em components/carousel/
      Afinal, o que é snap e como isso funciona? Minha tela não reage a cliques com o dedo
      Acho que um modo de interação desconhecido não é uma boa razão para recomendar uma biblioteca de elementos de UI