Programmering nivå 2 med HTML, CSS och JavaScript
Kapitel 2: Bygg quizappen
I det här kapitlet bygger vi det som behövs för quizappen: HTML-strukturen, den viktigaste CSS-stylingen och grunderna för att koppla ihop allt med JavaScript.
Innehåll
Följ stegen och bygg det som quizappen behöver från start.
Kapitelöversikt
Det här kapitlet visar hur du bygger grunden till en quizapp. Fokus ligger på den HTML som måste finnas, den CSS som gör layouten tydlig och den JavaScript-logik som senare rättar svaren.
2.1 Quizappens HTML-struktur
För att quizappen ska fungera måste HTML innehålla rätt delar från början: en huvudsektion, ett formulär, frågor, svarsalternativ, en knapp för att rätta och platser där resultatet kan visas.
Mål
- förstå vilka HTML-delar som måste finnas i quizappen
- se hur formulär och svarsalternativ byggs upp
- veta var resultat och feedback ska skrivas ut
HTML som måste finnas med
<main class="quiz-app">
<h1>Quiz om webben</h1>
<form id="quizForm" class="quiz-form">
<fieldset class="question" data-correct="B" data-explanation="HTML skapar struktur och innehåll.">
<legend>1. Vilken tagg används för rubriker?</legend>
<label><input type="radio" name="q1" value="A"> A. p</label>
<label><input type="radio" name="q1" value="B"> B. h1</label>
<label><input type="radio" name="q1" value="C"> C. div</label>
<p class="quiz-feedback" aria-live="polite"></p>
</fieldset>
<button type="submit" class="quiz-submit">Rätta quizet</button>
<p id="quiz-status" class="quiz-status" aria-live="polite"></p>
<div id="quiz-summary" class="quiz-summary" hidden></div>
</form>
</main>
<!-- Använd färdiga skriptet från kursen: -->
<script src="../js/quiz-app.js" defer></script>
Du kan också kopiera filen js/quiz-app.js till ditt projekt och länka med
<script src="main.js" defer>.
Övning
Bygg upp samma struktur i din egen index.html så att quizappen har ett formulär, en
knapp, statusrad och en sammanfattning.
2.2 CSS som måste finnas med
Quizappen behöver CSS som gör formuläret lätt att läsa, frågorna tydliga och knappen enkel att hitta. Den här stilen är en bra grund att starta från.
Mål
- förstå vilken CSS som behövs för quizappen
- styla formulär, frågor och feedback på ett tydligt sätt
- kunna göra sidan lättläst på både mobil och dator
CSS som måste finnas med
.quiz-app {
max-width: 760px;
margin: 0 auto;
padding: 2rem;
}
.quiz-form {
display: grid;
gap: 1.5rem;
}
.question {
border: 1px solid #cbd5e1;
border-radius: 1rem;
padding: 1rem;
background: #fff;
}
.question label {
display: block;
margin: 0.4rem 0;
}
.quiz-submit {
border: 0;
border-radius: 999px;
padding: 0.9rem 1.2rem;
background: #14532d;
color: #fff;
font-weight: 700;
}
.quiz-status,
.quiz-summary {
margin-top: 1rem;
}
Övning
Skapa style.css och lägg in grundstilen ovan. Ändra gärna färger och avstånd så att
quizappen blir tydlig och lätt att läsa.
2.3 Frågor, svar och data-attribut
När quizappen byggs behöver varje fråga ha rätt svar och en förklaring. Det kan du lagra direkt i
HTML med data-*-attribut, så att JavaScript senare kan läsa dem.
Mål
- förstå hur
data-correctochdata-explanationanvänds - veta varför rätt svar behöver vara tydligt markerat i HTML
- se hur frågorna kan rättas automatiskt senare
Exempel på fråga
<fieldset class="question" data-correct="B" data-explanation="HTML skapar struktur och innehåll.">
<legend>1. Vilken tagg används för rubriker?</legend>
<label><input type="radio" name="q1" value="A"> A. p</label>
<label><input type="radio" name="q1" value="B"> B. h1</label>
<label><input type="radio" name="q1" value="C"> C. div</label>
<p class="quiz-feedback" aria-live="polite"></p>
</fieldset>
Övning
Lägg in minst en fråga i din quizapp och skriv rätt svar i ett data-correct-attribut.
Skriv också en kort förklaring i data-explanation.
2.4 Koppla JavaScript till formuläret
När HTML och CSS finns på plats kan JavaScript kopplas in för att läsa in svar, jämföra dem och visa resultatet på sidan.
Mål
- förstå hur formuläret hittas i JavaScript
- veta att en submit-händelse används för att rätta quizet
- kunna visa status och sammanfattning på sidan
Vad koden kommer att behöva göra
- hitta formuläret med
getElementById - samla alla frågor med
querySelectorAll - visa om alla frågor är besvarade
- skriva rätt/fel och förklaringar i quizens feedbackfält
Övning
Förbered din main.js så att den hittar #quizForm, #quiz-status
och #quiz-summary. Det är de element som behövs för att rätta quizet.
JavaScript — komplett exempel (lägg i main.js)
Här är den kompletta koden samlad i ett stycke — kopiera rakt av till din main.js om du
vill ha en komplett fil direkt.
document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('quizForm');
const status = document.getElementById('quiz-status');
const summary = document.getElementById('quiz-summary');
if (!form) return;
form.addEventListener('submit', (e) => {
e.preventDefault();
const questions = Array.from(form.querySelectorAll('.question'));
const unanswered = [];
let correctCount = 0;
questions.forEach((q, i) => {
const nameInput = q.querySelector('input[type="radio"]');
const name = nameInput ? nameInput.name : null;
const selected = name ? q.querySelector(`input[name="${name}"]:checked`) : null;
const correct = q.dataset.correct;
const feedback = q.querySelector('.quiz-feedback');
if (!selected) {
unanswered.push(i + 1);
if (feedback) feedback.textContent = 'Besvara frågan.';
return;
}
const isCorrect = selected.value === correct;
if (isCorrect) {
correctCount += 1;
if (feedback) feedback.textContent = 'Rätt! ' + (q.dataset.explanation || '');
} else {
if (feedback) feedback.textContent = `Fel. Rätt svar är ${correct}. ` + (q.dataset.explanation || '');
}
});
if (unanswered.length) {
status.textContent = 'Alla frågor måste besvaras. Saknade: ' + unanswered.join(', ');
summary.hidden = true;
return;
}
status.textContent = `Du fick ${correctCount} av ${questions.length} rätt.`;
summary.hidden = false;
summary.innerHTML = `Resultat
Rätt: ${correctCount} / ${questions.length}
`;
});
});
JavaScript — uppdelat och förklarat (lägg i main.js)
Nedanför följer samma funktionalitet uppdelad i mindre kodstycken. Efter varje kodstycke finns en kort förklaring, varför det är viktigt enligt lärandeforskning, och ett litet gör själv-förslag.
1) Vänta på att DOM är färdig
document.addEventListener('DOMContentLoaded', () => {
// allt som berör DOM:en går här
});
Varför: säkerställer att elementen finns innan vi försöker hämta dem.
Gör
själv: ta bort lyssnaren och se vad som händer i konsolen.
2) Hämta de element vi behöver
const form = document.getElementById('quizForm');
const status = document.getElementById('quiz-status');
const summary = document.getElementById('quiz-summary');
Varför: vi måste ha referenser för att läsa/skriva i DOM.
Gör
själv: logga variablerna med console.log.
3) Avbryt formens standardbeteende
form.addEventListener('submit', (e) => {
e.preventDefault();
// rättningslogik här
});
Varför: normalt skickar ett formulär och laddar om sidan — det vill vi undvika så vi
kan visa resultat direkt.
Gör själv: kommentera ut
e.preventDefault() och återställ efter test.
4) Samla alla frågor till en array
const questions = Array.from(form.querySelectorAll('.question'));
let correctCount = 0;
const unanswered = [];
Varför: form.querySelectorAll('.question') returnerar en
NodeList — en samling DOM-noder. En NodeList har vissa metoder (t.ex. forEach)
men saknar andra vanliga arraymetoder som map, filter och
reduce. Därför använder vi Array.from(...) för att skapa en riktig
JavaScript Array som ger full tillgång till arraymetoder.
Gör själv: i webbläsarkonsolen prova:
const nodes = form.querySelectorAll('.question');
console.log(nodes instanceof NodeList); // true
const questions = Array.from(nodes);
console.log(Array.isArray(questions)); // true
Skriv sedan ut questions.length till status före rättningen för att verifiera
antal frågor.
5) Iterera och kontrollera svar
questions.forEach((q, i) => {
const nameInput = q.querySelector('input[type="radio"]');
const name = nameInput ? nameInput.name : null;
const selected = name ? q.querySelector(`input[name="${name}"]:checked`) : null;
const correct = q.dataset.correct;
const feedback = q.querySelector('.quiz-feedback');
if (!selected) {
unanswered.push(i + 1);
if (feedback) feedback.textContent = 'Besvara frågan.';
return;
}
const isCorrect = selected.value === correct;
if (isCorrect) {
correctCount += 1;
if (feedback) feedback.textContent = 'Rätt! ' + (q.dataset.explanation || '');
} else {
if (feedback) feedback.textContent = `Fel. Rätt svar är ${correct}. ` + (q.dataset.explanation || '');
}
});
Varför: här händer själva rättningen och feedbacken — omedelbar feedback stärker
minnet.
Gör själv: ändra feedback-meddelandena och se hur det påverkar
elevupplevelsen.
6) Hantera obesvarade och visa sammanfattning
if (unanswered.length) {
status.textContent = 'Alla frågor måste besvaras. Saknade: ' + unanswered.join(', ');
summary.hidden = true;
return;
}
status.textContent = `Du fick ${correctCount} av ${questions.length} rätt.`;
summary.hidden = false;
summary.innerHTML = `Resultat
Rätt: ${correctCount} / ${questions.length}
`;
Varför: tydlig summering och felhantering ger bättre lärande och mindre
frustration.
Gör själv: lägg till procent och rekommendationer beroende på
poäng.
7) Tillgänglighet och förbättring
Se till att .quiz-feedback använder aria-live så skärmläsare meddelar
uppdateringar. Fundera också på att extrahera delar av koden till små funktioner (t.ex.
checkQuestion(q)) — det underlättar repetition och testning.
8) Förslag på tre korta övningar (Gör själv)
- Markera varje fråga med en klass
.correcteller.incorrectefter rättning och ge olika bakgrundsfärg. - Lägg till en knapp "Rensa svar" som nollställer formuläret, feedback och sammanfattning.
- Spara resultatet i
localStorageoch visa tidigare bästa poäng i sidhuvudet.
Vill du att jag lägger in en färdig övningssektion med dessa tre uppgifter i kapiteltexten? Svara med ja eller nej.
2.5 Sammanfattning
För att bygga quizappen behöver du rätt HTML-struktur, tydlig CSS och JavaScript som kopplar ihop formuläret med resultatet. När grunden finns på plats kan du lägga till fler frågor och förbättra upplevelsen steg för steg.
- HTML ger quizappen struktur.
- CSS gör formuläret läsbart och tydligt.
- JavaScript rättar svaren och visar feedback.
- Data-attribut gör att rätt svar och förklaringar kan lagras i HTML.
Quiz
Välj ett svar per fråga. Quizet visar resultat och förklaringar när alla frågor är besvarade.