Todas as atividades
Quiz e Avaliação

Ligar Colunas

O aprendiz conecta itens de uma coluna com seus correspondentes em outra. Avalia associação de conceitos, definições, exemplos e categorias.

Compreensão correspondência associação colunas matching

Experimente

Clique em um item da esquerda e depois no correspondente da direita:

Termos

Definições

Código-fonte

PHP

Dados de exemplo

Pares fixos — a coluna direita embaralha a ORDEM DE EXIBIÇÃO, nunca o índice que identifica cada par.

1 <?php
2 $instrucao = 'Clique em um item da esquerda e depois no correspondente da direita:';
3 $pares = [
4 0 => ['esquerda' => 'HTML', 'direita' => 'Estrutura da página'],
5 1 => ['esquerda' => 'CSS', 'direita' => 'Aparência da página'],
6 2 => ['esquerda' => 'JavaScript', 'direita' => 'Comportamento da página'],
7 ];
8 $indicesDireita = array_keys($pares);
9 shuffle($indicesDireita);
10 ?>

Estrutura das duas colunas

Cada botão carrega seu índice (data-index); os da esquerda também recebem uma cor própria (data-cor), que a definição herda quando o par se forma.

1 <div class="questao" data-tipo="correspondencia-colunas">
2
3 <p class="questao-instrucao"><?= htmlspecialchars($instrucao) ?></p>
4
5 <div class="colunas">
6 <div class="coluna">
7 <p class="coluna-titulo">Termos</p>
8 <?php foreach ($pares as $i => $par): ?>
9 <button type="button" class="col-esquerda" data-index="<?= $i ?>" data-cor="<?= $i % 6 ?>">
10 <?= htmlspecialchars($par['esquerda']) ?>
11 </button>
12 <?php endforeach; ?>
13 </div>
14
15 <div class="coluna">
16 <p class="coluna-titulo">Definições</p>
17 <?php foreach ($indicesDireita as $i): $par = $pares[$i]; ?>
18 <button type="button" class="col-direita" data-index="<?= $i ?>">
19 <?= htmlspecialchars($par['direita']) ?>
20 </button>
21 <?php endforeach; ?>
22 </div>
23 </div>

Lista de pares conectados

Caixa vazia, preenchida pelo JavaScript a cada par formado; o modelo abaixo define a linha, com um botão para desfazer 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</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

Termos à esquerda, definições à 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 }

Caixas dos termos e definições

Botão de largura total, texto alinhado à esquerda.

1 .col-esquerda,
2 .col-direita {
3 display: block;
4 width: 100%;
5 margin-bottom: 8px;
6 padding: 10px 12px;
7 border: 1px solid #cbd5e1;
8 border-radius: 8px;
9 background: #f8fafc;
10 font: inherit;
11 text-align: left;
12 cursor: pointer;
13 }

Termo selecionado

Realce neutro enquanto aguarda o clique na definição correspondente.

1 .selecionada {
2 outline: 2px solid #6366f1;
3 background: rgba(99, 102, 241, 0.1);
4 }

Cor por par

Cada termo tem uma cor fixa (data-cor, de 0 a 5); a definição herda a cor do termo quando o par se forma, então as duas caixas de uma dupla sempre combinam — e nunca com as de outro par.

1 .associada[data-cor="0"] { border-color: #f59e0b; background: rgba(245, 158, 11, 0.1); }
2 .associada[data-cor="1"] { border-color: #8b5cf6; background: rgba(139, 92, 246, 0.1); }
3 .associada[data-cor="2"] { border-color: #06b6d4; background: rgba(6, 182, 212, 0.1); }
4 .associada[data-cor="3"] { border-color: #d946ef; background: rgba(217, 70, 239, 0.1); }
5 .associada[data-cor="4"] { border-color: #14b8a6; background: rgba(20, 184, 166, 0.1); }
6 .associada[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 — sobrepõe a cor do par, porque o resultado importa mais nesse momento.

1 .acerto { border-color: #22c55e; background: rgba(34, 197, 94, 0.1); }
2 .erro { 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="correspondencia-colunas"]').forEach(function (questao) {
3 var esquerda = questao.querySelectorAll('.col-esquerda');
4 var direita = questao.querySelectorAll('.col-direita');
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 item da esquerda selecionado, aguardando o clique no par da direita.
11 var selecionado = null;
12
13 function itemDireita(indice) {
14 return questao.querySelector('.col-direita[data-index="' + indice + '"]');
15 }
16
17 function limparSelecao() {
18 if (selecionado) selecionado.classList.remove('selecionada');
19 selecionado = null;
20 }

Lista de pares conectados

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

1 function entradaPar(itemEsq) {
2 return lista.querySelector('.par[data-index="' + itemEsq.dataset.index + '"]');
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.index = itemEsq.dataset.index;
11 lista.appendChild(fragmento);
12 }
13 entrada.dataset.cor = itemEsq.dataset.cor;
14 entrada.querySelector('.par-esquerda').textContent = itemEsq.textContent.trim();
15 entrada.querySelector('.par-direita').textContent = itemDir.textContent.trim();
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('.col-esquerda[data-index="' + entrada.dataset.index + '"]');
30 var itemDir = itemEsq.dataset.associado ? itemDireita(itemEsq.dataset.associado) : null;
31 delete itemEsq.dataset.associado;
32 itemEsq.classList.remove('associada');
33 if (itemDir) { itemDir.classList.remove('associada'); delete itemDir.dataset.cor; }
34 removerEntradaPar(itemEsq);
35 });

Selecionar um termo

Clique alterna a seleção; clicar em outro termo 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.classList.add('selecionada');
8 });
9 });

Associar à definição

Só reage com um termo selecionado; a definição herda a cor do termo, e a lista de pares 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.index;
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.classList.remove('associada');
15 removerEntradaPar(anterior);
16 }
17 if (antigaDireita && antigaDireita !== item) {
18 antigaDireita.classList.remove('associada');
19 delete antigaDireita.dataset.cor;
20 }
21
22 selecionado.dataset.associado = item.dataset.index;
23 selecionado.classList.remove('selecionada');
24 selecionado.classList.add('associada');
25 item.classList.add('associada');
26 item.dataset.cor = selecionado.dataset.cor;
27 criarOuAtualizarPar(selecionado, item);
28 selecionado = null;
29 });
30 });

Verificar

Um par está certo quando o índice associado bate com o próprio índice do termo — o mesmo índice nos dois lados é o gabarito.

1 verificar.addEventListener('click', function () {
2 var acertos = 0;
3 esquerda.forEach(function (item) {
4 var correto = item.dataset.associado === item.dataset.index;
5 item.classList.remove('associada');
6 item.classList.add(correto ? 'acerto' : 'erro');
7 if (correto) acertos++;
8 });
9
10 painel.querySelector('.questao-painel-mensagem').textContent = acertos === esquerda.length
11 ? 'Correto! Todos os pares correspondidos.'
12 : acertos + ' de ' + esquerda.length + ' pares corretos.';
13 painel.hidden = false;
14
15 // Os pares viraram resultado: o × deixa de fazer sentido depois de
16 // verificado.
17 lista.querySelectorAll('.par-remover').forEach(function (b) { b.hidden = true; });
18
19 verificar.hidden = true;
20 reset.hidden = false;
21 });

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.classList.remove('selecionada', 'associada', 'acerto', 'erro');
6 });
7 direita.forEach(function (item) {
8 item.classList.remove('associada');
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 });