Todas as atividades
Jogo e Combinação

Parear Imagens

O aprendiz conecta pares de imagens que compartilham relação semântica, causal ou sequencial. Desenvolve reconhecimento visual e associação de conceitos.

Compreensão e análise parear imagens associação pair

Experimente

Conecte: Causa e Efeito

Selecione um item da esquerda e seu par da direita.

Causa

Efeito

Código-fonte

PHP

Dados de exemplo

Cada par tem uma imagem e uma legenda dos dois lados; o id do par é o gabarito — mesmo id nos dois lados forma a resposta certa.

1 <?php
2 $instrucao = 'Conecte cada causa ao efeito correspondente:';
3 $pares = [
4 ['id' => 'p1', 'esqImagem' => 'semente.jpg', 'esqLegenda' => 'Semente plantada', 'dirImagem' => 'muda.jpg', 'dirLegenda' => 'Muda brotando'],
5 ['id' => 'p2', 'esqImagem' => 'nuvem.jpg', 'esqLegenda' => 'Nuvem de chuva', 'dirImagem' => 'rua-molhada.jpg', 'dirLegenda' => 'Rua molhada'],
6 ['id' => 'p3', 'esqImagem' => 'lagarta.jpg', 'esqLegenda' => 'Lagarta na folha', 'dirImagem' => 'borboleta.jpg', 'dirLegenda' => 'Borboleta colorida'],
7 ];
8 $paresDir = $pares;
9 shuffle($paresDir);
10 ?>

Estrutura da questão

Duas colunas de cartões com imagem — clicar um de cada lado forma um par; a cor do cartão mostra qual par é qual.

1 <div class="questao" data-tipo="parear-imagens">
2
3 <p class="questao-instrucao"><?= htmlspecialchars($instrucao) ?></p>
4
5 <div class="colunas">
6 <div class="coluna">
7 <p class="coluna-titulo">Causa</p>
8 <?php foreach ($pares as $i => $par): ?>
9 <button type="button" class="cartao cartao-esq" data-par-id="<?= $par['id'] ?>" data-cor="<?= $i % 6 ?>" data-estado="padrao">
10 <img src="<?= htmlspecialchars($par['esqImagem']) ?>" alt="<?= htmlspecialchars($par['esqLegenda']) ?>">
11 <span><?= htmlspecialchars($par['esqLegenda']) ?></span>
12 </button>
13 <?php endforeach; ?>
14 </div>
15
16 <div class="coluna">
17 <p class="coluna-titulo">Efeito</p>
18 <?php foreach ($paresDir as $par): ?>
19 <button type="button" class="cartao cartao-dir" data-par-id="<?= $par['id'] ?>" data-estado="padrao">
20 <img src="<?= htmlspecialchars($par['dirImagem']) ?>" alt="<?= htmlspecialchars($par['dirLegenda']) ?>">
21 <span><?= htmlspecialchars($par['dirLegenda']) ?></span>
22 </button>
23 <?php endforeach; ?>
24 </div>
25 </div>

Lista de pares conectados

Caixa vazia, preenchida pelo JavaScript a cada par formado; cada linha herda a cor do par e pode ser desfeita antes de verificar.

1 <div class="pares-lista" hidden></div>
2 <template class="par-template">
3 <div class="par">
4 <span class="par-esquerda"></span>
5 <span class="par-seta" aria-hidden="true">→</span>
6 <span class="par-direita"></span>
7 <button type="button" class="par-remover" aria-label="Remover esta correspondência">×</button>
8 </div>
9 </template>

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>
CSS

Duas colunas

Causas à esquerda, efeitos à direita, lado a lado.

1 .colunas {
2 display: grid;
3 grid-template-columns: 1fr 1fr;
4 gap: 16px;
5 margin-bottom: 20px;
6 }
7
8 .coluna-titulo {
9 margin: 0 0 8px;
10 font-size: 11px;
11 font-weight: 700;
12 letter-spacing: 0.05em;
13 text-transform: uppercase;
14 color: #64748b;
15 }

Cartão com imagem

Foto em cima, legenda colada embaixo — sem respiro entre as duas, pra dar impressão de continuidade.

1 .cartao {
2 display: block;
3 width: 100%;
4 margin-bottom: 8px;
5 border: 1px solid #cbd5e1;
6 border-radius: 12px;
7 overflow: hidden;
8 background: #f8fafc;
9 font: inherit;
10 text-align: left;
11 cursor: pointer;
12 }
13
14 .cartao img {
15 display: block;
16 width: 100%;
17 aspect-ratio: 1 / 1;
18 object-fit: cover;
19 }
20
21 .cartao span {
22 display: block;
23 padding: 8px 10px;
24 font-size: 14px;
25 font-weight: 500;
26 text-align: center;
27 }

Cartão selecionado

Realce neutro enquanto aguarda o clique no efeito correspondente.

1 .cartao[data-estado="selecionado"] {
2 outline: 2px solid #6366f1;
3 background: rgba(99, 102, 241, 0.1);
4 }

Cor por par

Cada cartão da esquerda tem uma cor fixa (data-cor, de 0 a 5); o cartão da direita herda a cor do da esquerda quando o par se forma, então as duas fotos de uma dupla sempre combinam — e nunca com as de outro par.

1 .cartao[data-estado="associado"][data-cor="0"] { border-color: #f59e0b; background: rgba(245, 158, 11, 0.1); }
2 .cartao[data-estado="associado"][data-cor="1"] { border-color: #8b5cf6; background: rgba(139, 92, 246, 0.1); }
3 .cartao[data-estado="associado"][data-cor="2"] { border-color: #06b6d4; background: rgba(6, 182, 212, 0.1); }
4 .cartao[data-estado="associado"][data-cor="3"] { border-color: #d946ef; background: rgba(217, 70, 239, 0.1); }
5 .cartao[data-estado="associado"][data-cor="4"] { border-color: #14b8a6; background: rgba(20, 184, 166, 0.1); }
6 .cartao[data-estado="associado"][data-cor="5"] { border-color: #f97316; background: rgba(249, 115, 22, 0.1); }

Resultado da verificação

Verde para quem acertou o par certo, vermelho para quem ficou sem par ou casou com o errado.

1 .cartao[data-estado="correta"] { border-color: #22c55e; background: rgba(34, 197, 94, 0.1); }
2 .cartao[data-estado="errada"] { border-color: #ef4444; background: rgba(239, 68, 68, 0.1); }

Lista de pares conectados

Caixa com uma linha por par formado, cada linha na mesma cor da dupla nas colunas acima.

1 .pares-lista {
2 margin-bottom: 20px;
3 padding: 16px;
4 border: 1px solid #cbd5e1;
5 border-radius: 12px;
6 background: #f8fafc;
7 }
8
9 .par {
10 display: flex;
11 align-items: center;
12 justify-content: space-between;
13 gap: 12px;
14 padding: 10px 12px;
15 margin-bottom: 8px;
16 border: 1px solid #cbd5e1;
17 border-radius: 8px;
18 font-size: 14px;
19 }
20
21 .par:last-child {
22 margin-bottom: 0;
23 }
24
25 .par[data-cor="0"] { border-color: #f59e0b; background: rgba(245, 158, 11, 0.08); }
26 .par[data-cor="1"] { border-color: #8b5cf6; background: rgba(139, 92, 246, 0.08); }
27 .par[data-cor="2"] { border-color: #06b6d4; background: rgba(6, 182, 212, 0.08); }
28 .par[data-cor="3"] { border-color: #d946ef; background: rgba(217, 70, 239, 0.08); }
29 .par[data-cor="4"] { border-color: #14b8a6; background: rgba(20, 184, 166, 0.08); }
30 .par[data-cor="5"] { border-color: #f97316; background: rgba(249, 115, 22, 0.08); }
31
32 .par-seta {
33 color: #6366f1;
34 font-weight: 700;
35 }

Remover um par

Botão pequeno e circular, ativo só antes de verificar.

1 .par-remover {
2 flex-shrink: 0;
3 width: 24px;
4 height: 24px;
5 border: none;
6 border-radius: 999px;
7 background: #e2e8f0;
8 color: #475569;
9 font-size: 14px;
10 line-height: 1;
11 cursor: pointer;
12 }

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
13 .questao-verificar {
14 background: #4f46e5;
15 color: #fff;
16 }
17
18 .questao-reset {
19 background: #e5e7eb;
20 color: #1f2937;
21 }

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 a contagem de acertos, abaixo das colunas.

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 }
JavaScript

Encontrar os elementos da questão

Localiza as duas colunas, a lista de pares, o modelo de linha e as ações.

1 document.addEventListener('DOMContentLoaded', function () {
2 document.querySelectorAll('.questao[data-tipo="parear-imagens"]').forEach(function (questao) {
3 var esquerda = questao.querySelectorAll('.cartao-esq');
4 var direita = questao.querySelectorAll('.cartao-dir');
5 var lista = questao.querySelector('.pares-lista');
6 var template = questao.querySelector('.par-template');
7 var verificar = questao.querySelector('.questao-verificar');
8 var painel = questao.querySelector('.questao-painel');
9 var reset = questao.querySelector('.questao-reset');
10 // O cartão da esquerda selecionado, aguardando o clique no par da direita.
11 var selecionado = null;
12
13 function itemDireita(parId) {
14 return questao.querySelector('.cartao-dir[data-par-id="' + parId + '"]');
15 }
16
17 function legenda(cartao) {
18 return cartao.querySelector('span').textContent.trim();
19 }
20
21 function limparSelecao() {
22 if (selecionado) selecionado.dataset.estado = selecionado.dataset.associado ? 'associado' : 'padrao';
23 selecionado = null;
24 }

Lista de pares conectados

Cria ou atualiza a linha do par (na mesma cor do cartão da esquerda) e permite desfazer com o × — só antes de verificar.

1 function entradaPar(itemEsq) {
2 return lista.querySelector('.par[data-par-id="' + itemEsq.dataset.parId + '"]');
3 }
4
5 function criarOuAtualizarPar(itemEsq, itemDir) {
6 var entrada = entradaPar(itemEsq);
7 if (!entrada) {
8 var fragmento = template.content.cloneNode(true);
9 entrada = fragmento.querySelector('.par');
10 entrada.dataset.parId = itemEsq.dataset.parId;
11 lista.appendChild(fragmento);
12 }
13 entrada.dataset.cor = itemEsq.dataset.cor;
14 entrada.querySelector('.par-esquerda').textContent = legenda(itemEsq);
15 entrada.querySelector('.par-direita').textContent = legenda(itemDir);
16 lista.hidden = false;
17 }
18
19 function removerEntradaPar(itemEsq) {
20 var entrada = entradaPar(itemEsq);
21 if (entrada) entrada.remove();
22 lista.hidden = !lista.children.length;
23 }
24
25 lista.addEventListener('click', function (evento) {
26 var botao = evento.target.closest('.par-remover');
27 if (!botao || verificar.disabled) return;
28 var entrada = botao.closest('.par');
29 var itemEsq = questao.querySelector('.cartao-esq[data-par-id="' + entrada.dataset.parId + '"]');
30 var itemDir = itemEsq.dataset.associado ? itemDireita(itemEsq.dataset.associado) : null;
31 delete itemEsq.dataset.associado;
32 itemEsq.dataset.estado = 'padrao';
33 if (itemDir) { itemDir.dataset.estado = 'padrao'; delete itemDir.dataset.cor; }
34 removerEntradaPar(itemEsq);
35 });

Selecionar um cartão da esquerda

Clique alterna a seleção; clicar em outro cartão troca, sem mexer no par que ele já tinha formado.

1 esquerda.forEach(function (item) {
2 item.addEventListener('click', function () {
3 if (verificar.disabled) return;
4 if (selecionado === item) { limparSelecao(); return; }
5 limparSelecao();
6 selecionado = item;
7 item.dataset.estado = 'selecionado';
8 });
9 });

Associar ao efeito

Só reage com um cartão da esquerda selecionado; o cartão da direita herda a cor do par, e a lista ganha (ou atualiza) uma linha.

1 direita.forEach(function (item) {
2 item.addEventListener('click', function () {
3 if (!selecionado || verificar.disabled) return;
4
5 var anterior = Array.prototype.find.call(esquerda, function (e) {
6 return e.dataset.associado === item.dataset.parId;
7 });
8 var antigaDireita = selecionado.dataset.associado
9 ? itemDireita(selecionado.dataset.associado)
10 : null;
11
12 if (anterior && anterior !== selecionado) {
13 delete anterior.dataset.associado;
14 anterior.dataset.estado = 'padrao';
15 removerEntradaPar(anterior);
16 }
17 if (antigaDireita && antigaDireita !== item) { antigaDireita.dataset.estado = 'padrao'; delete antigaDireita.dataset.cor; }
18
19 selecionado.dataset.associado = item.dataset.parId;
20 selecionado.dataset.estado = 'associado';
21 item.dataset.estado = 'associado';
22 item.dataset.cor = selecionado.dataset.cor;
23 criarOuAtualizarPar(selecionado, item);
24 selecionado = null;
25 });
26 });

Verificar

Um par está certo quando o par-id associado do cartão da esquerda bate com o próprio par-id.

1 verificar.addEventListener('click', function () {
2 var acertos = 0;
3 esquerda.forEach(function (item) {
4 var correto = item.dataset.associado === item.dataset.parId;
5 item.dataset.estado = correto ? 'correta' : 'errada';
6 if (correto) acertos++;
7 });
8
9 painel.querySelector('.questao-painel-mensagem').textContent = acertos === esquerda.length
10 ? 'Correto! Todos os pares conectados.'
11 : acertos + ' de ' + esquerda.length + ' pares corretos.';
12 painel.hidden = false;
13
14 lista.querySelectorAll('.par-remover').forEach(function (b) { b.hidden = true; });
15
16 verificar.hidden = true;
17 reset.hidden = false;
18 });

Reiniciar

Desfaz todas as associações, esvazia a lista de pares e devolve o estado inicial.

1 reset.addEventListener('click', function () {
2 selecionado = null;
3 esquerda.forEach(function (item) {
4 delete item.dataset.associado;
5 item.dataset.estado = 'padrao';
6 });
7 direita.forEach(function (item) {
8 item.dataset.estado = 'padrao';
9 delete item.dataset.cor;
10 });
11 lista.textContent = '';
12 lista.hidden = true;
13 painel.hidden = true;
14 verificar.hidden = false;
15 reset.hidden = true;
16 });