JavaScript/Tutorials/Spiele/Multiple-Choice-Quiz
Multiple Choice oder deutsch Mehrfachauswahl, auch Antwort-Wahl-Verfahren, ist eine in Prüfungen, Tests, Klausuren und Umfragen verwendete Fragetechnik, bei der zu einer Frage mehrere vorformulierte Antworten zur Auswahl stehen. So kann man Sachwissen abfragen, ohne dass die Schreibfähigkeiten (und Rechtschreibung) des Prüfenden ins Spiel kommen.
Dabei ist es zu beachten, dass Multiple Choice im Englischen strikt eine gültige Antwort aus mehreren bedeutet (daher ein falscher Freund[1]), was im Deutschen Single Choice entspricht, während mehrere gültige Antwortmöglichkeiten im Englischen als multiple response bezeichnet werden.[2]
Inhaltsverzeichnis
Spielidee
- Der Computer gibt eine Frage aus und stellt mehrere Antwortmöglichkeiten.
- Dabei werden Fragen und die Antwortmöglichkeiten nach dem Zufallsprinzip gemischt.
- Der Benutzer kann eine Antwortmöglichkeit durch Klicken auswählen.
- Der Computer berechnet am Ende den Prozentsatz oder Anteil der richtig beantworteten Fragen.
HTML
Wenn man etwas aus mehreren Möglichkeiten auswählen soll, bieten sich Radio-Buttons an:
<form id="quiz" action="">
<fieldset role="radiogroup">
<legend>Frage …</legend>
<input type="radio" name="answer" id="a27_0">
<label for="a27_0">Antwort 1</label>
<input type="radio" name="answer" id="a27_1">
<label for="a27_1">Antwort 2</label><
<input type="radio" name="answer" id="a27_2" value="Antwort 3">
<label for="a27_2">Antwort 3</label>
</fieldset>
<button type="submit">Auswahl bestätigen</button>
</form>
Radio-Buttons (input type="radio") lassen sich über ein gemeinsames name-Attribut miteinander verknüpfen. So kann jeweils nur ein Element ausgewählt werden – klickt man auf ein anderes, wird dieses automatisch selektiert.
Am Ende gibt es einen Absende-Button.
Dabei kann nicht nur mit der Maus auf die Radio-Buttons, sondern auch auf die zugehörigen Labels geklickt werden. Input-Elemente lassen sich auch mit der Tastatur bedienen – bei anderen Elementen müsste diese Funktionalität oft erst mit JavaScript nachgebaut werden. Mit der Tab-Taste ↹ navigiert man von einem Element zum nächsten; innerhalb einer Gruppe von Radio-Buttons kann man mit den Pfeiltasten wechseln.
Der Button kann durch Drücken der Enter- oder Leertaste ausgelöst werden
Da ist ja ein Formular – wir wollten doch aber ein Spiel?
Dies ist die semantisch passende Grundstruktur. Das Aussehen kann mit CSS beliebig verändert werden.
CSS
Die Radio-Buttons sehen eher „technisch“ aus. Nun wollen wir sie visuell verstecken und die labels so stylen, dass Nutzaktionen sichtbar werden.
#quiz input { /*visually-hidden */
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
Zuerst werden nun die input-Elemente mit den in visually-hidden vorgestellten Techniken so ausgeblendet, dass die labels weiterhin bedienbar sind.
/* Hover-Effekt */
#quiz label:hover {
background-color: lightyellow;
}
/* mache Fokus sichtbar */
#quiz input[type="radio"]:focus + label {
outline: 2px solid black;
outline-offset: 2px;
}
/* Auswahl */
#quiz input[type="radio"]:checked + label {
background-color: gold;
border-color: #866a00;
}
Dafür erhalten die dazugehörigen Labels nun mit display: block;
eine Box, die man anklicken oder mit der Tastatur fokussieren kann.
Diese beiden Zustände werden ebenfalls mit CSS so formatiert, dass man den gewählten Zustand erkennen kann.
input:checked ~ label
selektiert mit dem Geschwisterselektor den ausgewählten Radio-Button mit seinem Label.
JavaScript
Im Gegensatz zu den anderen in dieser Reihe besprochenen Spielen werden die Fragen bei einem Multiple-Choice-Quiz im Voraus zusammengestellt und nicht zufällig generiert.
Damit unser Script von Anfang an so flexibel wie möglich ist, sollen die Aufgaben aus einer externen Datei geladen werden.
Datenstruktur
Zunächst sollte überlegt werden, wie man die Fragen und Aufgaben strukturiert – inklusive der richtigen Antwort, falscher Antwortmöglichkeiten sowie einer Erklärung, die nach der Auswertung angezeigt wird. Die Datenstruktur sollte so flexibel gestaltet sein, dass sowohl beliebig viele Aufgaben als auch beliebig viele Antwortmöglichkeiten hinzugefügt werden können. Zudem sollte das Skript später mit mehreren Dat(ei)en unterschiedlicher Inhalte arbeiten können.
{
"category": "IT",
"question": "Welche Technologien sind clientseitig?",
"answers": [
{ "correct": true, "answer": "HTML" },
{ "correct": true, "answer": "CSS" },
{ "correct": true, "answer": "JavaScript" },
{ "correct": false, "answer": "PHP" }
],
"explanation": "HTML, CSS und JavaScript - Serverseitig PHP und JavaScript (mit node.js)"
}
Jedes Fragenset besteht aus einer Kategorie, der Frage, einer Liste von Antwortobjekten und einer Erklärung, warum bestimmte Antwortmöglichkeiten falsch oder richtig waren. Dabei können, anders als bei "Wer wird Millionär?" potenziell auch mehrere Optionen richtig sein – auch wenn unser Script das noch nicht berücksichtigen wird.
Ein solches Antwortobjekt besteht nun aus …
- einem Schalter
correct
, der den Wert true/false haben kann. - der
answer
und einer - Option für weitere Antwortattribute, wie z.B. Medienlinks.
Bei der Hauptstadtfrage könnte es so aussehen:
{
"data": [
{
"category": "Politik",
"question": "Welche Stadt wurde 1990 deutsche Hauptstadt?",
"answers": [
{
"correct": true,
"answer": "Berlin"
},
{
"correct": false,
"answer": "Frankfurt am Main"
},
{
"correct": false,
"answer": "Bonn"
},
{
"correct": false,
"answer": "München"
}
],
"explanation": "Berlin wurde am 03.10.1990 auf Grund des Einigungsvertrages wieder zur deutschen Bundeshauptstadt.<br>Frankfurt war 1949 als Bundeshauptstadt im Rennen,<br>Bonn setzte sich am 10.05.1949 gegen Frankfurt als Bundeshauptstadt durch, bis es am 03.10.1990 abgelöst wurde."
},
{
"category": "Biologie",
"question": "Erdbeeren sind …",
"answers": [
{
"correct": true,
"answer": "Nüsse"
},
{
"correct": false,
"answer": "Beeren"
},
{
"correct": false,
"answer": "Obst"
},
{
"correct": false,
"answer": "Gemüse"
}
],
"explanation": "In Wahrheit gehört die Erdbeere zu den Sammelnussfrüchten. Die vermeintlich rote Frucht ist in Wahrheit nur eine Scheinfrucht, auch Fruchtboden genannt."
}
]
}
Diese JSON-Datei können wir nun in unser Script und unsere Webseite laden.
Auch wenn dies bei einem Quiz kompliziert erscheint, ermöglicht es diese Vorgehensweise,
das selbe Script für mehrere Quizze zu verwenden.
Laden externer JSON-Dateien
Wie oben erklärt, trennen wir die Daten (im JSON-Objekt) von der Quiz-Logik. Sobald das Quiz startet, wird das externe JSON geladen:
document.addEventListener("DOMContentLoaded", function () {
const JSONUrl = "/extensions/Selfhtml/example.php/Beispiel:Multiple-choice-questions.json";
...
async function loadQuestions() {
try {
const response = await fetch(JSONUrl);
const data = await response.json();
questions = data.data;
} catch (error) {
console.error("Fehler beim Laden der Fragen:", error);
}
}
In einem try ..catch-Block, um Fehler abzufangen, wird nun ein GET REQUEST an die angegeben URL gesendet.[3]
- fetch liefert einen Promise mit der Antwort.
Durch das Schlüsselwort await wird das Script pausiert, bis die Antwort (Repsonse) erfolgt ist -
const data = await response.json();
liest den Inhalt der Antwort aus und parst es als JSON.
Diese ist nun imdata
-Objekt verfügbar.
Information: Anmerkung
Wenn man diese URL aufruft, bekommt man eine HTML-Datei, die einen Fehler erzeugt. - Hier hilft unsere
example.php
- deshalb die kryptische URL im Script.--Matthias Scharwies (Diskussion) 05:18, 23. Mai 2025 (CEST)
Initialisierung
Unsere Multiple-Choice-Aufgaben sind in einem data-Objekt - das unterschiedlich viele Aufgaben- und Antwortmöglichkeiten umfassen kann. Deshalb können wir kein festes HTML-Markup verwenden, sondern verfolgen drei mögliche Ansätze:
- Erzeugen der Elemente mit createElement
- Einfügen von HTML-Markup mit insertAdjacentHTML
- Einfügen eines HTML-Templates mit appendChild
function renderQuestion(index) {
const questionData = questions[index];
const oldFieldset = form.querySelector("fieldset");
if (oldFieldset) oldFieldset.remove();
const quizContent = template.content.cloneNode(true);
const fieldset = quizContent.querySelector("fieldset");
const legend = fieldset.querySelector("legend");
legend.textContent = `${questionData.category}: ${questionData.question}`;
fieldset.innerHTML = `<legend>${legend.textContent}</legend>`;
questionData.answers.forEach((answer, i) => {
const inputId = `q${index}_a${i}`;
const input = document.createElement("input");
input.type = "radio";
input.name = `q${index}`;
input.id = inputId;
input.value = answer.answer;
const label = document.createElement("label");
label.htmlFor = inputId;
label.textContent = answer.answer;
fieldset.appendChild(input);
fieldset.appendChild(label);
});
form.insertBefore(fieldset, button);
}
Ich habe mich für eine Mischung entschieden:
-
const quizContent = template.content.cloneNode(true);
lädt das template mit dem fieldset und der legend -
questionData.answers.forEach((answer, i) => { };
durchläuft alle Antworten und- erzeugt mit
document.createElement("input");
ein neues input-Element mit passendem label
- erzeugt mit
So ist man flexibel, wenn es einmal nur eine true/false-Frage oder drei Antwortmöglichkeiten gibt.
Auswertung
Sobald unser Script die Aufgabe geladen hat, warten wir auf eine Eingabe durch die Person vor dem Bildschirm, die dann vom Browser ausgewertet wird. Danach soll eine neue Aufgabe gestellt und zum Schluss das Ergebnis ausgegeben werden.
function handleSubmit() {
const selected = form.querySelector(`input[name="q${currentQuestionIndex}"]:checked`);
if (!selected) {
alertBox("Bitte wählen Sie eine Antwort aus!", "error");
return;
}
const question = questions[currentQuestionIndex];
const selectedValue = selected.value;
const selectedAnswerObj = question.answers.find(a => a.answer === selectedValue);
const correctAnswer = question.answers.find(a => a.correct);
const isCorrect = selectedAnswerObj?.correct;
// Store result
results.push({
question: question.question,
userAnswer: selectedValue,
isCorrect,
correctAnswer: correctAnswer.answer,
explanation: question.explanation || "",
});
currentQuestionIndex++;
if (currentQuestionIndex < questions.length) {
setTimeout(() => {
renderQuestion(currentQuestionIndex);
}, 500);
} else {
form.remove(); // remove quiz form
renderResults();
}
}
function renderResults() {
const resultList = document.createElement("ol");
resultList.id = "result";
results.forEach(result => {
const li = document.createElement("li");
const questionP = document.createElement("p");
questionP.className = "question";
questionP.textContent = result.question;
const answerP = document.createElement("p");
answerP.innerHTML = `Ihre Antwort: ${result.userAnswer}`;
const explanationP = document.createElement("p");
explanationP.innerHTML = `Erläuterung: ${result.explanation}`;
li.appendChild(questionP);
li.appendChild(answerP);
li.appendChild(explanationP);
resultList.appendChild(li);
});
Nun wird eine sortierte Liste erzeugt, in der jede Frage und die gewählte Antwort, sowie die richtige Lösung und eine Erklärung gezeigt werden.
Ergebnis: Dies ist ein Script, mit dem z. B. über ein Auswahlmenü mehrere Quizze geladen werden können, ohne das eigentliche Script anfassen und verändern zu müssen. Dabei ist es völlig responsiv und auch auf mobilen Geräten zu nutzen.
Anwendungsbeispiele
Mithilfe dieses Scripts haben wir zum Jubiläum 2025 ein aktuelles Rätsel erstellt sowie das Quiz zum 10-jährigen Jubiläum wieder zum Leben erweckt:
- 10 Jahre SELFHTML
1995-2005 - Weihnachtsquiz
2016 - 30 Jahre SELFHTML
1995-2025
Das Quiz-Script ist aus Gründen der einfacheren Handhabung des Weihnachts-Quiz 2016 im HTML-Dokument integriert. Man kann es im Quellcode des Dokuments betrachten und mit dem Seiteninspektor analysieren.
Weblinks
- ↑ falscher Freund (Wikipedia)
- ↑ Felix Riesterer, der Autor dieses Scripts ist seit 2005 bei SELFHTML aktiv. Er hat unter anderem ein JavaScript-Framework für interaktive Lernaufgaben geschrieben, dass unter einer GNU Lesser General Public License (LGPL) verfügbar ist. Mit diesem können mit einfachsten Mitteln diverse Quizze auf HTML-Seiten erstellt werden.
- ↑ Arbeiten mit JSON(developer.mozilla.org)