Programação Por Equipe DevBras

Capa do artigo: Faixa de aviso rolando no site: troque o marquee por um aviso que se lê

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.

  1. 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.
  2. 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.
  3. Coloque o resto numa lista. Uma seção "Avisos" na página inicial, em ordem de prazo, com data em cada item.
  4. Esconda o vencido automaticamente. Quem publica não vai lembrar de tirar. O sistema compara a validade com a data de hoje.
  5. 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-live num 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?

Avalie este artigo

Referência: http://remysharp.com/demo/marquee.html