diff --git a/README.md b/README.md index 57e6d16..1db0114 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Web Accessibility Project +Deployed site: [www.teamwind1.netlify.app](https://teamwind1.netlify.app) + A basic web server template focused on web accessibility practices. ### Installation diff --git a/about.html b/about.html index 5adbad6..2221385 100644 --- a/about.html +++ b/about.html @@ -1,10 +1,100 @@ - + About + - + + + + +
+
+

Who Built This Site and Why

+

+ We are committed to web accessibility as a group, driven by the + understanding that over 25% of the population lives with a disability, + and a significant majority will face accessibility issues online at + some point. Building inclusive digital experiences is central to our + work. +

+
+ Accessibility illustration +
+

The Team

+

Bianka

+

+ Bianka is a web developer with a unique perspective, blending 15 years + of experience in wellness coaching with a new passion for crafting + intuitive and inclusive digital experiences. Now, she focuses on + designing thoughtful solutions that simplify everyday challenges and + makes everyday life a little easier for everyone. +

+

Talo

+

+ A fullstack web developer based in Stockholm with roots in the Chilean + Patagonia. He focuses on accessible, user-friendly websites using + HTML, CSS, and JavaScript. With a background in music production, arts + education, and journalism, he loves combining creativity and code! +

+

Kasia

+

+ Kasia, a seasoned admin professional with a strong payroll and + accounting background in higher education, excels in accuracy, + compliance, and efficiency. Now, she’s exploring a tech career to + apply these strengths in new way with a new found passion for web + accessibility. +

+
+
+ + + + + diff --git a/assets/5.svg b/assets/5.svg new file mode 100644 index 0000000..8b122c7 --- /dev/null +++ b/assets/5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/dark-olive.svg b/assets/dark-olive.svg new file mode 100644 index 0000000..b10c641 --- /dev/null +++ b/assets/dark-olive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/github-icon.svg b/assets/github-icon.svg new file mode 100644 index 0000000..c2e3b15 --- /dev/null +++ b/assets/github-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/group-work.jpg b/assets/group-work.jpg new file mode 100644 index 0000000..7a08ffc Binary files /dev/null and b/assets/group-work.jpg differ diff --git a/assets/purple.svg b/assets/purple.svg new file mode 100644 index 0000000..b5a4486 --- /dev/null +++ b/assets/purple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/web-accessibility-image.jpg b/assets/web-accessibility-image.jpg new file mode 100644 index 0000000..a554796 Binary files /dev/null and b/assets/web-accessibility-image.jpg differ diff --git a/css/styles.css b/css/styles.css index e69de29..ea528ca 100644 --- a/css/styles.css +++ b/css/styles.css @@ -0,0 +1,712 @@ +/* Base styles with accessibility considerations */ +:root { + --primary-color: #1F5C63; + --background-color: #ffffff; + --accent-color: #000000; + --error-color: #e74c3c; + --success-color: #27ae60; + --focus-outline: 3px solid var(--accent-color); + --focus-ring-color: rgba(25, 74, 79, 0.698); + --progress-bg: #edf2f7; + --text-color: #2c3e50; + --border-color: #e2e8f0; + --hover-bg: rgba(0, 0, 0, 0.05); + --transition-speed: 0.3s; +} + +/* Apply box-sizing border-box to all elements */ +*, +*::before, +*::after { + box-sizing: border-box; +} + +/* Checkbox styling */ +.checkbox-container { + display: flex; + align-items: center; + margin-bottom: 0.5rem; +} + +.checkbox-container input[type='checkbox'] { + width: auto; + margin-right: 0.5rem; +} + +select { + width: 100%; + padding: 0.5rem; + font-size: 1rem; + border-radius: 4px; + border: 1px solid var(--primary-color); +} + +.checkbox-container label { + margin-bottom: 0; +} + +.intro-section { + display: flex; + gap: 1rem; + align-items: center; + justify-content: space-between; +} + +/* Base styles for readability */ +body { + font-family: "proxima-nova", sans-serif; + line-height: 1.6; + color: var(--primary-color); + background-color: var(--background-color); + margin: 0; + font-size: 16px; + min-width: auto; + max-width: 800px; + margin: 0 auto; + display: flex; + flex-direction: column; + min-height: 100vh; +} + +/* Skip link with enhanced visibility */ +.skip-link { + position: absolute; + top: -40px; + left: 0; + background: var(--accent-color); + color: #ffffff; + padding: 8px; + z-index: 100; + transition: top 0.3s; +} + +.skip-link:focus { + top: 0; + outline: var(--focus-outline); + outline-offset: 3px; +} + +/* Enhanced focus styles */ +:focus-visible { + outline: var(--focus-outline); + outline-offset: 3px; + border-radius: 3px; +} + +/* Progress bar styles */ +.quiz-progress { + margin: 2rem 0; +} + +.progress-bar { + background-color: var(--progress-bg); + border-radius: 8px; + height: 20px; + 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; + font-weight: 500; +} + +/* Question groups */ +.question-group { + margin-bottom: 2rem; + padding: 1rem; + border: 1px solid #e2e8f0; + border-radius: 8px; + background-color: #f8fafc; +} + +.question-heading { + color: var(--primary-color); + margin-bottom: 1rem; + font-size: 1.1rem; +} + +/* Form elements */ +fieldset { + border: 1px solid var(--primary-color); + margin: 1em 0; + padding: 1em; + border-radius: 4px; +} + +legend { + font-weight: bold; + padding: 0.5em 1em; + color: var(--primary-color); + background-color: #f8fafc; + border: 1px solid var(--primary-color); + border-radius: 4px; +} + +.radio-group { + margin: 1em 0; +} + +/* Enhanced radio button styling */ +.radio-option { + position: relative; + padding: 0.75em; + margin: 0.5em 0; + border-radius: 4px; + transition: background-color 0.2s; + display: flex; + align-items: center; +} + +.radio-option:hover { + background-color: rgba(44, 62, 80, 0.1); +} + +/* Custom radio button styling */ +input[type='radio'] { + margin-right: 0.75em; + width: 20px; + height: 20px; +} + +input[type='radio']:focus-visible + label { + outline: var(--focus-outline); + outline-offset: 2px; + border-radius: 2px; +} + +input[type='radio'] + label { + cursor: pointer; + padding: 4px 8px; + border-radius: 4px; + transition: background-color 0.2s; + flex: 1; +} + +/* Instructions section */ +.quiz-instructions { + background-color: #f8f9fa; + padding: 1em; + margin: 1em 0; + border-left: 4px solid var(--accent-color); + border-radius: 0 4px 4px 0; +} + +/* Submit button */ +.form-controls { + margin-top: 2rem; + text-align: center; +} + +.submit-button { + margin-top: 20px; + font-family: 'Proxima Nova', sans-serif; + font-size: 1.125rem; + font-weight: 700; + font-style: normal; + letter-spacing: 0.5px; + color: var(--background-color); + background: linear-gradient(145deg, var(--primary-color), var(--accent-color)); + border: 2px solid transparent; + border-radius: 12px; + padding: 14px 28px; + cursor: pointer; + transition: background 0.3s, border-color 0.3s, transform 0.1s ease, box-shadow 0.3s; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +.submit-button:hover { + background: linear-gradient(145deg, var(--accent-color), var(--primary-color)); + border-color: var(--accent-color); + box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); +} + +.submit-button:focus { + outline: none; +} + +.submit-button:focus-visible { + box-shadow: 0 0 0 4px var(--focus-ring-color); +} + +.submit-button:active { + transform: scale(0.98); + box-shadow: 0 3px 4px rgba(0, 0, 0, 0.2); +} + +/* Results section */ +#results { + margin-top: 2rem; + padding: 1.5rem; + border-radius: 8px; + background-color: #f8fafc; + border: 1px solid var(--primary-color); + margin-bottom: 3rem; +} + +.quiz-details { + margin-top: 1rem; + padding: 1rem; + border-radius: 4px; +} + +#quiz-form { + margin-bottom: 3rem; +} + +/* Utility classes */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* High contrast mode */ +@media (prefers-contrast: more) { + :root { + --primary-color: #000000; + --background-color: #ffffff; + --accent-color: #0000ff; + --error-color: #ff0000; + --success-color: #008000; + --text-color: #000000; + --border-color: #000000; + --hover-bg: #000000; + --focus-outline: 3px solid #000000; + --focus-ring-color: #000000; + --progress-bg: #ffffff; + } + + body { + background-color: var(--background-color); + color: var(--text-color); + } + + a { + color: var(--accent-color); + text-decoration: underline; + } + + button, + input, + select, + textarea { + border: 3px solid var(--text-color); + background-color: var(--background-color); + color: var(--text-color); + } + + fieldset { + border: 2px solid var(--text-color); + } + + legend { + border: 2px solid var(--text-color); + background-color: var(--background-color); + } + + .radio-option:hover, + .checkbox-container:hover { + background-color: var(--hover-bg); + } + + .progress-bar { + border: 2px solid var(--text-color); + } + + .progress-fill { + background-color: var(--text-color); + } +} + +/* Reduced motion */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } + + .progress-fill { + transition: none; + } + + .skip-link { + transition: none; + } + + button, + input, + select, + textarea { + transition: none; + } +} + +/* Add a class for manual high contrast toggle */ +.high-contrast-mode { + --primary-color: #000000 !important; + --background-color: #ffffff !important; + --accent-color: #0000ff !important; + --error-color: #ff0000 !important; + --success-color: #008000 !important; + --text-color: #000000 !important; + --border-color: #000000 !important; + --hover-bg: #000000 !important; + --focus-outline: 3px solid #000000 !important; + --focus-ring-color: #000000 !important; + --progress-bg: #ffffff !important; +} + +/* Basic responsive design */ +@media (max-width: 600px) { + fieldset { + padding: 0.5em; + } + + header { + padding: 1.25rem; + } + + nav ul { + gap: 0.75rem; + } + + .intro-section { + flex-direction: column; + } +} + +/* User Info Form */ +#user-info { + margin-bottom: 2rem; + padding: 1.5rem; + background-color: #f8fafc; + border-radius: 8px; + border: 1px solid #e2e8f0; +} + +.form-control { + margin-bottom: 1.5rem; + position: relative; +} + +.form-control label { + display: block; + margin-bottom: 0.5rem; + font-weight: 500; + color: var(--primary-color); +} + +.form-control input { + width: 100%; + padding: 0.75rem; + font-size: 1rem; + border: 1px solid var(--primary-color); + border-radius: 4px; + transition: border-color 0.2s, box-shadow 0.2s; + box-sizing: border-box; +} + +.form-control input:focus { + outline: none; + border-color: var(--accent-color); + box-shadow: 0 0 0 3px var(--focus-ring-color); +} + +.form-control input[aria-invalid='true'] { + border-color: var(--error-color); +} + +.form-control input[aria-invalid='true']:focus { + box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.25); +} + +.error { + color: var(--error-color); + font-size: 0.875rem; + margin-top: 0.25rem; +} + +.hint { + color: var(--secondary-color); + font-size: 0.875rem; + margin-top: 0.25rem; +} + +/* Introduction section and images */ +#introduction { + padding: 2rem; + margin-bottom: 2rem; + background-color: #f8fafc; + border-radius: 12px; +} + +#introduction h2 { + color: var(--primary-color); + font-size: 2rem; + margin-bottom: 1.5rem; +} + +#introduction p { + max-width: 800px; + margin: 0 auto 2rem; +} + +.hero-images { + display: flex; + flex-direction: column; + align-items: center; + gap: 2rem; + margin: 2rem 0; +} + +.decorative-image, +.info-image { + max-width: 100%; + height: auto; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + padding: 1rem; + background: white; +} + + +/* Full-width banner */ +#banner { + margin: -20px -20px 2rem; + width: 100vw; + position: relative; + left: 50%; + right: 50%; + margin-left: -50vw; + margin-right: -50vw; + overflow: hidden; +} + +#banner img { + width: 100%; + height: 200px; + object-fit: cover; +} + +h1, +h2 { + margin-bottom: 1rem; +} + +nav ul { + list-style: none; + padding: 0; + display: flex; + gap: 1.5rem; +} + +nav a { + color: var(--accent-color); + text-decoration: none; +} + +nav a:hover { + text-decoration: underline; +} + +/* About page specific styles */ +#about { + padding: 2rem; + background-color: #f8fafc; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); +} + +#about h2 { + color: #2c3e50; + font-size: 2.5rem; + margin-bottom: 1.5rem; + border-bottom: 3px solid #3498db; + padding-bottom: 0.5rem; + display: inline-block; +} + +#about p { + font-size: 1.2rem; + line-height: 1.6; + color: #34495e; + margin-bottom: 2rem; + max-width: 800px; +} + +#about .hero-images img { + max-width: 100%; + height: auto; + border-radius: 12px; + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease; +} + +#about .hero-images img:hover { + transform: scale(1.02); +} + +/* Header improvements */ +#header { + width: 100vw; + margin-left: calc(-50vw + 50%); + margin-right: calc(-50vw + 50%); + background-color: var(--primary-color); + color: white; + padding: 2rem 0; +} + +#header .header-content { + display: flex; + justify-content: space-between; + align-items: center; + max-width: 900px; + margin: 0 auto; + padding: 0 1rem; +} + +#header h1 { + color: white; + margin-bottom: 1rem; +} + +#header nav ul { + list-style: none; + padding: 0; + margin: 1rem 1rem; + display: flex; + gap: 2rem; +} + +#header nav a { + color: white; + text-decoration: none; + font-size: 1.1rem; + font-weight: 500; + padding: 0.5rem 1rem; + border-radius: 6px; + transition: opacity var(--transition-speed); +} + +#header nav a:hover { + background-color: rgba(255, 255, 255, 0.391); +} + +/* Media Queries */ +@media (max-width: 600px) { + #header { + padding: 1.5rem 0; + } + + #header nav ul { + gap: 1rem; + } + + #header .header-content { + flex-wrap: wrap; + justify-content: center; + } +} + +@media (min-width: 768px) { + .hero-images { + flex-direction: row; + justify-content: center; + gap: 3rem; + } + + .decorative-image, + .info-image { + width: 55%; + } +} + +/* Footer styles */ +footer { + width: 100vw; + margin-left: calc(-50vw + 50%); + margin-right: calc(-50vw + 50%); + background-color: var(--primary-color); + color: white; + padding: 2rem 0; + margin-top: auto; +} + +.footer-content { + max-width: 800px; + margin: 0 auto; + padding: 0 1rem; + display: grid; + justify-content: center; + gap: 2rem; +} + +.footer-content nav { + margin-bottom: 1rem; +} + +.footer-content h3 { + color: white; + margin-bottom: 1rem; + font-size: 1.2rem; +} + +.footer-content ul { + list-style: none; + padding: 0; + margin: 0; +} + +.footer-content a { + color: white; + text-decoration: none; + padding: 0.5rem 0; + display: block; + transition: opacity var(--transition-speed); +} + +.footer-content a:hover { + opacity: 0.8; +} + +.footer-info { + grid-column: 1 / -1; + text-align: center; + padding-top: 1rem; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +@media (max-width: 600px) { + footer { + padding-bottom: 4rem; + } + +} + +/* Reduced motion support */ +@media (prefers-reduced-motion: reduce) { + .accordion-button, + .accordion-icon, + .accordion-icon::before, + .accordion-icon::after, + .accordion-content { + transition: none; + } +} \ No newline at end of file diff --git a/index.html b/index.html index a9a33db..c13eb37 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,417 @@ - + + - Title + Accessibility Site - By Wind 1 + + -

This is the starting point.

+ + + +
+ +
+

Welcome to our Accessibility quiz!

+

+ Hello there! Thank you for exploring the important topic of web accessibility. Please feel welcome to take the quiz below to assess your understanding of key accessibility principles in web development. Accessibility is fundamental to creating inclusive digital experiences, and we encourage you to share this resource with others who may benefit from learning more. +

+

This quiz has been developed with a strong focus on web accessibility principles to ensure a positive experience for all users, including those with disabilities. +

+
+ +
+ A graphic image representing web accessibility +
+
+
+ + + + + + + +
+ +
+ + + + + + diff --git a/js/main.js b/js/main.js index e69de29..64aaf6c 100644 --- a/js/main.js +++ b/js/main.js @@ -0,0 +1,206 @@ +document.addEventListener('DOMContentLoaded', () => { + const introSection = document.getElementById('introduction'); + const userInfoSection = document.getElementById('user-info'); + const announcer = document.getElementById('announcer'); + + const introContinueButton = document.getElementById('intro-continue'); + + introContinueButton.addEventListener('click', () => { + introSection.hidden = true; + userInfoSection.hidden = false; + window.location.hash = '#user-info'; + document.getElementById('name').focus(); + announcer.textContent = 'Moved to user information section'; + }); + + const userInfoForm = document.getElementById('user-info-form'); + const nameInput = document.getElementById('name'); + const emailInput = document.getElementById('email'); + const nameError = document.getElementById('name-error'); + const emailError = document.getElementById('email-error'); + let userName = ''; + + function clearError(input, errorElement) { + input.removeAttribute('aria-invalid'); + errorElement.textContent = ''; + errorElement.hidden = true; + } + + function showError (input, errorElement, message) { + input.setAttribute('aria-invalid', 'true'); + errorElement.textContent = message; + errorElement.hidden = false; + } + + function isValidEmail(email) { + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + } + + nameInput.addEventListener('input', () => { + if(nameInput.value.trim()) { + clearError(nameInput, nameError) + } + }) + + emailInput.addEventListener('input', () => { + if(emailInput.value.trim()) { + if(isValidEmail(emailInput.value)) { + clearError(emailInput, emailError) + } + } + }); + + userInfoForm.addEventListener('submit', (e) => { + e.preventDefault(); + let isValid = true; + + if (!nameInput.value.trim()) { + showError(nameInput, nameError, 'Please enter your name'); + isValid = false; + nameInput.focus(); + } else { + clearError(nameInput, nameError); + } + + if (!emailInput.value.trim()) { + showError(emailInput, emailError, 'Please enter your email address'); + isValid = false; + if (!nameError.textContent) { + emailInput.focus(); + } + } else if (!isValidEmail(emailInput.value.trim())) { + showError(emailInput, emailError, 'Please enter a valid email address'); + isValid = false; + if (!nameError.textContent) { + emailInput.focus (); + } + } else { + clearError(emailInput, emailError); + } + + if (isValid) { + userName = nameInput.value.trim(); + userInfoSection.hidden = true; + quizSection.hidden = false; + quizSection.scrollIntoView({ behavior: 'smooth' }); + document.querySelector('#quiz-form input[type="radio"]').focus(); + announcer.textContent = "Moved to accessibility quiz section"; + } + }); + + const quizSection = document.getElementById('temp-quiz'); + const resultsSection = document.getElementById('results'); + + const form = document.getElementById('quiz-form'); + const resultsContent = document.getElementById('results-content'); + const quizDetails = document.querySelector('.quiz-details'); + const progressFill = document.querySelector('.progress-fill'); + const progressText = document.querySelector('.progress-text'); + let answeredQuestions = new Set(); + + function updateProgress() { + const totalQuestions = 6; + const answeredCount = answeredQuestions.size; + const percentage = (answeredCount / totalQuestions) * 100; + + progressFill.style.width = `${percentage}%`; + progressText.textContent = `${answeredCount} of ${totalQuestions} sections completed`; + announcer.textContent = `${answeredCount} of ${totalQuestions} sections completed`; + } + + form.querySelectorAll('input[type="radio"]').forEach((radio) => { + radio.addEventListener('change', () => { + const questionName = radio.name; + answeredQuestions.add(questionName); + updateProgress(); + }); + }); + + form.addEventListener('submit', (e) => { + e.preventDefault(); + + const formData = new FormData(form); + const userAnswers = Object.fromEntries(formData); + + let feedback = `Thank you for taking our quiz, ${userName}. `; + + const detailedFeedback = []; + + if (userAnswers.question1 === 'q1-correct') { + detailedFeedback.push('✓ Accessibility: You got this right!') + } else if (userAnswers.question1 === 'q1-incorrect') { + detailedFeedback.push('! Accessibility: Try again!' + ); + } + + if (userAnswers.question2 === 'q2-correct') { + detailedFeedback.push('✓ Semantic HTML: You got this right!') + } else if (userAnswers.question2 === 'q2-incorrect') { + detailedFeedback.push('! Semantic HTML: Try again!' + ); + } + + if (userAnswers.question3 === 'q3-correct') { + detailedFeedback.push('✓ "Skip to content" purpose: You got this right!') + } else if (userAnswers.question3 === 'q3-incorrect') { + detailedFeedback.push('! "Skip to content" purpose: Try again!' + ); + } + + if (userAnswers.question4 === 'q4-correct') { + detailedFeedback.push('✓ What EAA stands for: You got this right!') + } else if (userAnswers.question4 === 'q4-incorrect') { + detailedFeedback.push('! What EAA stands for: Try again!' + ); + } + + if (userAnswers.question5 === 'q5-correct') { + detailedFeedback.push('✓ EEA’s requirements and obligations: You got this right!') + } else if (userAnswers.question5 === 'q5-incorrect') { + detailedFeedback.push('! EEA’s requirements and obligations: Try again!' + ); + } + + if (userAnswers.question6 === 'q6-correct') { + detailedFeedback.push('✓ Purpose of ARIA attributes: You got this right!') + } else if (userAnswers.question6 === 'q6-incorrect') { + detailedFeedback.push('! Purpose of ARIA attributes: Try again!' + ); + } + + const positiveAnswers = ['q1-correct', 'q2-correct', 'q3-correct', 'q4-correct', 'q5-correct', 'q6-correct']; + + const userAnswerValues = Object.values(userAnswers) + + let positiveResponses = 0 + + for (const answer of userAnswerValues) { + if(positiveAnswers.includes(answer)) { + positiveResponses += 1; + } + } + const totalResponses = Object.keys(userAnswers).length; + const scorePercentage = Math.round((positiveResponses / totalResponses)*100) + + feedback += `Based on your responses, you got ${scorePercentage}% questions correct. `; + feedback += positiveResponses >= totalResponses / 2 + ? 'Congratulations! You are a great a11y ally 😊' + : 'No worries, you can try again!'; + + quizSection.hidden = true; + resultsSection.hidden = false; + resultsContent.textContent = feedback; + + quizDetails.innerHTML = detailedFeedback + .map((text) => `

${text}

`) + .join(''); + + resultsSection.setAttribute('tabindex', '-1'); + resultsSection.focus(); + announcer.textContent = + 'Quiz submitted. Your results are now displayed.'; + + confetti(); + }); + +}); \ No newline at end of file