Acessibilidade além da sintaxe
Regras confirmam que a página tem título, o link tem texto e a imagem tem alt. Não percebem que “Untitled document”, “Click here” ou alt="img-1" não dizem nada. O Rampa roda o axe-core, pergunta a um modelo só o que as regras não decidem e só mantém um achado quando a evidência confere na página.
Código aberto, licença MIT. Funciona com modelo local ou com os grandes provedores.
Regras veem o atributo, não o que ele diz
Em fevereiro de 2026, 95,9% das home pages do milhão de sites mais acessados tinham falhas WCAG que ferramentas automáticas detectam, segundo o WebAIM Million. Essas são as fáceis.
Um título “Untitled document”, um “Click here” solto, um título “Section 2” em cima das avaliações, um alt que nomeia a coisa errada: verificadores de regras aprovam todos, porque o elemento está lá.
<img src="dog.svg" alt="img-1">alt="img-1".- axe-core
Aprova
A imagem tem texto alternativo. regra image-alt
- Rampa
Reprova
O texto alternativo "img-1" é um nome de arquivo ou um placeholder.
Evidência, encontrada na página:
img-1Sugestão no idioma da página:
alt="Ilustração de um cachorro marrom com coleira vermelha"
A sugestão é para uma pessoa revisar. O Rampa nunca reescreve a sua página.
Mais cinco que passam em todas as regras
| Na página | axe-core | Rampa |
|---|---|---|
WCAG 2.4.2 <title>Untitled document</title> | aprova | O título da página “Untitled document” não diz nada sobre esta página. |
WCAG 2.4.4 <a href="shipping.html">Click here</a> | aprova | O texto do link “Click here” não diz para onde o link leva, e nada ao redor diz. |
WCAG 2.4.6 <h2>Section 2</h2> | aprova | O título “Section 2” não diz nada sobre o conteúdo abaixo dele. |
WCAG 2.4.6 <label for="email">Field 1</label> | aprova | O rótulo “Field 1” não diz o que preencher. |
WCAG 3.1.1 <html lang="en">numa página em português | aprova | A página está marcada como lang="en", mas a maior parte do texto está em português (pt). |
Cada linha é um achado real dos exemplos da loja e da feira no repositório, com evidência e patch.
Um critério por vez, e só com evidência
Toda execução passa por cinco etapas. O modelo só vê o que as etapas anteriores não resolveram.
Coletar
A página vira um snapshot de acessibilidade normalizado: papéis, nomes, idiomas, estados e cada imagem como foi renderizada.
Regras primeiro
O axe-core roda na página. O que as regras decidem vai direto para o relatório, sem modelo nenhum.
Julgar o resíduo
O que as regras não decidem vai para um modelo: um prompt por critério WCAG, o menor contexto que responde à pergunta e uma resposta tipada.
Conferir a evidência
Toda alegação precisa citar um nó que existe e um texto que está de fato nele. A que não confere é descartada e contada, nunca mostrada.
Relatar a cobertura
Os achados vêm com patch, e o relatório lista o que ninguém verificou. Nunca declara uma página acessível.
Rode numa página
Uma página de loja com nove problemas. O axe-core pega a logo sem texto alternativo; os outros oito passam em todas as regras: três textos alternativos, o título da página, um link, um título de seção, um rótulo de campo e uma citação no idioma errado. Esta é a saída real de uma execução com modelo local.
rampa check examples/store/before.html examples/store/before.html Superfície: web · axe-core 4.14.0 · Modelo: ollama:gemma4:12b WCAG 1.1.1 (A) — Conteúdo não textual ✗ html > body > header > img Imagens devem ter texto alternativo alta · regra image-alt ✗ html > body > main > div > figure:nth-of-type(1) > img O texto alternativo "IMG_2034.jpg" é um nome de arquivo ou um placeholder. Evidência: "IMG_2034.jpg" Patch: - <img src="mug.svg" alt="IMG_2034.jpg"> + <img src="mug.svg" alt="Blue mug with steam"> confiança alta · 1/1 rodadas · evidência verificada · id 2c1d064d9cc7 ✗ html > body > main > div > figure:nth-of-type(2) > img O texto alternativo "Ceramic coffee mug" descreve algo que a imagem não mostra. Evidência: "Ceramic coffee mug" Patch: - <img src="umbrella.svg" alt="Ceramic coffee mug"> + <img src="umbrella.svg" alt="Pink umbrella in the rain"> confiança alta · 1/1 rodadas · evidência verificada · id 55249d898b55 ✗ html > body > main > div > figure:nth-of-type(3) > img O texto alternativo "product" é genérico demais para descrever a imagem. Evidência: "product" Patch: - <img src="plant.svg" alt="product"> + <img src="plant.svg" alt="Potted plant"> confiança alta · 1/1 rodadas · evidência verificada · id a2e0ae93ad7c WCAG 2.4.2 (A) — Página com título ✗ html O título da página "Untitled document" não diz nada sobre esta página. Evidência: "Untitled document" Patch: - <title>Untitled document</title> + <title>Corner Store - New Arrivals</title> confiança alta · 1/1 rodadas · evidência verificada · id a7fe7f746d48 WCAG 2.4.4 (A) — Finalidade do link (em contexto) ✗ html > body > main > p:nth-of-type(2) > a O texto do link "Click here" não diz para onde o link leva, e nada ao redor diz. Evidência: "Click here" Patch: - <a href="shipping.html">Click here</a> + <a href="shipping.html">View shipping information</a> confiança alta · 1/1 rodadas · evidência verificada · id 1af8a73e209d WCAG 2.4.6 (AA) — Cabeçalhos e rótulos ✗ html > body > main > h2:nth-of-type(1) O título "Section 2" não diz nada sobre o conteúdo abaixo dele. Evidência: "Section 2" Patch: - <h2>Section 2</h2> + <h2>Customer Reviews</h2> confiança alta · 1/1 rodadas · evidência verificada · id ef7716588da6 ✗ #email O rótulo "Field 1" não diz o que preencher. Evidência: "Field 1" Patch: - <label for="email">Field 1</label> + <label for="email">Email address</label> confiança alta · 1/1 rodadas · evidência verificada · id 064fe292df3a WCAG 3.1.2 (AA) — Idioma de partes ✗ html > body > main > blockquote:nth-of-type(1) Marcado como lang="es", mas o texto está em holandês (nl). Evidência: "Prachtige mok, de koffie blijft lang warm. Ik koop er zeker nog een!" Patch: - <blockquote lang="es"> + <blockquote lang="nl"> confiança alta · 1/1 rodadas · evidência verificada · id ade39251a2e7 Chamadas ao modelo: 13 novas, 0 do cache · 7,1 mil tokens de entrada / 0,9 mil de saída · modelo local, sem custo de API Cobertura desta execução Verificado pelo axe-core (parcial): 1.1.1, 1.3.1, 1.3.5, 1.4.3, 2.4.1, 2.4.2, 2.4.4, 3.1.1, 3.1.2, 3.3.2, 4.1.2 Julgado com evidência verificada: 1.1.1, 2.4.2, 2.4.4, 2.4.6, 3.1.1, 3.1.2 Não verificado automaticamente: 38 de 50 critérios WCAG 2.1 A/AA (--verbose lista) Este relatório não declara a página acessível. O que não foi verificado exige revisão manual e teste com pessoas.
Medido com os casos de teste do próprio W3C
O W3C publica casos de teste com o resultado esperado para cada regra de acessibilidade. O rampa eval roda o axe-core sozinho e o axe-core com o Rampa nas mesmas páginas, nos seis critérios.
| Conjunto | Testa | Casos | axe-core, precisão / recall | Rampa, precisão / recall / F1 |
|---|---|---|---|---|
| 1.1.1, imagem tem nome (ACT 23a2a8) | sintaxe | 18 | 1,00 / 1,00 | 1,00 / 1,00 / 1,00 |
| 1.1.1, nome descreve a imagem (ACT qt1vmo) | significado | 16 | não definida, nada apontado / 0,00 | 1,00 / 1,00 / 1,00 |
| 2.4.2, página tem título (ACT 2779a5) | sintaxe | 12 | 1,00 / 1,00 | 0,50 / 1,00 / 0,67 |
| 2.4.2, título descreve a página (ACT c4a8a4) | significado | 6 | não definida, nada apontado / 0,00 | 1,00 / 1,00 / 1,00 |
| 2.4.4, link tem nome (ACT c487ae) | sintaxe | 28 | 1,00 / 1,00 | 0,92 / 1,00 / 0,96 |
| 2.4.4, link é descritivo no contexto (ACT 5effbb) | significado | 18 | não definida, nada apontado / 0,00 | 0,67 / 1,00 / 0,80 |
| 2.4.6, título de seção é descritivo (ACT b49b2e) | significado | 12 | não definida, nada apontado / 0,00 | 0,80 / 1,00 / 0,89 |
| 2.4.6, rótulo de campo é descritivo (ACT cc0f0a) | significado | 16 | não definida, nada apontado / 0,00 | 1,00 / 0,83 / 0,91 |
| 3.1.1, página tem lang válido (ACT b5c3f8, bf051a) | sintaxe | 11 | 1,00 / 1,00 | 1,00 / 1,00 / 1,00 |
| 3.1.1, lang confere com a página (ACT ucwvc8) | significado | 14 | 0,00 / 0,00 | 0,50 / 1,00 / 0,67 |
| 3.1.2, lang válido em trechos (ACT de46e4) | sintaxe | 19 | 1,00 / 1,00 | 1,00 / 1,00 / 1,00 |
| 3.1.2, lang confere com o texto (ACT off6ek) | significado | 13 | não definida, nada apontado / 0,00 | 0,80 / 1,00 / 0,89 |
Quebre uma página de propósito e veja quem percebe
Cada par é uma página de teste que passa e uma cópia quebrada de propósito. Um alt vira img-1, o título vira “Welcome”, os títulos de seção viram “Part 1” e os rótulos “Entry 1”, um lang vira outro idioma válido. Nenhuma dessas palavras aparece nos prompts. Quem dá o mesmo veredito às duas versões não está julgando.
O método vem de López-Gil e Pereira (2025).
| Quebrado de propósito | Pares | axe-core, separou | Rampa, separou |
|---|---|---|---|
| Alt de imagem | 2 | 0 | 2 |
| Título da página | 3 | 0 | 3 |
| Títulos e rótulos | 9 | 0 | 8 |
| lang da página | 4 | 0 | 4 |
| lang em trechos | 5 | 0 | 4 |
| Todos os pares | 23 | 0 | 21 |
Numa GPU local, a avaliação não custa nada. Com o gpt-6-luna, os 36 julgamentos de 1.1.1 e 3.1.2 levaram 29 segundos e cerca de meio centavo de dólar, e duas rodadas com chamadas novas deram o mesmo veredito em todos os casos.
As amostras são pequenas e cada conjunto rodou uma vez. Os prompts dos quatro critérios novos foram ajustados depois de ler os erros deles nestes casos, então esses números são otimistas até páginas novas confirmarem. Duas precisões baixas são da contagem: o 2779a5 só pede que o título exista, e as páginas dele se chamam “Title of the page.”; o ucwvc8 conta como falso positivo páginas sem lang válido, que o axe-core reprova.
Roda no seu modelo
Escolha o modelo de cada critério com o rampa eval, não pela fama. Toda resposta fica em cache, então a mesma entrada nunca chama um modelo duas vezes.
Na sua máquina
Nada sai do seu computador, e não há custo de API.
- Ollama
- LM Studio
- Qualquer servidor compatível com a OpenAI, como vLLM ou llama.cpp
Com uma chave
Só o que as regras não decidiram sai da sua máquina.
- OpenAI
- Anthropic
- Google Gemini
- Azure OpenAI
- Amazon Bedrock
- Google Vertex AI
- Mistral AI
- xAI
- Groq
- DeepSeek
- Together AI
- Fireworks AI
- Cerebras
- OpenRouter
- Vercel AI Gateway
Escolha por opção, variável de ambiente ou arquivo de configuração:
$ rampa check https://example.com --model ollama:gemma4:12b
$ RAMPA_MODEL=openai:gpt-6-luna rampa check https://example.com
$ rampa modelsO que o Rampa não faz
- Declarar uma página acessível.
- Todo relatório lista o que foi verificado, o que foi julgado e o que ninguém verificou. Passar numa verificação não é o mesmo que ser acessível.
- Mostrar o que não consegue provar.
- A alegação de um modelo só chega a você se o nó citado existe e o trecho citado está nele.
- Afogar você em ruído.
- Falso positivo é o que faz equipes desligarem um verificador, então limiar de confiança, dispensas e votação entre rodadas fazem parte do projeto.
- Mexer nas suas páginas em produção.
- Não é overlay. Roda onde você constrói: na sua máquina e no CI.
- Mandar dados para fora.
- Não há telemetria. Com modelo local, nada sai do seu computador.
- Prender você a um fornecedor.
- Use qualquer provedor, e deixe o
rampa evalmedir em qual modelo confiar para cada critério. - Substituir pessoas.
- Verificação automática cobre parte da WCAG. Auditoria e teste com pessoas com deficiência cobrem o resto.
A web hoje, qualquer tela depois
Os critérios leem um snapshot normalizado, nunca o DOM. Uma tela de Android ou iOS vira o mesmo formato, então a verificação do critério 1.1.1 vale igual para alt, contentDescription ou accessibilityLabel. Os coletores de Android e iOS estão no roadmap, e um snapshot exportado pelos testes do seu app já pode ser verificado hoje.
- Web
altDisponível - Android
contentDescriptionNo roadmap - iOS
accessibilityLabelNo roadmap
Perguntas sobre teste automático de acessibilidade
O axe-core basta para cumprir a WCAG?
Nenhuma ferramenta automática basta. O axe-core acha com segurança o que a marcação prova: alt ausente, link vazio, contraste baixo. Ele não sabe se um alt descreve a imagem ou se um título descreve a seção. O Rampa mantém o axe-core no que as regras decidem e julga parte do resto; a maioria dos critérios da WCAG ainda precisa de pessoas.
IA consegue verificar acessibilidade na web?
Em parte. Um modelo de linguagem julga significado, como se o texto de um link diz para onde ele leva, mas também pode inventar problemas. O Rampa pergunta um critério por vez, com o menor contexto, e descarta toda alegação cuja evidência não está na página. O rampa eval mede o resultado com os casos de teste ACT do W3C.
Quais critérios da WCAG o Rampa verifica?
O axe-core cobre partes de cerca de uma dúzia de critérios WCAG 2.1 A e AA. O Rampa ainda julga seis com evidência: 1.1.1 Conteúdo não textual, 2.4.2 Página com título, 2.4.4 Finalidade do link (em contexto), 2.4.6 Cabeçalhos e rótulos, 3.1.1 Idioma da página e 3.1.2 Idioma de partes.
Minha página sai da minha máquina?
Não com um modelo local pelo Ollama. Com um provedor na nuvem, só vai o que as regras não decidiram, um elemento e seu contexto por pergunta. Não há telemetria.
Qual a diferença entre o Rampa e um overlay de acessibilidade?
Um overlay muda a página no ar para quem visita e deixa o código como estava. O Rampa roda onde você constrói, no terminal ou no CI, e entrega cada achado com um patch para uma pessoa revisar.
Verifique uma página
O Rampa ainda não está no npm. Clone e rode a partir do código, com Node.js 22.12 ou mais novo e Chrome ou Edge.
Com o Ollama rodando, o Rampa escolhe um modelo local sozinho. Senão, coloque uma chave como OPENAI_API_KEY num arquivo .env. O node dist/cli.mjs doctor diz o que falta.
git clone https://github.com/guilhermebsantiago/rampa-cli.git
cd rampa-cli
pnpm install && pnpm build
node dist/cli.mjs check https://example.com