Trilha de Perguntas
Sequência de questões onde cada resposta correta desbloqueia a próxima. O aprendiz avança na trilha progressivamente, com dificuldade crescente. Cria senso de jornada e progressão.
Experimente
Trilha: O Cofre Perdido
1/6Você encontra um mapa antigo com a primeira pista: "Conte as pontas de uma estrela comum de cinco pontas." Quantas pontas ela tem?
Código-fonte
Dados de exemplo
Cada etapa depende da resposta da anterior — a pergunta usa o número descoberto antes.
| 1 |
<?php
|
| 2 |
$etapas = [
|
| 3 |
[
|
| 4 |
'pergunta' => 'O cadeado tem discos numéricos. Quantos lados tem um triângulo?',
|
| 5 |
'opcoes' => [
|
| 6 |
['texto' => '2', 'correta' => false],
|
| 7 |
['texto' => '3', 'correta' => true],
|
| 8 |
['texto' => '4', 'correta' => false],
|
| 9 |
],
|
| 10 |
'feedback' => 'Correto! Primeiro número do cadeado: 3.',
|
| 11 |
],
|
| 12 |
[
|
| 13 |
'pergunta' => 'Dobre o número que você descobriu na etapa anterior. Qual é o resultado?',
|
| 14 |
'opcoes' => [
|
| 15 |
['texto' => '5', 'correta' => false],
|
| 16 |
['texto' => '6', 'correta' => true],
|
| 17 |
['texto' => '7', 'correta' => false],
|
| 18 |
],
|
| 19 |
'feedback' => 'Isso! Segundo número: 6 (3 × 2).',
|
| 20 |
],
|
| 21 |
[
|
| 22 |
'pergunta' => 'Some 4 ao número da etapa anterior. Qual é o resultado?',
|
| 23 |
'opcoes' => [
|
| 24 |
['texto' => '9', 'correta' => false],
|
| 25 |
['texto' => '10', 'correta' => true],
|
| 26 |
['texto' => '11', 'correta' => false],
|
| 27 |
],
|
| 28 |
'feedback' => 'Exato! Terceiro número: 10 (6 + 4).',
|
| 29 |
],
|
| 30 |
[
|
| 31 |
'pergunta' => 'Some os três números descobertos (3, 6 e 10). Qual é o total — a combinação do cadeado?',
|
| 32 |
'opcoes' => [
|
| 33 |
['texto' => '18', 'correta' => false],
|
| 34 |
['texto' => '19', 'correta' => true],
|
| 35 |
['texto' => '20', 'correta' => false],
|
| 36 |
],
|
| 37 |
'feedback' => 'O cadeado abre! Combinação: 19 (3 + 6 + 10). Trilha concluída.',
|
| 38 |
],
|
| 39 |
];
|
| 40 |
?>
|
Estrutura da trilha
Pontos de progresso, uma etapa visível por vez, e o painel final.
| 1 |
<div class="trilha" data-tipo="trilha" data-total="<?= count($etapas) ?>">
|
| 2 |
|
| 3 |
<div class="trilha-progresso">
|
| 4 |
<?php foreach ($etapas as $i => $etapa): ?>
|
| 5 |
<div class="trilha-ponto<?= $i === 0 ? ' ativo' : '' ?>" data-idx="<?= $i ?>"></div>
|
| 6 |
<?php endforeach; ?>
|
| 7 |
</div>
|
| 8 |
|
| 9 |
<?php foreach ($etapas as $i => $etapa): ?>
|
| 10 |
<div class="trilha-etapa<?= $i > 0 ? ' trilha-etapa-oculta' : '' ?>"
|
| 11 |
data-idx="<?= $i ?>"
|
| 12 |
data-feedback="<?= htmlspecialchars($etapa['feedback']) ?>">
|
| 13 |
<p class="trilha-pergunta"><?= htmlspecialchars($etapa['pergunta']) ?></p>
|
| 14 |
<div class="trilha-opcoes">
|
| 15 |
<?php foreach ($etapa['opcoes'] as $opcao): ?>
|
| 16 |
<button type="button" class="trilha-opcao" data-correta="<?= $opcao['correta'] ? 'true' : 'false' ?>">
|
| 17 |
<?= htmlspecialchars($opcao['texto']) ?>
|
| 18 |
</button>
|
| 19 |
<?php endforeach; ?>
|
| 20 |
</div>
|
| 21 |
<div class="trilha-feedback" hidden></div>
|
| 22 |
<button type="button" class="trilha-proximo" hidden>Próxima etapa</button>
|
| 23 |
</div>
|
| 24 |
<?php endforeach; ?>
|
| 25 |
|
| 26 |
<div class="trilha-fim" hidden>
|
| 27 |
<p>Trilha concluída!</p>
|
| 28 |
<button type="button" class="trilha-reiniciar">Recomeçar trilha</button>
|
| 29 |
</div>
|
| 30 |
</div>
|
Pontos de progresso
Uma barra por etapa; a que já foi alcançada fica destacada.
| 1 |
.trilha-progresso {
|
| 2 |
display: flex;
|
| 3 |
gap: 6px;
|
| 4 |
margin-bottom: 16px;
|
| 5 |
}
|
| 6 |
|
| 7 |
.trilha-ponto {
|
| 8 |
flex: 1;
|
| 9 |
height: 6px;
|
| 10 |
border-radius: 999px;
|
| 11 |
background: #e2e8f0;
|
| 12 |
}
|
| 13 |
|
| 14 |
.trilha-ponto.ativo {
|
| 15 |
background: #6366f1;
|
| 16 |
}
|
Etapas e opções
Só a etapa atual fica visível; as opções ficam em coluna.
| 1 |
.trilha-etapa-oculta {
|
| 2 |
display: none;
|
| 3 |
}
|
| 4 |
|
| 5 |
.trilha-pergunta {
|
| 6 |
font-weight: 600;
|
| 7 |
margin-bottom: 12px;
|
| 8 |
}
|
| 9 |
|
| 10 |
.trilha-opcoes {
|
| 11 |
display: flex;
|
| 12 |
flex-direction: column;
|
| 13 |
gap: 8px;
|
| 14 |
}
|
| 15 |
|
| 16 |
.trilha-opcao {
|
| 17 |
padding: 10px 14px;
|
| 18 |
border: 2px solid #d1d5db;
|
| 19 |
border-radius: 8px;
|
| 20 |
background: #fff;
|
| 21 |
text-align: left;
|
| 22 |
cursor: pointer;
|
| 23 |
transition: border-color 0.2s, background-color 0.2s;
|
| 24 |
}
|
| 25 |
|
| 26 |
.trilha-opcao:hover {
|
| 27 |
border-color: #6366f1;
|
| 28 |
}
|
Resultado da resposta
Borda e fundo mudam por completo — nunca só metade da cor antiga some, senão o estado novo não aparece.
| 1 |
.trilha-opcao.acerto {
|
| 2 |
border-color: #22c55e;
|
| 3 |
background: #f0fdf4;
|
| 4 |
}
|
| 5 |
|
| 6 |
.trilha-opcao.erro {
|
| 7 |
border-color: #ef4444;
|
| 8 |
background: #fef2f2;
|
| 9 |
}
|
| 10 |
|
| 11 |
.trilha-opcao:disabled {
|
| 12 |
cursor: not-allowed;
|
| 13 |
}
|
Encontrar os elementos da trilha
Localiza etapas, pontos de progresso e o painel final.
| 1 |
document.addEventListener('DOMContentLoaded', function () {
|
| 2 |
document.querySelectorAll('.trilha[data-tipo="trilha"]').forEach(function (trilha) {
|
| 3 |
var total = parseInt(trilha.dataset.total, 10);
|
| 4 |
var etapas = trilha.querySelectorAll('.trilha-etapa');
|
| 5 |
var pontos = trilha.querySelectorAll('.trilha-ponto');
|
| 6 |
var fim = trilha.querySelector('.trilha-fim');
|
| 7 |
var reiniciar = trilha.querySelector('.trilha-reiniciar');
|
Responder uma etapa
Só avança quando a opção certa é clicada; errar só desabilita aquela opção e deixa tentar outra.
| 1 |
etapas.forEach(function (etapa, idx) {
|
| 2 |
var opcoes = etapa.querySelectorAll('.trilha-opcao');
|
| 3 |
var feedback = etapa.querySelector('.trilha-feedback');
|
| 4 |
var proximo = etapa.querySelector('.trilha-proximo');
|
| 5 |
|
| 6 |
opcoes.forEach(function (opcao) {
|
| 7 |
opcao.addEventListener('click', function () {
|
| 8 |
if (opcao.disabled) return;
|
| 9 |
var correta = opcao.dataset.correta === 'true';
|
| 10 |
|
| 11 |
if (correta) {
|
| 12 |
opcoes.forEach(function (o) { o.disabled = true; });
|
| 13 |
opcao.classList.add('acerto');
|
| 14 |
feedback.textContent = etapa.dataset.feedback;
|
| 15 |
feedback.hidden = false;
|
| 16 |
proximo.hidden = false;
|
| 17 |
} else {
|
| 18 |
opcao.disabled = true;
|
| 19 |
opcao.classList.add('erro');
|
| 20 |
feedback.textContent = 'Não é essa. Tente outra opção.';
|
| 21 |
feedback.hidden = false;
|
| 22 |
}
|
| 23 |
});
|
| 24 |
});
|
Avançar para a próxima etapa
Esconde a etapa atual, acende o próximo ponto e mostra a etapa seguinte (ou o painel final).
| 1 |
if (proximo) proximo.addEventListener('click', function () {
|
| 2 |
etapa.classList.add('trilha-etapa-oculta');
|
| 3 |
var proximoIdx = idx + 1;
|
| 4 |
var pontoProximo = trilha.querySelector('.trilha-ponto[data-idx="' + proximoIdx + '"]');
|
| 5 |
if (pontoProximo) pontoProximo.classList.add('ativo');
|
| 6 |
|
| 7 |
if (proximoIdx >= total) {
|
| 8 |
fim.hidden = false;
|
| 9 |
} else {
|
| 10 |
etapas[proximoIdx].classList.remove('trilha-etapa-oculta');
|
| 11 |
}
|
| 12 |
});
|
| 13 |
});
|
Reiniciar
Volta para a primeira etapa e limpa seleção, feedback e pontos de progresso.
| 1 |
if (reiniciar) reiniciar.addEventListener('click', function () {
|
| 2 |
fim.hidden = true;
|
| 3 |
etapas.forEach(function (etapa, idx) {
|
| 4 |
etapa.classList.toggle('trilha-etapa-oculta', idx > 0);
|
| 5 |
etapa.querySelectorAll('.trilha-opcao').forEach(function (o) {
|
| 6 |
o.disabled = false;
|
| 7 |
o.classList.remove('acerto', 'erro');
|
| 8 |
});
|
| 9 |
etapa.querySelector('.trilha-feedback').hidden = true;
|
| 10 |
etapa.querySelector('.trilha-proximo').hidden = true;
|
| 11 |
});
|
| 12 |
pontos.forEach(function (ponto, idx) { ponto.classList.toggle('ativo', idx === 0); });
|
| 13 |
});
|