Embaralhar Letras
Letras de uma palavra são exibidas em ordem aleatória. O aprendiz as reorganiza para formar o termo correto. Reforça a ortografia de vocabulário técnico de forma lúdica.
Experimente
Grupo de estrelas que forma um padrão reconhecível no céu noturno, usado para orientação desde a Antiguidade
Clique ou arraste as letras abaixo para montar a palavra.
Arraste entre duas letras já posicionadas para inserir ali; clique ou arraste de volta para cima para remover.
Código-fonte
Dados de exemplo
A palavra certa e a dica que orienta o aprendiz antes de ver as letras embaralhadas.
| 1 |
<?php
|
| 2 |
$palavra = 'ATMOSFERA';
|
| 3 |
$embaralhado = 'FTAROSAEM'; // mesmas letras de $palavra, em outra ordem
|
| 4 |
$dica = 'Camada de gases que envolve um planeta e retém calor.';
|
| 5 |
?>
|
Estrutura da questão
A caixa de resposta nasce vazia; as letras da bandeja abaixo se movem pra lá por clique ou arraste.
| 1 |
<div class="questao" data-tipo="embaralhar-letras" data-resposta="<?= htmlspecialchars($palavra) ?>">
|
| 2 |
|
| 3 |
<p class="questao-dica"><?= htmlspecialchars($dica) ?></p>
|
| 4 |
|
| 5 |
<div class="letras">
|
| 6 |
<?php foreach (str_split($embaralhado) as $letra): ?>
|
| 7 |
<button type="button" class="letra" draggable="true" data-letra="<?= $letra ?>"><?= $letra ?></button>
|
| 8 |
<?php endforeach; ?>
|
| 9 |
</div>
|
| 10 |
|
| 11 |
<div class="resposta">
|
| 12 |
<span class="resposta-vazia">Nenhuma letra posicionada ainda.</span>
|
| 13 |
</div>
|
Ações da questão
Verificar, o painel de resultado e o botão de reiniciar — os dois últimos nascem ocultos.
| 1 |
<button type="button" class="questao-verificar">Verificar resposta</button>
|
| 2 |
|
| 3 |
<div class="questao-painel" hidden>
|
| 4 |
<p class="questao-painel-mensagem"></p>
|
| 5 |
</div>
|
| 6 |
|
| 7 |
<button type="button" class="questao-reset" hidden>Tentar novamente</button>
|
| 8 |
|
| 9 |
</div>
|
Dica
O conceito que o aprendiz precisa reconhecer antes de tentar montar a palavra.
| 1 |
.questao-dica {
|
| 2 |
margin: 0 0 12px;
|
| 3 |
font-size: 14px;
|
| 4 |
color: #475569;
|
| 5 |
}
|
Bandeja de letras
As letras embaralhadas, na ordem sorteada. Cada uma pode ser clicada ou arrastada até a caixa de resposta.
| 1 |
.letras {
|
| 2 |
display: flex;
|
| 3 |
flex-wrap: wrap;
|
| 4 |
gap: 8px;
|
| 5 |
margin: 16px 0;
|
| 6 |
}
|
Letra da bandeja
Fica esmaecida e inativa assim que é usada, mas continua no lugar — preserva a disposição embaralhada original.
| 1 |
.letra {
|
| 2 |
width: 40px;
|
| 3 |
height: 40px;
|
| 4 |
border: 1px solid #a5b4fc;
|
| 5 |
border-radius: 10px;
|
| 6 |
background: rgba(99, 102, 241, 0.08);
|
| 7 |
color: #4338ca;
|
| 8 |
font: inherit;
|
| 9 |
font-weight: 700;
|
| 10 |
font-size: 18px;
|
| 11 |
cursor: grab;
|
| 12 |
}
|
| 13 |
.letra:disabled {
|
| 14 |
opacity: 0.3;
|
| 15 |
cursor: default;
|
| 16 |
}
|
Caixa de resposta
Nasce vazia com uma mensagem central; recebe as peças conforme o aprendiz monta a palavra.
| 1 |
.resposta {
|
| 2 |
display: flex;
|
| 3 |
flex-wrap: wrap;
|
| 4 |
gap: 8px;
|
| 5 |
min-height: 56px;
|
| 6 |
margin-bottom: 16px;
|
| 7 |
padding: 10px;
|
| 8 |
border: 1px solid #cbd5e1;
|
| 9 |
border-radius: 12px;
|
| 10 |
background: rgba(148, 163, 184, 0.08);
|
| 11 |
}
|
| 12 |
.resposta-vazia {
|
| 13 |
align-self: center;
|
| 14 |
font-size: 13px;
|
| 15 |
color: #64748b;
|
| 16 |
}
|
Peça posicionada
A cópia da letra que entra na caixa de resposta — clicável ou arrastável de volta pra bandeja a qualquer momento.
| 1 |
.peca {
|
| 2 |
position: relative;
|
| 3 |
width: 40px;
|
| 4 |
height: 40px;
|
| 5 |
border: 1px solid #475569;
|
| 6 |
border-radius: 10px;
|
| 7 |
background: #334155;
|
| 8 |
color: #f1f5f9;
|
| 9 |
font: inherit;
|
| 10 |
font-weight: 700;
|
| 11 |
font-size: 18px;
|
| 12 |
cursor: grab;
|
| 13 |
}
|
| 14 |
.peca.arrastando {
|
| 15 |
opacity: 0.5;
|
| 16 |
}
|
Indicador de inserção
Uma linha vertical aparece do lado em que a peça arrastada vai entrar, enquanto passa por cima de outra já posicionada.
| 1 |
.peca[data-insercao="antes"]::before,
|
| 2 |
.peca[data-insercao="depois"]::after {
|
| 3 |
content: '';
|
| 4 |
position: absolute;
|
| 5 |
top: -4px;
|
| 6 |
bottom: -4px;
|
| 7 |
width: 3px;
|
| 8 |
border-radius: 999px;
|
| 9 |
background: #6366f1;
|
| 10 |
}
|
| 11 |
.peca[data-insercao="antes"]::before { left: -6px; }
|
| 12 |
.peca[data-insercao="depois"]::after { right: -6px; }
|
Ações
Botões de largura total, um de cada vez na tela.
| 1 |
.questao-verificar,
|
| 2 |
.questao-reset {
|
| 3 |
display: block;
|
| 4 |
width: 100%;
|
| 5 |
padding: 12px 16px;
|
| 6 |
border: none;
|
| 7 |
border-radius: 10px;
|
| 8 |
font: inherit;
|
| 9 |
font-weight: 600;
|
| 10 |
cursor: pointer;
|
| 11 |
}
|
| 12 |
.questao-verificar {
|
| 13 |
background: #4f46e5;
|
| 14 |
color: #fff;
|
| 15 |
}
|
| 16 |
.questao-reset {
|
| 17 |
background: #e5e7eb;
|
| 18 |
color: #1f2937;
|
| 19 |
}
|
Estado oculto
O atributo hidden nativo tem a mesma especificidade da regra de exibição acima — sem isto, "Tentar novamente" apareceria antes de verificar.
| 1 |
.questao-verificar[hidden],
|
| 2 |
.questao-reset[hidden] {
|
| 3 |
display: none;
|
| 4 |
}
|
Painel de resultado
Caixa de destaque com o resultado da verificação.
| 1 |
.questao-painel {
|
| 2 |
margin: 16px 0;
|
| 3 |
padding: 16px;
|
| 4 |
border-radius: 12px;
|
| 5 |
background: #1e3a8a;
|
| 6 |
color: #dbeafe;
|
| 7 |
font-weight: 600;
|
| 8 |
}
|
Encontrar os elementos da questão
Localiza a bandeja de letras, a caixa de resposta e as ações.
| 1 |
document.addEventListener('DOMContentLoaded', function () {
|
| 2 |
document.querySelectorAll('.questao[data-tipo="embaralhar-letras"]').forEach(function (questao) {
|
| 3 |
var resposta = questao.dataset.resposta;
|
| 4 |
var letras = questao.querySelector('.letras');
|
| 5 |
var caixa = questao.querySelector('.resposta');
|
| 6 |
var vazia = caixa.querySelector('.resposta-vazia');
|
| 7 |
var verificar = questao.querySelector('.questao-verificar');
|
| 8 |
var painel = questao.querySelector('.questao-painel');
|
| 9 |
var reset = questao.querySelector('.questao-reset');
|
| 10 |
// A peça sendo arrastada no momento — tanto uma letra ainda na bandeja
|
| 11 |
// quanto uma peça já colocada na caixa de resposta.
|
| 12 |
var arrastada = null;
|
| 13 |
var travada = false;
|
Criar e mover uma peça
Um único ponto de movimentação — cria a peça na caixa numa posição específica (ou reordena uma peça já lá) e reverte devolvendo a letra pra bandeja.
| 1 |
function pecasDaCaixa() {
|
| 2 |
return Array.prototype.slice.call(caixa.querySelectorAll('.peca'));
|
| 3 |
}
|
| 4 |
|
| 5 |
function atualizarVazia() {
|
| 6 |
vazia.hidden = pecasDaCaixa().length > 0;
|
| 7 |
}
|
| 8 |
|
| 9 |
function reverter(peca) {
|
| 10 |
peca.remove();
|
| 11 |
peca.origem.disabled = false;
|
| 12 |
atualizarVazia();
|
| 13 |
}
|
| 14 |
|
| 15 |
function configurarPeca(peca) {
|
| 16 |
peca.addEventListener('click', function () {
|
| 17 |
if (travada) return;
|
| 18 |
reverter(peca);
|
| 19 |
});
|
| 20 |
|
| 21 |
peca.addEventListener('dragstart', function (evento) {
|
| 22 |
if (travada) { evento.preventDefault(); return; }
|
| 23 |
arrastada = peca;
|
| 24 |
peca.classList.add('arrastando');
|
| 25 |
evento.dataTransfer.setData('text/plain', peca.textContent);
|
| 26 |
});
|
| 27 |
peca.addEventListener('dragend', function () {
|
| 28 |
peca.classList.remove('arrastando');
|
| 29 |
delete peca.dataset.insercao;
|
| 30 |
arrastada = null;
|
| 31 |
});
|
| 32 |
|
| 33 |
// A própria peça também é alvo de drop: soltar na metade esquerda dela
|
| 34 |
// insere antes, na direita insere depois — é isso que permite encaixar
|
| 35 |
// em qualquer posição da caixa, não só no fim.
|
| 36 |
peca.addEventListener('dragover', function (evento) {
|
| 37 |
if (travada || !arrastada || arrastada === peca) return;
|
| 38 |
evento.preventDefault();
|
| 39 |
var caixaPeca = peca.getBoundingClientRect();
|
| 40 |
peca.dataset.insercao = evento.clientX < caixaPeca.left + caixaPeca.width / 2 ? 'antes' : 'depois';
|
| 41 |
});
|
| 42 |
peca.addEventListener('dragleave', function () { delete peca.dataset.insercao; });
|
| 43 |
peca.addEventListener('drop', function (evento) {
|
| 44 |
if (travada || !arrastada || arrastada === peca) return;
|
| 45 |
evento.preventDefault();
|
| 46 |
var antes = peca.dataset.insercao === 'antes';
|
| 47 |
delete peca.dataset.insercao;
|
| 48 |
inserir(arrastada, antes ? peca : peca.nextSibling);
|
| 49 |
});
|
| 50 |
}
|
| 51 |
|
| 52 |
function inserir(origem, referencia) {
|
| 53 |
var peca = origem.classList.contains('peca') ? origem : criarPeca(origem);
|
| 54 |
if (peca !== origem) origem.disabled = true;
|
| 55 |
caixa.insertBefore(peca, referencia || null);
|
| 56 |
atualizarVazia();
|
| 57 |
}
|
| 58 |
|
| 59 |
function criarPeca(origem) {
|
| 60 |
var peca = document.createElement('button');
|
| 61 |
peca.type = 'button';
|
| 62 |
peca.className = 'peca';
|
| 63 |
peca.textContent = origem.dataset.letra;
|
| 64 |
peca.draggable = true;
|
| 65 |
peca.origem = origem;
|
| 66 |
configurarPeca(peca);
|
| 67 |
return peca;
|
| 68 |
}
|
Clicar e arrastar uma letra da bandeja
Clique adiciona no fim da palavra montada; arrastar solta em qualquer ponto da caixa, inclusive entre peças já posicionadas.
| 1 |
letras.querySelectorAll('.letra').forEach(function (letra) {
|
| 2 |
letra.addEventListener('click', function () {
|
| 3 |
if (travada || letra.disabled) return;
|
| 4 |
inserir(letra, null);
|
| 5 |
});
|
| 6 |
|
| 7 |
letra.addEventListener('dragstart', function (evento) {
|
| 8 |
if (travada || letra.disabled) { evento.preventDefault(); return; }
|
| 9 |
arrastada = letra;
|
| 10 |
evento.dataTransfer.setData('text/plain', letra.dataset.letra);
|
| 11 |
});
|
| 12 |
letra.addEventListener('dragend', function () { arrastada = null; });
|
| 13 |
});
|
Espaço vazio como alvo
Soltar fora de qualquer peça — na caixa manda pro fim da palavra; na bandeja reverte a peça arrastada.
| 1 |
caixa.addEventListener('dragover', function (evento) { if (!travada && arrastada) evento.preventDefault(); });
|
| 2 |
caixa.addEventListener('drop', function (evento) {
|
| 3 |
if (travada || evento.target.closest('.peca')) return;
|
| 4 |
evento.preventDefault();
|
| 5 |
if (arrastada) inserir(arrastada, null);
|
| 6 |
});
|
| 7 |
|
| 8 |
letras.addEventListener('dragover', function (evento) {
|
| 9 |
if (travada || !arrastada || !arrastada.classList.contains('peca')) return;
|
| 10 |
evento.preventDefault();
|
| 11 |
});
|
| 12 |
letras.addEventListener('drop', function (evento) {
|
| 13 |
if (travada || !arrastada || !arrastada.classList.contains('peca')) return;
|
| 14 |
evento.preventDefault();
|
| 15 |
reverter(arrastada);
|
| 16 |
});
|
Verificar
Junta as letras na ordem em que estão na caixa e compara com a resposta certa; trava a questão e mostra o resultado.
| 1 |
verificar.addEventListener('click', function () {
|
| 2 |
var tentativa = pecasDaCaixa().map(function (peca) { return peca.textContent; }).join('');
|
| 3 |
var certo = tentativa.toUpperCase() === resposta.toUpperCase();
|
| 4 |
painel.querySelector('.questao-painel-mensagem').textContent = certo
|
| 5 |
? 'Correto!'
|
| 6 |
: 'Não é esta combinação. Resposta certa: ' + resposta;
|
| 7 |
painel.hidden = false;
|
| 8 |
|
| 9 |
verificar.hidden = true;
|
| 10 |
reset.hidden = false;
|
| 11 |
travada = true;
|
| 12 |
});
|
Reiniciar
Devolve todas as peças pra bandeja e destrava a questão.
| 1 |
reset.addEventListener('click', function () {
|
| 2 |
travada = false;
|
| 3 |
pecasDaCaixa().forEach(function (peca) { reverter(peca); });
|
| 4 |
painel.hidden = true;
|
| 5 |
verificar.hidden = false;
|
| 6 |
reset.hidden = true;
|
| 7 |
});
|