Acordeão
Apresenta conteúdo em seções expansíveis. O aprendiz clica em cada item para revelar o texto oculto, controlando o ritmo da leitura e evitando sobrecarga de informação.
Experimente
Camadas da Terra
É a camada mais externa e fina do planeta, onde vivemos. Varia de 5 km (sob os oceanos) a 70 km (sob as montanhas) de espessura, e é dividida em placas tectônicas que se movem lentamente ao longo do tempo geológico.
Camada intermediária, com quase 2.900 km de espessura, composta por rocha em estado semi-sólido que se movimenta em correntes de convecção — esse movimento é o que empurra as placas tectônicas na superfície.
A camada mais interna, dividida em núcleo externo (líquido, de ferro e níquel) e núcleo interno (sólido, sob pressão extrema). O movimento do núcleo externo gera o campo magnético que protege o planeta.
Código-fonte
Dados de exemplo
Cada item tem um título curto (o que a pessoa vê antes de clicar) e o conteúdo, que só aparece depois.
| 1 |
<?php
|
| 2 |
$itens = [
|
| 3 |
['titulo' => 'Sono leve', 'conteudo' => 'Primeira fase do ciclo, transição entre acordado e dormindo. A respiração e os batimentos cardíacos começam a desacelerar, e a pessoa desperta fácil com qualquer estímulo.'],
|
| 4 |
['titulo' => 'Sono profundo', 'conteudo' => 'Fase de recuperação física do corpo — os músculos relaxam ao máximo, a pressão arterial cai e o corpo libera hormônios de crescimento. É a fase mais difícil de interromper.'],
|
| 5 |
['titulo' => 'Sono REM', 'conteudo' => 'Fase de maior atividade cerebral, onde ocorrem a maioria dos sonhos. Os olhos se movem rapidamente sob as pálpebras e o corpo fica temporariamente paralisado.'],
|
| 6 |
];
|
| 7 |
?>
|
Estrutura do item
Cada item tem dois níveis — ".item" (recebe a linha divisória entre um item e outro) envolvendo ".borda" (recebe a cor de destaque quando aberto). Ver o bloco "Cor de destaque" do CSS pra entender por que são dois níveis, não um só.
| 1 |
<div class="acordeao">
|
| 2 |
<?php foreach ($itens as $i => $item): $aberto = $i === 0; ?>
|
| 3 |
<div class="item">
|
| 4 |
<div class="borda<?= $aberto ? ' aberto' : '' ?>">
|
| 5 |
<button type="button" class="cabecalho" aria-expanded="<?= $aberto ? 'true' : 'false' ?>">
|
| 6 |
<span class="numero"><?= $i + 1 ?></span>
|
| 7 |
<span class="titulo"><?= htmlspecialchars($item['titulo']) ?></span>
|
| 8 |
<span class="seta<?= $aberto ? ' girada' : '' ?>">▾</span>
|
| 9 |
</button>
|
| 10 |
<div class="conteudo<?= $aberto ? ' expandido' : '' ?>">
|
| 11 |
<div class="conteudo-interno">
|
| 12 |
<p class="texto"><?= htmlspecialchars($item['conteudo']) ?></p>
|
| 13 |
</div>
|
| 14 |
</div>
|
| 15 |
</div>
|
| 16 |
</div>
|
| 17 |
<?php endforeach; ?>
|
| 18 |
</div>
|
Cartão
Contêiner geral do acordeão.
| 1 |
.acordeao {
|
| 2 |
border: 1px solid #e2e8f0;
|
| 3 |
border-radius: 12px;
|
| 4 |
overflow: hidden;
|
| 5 |
font-family: inherit;
|
| 6 |
}
|
Divisória entre itens
Usa border-top (não o atalho "border") pra nunca colidir com a cor de destaque do item aberto, que fica num elemento diferente e usa border-left. Misturar os dois na mesma propriedade é a receita de uma cor apagar a outra.
| 1 |
.item + .item {
|
| 2 |
border-top: 1px solid #e2e8f0;
|
| 3 |
}
|
Cor de destaque do item aberto
Mora num filho do item (.borda), não no próprio .item — separar os dois níveis evita qualquer disputa de especificidade entre a linha divisória de cima e a cor lateral, mesmo que uma das duas regras mude no futuro.
| 1 |
.borda {
|
| 2 |
border-left: 4px solid transparent;
|
| 3 |
transition: border-color 0.2s ease, background-color 0.2s ease;
|
| 4 |
}
|
| 5 |
.borda.aberto {
|
| 6 |
border-left-color: #6366f1;
|
| 7 |
background: rgba(99, 102, 241, 0.06);
|
| 8 |
}
|
Cabeçalho clicável
Número, título e seta numa linha só; toda a largura é clicável, não só o texto.
| 1 |
.cabecalho {
|
| 2 |
width: 100%;
|
| 3 |
display: flex;
|
| 4 |
align-items: center;
|
| 5 |
gap: 12px;
|
| 6 |
padding: 16px 20px;
|
| 7 |
border: none;
|
| 8 |
background: none;
|
| 9 |
text-align: left;
|
| 10 |
font: inherit;
|
| 11 |
cursor: pointer;
|
| 12 |
}
|
| 13 |
.cabecalho:hover {
|
| 14 |
background: rgba(99, 102, 241, 0.04);
|
| 15 |
}
|
| 16 |
.cabecalho:focus-visible {
|
| 17 |
outline: 2px solid #6366f1;
|
| 18 |
outline-offset: -2px;
|
| 19 |
}
|
| 20 |
|
| 21 |
.numero {
|
| 22 |
flex-shrink: 0;
|
| 23 |
width: 24px;
|
| 24 |
height: 24px;
|
| 25 |
border-radius: 999px;
|
| 26 |
background: #f1f5f9;
|
| 27 |
color: #64748b;
|
| 28 |
font-size: 12px;
|
| 29 |
font-weight: 700;
|
| 30 |
display: flex;
|
| 31 |
align-items: center;
|
| 32 |
justify-content: center;
|
| 33 |
}
|
| 34 |
|
| 35 |
.titulo {
|
| 36 |
flex: 1;
|
| 37 |
font-weight: 600;
|
| 38 |
font-size: 14px;
|
| 39 |
color: #1e293b;
|
| 40 |
}
|
| 41 |
|
| 42 |
.seta {
|
| 43 |
flex-shrink: 0;
|
| 44 |
color: #64748b;
|
| 45 |
transition: transform 0.2s ease;
|
| 46 |
}
|
| 47 |
.seta.girada {
|
| 48 |
transform: rotate(180deg);
|
| 49 |
}
|
Conteúdo revelado
grid-template-rows de 0fr pra 1fr anima a altura sem precisar medir pixel em JS — funciona pra qualquer tamanho de texto, sem cortar conteúdo grande nem deixar curto demais parecendo instantâneo.
| 1 |
.conteudo {
|
| 2 |
display: grid;
|
| 3 |
grid-template-rows: 0fr;
|
| 4 |
transition: grid-template-rows 0.2s ease-in-out;
|
| 5 |
}
|
| 6 |
.conteudo.expandido {
|
| 7 |
grid-template-rows: 1fr;
|
| 8 |
}
|
| 9 |
.conteudo-interno {
|
| 10 |
overflow: hidden;
|
| 11 |
}
|
| 12 |
.texto {
|
| 13 |
margin: 0;
|
| 14 |
padding: 0 20px 16px 56px;
|
| 15 |
font-size: 14px;
|
| 16 |
line-height: 1.6;
|
| 17 |
color: #475569;
|
| 18 |
}
|
Encontrar os itens
Localiza cada item do acordeão e guarda a lista inteira, pra poder fechar os outros quando um abre.
| 1 |
document.addEventListener('DOMContentLoaded', function () {
|
| 2 |
document.querySelectorAll('.acordeao').forEach(function (acordeao) {
|
| 3 |
var itens = acordeao.querySelectorAll('.item');
|
Trocar o estado de um item
Cabeçalho, seta, borda e conteúdo mudam juntos — nunca só uma parte, senão o visual e o aria-expanded saem de sincronia.
| 1 |
function aplicar(item, aberto) {
|
| 2 |
var borda = item.querySelector('.borda');
|
| 3 |
var cabecalho = item.querySelector('.cabecalho');
|
| 4 |
var seta = cabecalho.querySelector('.seta');
|
| 5 |
var conteudo = item.querySelector('.conteudo');
|
| 6 |
|
| 7 |
cabecalho.setAttribute('aria-expanded', aberto ? 'true' : 'false');
|
| 8 |
seta.classList.toggle('girada', aberto);
|
| 9 |
borda.classList.toggle('aberto', aberto);
|
| 10 |
conteudo.classList.toggle('expandido', aberto);
|
| 11 |
}
|
Abertura exclusiva
Ao abrir um item, todos os outros fecham primeiro — só um fica visível de cada vez. É isso que faz o acordeão controlar o ritmo da leitura; permitir vários abertos ao mesmo tempo vira só um bloco de texto comum.
| 1 |
itens.forEach(function (item) {
|
| 2 |
var cabecalho = item.querySelector('.cabecalho');
|
| 3 |
cabecalho.addEventListener('click', function () {
|
| 4 |
var estavaAberto = cabecalho.getAttribute('aria-expanded') === 'true';
|
| 5 |
itens.forEach(function (outro) { if (outro !== item) aplicar(outro, false); });
|
| 6 |
aplicar(item, !estavaAberto);
|
| 7 |
});
|
| 8 |
});
|