diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..02582f8 Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md index 57e6d16..2588c3e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ -# Web Accessibility Project +# Web Accessibility Quiz -A basic web server template focused on web accessibility practices. +A simple interactive quiz built with JavaScript that tests users on essential web accessibility concepts based on WCAG guidelines. Designed with accessibility in mind, it includes semantic HTML, proper focus management, ARIA roles, and keyboard navigation to ensure an inclusive user experience. -### Installation - -1. Fork this repository by clicking the "Fork" button at the top right of the GitHub repository page. - -2. Clone your forked repository +https://accessibility-guiz.netlify.app diff --git a/about.html b/about.html index 5adbad6..3c0ca6a 100644 --- a/about.html +++ b/about.html @@ -1,10 +1,88 @@ - - - - - About - - - - + + + + + + About + + + + + + + + +
+ + + +
+

Introduction to our team

+

We are a team of designers and developers, who believe accessibility should not be a feature — but a + foundation. Whether you're new to the topic or already passionate about inclusive design, we hope this helps you + see things from new perspectives — and inspires you to build with empathy, for everyone. +

+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/assets/Banner.png b/assets/Banner.png new file mode 100644 index 0000000..93260c1 Binary files /dev/null and b/assets/Banner.png differ diff --git a/assets/Disability_three.png b/assets/Disability_three.png new file mode 100644 index 0000000..dfab07c Binary files /dev/null and b/assets/Disability_three.png differ diff --git a/assets/Disability_two.png b/assets/Disability_two.png new file mode 100644 index 0000000..a876b56 Binary files /dev/null and b/assets/Disability_two.png differ diff --git a/assets/disability.jpg b/assets/disability.jpg new file mode 100644 index 0000000..08ccfdb Binary files /dev/null and b/assets/disability.jpg differ diff --git a/assets/disability1.jpg b/assets/disability1.jpg new file mode 100644 index 0000000..e323ad6 Binary files /dev/null and b/assets/disability1.jpg differ diff --git a/css/styles.css b/css/styles.css index e69de29..59ea836 100644 --- a/css/styles.css +++ b/css/styles.css @@ -0,0 +1,601 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap'); + +/* Base styles with accessibility considerations */ +:root { + --primary-color: #042778; + --background-color: rgb(213, 233, 250, 0.5); + --accent-color: #0073e6; + --selected-bg-color: #cce4ff; + --white-color: white; + --error-color: #e74c3c; + --focus-outline-color: #00509e; + --focus-outline: 2px solid var(--accent-color); + --text-color: #042778; + --border-color: #054fb9; + --transition-speed: 0.3s; +} + +/* Box-sizing */ +*, +*::before, +*::after { + box-sizing: border-box; +} + + +/* Base styles */ +body { + font-family: "Roboto", sans-serif; + line-height: 1.6; + color: var(--primary-color); + background-color: var(--background-color); + font-size: 16px; + margin: 0 auto; + display: flex; + flex-direction: column; + min-height: 100vh; +} + +/* Base sizes */ +h1 { + font-size: 1.5rem; + /* 24px */ +} + +h2 { + font-size: 1.25rem; + /* 20px */ +} + +h3 { + font-size: 1.125rem; + /* 18px */ +} + +p, +legend, +label { + font-size: 1rem; + /* 16px */ +} + +nav a { + font-size: 1.125rem; + /* 18px */ +} + +/* Skip link */ +.skip-link { + position: absolute; + top: -2.5rem; + left: 0; + background: var(--accent-color); + color: var(--white-color); + padding: 8px; + z-index: 100; + transition: top 0.3s; +} + +.skip-link:focus { + top: 0; + outline: var(--focus-outline); + outline-offset: 2px; +} + +:focus-visible { + outline: var(--focus-outline); + outline-offset: 2px; + border-radius: 2px; +} + +/* Header */ +#header { + width: 100vw; + background-color: var(--primary-color); + color: var(--white-color); + padding: 2rem 0; + +} + +#header .header-content { + max-width: 1000px; + margin: 0 auto; + padding: 0 3rem; + display: flex; + align-items: center; + text-align: center; + justify-content: space-between; +} + +#header h1 { + color: var(--white-color); + margin: 0; +} + +#header nav ul { + list-style: none; + padding: 0; + margin: 1rem 0; + display: flex; + gap: 2rem; +} + +#header nav a { + color: var(--white-color); + text-decoration: none; + padding: 8px 16px; + border-radius: 6px; + transition: opacity var(--transition-speed); +} + +#header nav a:hover { + text-decoration: underline; +} + +/* Quiz instructions*/ +#accessibility-quiz { + margin: 5% 20%; + border-radius: 8px; + background-color: var(--background-color); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08); + width: 100%; +} + +#accessibility-quiz h2 { + text-align: center; + margin-top: 1rem; + margin-bottom: 2rem; +} + +.quiz-instructions { + display: flex; + flex-direction: column; + align-items: center; + background-color: var(--white-color); + color: var(--text-color); + margin: 1rem auto; + max-width: 600px; + width: 100%; + padding: 1rem; + border-radius: 0 4px 4px 0; +} + +.info-image { + background: var(--white-color); + padding: 1rem; + max-width: 100%; + height: auto; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +/*Quiz card*/ +.quiz-card { + display: none; +} + +.quiz-card.active { + display: block; + margin: 1rem auto; + width: 100%; + max-width: 600px; + text-align: left; +} + +fieldset { + border: none; + margin: 1rem 0; + padding: 1rem; + border-radius: 4px; +} + +legend { + font-weight: bold; + text-align: left; + margin-bottom: 1rem; + color: var(--text-color); + border-radius: 4px; +} + +input { + text-align: left; +} + +input[type="radio"] { + cursor: pointer; + accent-color: var(--primary-color); + width: 1.1rem; + height: 1.1rem; + vertical-align: top; + margin-top: 5px; +} + +label { + padding-left: 8px; + margin-bottom: 8px; + width: 85%; +} + +input[type="radio"]+label { + display: inline-block; + word-wrap: break-word; +} + +input[type="radio"]:hover { + outline: 2px solid var(--accent-color); + outline-offset: 2px; +} + +/*Style for navigation w. keyboard*/ +input[type="radio"]:checked+label { + background-color: var(--selected-bg-color); + border-radius: 4px; +} + +input[type="radio"]:focus-visible+label { + outline: var(--focus-outline); + border-radius: 4px; +} + +.nav-buttons { + display: flex; + justify-content: space-between; + margin-top: 2em; +} + +.nav-buttons button { + background-color: var(--primary-color); + color: var(--white-color); + padding: 12px 16px; + border-radius: 4px; + font-size: 1em; + width: 6em; + cursor: pointer; +} + +.nav-buttons button:hover { + background-color: var(--accent-color); + border: 2px solid var(--primary-color) +} + +.next-btn:active, +.prev-btn:active { + transform: scale(0.98); +} + +.next-btn:focus-visible, +.prev-btn:focus-visible { + outline: var(--focus-outline); + outline-offset: 2px; +} + +/*Summary card*/ +#summary-card h2 { + text-align: center; + margin: 0 auto 0.75rem auto; +} + +#summary-content h3 { + text-align: center; + word-wrap: break-word; + margin: 1rem auto 0.5rem auto; +} + +#summary-card p { + text-align: center; + margin: 0 auto 0.5rem auto; +} + + +/* Progress bar */ +.quiz-progress { + margin: 2rem 0; +} + +.progress-bar { + background-color: var(--selected-bg-color); + border-radius: 8px; + height: 20px; + margin: 0 2rem 0 2rem; + overflow: hidden; + position: relative; +} + +.progress-fill { + background-color: var(--primary-color); + height: 100%; + transition: width 0.3s ease; + border-radius: 8px; +} + +.progress-text { + margin-top: 0.5rem; + text-align: center !important; + font-weight: 500; +} + +.error-message { + color: var(--error-color); + font-size: 1rem; + font-weight: 600; + padding-left: 0.5rem; +} + +.error-container { + margin-top: 2rem; +} + +#restart-btn { + background-color: var(--primary-color); + color: var(--white-color); + padding: 12px 16px; + border-radius: 4px; + font-size: 1rem; + width: 8rem; + cursor: pointer; + display: block; + margin: 0 auto; + margin-top: 2rem; +} + +#restart-btn:hover { + background-color: var(--accent-color); + border: 2px solid var(--primary-color) +} + +#restart-btn:active { + transform: scale(0.98); +} + +#restart-btn:focus-visible { + outline: var(--focus-outline); + outline-offset: 2px; +} + +/* About page*/ +.noinfo-image { + width: 100%; + aspect-ratio: 2.48 / 1; + /*to better cls*/ + object-fit: cover; +} + +#introduction { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + padding-left: 10px; + padding-right: 10px; + min-height: 300px; + /*for better cls*/ + +} + +#introduction h2 { + color: var(--primary-color); + margin-bottom: 1.5rem; +} + +#introduction p { + max-width: 800px; + margin: 0 auto 2rem; + text-align: left; + padding: 0.5rem; +} + +/* Footer */ +.footer-content { + width: 100vw; + background-color: var(--primary-color); + color: var(--white-color); + padding: 2rem 0; + margin-top: 2rem; +} + +footer nav ul { + list-style: none; + padding: 0.5rem 1rem; + margin: 1rem 0; + display: flex; + gap: 4rem; + justify-content: center; + background-color: var(--primary-color); +} + +nav a { + color: var(--white-color); + text-decoration: none; +} + +nav a:hover { + text-decoration: underline; +} + +/*Media Queries*/ +@media (min-width: 320px) and (max-width: 480px) { + + #header .header-content { + flex-direction: column; + } +} + +/* 480px to 768px */ +@media (min-width: 481px) and (max-width: 768px) { + #header .header-content { + flex-direction: column; + } + + #header h1 { + font-size: 1.625rem; + /* 26px */ + } + + #header nav a, + footer nav a { + font-size: 1.25rem; + /* 20px */ + } + + .quiz-instructions { + width: 90%; + } + + h2 { + font-size: 1.375rem; + /* 22px */ + } + + p, + legend, + label { + font-size: 1.125rem; + /* 18px */ + } + + .nav-buttons button { + width: 7.5rem; + } + + #restart-btn { + width: 9rem; + } +} + +/* 768px to 1024px */ +@media (min-width: 769px) and (max-width: 1024px) { + + #header h1 { + font-size: 1.625rem; + /* 26px */ + } + + #header nav a, + footer nav a { + font-size: 1.375rem; + /* 22px */ + } + + .quiz-instructions { + padding: 2em; + } + + .quiz-instructions p { + text-align: left; + } + + h2 { + font-size: 1.375rem; + /* 22px */ + } + + p, + legend, + label { + font-size: 1.125rem; + /* 18px */ + } + + .quiz-card.active p { + text-align: left; + } + + .nav-buttons button { + width: 7.5rem; + } + + #restart-btn { + width: 9rem; + } + + #summary-content { + padding-left: 4rem; + } + + #summary-card h2 { + padding-left: 4rem; + } + + #summary-card h2, + #summary-content h3, + #summary-content p { + text-align: left; + } + + #instruction p { + text-align: left; + } + + footer nav ul { + justify-content: flex-end; + gap: 4rem; + padding-right: 5rem; + } +} + +@media (min-width: 1025px) { + #header h1 { + font-size: 1.75rem; + /* 28px */ + } + + #header nav a, + footer nav a { + font-size: 1.375rem; + /* 22px */ + } + + .quiz-instructions { + padding: 2rem; + + } + + .quiz-instructions p { + text-align: left; + } + + h2 { + font-size: 1.5rem; + /* 24px */ + } + + p, + legend, + label { + font-size: 1.25rem; + /* 20px */ + } + + .nav-buttons button { + width: 7.5rem; + } + + #restart-btn { + width: 9rem; + } + + #summary-content { + padding-left: 4rem; + } + + #summary-card h2 { + padding-left: 4rem; + } + + #summary-card h2, + #summary-content h3, + #summary-content p { + text-align: left; + } + + #instruction p { + text-align: left; + } + + footer nav ul { + justify-content: flex-end; + gap: 4rem; + padding-right: 5rem; + } + +} \ No newline at end of file diff --git a/index.html b/index.html index a9a33db..b096e66 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,376 @@ - - - - - Title - - - -

This is the starting point.

- - - + + + + + + Web Accessibility + + + + + + + +
+ + +
+

+ Welcome to our quiz +

+

+ Our quiz follows accessibility principles to ensure it can be used by everyone. We use clearly group related + questions. Labeling for screen reader support. + Keyboard navigation is fully supported, allowing users to move through the quiz without a mouse. Overall, the + design is + simple, clear, and inclusive for all users.

This quiz is part of our mission to help more people understand what + accessibility really means, and how disability can affect the way people experience the world. +

+ Portrait of a group of friends with disability +
+

Accessibility Quiz

+ +
+
+
+
+

0 of 6 questions answered

+
+ +
+ + 1. Meet Camilla. + Camilla uses a screen reader. What helps her most on a website? + + +
+ + +
+ + + + +
+ + +
+ + +
+ + 2. Meet Priya. + Priya has ADHD. What helps her stay focused? + + +
+ + +
+ + + + +
+ + +
+ +
+ + 3. Meet Lisa. + Lisa has low vision. What helps her most? + + + +
+ + +
+ + + + +
+ + +
+ +
+ + 4. Meet Erik. + Erik has dyslexia. What supports easier reading? + + + +
+ + +
+ + + + +
+ + +
+ +
+ + 5. Meet Anders. + Anders has hearing loss. What helps him on video sites? + + + +
+ + +
+ + + + +
+ + +
+ +
+ + 6. Meet Nour. + Nour has limited mobility and uses a keyboard. What helps most? + + + +
+ + +
+ + + + +
+ + + + +
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/js/main.js b/js/main.js index e69de29..a835896 100644 --- a/js/main.js +++ b/js/main.js @@ -0,0 +1,189 @@ +document.addEventListener('DOMContentLoaded', function () { + + const cards = document.querySelectorAll('.quiz-card'); + let currentIndex = 0; + let userAnswers = {}; + + const correctAnswers = { + 0: "Images with helpful descriptions", + 1: "Collapsible sections", + 2: "A dark mode option", + 3: "Simple layout and easy-to-read text", + 4: "Videos with captions and text", + 5: "Keyboard friendly buttons", + }; + + //A function that loops through all the quiz cards and only shows the one that matches the target index, by adding the active class to it and hiding the rest + const showCard = (targetIndex) => { + cards.forEach((card, index) => { + card.classList.toggle('active', index === targetIndex); + }); + }; + + // Gets all next buttons and adds an action + const nextButtons = document.querySelectorAll('.next-btn') + nextButtons.forEach((button) => { + button.addEventListener('click', () => { + // Move to the next question + if (currentIndex <= cards.length - 1) { + handleNext(); + } + }); + }); + + //Gets all previous buttons and adds an action + const previousButtons = document.querySelectorAll('.prev-btn') + previousButtons.forEach((button) => { + button.addEventListener('click', () => { + if (currentIndex > 0) { + handlePrevious(); + } + }); + }); + + //Start by showing first card + showCard(currentIndex) + + //Get the answer selected by the user + + const getSelectedAnswer = () => { + const selectedOption = document.querySelector(`.quiz-card.active input[type="radio"]:checked`); + return selectedOption ? selectedOption.value : null; + }; + + // Progress bar logic + + const form = document.getElementById('accessibility-quiz'); + const progressBar = document.querySelector(".quiz-progress"); + const progressFill = document.querySelector('.progress-fill'); + const progressText = document.querySelector('.progress-text'); + let answeredQuestions = new Set(); + + const updateProgress = () => { + const totalQuestions = 6; + const answeredCount = answeredQuestions.size; + const percentage = (answeredCount / totalQuestions) * 100; + + progressFill.style.width = `${percentage}%`; + progressText.textContent = `${answeredCount} of ${totalQuestions} questions answered`; + } + + form.querySelectorAll('input[type="radio"]').forEach((radio) => { + radio.addEventListener('change', () => { + const questionName = radio.name; + answeredQuestions.add(questionName); + updateProgress(); + }); + }); + + const createErrorMessage = () => { + const errorContainer = document.querySelectorAll('.error-container')[currentIndex]; + let errorMessage = document.createElement("p"); + errorMessage.classList.add("error-message"); + errorMessage.textContent = "Please select an answer before proceeding."; + errorContainer.appendChild(errorMessage); + } + + const showSummary = () => { + let summaryCard = document.getElementById("summary-card"); + progressBar.setAttribute("hidden", "true"); + + if (!summaryCard) { + summaryCard = document.createElement("fieldset"); + summaryCard.id = "summary-card"; + summaryCard.classList.add("quiz-card"); + summaryCard.innerHTML = ` +

Your results:

+
+ + `; + document.getElementById("accessibility-quiz").appendChild(summaryCard); + } + + summaryCard.classList.add("active"); + + const summaryContent = document.getElementById("summary-content"); + summaryContent.innerHTML = ""; + + let correctCount = 0; + Object.keys(userAnswers).forEach(index => { + const answer = userAnswers[index]; + const resultText = answer.isCorrect ? "Correct ✅" : "Incorrect ❌"; + if (answer.isCorrect) { + correctCount++; + } + + summaryContent.innerHTML += ` +

Question ${parseInt(index) + 1}: ${resultText}

+ `; + }); + + summaryContent.innerHTML += `

You got ${correctCount} out of ${cards.length} questions right!

`; + + const restartButton = document.getElementById("restart-btn"); + restartButton.addEventListener("click", () => { + currentIndex = 0; + userAnswers = {}; + + progressBar.removeAttribute("hidden"); + summaryCard.classList.remove("active"); + + document.querySelectorAll('input[type="radio"]:checked').forEach((radio) => { + radio.checked = false; + }); + + answeredQuestions.clear(); + + showCard(currentIndex); + + updateProgress(); + + }); + + showCard(cards.length); + } + + // Function that gets the user's answer, compares it to the right answer, and marks answer as right or wrong + const handleNext = () => { + + const currentCard = cards[currentIndex]; + const selectedAnswer = getSelectedAnswer(); + const errorContainer = document.querySelectorAll('.error-container')[currentIndex]; + + if (errorContainer.querySelector(".error-message")) { + let error = errorContainer.querySelector(".error-message"); + error.remove(); + } + + if (!selectedAnswer) { + createErrorMessage(); + return; + } + + // Store user's answer and correctness + const correctAnswer = correctAnswers[currentIndex]; + userAnswers[currentIndex] = { + selected: selectedAnswer, + isCorrect: selectedAnswer === correctAnswer + }; + + if (currentIndex < cards.length) { + currentIndex++; + } + + // If at the end, show summary + if (currentIndex === cards.length) { + showSummary(); + } else { + showCard(currentIndex); + } + } + + const handlePrevious = () => { + if (currentIndex > 0) { + currentIndex--; + showCard(currentIndex); + } + } + +}); \ No newline at end of file