Faixa de aviso rolando no site: troque o marquee por um aviso que se lê
Substitua o marquee ou o letreiro animado por um aviso parado, com data e validade, e, se a faixa for obrigatória, dê a ela botão de pausa e respeito a quem pediu menos movimento.
No site da escola municipal, uma faixa vermelha atravessa o topo da página: "Matrículas até 28/11 — Reunião de pais dia 12 — Cardápio de novembro disponível — Vacinação na quadra...". Uma mãe entra pelo celular, pega o texto no meio de "Reunião", espera a faixa dar a volta, se distrai e desiste. Na secretaria, o telefone toca o dia inteiro com perguntas que estavam escritas ali. Escritas, mas não legíveis.
A resposta curta: aviso importante fica parado. Um aviso principal no topo, com data e prazo de validade, e o restante numa lista de avisos. Se alguém insistir na faixa rolando, ela precisa de um botão de pausa e tem de parar sozinha para quem configurou o sistema para reduzir movimento. A tag <marquee> está obsoleta no HTML e não deve ser usada em página nova.
Por que texto em movimento não comunica
Ler é mover o olho em saltos curtos sobre um texto parado. Quando o texto anda, o olho precisa perseguir as palavras e saltar ao mesmo tempo. Quem lê devagar, quem tem dislexia, baixa visão ou está no ônibus balançando perde o fio. E ninguém controla a velocidade: rápida demais para uns, lenta demais para quem só queria a terceira frase.
Há um custo para quem nem tenta ler. Movimento na periferia da visão puxa a atenção, e para algumas pessoas com distúrbios vestibulares ou de atenção ele causa tontura e impede a leitura do resto da página. Por isso os sistemas operacionais têm uma opção para reduzir movimento, que o navegador expõe ao CSS como prefers-reduced-motion.
As diretrizes de acessibilidade do W3C, o WCAG, tratam disso no critério "Pausar, parar, ocultar": conteúdo que se move sozinho, dura mais de cinco segundos e aparece junto com outro conteúdo precisa de um jeito de ser pausado, parado ou escondido. A faixa da escola falhava nos três.
E o leitor de tela? Depende da implementação. Letreiros feitos em JavaScript costumam duplicar os itens para criar o efeito de laço, e o leitor lê tudo duas vezes. Outros trocam o texto a cada poucos segundos e o leitor anuncia cada troca, ou nenhuma.
Como trocar a faixa por avisos que funcionam
Na escola, a troca levou uma tarde.
- Liste os avisos e dê a cada um uma data de validade. "Matrículas até 28/11" vale até 28/11. "Cardápio de novembro" vale até 30/11. Aviso sem validade fica no site para sempre e ensina as pessoas a ignorar a área.
- Escolha um aviso principal. O que gera mais ligação ou tem prazo mais curto. Ele fica parado no topo, com uma frase, a data e um link para os detalhes.
- Coloque o resto numa lista. Uma seção "Avisos" na página inicial, em ordem de prazo, com data em cada item.
- Esconda o vencido automaticamente. Quem publica não vai lembrar de tirar. O sistema compara a validade com a data de hoje.
- Escreva o aviso para ser lido de passagem. O que, até quando, onde saber mais. "Matrículas para 2027 abertas até 28/11. Documentos e horários na página de matrícula."
O HTML do topo fica simples:
<div class="aviso-principal">
<p>
<strong>Matrículas para 2027 abertas até 28/11.</strong>
<a href="/matriculas">Documentos e horários</a>
</p>
</div>
<section aria-labelledby="titulo-avisos">
<h2 id="titulo-avisos">Avisos</h2>
<ul>
<li><time datetime="2026-11-12">12/11</time> Reunião de pais, 19h, no auditório.</li>
<li><time datetime="2026-11-30">até 30/11</time> <a href="/cardapio">Cardápio de novembro</a></li>
</ul>
</section>
E a validade, no PHP que monta a página, é um filtro antes do laço:
$hoje = (new DateTimeImmutable('today', new DateTimeZone('America/Sao_Paulo')))->format('Y-m-d');
$stmt = $pdo->prepare(
'SELECT titulo, texto, link, valido_ate
FROM avisos
WHERE valido_ate >= :hoje
ORDER BY valido_ate'
);
$stmt->execute(['hoje' => $hoje]);
$avisos = $stmt->fetchAll();
O fuso é explícito porque "hoje" no servidor em UTC vira amanhã às 21h de Brasília, e o aviso sumiria três horas antes do prazo. O assunto rende um guia à parte: fuso horário no PHP.
Se a faixa rolando for obrigatória
Às vezes a decisão não é sua. Nesse caso, faça a faixa com CSS, nunca com <marquee>, e cumpra três condições: pausa com o mouse e com o foco do teclado, um botão visível de pausar e parada total para quem pediu menos movimento.
<div class="faixa" id="faixa">
<p class="faixa__trilho">Matrículas até 28/11. Reunião de pais dia 12, às 19h.</p>
</div>
<button type="button" id="pausar-faixa" aria-pressed="false">Pausar avisos</button>
<style>
.faixa { overflow: hidden; white-space: nowrap; }
.faixa__trilho {
display: inline-block;
margin: 0;
padding-left: 100%;
animation: rolar 30s linear infinite;
}
.faixa:hover .faixa__trilho,
.faixa:focus-within .faixa__trilho,
.faixa.pausada .faixa__trilho { animation-play-state: paused; }
@keyframes rolar { to { transform: translateX(-100%); } }
@media (prefers-reduced-motion: reduce) {
.faixa { white-space: normal; }
.faixa__trilho { animation: none; padding-left: 0; }
}
</style>
<script>
const botao = document.getElementById('pausar-faixa');
botao.addEventListener('click', () => {
const pausada = document.getElementById('faixa').classList.toggle('pausada');
botao.setAttribute('aria-pressed', String(pausada));
botao.textContent = pausada ? 'Continuar avisos' : 'Pausar avisos';
});
</script>
Com a preferência de reduzir movimento ligada, o bloco @media desliga a animação e deixa o texto quebrar linha, como um parágrafo comum. Para testar sem mexer no sistema, o DevTools do Chrome permite emular prefers-reduced-motion no painel de renderização. Um item só, sem duplicação, evita que o leitor de tela repita o texto.
Movimento em outras partes da interface segue a mesma lógica, explicada em animação contínua que respeita quem pediu menos movimento. Carrossel automático de banners é o primo da faixa e tem os mesmos problemas.
Erros comuns
- Usar
<marquee>porque "ainda funciona". É uma tag obsoleta, sem controle de pausa e sem respeito à preferência de movimento. - Colocar cinco avisos na mesma faixa. A pessoa precisa esperar o laço inteiro para achar o dela, e o mais urgente fica igual ao menos urgente.
- Aviso sem data de validade. O aviso de agosto continua no ar em novembro e ninguém confia mais na área.
- Pausa só no mouse. No celular não há mouse, e quem navega pelo teclado também não consegue parar.
- Ignorar
prefers-reduced-motion. Quem configurou o sistema justamente para evitar isso recebe o movimento mesmo assim. - Pôr
aria-livenum letreiro que troca sozinho. O leitor de tela interrompe a pessoa a cada troca, no meio do que ela estava lendo.
Checklist
- Não há
<marquee>no código do site. - O aviso principal está parado, com data e link para detalhes.
- Todo aviso tem data de validade e some sozinho depois dela.
- A data de "hoje" é calculada no fuso do público, não no do servidor.
- Se existe faixa animada, ela tem botão de pausa visível e pausa no foco do teclado.
- Com a emulação de movimento reduzido ligada, nada se move sozinho na página.
- O leitor de tela lê cada aviso uma vez só.
Abra a página inicial do seu site e tente ler o aviso mais importante do começo ao fim sem esperar nada se mover: dá para fazer isso agora?
Referência: http://remysharp.com/demo/marquee.html