Acessibilidade (a11y) é uma habilidade crítica para desenvolvedores trabalhando com qualquer stack de tecnologia. Especificamente no front-end, CSS moderno fornece recursos que podemos aproveitar para tornar os layouts mais acessíveis e inclusivos para pessoas de todas os níveis de habilidades, em qualquer tipo de dispositivo.
O que significa “acessível”?
Sites acessíveis são aqueles criados sem barreiras para que pessoas de vários níveis de habilidades acessem o conteúdo ou executem ações. Um padrão aceito internacionalmente, denominado Web Content Accessibility Guidelines (WCAG) fornece critérios de sucesso para ajudar a orientar na criação de experiências acessíveis.
Alguns exemplos de barreiras comuns de acessibilidade são:
- Incapacidade de ver o conteúdo ou distinguir elementos da interface devido a baixo contraste de cores;
- Acesso reduzido ou removido a conteúdo não textual, como imagens ou gráficos, devido a falhas em fornecer textos alternativos;
- Pessoas que usam primariamente o teclado “presas” no site devido a não gerenciamento do foco para elementos interativos;
- Determinados tipos de movimentos e animações causando dores de cabeça (ou pior) em pessoas com distúrbios vestibulares;
- Impedimento de pessoas que usam tecnologias assistivas, como leitores de tela, executarem ações devido à falha em desenvolver controles personalizados acomodarem padrões esperados;
- Limitação dos métodos de navegação de tecnologias assistivas comuns devido ao não uso de HTML semântico, incluindo hierarquia de títulos e elementos de referência (landmark elements).
Os Critérios de Sucesso (Success Criteria) “são projetados para serem amplamente aplicáveis às tecnologias da Web atuais e futuras, incluindo aplicativos dinâmicos, celular, televisão digital etc.”.
A seguir, veja a análise de alguns critérios de sucesso e como o CSS moderno ajuda a fornecer soluções acessíveis.
Visibilidade do foco (Focus visibility)
Uma violação de CSS dos critérios de acessibilidade muito comum é remover :focus
em links, botões e outros controles interativos. Sem fornecer uma alternativa ao estilo de :focus
, isso é imediatamente uma violação do Critério de Sucesso 2.4.11 das WCAG: Aparência de Foco (Focus Appearance).
Comumente, a razão pela qual ele é removido é devido à sensação de que o estilo nativo do navegador não é atraente ou não se encaixa nas opções de design do meta. Mas, com CSS moderno, surge uma nova propriedade que pode ajudar a tornar os contornos mais atraentes.
Ao usar outline-offset
, é possível fornecer um valor positivo para posicionar o contorno longe do elemento. Para o deslocamento (offset), usa-se a unidade CSS em
para posicionar o contorno em relação ao elemento com base no font-size
.
1 2 3 4 |
button:focus { outline: max(1px, 0.1em) solid currentColor; outline-offset: 0.25em; } |
Como alternativa, é possível definir o outline-offset
usando um valor negativo para inserir o contorno do perímetro do elemento.
1 2 3 4 |
button:focus { outline: max(1px, 0.1em) dashed currentColor; outline-offset: -0.25em; } |
Há, também, uma nova pseudo-classe que pode ter o uso considerado em algumas circunstâncias para melhorar bastante a questão de acessibilidade com CSS.
A pseudo-classe :focus-visible
exibirá um outline (ou outro estilo definido) somente quando o dispositivo/navegador (user agent) determinar que ele precisa estar visível. Normalmente, isso significa que ele aparecerá para usuários de teclado na interação com a tecla de tabulação, mas não para quem usa mouse.
Fazendo essa atualização no snippet, os estilos de botão provavelmente só serão exibidos quando ocorrer o foco através da tecla Tab:
1 2 3 4 5 6 7 8 |
button:focus { outline: none; } button:focus-visible { outline: max(1px, 0.1em) dashed currentColor; outline-offset: -0.25em; } |
O suporte a :focus-visible
, apesar de já bem decente, ainda não é total (na data da publicação deste artigo), então, para uma abordagem progressive enhancement, é possível usar:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
button:focus { outline: max(1px, 0.1em) dashed currentColor; outline-offset: -0.25em; } button:focus:not(:focus-visible) { outline: none; } button:focus-visible { outline: max(1px, 0.1em) dashed currentColor; outline-offset: -0.25em; } |
Foco vs. Source Order
Outro critério importante de CSS para acessibilidade, relacionado com foco é o Critério de Sucesso 2.4.3: Ordem do Foco. Para usuários visuais e não visuais, a ordem do foco — que, normalmente, é iniciada pela tabulação do teclado — deve prosseguir logicamente.
Particularmente, para usuários visuais, a ordem do foco deve seguir um caminho esperado, o que geralmente significa seguir a ordem da fonte (source order).
Como consta na documentação citada:
Por exemplo, um usuário de leitor de tela interage com a ordem de leitura determinada de maneira programática, enquanto um usuário de teclado com visão interage com a apresentação visual da página Web. Deve-se tomar cuidado para que a ordem do foco faça sentido para ambos os conjuntos de usuários e não pareça, para nenhum deles, alternar aleatoriamente.
CSS moderno oferece propriedades de layout (CSS Grid, Flexbox) para reorganizar a ordem visual (visual order) em algo diferente da ordem de origem (source order). O impacto disso é potencialmente falhar no critério de sucesso da ordem de foco se houver elementos focalizáveis que estão sendo reorganizados em uma ordem surpreendente.
A ideia ao comentar sobre isso é mais fornecer consciência desse critério ao considerar como resolver determinados desafios de layout.
Como adendo, leia o artigo de Manuel Matuzovic tem um guia excelente com considerações de layout de CSS Grid e alteração da ordem de origem.
Desktop Zoom e Reflow
Comumente, devs testamos vários tamanhos de viewport usando ferramentas de desenvolvimento de navegador (DevTools), bem como em dispositivos móveis reais, e ficamos satisfeitos com o comportamento responsivo do projeto.
Mas, provavelmente, você está perdendo um ponto de teste: zoom da área de trabalho (desktop zoom).
Segundo o Critério de Sucesso das WCAG 1.4.10: Reflow:
Reflow é o termo usado para oferecer suporte a zoom da área de trabalho de até 400%. Em uma resolução de 1280px de largura a 400%, o conteúdo da viewport é equivalente a 320 pixels CSS de largura. A intenção de um usuário com esta configuração é acionar o conteúdo para refluir em uma única coluna para facilitar a leitura.
Normalmente, o zoom começa a acionar o comportamento responsivo definido através de media queries. Mas, atualmente, não há media queries de zoom. Consequentemente, a proporção da imagem de uma área de trabalho com zoom de 400% pode causar problemas de reflow no conteúdo.
Alguns exemplos de possíveis problemas:
- Navegação sticky que cobre metade (ou mais) da viewport;
- Resultados indesejados ao usar técnicas de tipografia fluida;
- Problemas de overflow ou overlap que cortam o conteúdo;
- Espaçamento de
margin
epadding
parecendo muito grandes em relação ao tamanho do conteúdo; - etc.
Sem uma media query de zoom, pode ser difícil conceber soluções de zoom que sejam independentes das suposições de tamanho da viewport.
No entanto, com funções CSS modernas como min()
e max()
, há maneiras de resolver algumas questões de zoom sem prejudicar a intenção original do planejamento mobile.
Para um exemplo prático, veja a situação de controle de espaço vertical. Uma prática comum é os designers criarem um “escala” (pixel ramp) para espaçamento, talvez com base em uma unidade de 8 pixels. Então, podem surgir utilitários de espaçamento semelhantes a:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.margin-top-xs { margin-top: 8px; } .margin-top-sm { margin-top: 16px; } .margin-top-md { margin-top: 32px; } .margin-top-lg { margin-top: 64px; } .margin-top-xl { margin-top: 128px; } |
E assim por diante, para acomodar toda a extensão da “rampa”. Isso, geralmente, funciona em uma variedade padrão de dispositivos, mas considere que o valor xl
(128px
) em uma área de trabalho com zoom de 400% torna-se a metade da altura da viewport!
Em vez disso, é possível atualizar a extremidade superior do intervalo com min()
para selecionar o menor valor calculado. Isso significa que, para janelas de exibição sem zoom, 128px
será usado e, para viewports com zoom de 400%, um valor de unidade de viewport alternativo pode ser usado:
1 |
margin-top: min(128px, 15vh); |
Tamanho de alvos interativos (Sizing Interactive Targets)
Também é importante considerar o tamanho adequado de alvos interativos, em que o termo “alvo” vem do Critério de Sucesso 2.5.5: Tamanho do Alvo:
A intenção deste critério de sucesso é garantir que os tamanhos de alvo sejam grandes o suficiente para que os usuários os ativem facilmente, mesmo se o usuário estiver acessando o conteúdo em um pequeno dispositivo portátil com tela de toque, tiver destreza limitada ou tiver problemas para ativar pequenos alvos por outros motivos . Por exemplo, mouses e dispositivos apontadores semelhantes podem ser difíceis de usar para esses usuários, e um alvo maior os ajudará a ativar o alvo.
Apresentado nas WCAG 2.2 está o Critério de Sucesso 2.5.8: Espaçamento do Alvo do Indicador. Juntos, a orientação indica que os controles geralmente interativos devem:
- Ter um tamanho mínimo de 44 px; ou
- Permitido um tamanho mínimo (incluindo o espaçamento entre o controle e outros elementos) de 44px.
É bastante comum ter que alternar tipos de interação com base no tipo de dispositivo usado. Pode ser bastante útil saber como detectar touch com CSS puro.
Movimento (Motion) Reduzido
Sabia que algumas pessoas podem ter distúrbios vestibulares e correr o risco de dores de cabeça, náusea ou até convulsões devido ao movimento e animações piscando?
Existem 3 critérios principais:
- Critério de Sucesso 2.3.1: Três flashes ou abaixo do limite. As páginas da Web não contêm nada que pisque mais do que 3 vezes em qualquer período de 1 segundo, ou o flash está abaixo dos limites gerais de flash vermelho;
- Critério de Sucesso 2.3.2: Três Flashes. Páginas da Web não contêm nada que pisque mais de 3 vezes em qualquer período de 1 segundo;
- Critério de Sucesso 2.3.3: Animação de Interações. A animação de movimento acionada pela interação pode ser desativada, a menos que a animação seja essencial para a funcionalidade ou a informação que está sendo transmitida.
CSS moderno oferece uma media feature que pode ser usada para testar a preferência definida pelo sistema operacional do usuário sobre o movimento. Embora suas animações/transições de base devam atender aos limites relacionados ao flash conforme observado nos critérios WCAG, é possível evitá-los totalmente se um usuário preferir movimento reduzido.
Aqui está uma regra rápida definida para lidar globalmente com isso, cortesia do Modern CSS Reset:
1 2 3 4 5 6 7 8 9 10 11 12 |
/* Remove todas as animações e transições para pessoas que preferem não vê-los */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } |
As animações são executadas uma vez e todas as transições acontecerão instantaneamente. Em alguns casos, você desejará planejar animações para essa possibilidade para garantir que elas “congelem” no quadro desejado.
É possível testar os resultados dessa media feature no Chrome, abrindo as DevTools e selecionando o menu kebab (3 pontos verticais), depois em “Mais ferramentas” e “Renderização”. Em seguida, você pode alternar as configurações na seção “Emular o recurso de mídia CSS prefere movimento reduzido”.
Cor e contraste
Dark mode parece uma moda passageira, mas para alguns usuários é essencial para garantir que eles possam ler seu conteúdo. Embora, atualmente, não haja diretrizes instruindo que os modos escuro e claro para o conteúdo sejam necessários, é possível começar a se preocupar com o futuro considerando a oferta de ambos os modos.
O que é um requisito é que, se você oferecer o modo escuro, continue a passar pelo menos nas diretrizes de contraste de cor padrão disponíveis no Critério de Sucesso 1.4.3: Contraste (Mínimo).
As taxas de contraste mínimas a serem atendidas são de, pelo menos:
- 4.5:1 para texto normal;
- 3:1 para texto grande — definido como 18.66px e negrito ou maior, ou 24px e maior;
- 3:1 para gráficos e componentes de interface do usuário (como bordas de inputs formulário).
Independentemente de você fornecer ou não o modo claro e escuro, os usuários de dispositivos Windows 10 podem selecionar uma configuração do sistema para habilitar o Modo de Alto Contraste (High Contrast Mode).
Na maioria dos casos, você deve permitir que as configurações do usuário neste modo sejam aplicadas. Ocasionalmente, a aplicação das configurações de alto contraste significa que as cores que são importantes para a compreensão da sua interface serão removidas.
Existe uma lista completa de propriedades afetadas por este modo de “cor forçada”, mas 3 propriedades frequentemente críticas que geralmente serão removidas no Modo de alto contraste do Windows são:
box-shadow
;background-color
;background-image
a menos que haja um valorurl()
.
E 2 propriedades críticas que terão suas cores trocadas pelo equivalente da “cor do sistema” (system color):
color
border-color
Às vezes, essas propriedades podem ser compensadas usando alternativas transparentes. Por exemplo, se você estiver usando box-shadow
como uma alternativa para o outline
a fim de combinar o border-radius
em :focus
, ainda é preciso incluir um outline
com o valor de cor definido como transparent
como o complemento para manter o estilo :focus
para forçado modos de cor.
Se você estiver usando ícones SVG, passar currentColor
como o valor de fill
ou stroke
ajudará a garantir que eles respondam às configurações de cores forçadas.
Conclusão
Apesar de parecer que não, acessibilidade e CSS (a11y+CSS) podem andar juntos para prover experiências excelentes de uso para todos os visitantes de um projeto Web.
Acessibilidade na Web ainda é bastante negligenciada, especialmente, aqui, no Brasil. Cabe a nós, desenvolvedores, estudarmos sobre o assunto para conseguirmos avaliar melhor os impactos de implementações acessíveis para os projetos.
Os tópicos deste artigo clareiam muita coisa sobre CSS e acessibilidade e como eles podem (e devem) andar juntos.