Project Overview
Welcome to your weekend project! This is your opportunity to consolidate everything you've learned this week about HTML, CSS, and JavaScript by creating a complete, responsive website from scratch. Think of this project as building a digital house—you'll lay the foundation with HTML, design the aesthetics with CSS, and add functionality with JavaScript.
Unlike previous assignments that focused on specific aspects of web development, this project requires you to integrate all three technologies into a cohesive, functioning website. This reflects real-world development, where these technologies work together to create comprehensive user experiences.
Learning Objectives
- Apply semantic HTML to create well-structured, accessible content
- Implement responsive CSS layouts that work on devices of all sizes
- Add interactive features using JavaScript to enhance user experience
- Practice organizing files in a professional project structure
- Experience the full development cycle from planning to implementation
- Create a portfolio-worthy project that demonstrates your skills
Step 1: Understanding the Problem
Before writing any code, let's clarify what we're trying to build and what success looks like. This first step in Polya's problem-solving method ensures we have a clear vision before proceeding.
Project Requirements
Your website must include:
- Multiple Pages: At least 4 interconnected HTML pages (e.g., Home, About, Services/Products, Contact)
- Responsive Design: The site must look good and function well on mobile phones, tablets, and desktops
- Semantic HTML: Proper use of semantic elements like
<header>,<nav>,<main>,<section>, etc. - CSS Styling: Custom styling with well-organized CSS, including responsive techniques
- JavaScript Interactivity: At least 3 interactive features using JavaScript
- Contact Form: A functional form with validation
- Navigation: A consistent, responsive navigation menu
Theme Options
You may choose from the following website themes:
- Portfolio Website: Showcase your skills, projects, and background
- Small Business Site: A website for a fictional local business (restaurant, salon, store, etc.)
- Educational Resource: An informational site about a topic you're knowledgeable about
- Community Organization: A website for a fictional community group or non-profit
- Product Showcase: A site featuring a fictional product or service
Choose a theme that interests you, as your enthusiasm will drive better results. Consider what type of content you'll need to generate and what interactive elements would make sense for your chosen theme.
Expected Outcomes
By the end of this project, you should have:
- A complete, multi-page website with consistent styling
- A responsive design that works well on different devices
- Interactive features that enhance user experience
- A well-organized project with clean, efficient code
- A deeper understanding of how HTML, CSS, and JavaScript work together
- A project you can proudly add to your portfolio
Step 2: Devising a Plan
Now that we understand what we're building, let's create a systematic plan for development. This exemplifies the second step of Polya's problem-solving method.
Project Whiteboard Plan
- Choose a theme and sketch the basic layout for each page
- Set up project folder structure and create necessary files
- Build the HTML structure for all pages with proper semantic elements
- Create the CSS styling, starting with global styles and then page-specific styles
- Implement responsive design using media queries
- Add JavaScript interactivity for key features
- Test the site across different devices and browsers
- Optimize and refine the code
Project Structure
Let's establish a professional folder and file organization:
project_folder/ │ ├── index.html (Home page) ├── about.html (About page) ├── services.html (Services/Products page) ├── contact.html (Contact page) │ ├── css/ │ ├── styles.css (Main CSS file) │ └── responsive.css (Responsive styles) │ ├── js/ │ ├── main.js (Main JavaScript file) │ ├── validation.js (Form validation) │ └── slider.js (Image slider or carousel) │ ├── images/ │ ├── logo.png (Website logo) │ ├── banner.jpg (Hero/banner image) │ ├── product1.jpg (Product/service images) │ ├── product2.jpg │ └── team.jpg (Team or about page image) │ └── favicon.png (Website favicon)
Planned Interactive Features
Consider implementing these JavaScript features (choose at least 3):
- Responsive Navigation: Hamburger menu for mobile that expands/collapses
- Image Slider/Carousel: Rotating feature to showcase multiple images
- Form Validation: Real-time feedback on form input
- Modal/Popup: Information overlay for important messages or details
- Accordion/Collapsible Sections: Expandable content areas
- Tabbed Content Interface: Switch between content panels without page reload
- Animated Counters: Numbers that count up for statistics or achievements
- Filter/Sort Functionality: Allow users to filter or sort content
- Interactive Gallery: Lightbox or grid of clickable images
- Sticky Navigation: Navigation that stays visible when scrolling
Responsive Design Approach
We'll use a mobile-first approach, designing for small screens first and then adding complexity for larger screens:
- Base Styles: Default styling for all devices (primarily mobile)
- Tablet Breakpoint: Media query around 768px
- Desktop Breakpoint: Media query around 1024px
- Large Desktop Breakpoint: Media query around 1440px (optional)
Helpful Tools and Resources
- Design Inspiration: Dribbble, Behance, or Awwwards for visual ideas
- Color Schemes: Coolors.co or Adobe Color
- Typography: Google Fonts for web-safe fonts
- Icons: Font Awesome or Material Icons
- Placeholder Images: Unsplash, Pexels, or Lorem Picsum
- Placeholder Text: Lorem Ipsum generators
- Testing: Browser dev tools for responsive testing
Step 3: Executing the Plan
Now we'll implement our plan, following Polya's third step. I'll provide guidance for each major component of the project.
Setting Up the Project
File path: Create a new folder named weekend_project on your computer.
Inside this folder, create the following structure:
- Create the main HTML files:
index.html,about.html,services.html, andcontact.html - Create folders:
css,js, andimages - Inside the
cssfolder, createstyles.cssandresponsive.css - Inside the
jsfolder, createmain.js,validation.js, and other JS files based on your chosen features
Building the HTML Structure
Let's create a template for our HTML pages to ensure consistency. Here's a basic structure for index.html that you can adapt for other pages:
HTML Template (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Site Name | Home</title>
<meta name="description" content="Description of your website">
<!-- CSS Files -->
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/responsive.css">
<!-- Favicon -->
<link rel="icon" href="favicon.png">
<!-- Optional: Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&family=Playfair+Display:wght@700&display=swap" rel="stylesheet">
</head>
<body>
<!-- Skip Navigation for Accessibility -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>
<div class="container">
<div class="logo">
<a href="index.html">
<img src="images/logo.png" alt="Your Site Name">
</a>
</div>
<nav>
<button class="mobile-menu-toggle" aria-label="Toggle navigation menu">
<span></span>
<span></span>
<span></span>
</button>
<ul class="nav-menu">
<li><a href="index.html" class="active">Home</a></li>
<li><a href="about.html">About Us</a></li>
<li><a href="services.html">Services</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</div>
</header>
<main id="main-content">
<section class="hero">
<div class="container">
<h1>Welcome to Your Site Name</h1>
<p>A brief tagline or value proposition</p>
<a href="contact.html" class="btn primary-btn">Get Started</a>
</div>
</section>
<section class="features">
<div class="container">
<h2>Our Features</h2>
<div class="feature-grid">
<div class="feature-item">
<img src="images/feature1.jpg" alt="Feature 1">
<h3>Feature 1</h3>
<p>Description of this feature or service.</p>
</div>
<div class="feature-item">
<img src="images/feature2.jpg" alt="Feature 2">
<h3>Feature 2</h3>
<p>Description of this feature or service.</p>
</div>
<div class="feature-item">
<img src="images/feature3.jpg" alt="Feature 3">
<h3>Feature 3</h3>
<p>Description of this feature or service.</p>
</div>
</div>
</div>
</section>
<section class="testimonials">
<div class="container">
<h2>What Our Clients Say</h2>
<div class="testimonial-slider">
<div class="testimonial">
<p>"Testimonial text goes here. Make it compelling and authentic."</p>
<cite>— Client Name, Position</cite>
</div>
<div class="testimonial">
<p>"Another testimonial text. Focus on specific results or benefits."</p>
<cite>— Another Client, Position</cite>
</div>
<div class="testimonial">
<p>"A third testimonial for good measure."</p>
<cite>— Third Client, Position</cite>
</div>
<div class="slider-controls">
<button class="prev-btn" aria-label="Previous testimonial">←</button>
<button class="next-btn" aria-label="Next testimonial">→</button>
</div>
</div>
</div>
</section>
<section class="cta">
<div class="container">
<h2>Ready to Get Started?</h2>
<p>Call-to-action text encouraging the user to take the next step.</p>
<a href="contact.html" class="btn primary-btn">Contact Us Today</a>
</div>
</section>
</main>
<footer>
<div class="container">
<div class="footer-grid">
<div class="footer-col">
<h3>Your Site Name</h3>
<p>Short description or mission statement.</p>
</div>
<div class="footer-col">
<h3>Quick Links</h3>
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="about.html">About Us</a></li>
<li><a href="services.html">Services</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</div>
<div class="footer-col">
<h3>Contact Info</h3>
<address>
123 Main Street<br>
City, State ZIP<br>
<a href="tel:+11234567890">(123) 456-7890</a><br>
<a href="mailto:info@yoursite.com">info@yoursite.com</a>
</address>
</div>
<div class="footer-col">
<h3>Follow Us</h3>
<div class="social-links">
<a href="#" aria-label="Facebook">Facebook</a>
<a href="#" aria-label="Twitter">Twitter</a>
<a href="#" aria-label="Instagram">Instagram</a>
<a href="#" aria-label="LinkedIn">LinkedIn</a>
</div>
</div>
</div>
<div class="copyright">
<p>© 2025 Your Site Name. All rights reserved.</p>
</div>
</div>
</footer>
<!-- JavaScript Files -->
<script src="js/main.js"></script>
<script src="js/slider.js"></script>
</body>
</html>
HTML Explanation:
- The document begins with the
DOCTYPEdeclaration and includes proper language attributes. - The
headsection contains meta tags for character encoding, viewport settings, and page description. - External CSS files are linked, and a favicon is specified.
- The semantic structure includes
header,nav,main,section, andfooterelements. - A skip link is provided for accessibility, allowing keyboard users to bypass navigation.
- The navigation is structured as an unordered list with links to all pages.
- Content sections use descriptive class names for styling.
- JavaScript files are linked at the bottom of the body for better performance.
Use this template as a starting point for all your pages, modifying the main content as appropriate for each page. For example:
- About page: Include team information, company history, and mission/vision
- Services page: Detailed descriptions of services/products with images
- Contact page: Contact form, map, and direct contact information
Contact Form HTML (for contact.html)
<section class="contact-form">
<div class="container">
<h2>Contact Us</h2>
<p>Fill out the form below to get in touch with us.</p>
<form id="contactForm" action="#" method="POST" novalidate>
<div class="form-group">
<label for="name">Your Name</label>
<input type="text" id="name" name="name" required>
<span class="error-message" id="nameError"></span>
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required>
<span class="error-message" id="emailError"></span>
</div>
<div class="form-group">
<label for="phone">Phone Number (optional)</label>
<input type="tel" id="phone" name="phone">
<span class="error-message" id="phoneError"></span>
</div>
<div class="form-group">
<label for="subject">Subject</label>
<select id="subject" name="subject" required>
<option value="">Please select...</option>
<option value="general">General Inquiry</option>
<option value="support">Technical Support</option>
<option value="billing">Billing Question</option>
<option value="other">Other</option>
</select>
<span class="error-message" id="subjectError"></span>
</div>
<div class="form-group">
<label for="message">Your Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<span class="error-message" id="messageError"></span>
</div>
<div class="form-group checkbox-group">
<input type="checkbox" id="consent" name="consent" required>
<label for="consent">I agree to the privacy policy and terms of service.</label>
<span class="error-message" id="consentError"></span>
</div>
<button type="submit" class="btn primary-btn">Send Message</button>
</form>
</div>
</section>
Creating the CSS Styling
Let's implement our CSS styles, starting with a reset and global styles. Here's the structure for styles.css:
Basic CSS Styling (css/styles.css)
/*
* styles.css
* Main styles for Your Site Name
*/
/*
* TABLE OF CONTENTS
*
* 1. CSS Reset and Base Styles
* 2. Typography
* 3. Layout & Containers
* 4. Header and Navigation
* 5. Buttons and Forms
* 6. Hero Section
* 7. Features Section
* 8. Testimonials Section
* 9. CTA Section
* 10. Footer Styles
* 11. About Page Styles
* 12. Services Page Styles
* 13. Contact Page Styles
* 14. Utilities
*/
/* ========================================
1. CSS Reset and Base Styles
======================================== */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Remove default margin */
body, h1, h2, h3, h4, p, ul, ol, figure, blockquote, dl, dd {
margin: 0;
}
/* Set core body defaults */
body {
min-height: 100vh;
scroll-behavior: smooth;
text-rendering: optimizeSpeed;
line-height: 1.6;
font-family: 'Open Sans', sans-serif;
color: #333;
background-color: #fff;
}
/* Remove list styles on ul, ol elements with a class */
ul, ol {
list-style: none;
}
/* Make images easier to work with */
img {
max-width: 100%;
display: block;
}
/* Inherit fonts for inputs and buttons */
input, button, textarea, select {
font: inherit;
}
/* Accessibility: Skip to content link */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: white;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
/* ========================================
2. Typography
======================================== */
h1, h2, h3, h4 {
font-family: 'Playfair Display', serif;
line-height: 1.2;
margin-bottom: 1rem;
}
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2rem;
margin-bottom: 2rem;
}
h3 {
font-size: 1.5rem;
}
p {
margin-bottom: 1rem;
}
a {
color: #0066cc;
text-decoration: none;
transition: color 0.3s ease;
}
a:hover, a:focus {
color: #004999;
text-decoration: underline;
}
/* ========================================
3. Layout & Containers
======================================== */
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
padding: 0 15px;
}
section {
padding: 3rem 0;
}
/* Grid layouts */
.feature-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
}
.footer-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
/* ========================================
4. Header and Navigation
======================================== */
header {
background-color: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
position: relative;
z-index: 100;
padding: 1rem 0;
}
header .container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo img {
max-height: 50px;
}
/* Mobile Navigation */
.mobile-menu-toggle {
display: block;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
}
.mobile-menu-toggle span {
display: block;
width: 25px;
height: 3px;
background-color: #333;
margin: 5px 0;
transition: transform 0.3s ease, opacity 0.3s ease;
}
/* Navigation menu */
.nav-menu {
position: absolute;
top: 100%;
left: 0;
width: 100%;
background-color: #fff;
box-shadow: 0 4px 4px rgba(0,0,0,0.1);
padding: 1rem 0;
transform: translateY(-100%);
opacity: 0;
visibility: hidden;
transition: transform 0.3s ease, opacity 0.3s ease, visibility 0.3s ease;
}
.nav-menu.active {
transform: translateY(0);
opacity: 1;
visibility: visible;
}
.nav-menu li {
text-align: center;
margin: 1rem 0;
}
.nav-menu a {
color: #333;
font-weight: 700;
text-transform: uppercase;
font-size: 0.9rem;
letter-spacing: 1px;
transition: color 0.3s ease;
}
.nav-menu a:hover,
.nav-menu a:focus,
.nav-menu a.active {
color: #0066cc;
}
/* ========================================
5. Buttons and Forms
======================================== */
/* Button styles */
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
border-radius: 5px;
font-weight: 700;
text-align: center;
text-transform: uppercase;
letter-spacing: 1px;
cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
}
.primary-btn {
background-color: #0066cc;
color: white;
border: 2px solid #0066cc;
}
.primary-btn:hover, .primary-btn:focus {
background-color: #004999;
border-color: #004999;
transform: translateY(-3px);
text-decoration: none;
color: white;
}
.secondary-btn {
background-color: transparent;
color: #0066cc;
border: 2px solid #0066cc;
}
.secondary-btn:hover, .secondary-btn:focus {
background-color: #0066cc;
color: white;
transform: translateY(-3px);
text-decoration: none;
}
/* Form styles */
form {
max-width: 600px;
margin: 2rem auto;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
}
input, select, textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
input:focus, select:focus, textarea:focus {
border-color: #0066cc;
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.25);
outline: none;
}
.checkbox-group {
display: flex;
align-items: flex-start;
}
.checkbox-group input {
width: auto;
margin-right: 10px;
margin-top: 5px;
}
.checkbox-group label {
margin-bottom: 0;
font-weight: normal;
}
.error-message {
color: #cc0000;
font-size: 0.85rem;
margin-top: 0.25rem;
display: block;
}
/* ========================================
6. Hero Section
======================================== */
.hero {
background-color: #f8f9fa;
text-align: center;
padding: 5rem 0;
}
.hero h1 {
margin-bottom: 1rem;
}
.hero p {
font-size: 1.2rem;
max-width: 600px;
margin: 0 auto 2rem;
}
/* ========================================
7. Features Section
======================================== */
.features {
text-align: center;
}
.feature-item {
padding: 1.5rem;
border-radius: 8px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.feature-item:hover {
transform: translateY(-10px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.feature-item img {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 1rem;
}
/* ========================================
8. Testimonials Section
======================================== */
.testimonials {
background-color: #f8f9fa;
text-align: center;
}
.testimonial-slider {
position: relative;
max-width: 800px;
margin: 0 auto;
overflow: hidden;
}
.testimonial {
padding: 2rem;
}
.testimonial p {
font-style: italic;
font-size: 1.1rem;
margin-bottom: 1rem;
}
.testimonial cite {
font-style: normal;
font-weight: 700;
}
.slider-controls {
margin-top: 1rem;
}
.prev-btn, .next-btn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem 1rem;
margin: 0 0.5rem;
transition: color 0.3s ease;
}
.prev-btn:hover, .next-btn:hover {
color: #0066cc;
}
/* ========================================
9. CTA Section
======================================== */
.cta {
text-align: center;
padding: 5rem 0;
background-color: #0066cc;
color: white;
}
.cta h2 {
color: white;
}
.cta .btn {
background-color: white;
color: #0066cc;
border-color: white;
}
.cta .btn:hover {
background-color: transparent;
color: white;
}
/* ========================================
10. Footer Styles
======================================== */
footer {
background-color: #333;
color: white;
padding: 3rem 0 1.5rem;
}
footer h3 {
color: white;
margin-bottom: 1.5rem;
font-size: 1.2rem;
}
footer a {
color: #ccc;
}
footer a:hover {
color: white;
}
.social-links {
display: flex;
gap: 1rem;
}
.copyright {
text-align: center;
padding-top: 1.5rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
/* ========================================
11. About Page Styles
======================================== */
.about-intro {
text-align: center;
max-width: 800px;
margin: 0 auto 3rem;
}
.team-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
}
.team-member {
text-align: center;
}
.team-member img {
width: 200px;
height: 200px;
object-fit: cover;
border-radius: 50%;
margin: 0 auto 1rem;
}
/* ========================================
12. Services Page Styles
======================================== */
.service-item {
margin-bottom: 3rem;
padding-bottom: 3rem;
border-bottom: 1px solid #eee;
}
.service-item:last-child {
border-bottom: none;
}
.service-item img {
width: 100%;
height: 300px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 1.5rem;
}
/* ========================================
13. Contact Page Styles
======================================== */
.contact-info {
margin-bottom: 3rem;
}
.contact-info-item {
display: flex;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.contact-form {
background-color: #f8f9fa;
padding: 3rem 0;
}
.map-container {
height: 400px;
margin-top: 2rem;
}
.map-container iframe {
width: 100%;
height: 100%;
border: none;
border-radius: 8px;
}
/* ========================================
14. Utilities
======================================== */
.text-center {
text-align: center;
}
.mt-1 { margin-top: 1rem; }
.mt-2 { margin-top: 2rem; }
.mt-3 { margin-top: 3rem; }
.mb-1 { margin-bottom: 1rem; }
.mb-2 { margin-bottom: 2rem; }
.mb-3 { margin-bottom: 3rem; }
.hidden {
display: none;
}
CSS Explanation:
- The CSS begins with a reset to normalize browser styles and set consistent defaults.
- The code is organized into logical sections with clear comments for maintainability.
- Global typography styles establish a consistent hierarchy using the imported Google Fonts.
- The
.containerclass creates a responsive wrapper with consistent padding. - The mobile menu is initially hidden and appears when the
.activeclass is added via JavaScript. - Buttons have hover and focus states for better interactivity.
- Form elements are styled with clear focus states for accessibility.
- Each section has specific styles to create visual variety and structure.
- Utility classes provide quick styling options for common needs.
Now, let's create our responsive styles in the responsive.css file:
Responsive Styles (css/responsive.css)
/*
* responsive.css
* Media queries for responsive design
*/
/* ========================================
Media Queries
======================================== */
/* Small devices (landscape phones, 576px and up) */
@media screen and (min-width: 576px) {
h1 {
font-size: 3rem;
}
h2 {
font-size: 2.25rem;
}
h3 {
font-size: 1.75rem;
}
}
/* Medium devices (tablets, 768px and up) */
@media screen and (min-width: 768px) {
/* Grid layouts */
.feature-grid {
grid-template-columns: repeat(2, 1fr);
}
.footer-grid {
grid-template-columns: repeat(2, 1fr);
}
.team-grid {
grid-template-columns: repeat(2, 1fr);
}
/* Hero section */
.hero {
padding: 6rem 0;
}
/* Service items */
.service-item {
display: flex;
align-items: center;
gap: 2rem;
}
.service-item:nth-child(even) {
flex-direction: row-reverse;
}
.service-item img {
width: 40%;
margin-bottom: 0;
}
.service-content {
width: 60%;
}
}
/* Large devices (desktops, 992px and up) */
@media screen and (min-width: 992px) {
/* Header and navigation */
.mobile-menu-toggle {
display: none;
}
.nav-menu {
position: static;
display: flex;
transform: none;
opacity: 1;
visibility: visible;
box-shadow: none;
padding: 0;
}
.nav-menu li {
margin: 0 0 0 1.5rem;
}
/* Grid layouts */
.feature-grid {
grid-template-columns: repeat(3, 1fr);
}
.footer-grid {
grid-template-columns: repeat(4, 1fr);
}
.team-grid {
grid-template-columns: repeat(3, 1fr);
}
/* Contact layout */
.contact-page-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
}
/* Extra large devices (large desktops, 1200px and up) */
@media screen and (min-width: 1200px) {
h1 {
font-size: 3.5rem;
}
h2 {
font-size: 2.5rem;
}
h3 {
font-size: 2rem;
}
.container {
padding: 0;
}
.hero {
padding: 8rem 0;
}
}
Responsive CSS Explanation:
- We use a mobile-first approach, starting with styles for small screens and adding complexity for larger screens.
- Each media query targets a common breakpoint (576px, 768px, 992px, 1200px).
- At 768px (tablet), we introduce two-column layouts and more spacing.
- At 992px (desktop), we transform the mobile menu into a horizontal navigation bar and create three or four-column layouts.
- Flexible layouts like CSS Grid adapt the number of columns based on screen size.
- Typography scales up for larger screens for better readability.
Adding JavaScript Interactivity
Now, let's implement some JavaScript features. First, the main script that handles the mobile navigation:
Main JavaScript (js/main.js)
/*
* main.js
* Main JavaScript functionality for the website
*/
// Wait for the DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Mobile navigation toggle
const menuToggle = document.querySelector('.mobile-menu-toggle');
const navMenu = document.querySelector('.nav-menu');
if (menuToggle && navMenu) {
// Toggle mobile menu when hamburger is clicked
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('active');
// Toggle hamburger to X animation
const bars = menuToggle.querySelectorAll('span');
bars.forEach(bar => bar.classList.toggle('active'));
// Toggle aria-expanded attribute for accessibility
const isExpanded = navMenu.classList.contains('active');
menuToggle.setAttribute('aria-expanded', isExpanded);
});
// Close mobile menu when clicking outside
document.addEventListener('click', function(event) {
if (!navMenu.contains(event.target) && !menuToggle.contains(event.target) && navMenu.classList.contains('active')) {
navMenu.classList.remove('active');
const bars = menuToggle.querySelectorAll('span');
bars.forEach(bar => bar.classList.remove('active'));
menuToggle.setAttribute('aria-expanded', false);
}
});
}
// Add active class to current navigation link
const currentPage = window.location.pathname.split('/').pop() || 'index.html';
const navLinks = document.querySelectorAll('.nav-menu a');
navLinks.forEach(link => {
if (link.getAttribute('href') === currentPage) {
link.classList.add('active');
}
});
});
JavaScript Explanation:
- The script waits for the DOM to be fully loaded using the
DOMContentLoadedevent. - It selects the mobile menu toggle button and the navigation menu.
- It adds a click event listener to toggle the menu's visibility.
- The
aria-expandedattribute is updated for accessibility. - A click event listener on the document closes the menu when clicking outside.
- The script also highlights the current page in the navigation by adding the
activeclass.
Next, let's create a testimonial slider:
Testimonial Slider (js/slider.js)
/*
* slider.js
* Testimonial slider functionality
*/
document.addEventListener('DOMContentLoaded', function() {
// Select slider elements
const slider = document.querySelector('.testimonial-slider');
// Only run if slider exists on the page
if (slider) {
const testimonials = slider.querySelectorAll('.testimonial');
const prevBtn = slider.querySelector('.prev-btn');
const nextBtn = slider.querySelector('.next-btn');
// If testimonials exist and there's more than one
if (testimonials.length > 1) {
// Initialize slider variables
let currentIndex = 0;
let interval;
// Function to show a specific testimonial
function showTestimonial(index) {
// Hide all testimonials
testimonials.forEach(testimonial => {
testimonial.style.display = 'none';
});
// Show the current testimonial
testimonials[index].style.display = 'block';
// Update current index
currentIndex = index;
}
// Function to show next testimonial
function nextTestimonial() {
currentIndex = (currentIndex + 1) % testimonials.length;
showTestimonial(currentIndex);
}
// Function to show previous testimonial
function prevTestimonial() {
currentIndex = (currentIndex - 1 + testimonials.length) % testimonials.length;
showTestimonial(currentIndex);
}
// Add event listeners to buttons
if (nextBtn) {
nextBtn.addEventListener('click', function() {
nextTestimonial();
resetInterval();
});
}
if (prevBtn) {
prevBtn.addEventListener('click', function() {
prevTestimonial();
resetInterval();
});
}
// Start automatic slider
function startInterval() {
interval = setInterval(nextTestimonial, 5000); // Change every 5 seconds
}
// Reset interval after manual navigation
function resetInterval() {
clearInterval(interval);
startInterval();
}
// Initialize slider
showTestimonial(currentIndex);
startInterval();
// Pause automatic sliding when hovering over the slider
slider.addEventListener('mouseenter', function() {
clearInterval(interval);
});
// Resume automatic sliding when mouse leaves
slider.addEventListener('mouseleave', function() {
startInterval();
});
// Add keyboard navigation for accessibility
slider.setAttribute('tabindex', '0');
slider.addEventListener('keydown', function(event) {
if (event.key === 'ArrowLeft') {
prevTestimonial();
resetInterval();
} else if (event.key === 'ArrowRight') {
nextTestimonial();
resetInterval();
}
});
}
}
});
JavaScript Explanation:
- This script creates a simple testimonial slider that rotates through testimonials.
- It shows one testimonial at a time and provides previous/next buttons for navigation.
- The slider automatically advances every 5 seconds, but pauses on hover.
- Keyboard navigation is implemented for accessibility (left/right arrow keys).
- The script includes checks to only run if the slider exists on the current page.
Finally, let's implement form validation for the contact form:
Form Validation (js/validation.js)
/*
* validation.js
* Contact form validation
*/
document.addEventListener('DOMContentLoaded', function() {
// Select the form element
const contactForm = document.getElementById('contactForm');
// Only run if the form exists on the page
if (contactForm) {
// Form fields
const nameInput = document.getElementById('name');
const emailInput = document.getElementById('email');
const phoneInput = document.getElementById('phone');
const subjectInput = document.getElementById('subject');
const messageInput = document.getElementById('message');
const consentInput = document.getElementById('consent');
// Error message elements
const nameError = document.getElementById('nameError');
const emailError = document.getElementById('emailError');
const phoneError = document.getElementById('phoneError');
const subjectError = document.getElementById('subjectError');
const messageError = document.getElementById('messageError');
const consentError = document.getElementById('consentError');
// Validation patterns
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const phonePattern = /^[\d\s()+.-]{7,20}$/; // Basic phone format
// Add form submission event listener
contactForm.addEventListener('submit', function(event) {
// Prevent default form submission
event.preventDefault();
// Track form validity
let isValid = true;
// Reset previous error messages
clearErrors();
// Validate name
if (!nameInput.value.trim()) {
showError(nameError, 'Please enter your name');
isValid = false;
}
// Validate email
if (!emailInput.value.trim()) {
showError(emailError, 'Please enter your email address');
isValid = false;
} else if (!emailPattern.test(emailInput.value)) {
showError(emailError, 'Please enter a valid email address');
isValid = false;
}
// Validate phone (if provided)
if (phoneInput.value.trim() && !phonePattern.test(phoneInput.value)) {
showError(phoneError, 'Please enter a valid phone number');
isValid = false;
}
// Validate subject
if (!subjectInput.value) {
showError(subjectError, 'Please select a subject');
isValid = false;
}
// Validate message
if (!messageInput.value.trim()) {
showError(messageError, 'Please enter your message');
isValid = false;
} else if (messageInput.value.trim().length < 10) {
showError(messageError, 'Your message must be at least 10 characters');
isValid = false;
}
// Validate consent
if (!consentInput.checked) {
showError(consentError, 'You must agree to the terms');
isValid = false;
}
// If form is valid, submit (or show success message for this example)
if (isValid) {
// In a real application, you would submit the form data to a server
// For this example, we'll just show a success message
contactForm.innerHTML = `
`;
// Scroll to the success message
contactForm.scrollIntoView({ behavior: 'smooth' });
}
});
// Function to show error message
function showError(errorElement, message) {
if (errorElement) {
errorElement.textContent = message;
}
}
// Function to clear all error messages
function clearErrors() {
const errorElements = [nameError, emailError, phoneError, subjectError, messageError, consentError];
errorElements.forEach(element => {
if (element) {
element.textContent = '';
}
});
}
// Real-time validation on input
const formInputs = [nameInput, emailInput, phoneInput, subjectInput, messageInput];
formInputs.forEach(input => {
if (input) {
input.addEventListener('input', function() {
// Clear the error message when user starts typing
const errorId = input.id + 'Error';
const errorElement = document.getElementById(errorId);
if (errorElement) {
errorElement.textContent = '';
}
});
}
});
// Special handling for checkbox
if (consentInput) {
consentInput.addEventListener('change', function() {
if (consentError) {
consentError.textContent = '';
}
});
}
}
});
JavaScript Explanation:
- This script implements form validation for the contact form.
- It checks for required fields, proper email format, minimum message length, and consent checkbox.
- Error messages appear below each invalid field when the form is submitted.
- Real-time validation clears error messages as the user corrects issues.
- A success message replaces the form when it's successfully submitted.
- Regular expressions validate email and phone formats.
Testing and Optimization
After building your website, it's crucial to test it thoroughly:
- Cross-Browser Testing: Test in Chrome, Firefox, Safari, and Edge to ensure consistent rendering.
- Responsive Testing: Use browser developer tools to test various screen sizes and orientations.
- Functionality Testing: Verify all links, form validation, and JavaScript features work correctly.
- Accessibility Testing: Check keyboard navigation, screen reader compatibility, and appropriate contrast.
- Performance Optimization:
- Optimize images by compressing them without losing quality
- Minify CSS and JavaScript files
- Check for any render-blocking resources
Use browser developer tools to identify and fix any issues that arise during testing.
Step 4: Looking Back and Learning
In the final step of Polya's method, we reflect on our work and consider what we've learned.
Project Review Checklist
Use this checklist to evaluate your completed website:
- HTML Structure:
- Does the site use semantic HTML elements appropriately?
- Is the content organized in a logical, accessible structure?
- Are images properly sized with descriptive alt text?
- Are forms labeled correctly with proper accessibility attributes?
- Is the navigation consistent across all pages?
- CSS Styling:
- Is the design visually appealing and professional?
- Does the site display correctly on mobile, tablet, and desktop?
- Are styles organized in a logical, maintainable way?
- Is there consistent spacing, typography, and color usage?
- Are interactive elements (links, buttons) visually distinct?
- JavaScript Functionality:
- Do all interactive features work as expected?
- Is there appropriate error handling?
- Does the site work if JavaScript is disabled (graceful degradation)?
- Are interactions smooth and performant?
- Is there keyboard accessibility for interactive elements?
- Content and Usability:
- Is the content clear, concise, and free of spelling/grammar errors?
- Is the navigation intuitive and easy to use?
- Are calls-to-action clear and prominent?
- Does the site have a consistent voice and style?
- Is information organized in a user-friendly way?
Learning Outcomes
By completing this project, you've demonstrated your ability to:
- Structure a multi-page website with semantic HTML
- Create responsive layouts using CSS grid and flexbox
- Implement a mobile-first design approach with media queries
- Add interactivity with JavaScript for enhanced user experience
- Validate form input and provide user feedback
- Organize code in a maintainable, scalable structure
- Apply web accessibility best practices
- Test and optimize a website across different devices
What Could Be Improved?
As with any project, there's always room for improvement. Here are some ways you could enhance your website in the future:
- Backend Integration: Connect your form to a real backend for actual submission
- Performance Optimization: Implement lazy loading for images and optimize JavaScript
- Enhanced Animations: Add more sophisticated animations and transitions
- Advanced Interactions: Add features like filtering or sorting content
- CSS Preprocessing: Use Sass or Less for more maintainable styling
- Expanded Content: Add more pages and content sections
- Search Functionality: Implement a search feature for larger sites
- Analytics Integration: Add tools to track user behavior
Beyond the Basics: Advanced Concepts
If you enjoyed this project and want to take your web development skills further, consider exploring these advanced topics:
Advanced CSS Techniques
- CSS Animations and Keyframes: Create more complex animations between states
- CSS Custom Properties: Implement a theming system with CSS variables
- CSS Grid Advanced Layouts: Use named grid areas for complex layouts
- CSS Preprocessors: Learn Sass or Less for variables, mixins, and nesting
Example: CSS Animation with Keyframes
/* Define the animation */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Apply the animation to elements */
.animate-on-scroll {
opacity: 0;
}
.animate-on-scroll.visible {
animation: fadeIn 0.8s ease forwards;
}
Advanced JavaScript Patterns
- Module Pattern: Organize JavaScript code into reusable modules
- Promises and Async/Await: Handle asynchronous operations more effectively
- Local Storage: Save user preferences or form data locally
- Intersection Observer: Trigger actions when elements come into view
Example: Intersection Observer for Scroll Animations
// Create an observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// If the element is in view
if (entry.isIntersecting) {
// Add the 'visible' class
entry.target.classList.add('visible');
// Stop observing the element
observer.unobserve(entry.target);
}
});
}, {
threshold: 0.1 // Trigger when 10% of the element is visible
});
// Observe all elements with the 'animate-on-scroll' class
document.querySelectorAll('.animate-on-scroll').forEach(element => {
observer.observe(element);
});
Performance Optimization
- Image Optimization: Use modern formats (WebP) and responsive images
- Code Splitting: Load JavaScript only when needed
- Critical CSS: Inline critical styles for faster initial rendering
- Lazy Loading: Defer loading of off-screen images and content
Example: Responsive Images
<picture>
<source srcset="image-large.webp" media="(min-width: 1024px)" type="image/webp">
<source srcset="image-medium.webp" media="(min-width: 640px)" type="image/webp">
<source srcset="image-small.webp" type="image/webp">
<img src="image-fallback.jpg" alt="Description" loading="lazy">
</picture>
Accessibility Enhancements
- ARIA Attributes: Improve screen reader compatibility
- Focus Management: Ensure keyboard users can navigate effectively
- Color Contrast: Verify text meets WCAG contrast guidelines
- Semantic HTML Extensions: Use more specific roles and landmarks
Example: Accessible Modal Dialog
<div id="modal" class="modal" role="dialog" aria-labelledby="modalTitle" aria-modal="true" aria-hidden="true">
<div class="modal-content">
<h2 id="modalTitle">Modal Title</h2>
<p>Modal content goes here.</p>
<button class="close-button" aria-label="Close dialog">×</button>
</div>
</div>
Additional Resources
Documentation and References
- MDN Web Docs - Comprehensive documentation for HTML, CSS, and JavaScript
- web.dev - Best practices for modern web development
- CSS-Tricks - Tutorials and reference for CSS techniques
- Can I Use - Browser compatibility tables
Tools
- W3C HTML Validator - Check HTML for errors
- W3C CSS Validator - Validate CSS
- WAVE - Web accessibility evaluation tool
- Lighthouse - Performance, accessibility, SEO, and best practices auditing
Learning Platforms
- freeCodeCamp - Free tutorials and projects
- Frontend Mentor - Real-world projects to improve your skills
- Codecademy - Interactive coding lessons
Community Forums
- Stack Overflow - Q&A for developers
- r/webdev - Web development subreddit
- DEV Community - Community of software developers
- SitePoint Community - Web development forum
Final Thoughts
Creating a complete, responsive website from scratch is a significant achievement! You've applied HTML, CSS, and JavaScript together to build a professional web presence that works across devices and provides a good user experience.
Remember that web development is an iterative process. Even professional websites are continually refined and improved. Don't worry if your site isn't perfect—focus on what you've learned and the skills you've developed.
This project represents a solid foundation for your web development journey. As you continue to learn and practice, you'll build on these basics to create increasingly sophisticated and polished websites. Each new technique you master opens up new possibilities for creativity and functionality.
Congratulations on completing this comprehensive weekend project! Be sure to add it to your portfolio as a demonstration of your frontend web development skills.
What's Next?
As we move forward in the course, we'll build on these fundamentals to explore:
- Server-side programming with Python and Flask
- Database integration and management
- Full-stack web application development
- API creation and consumption
- Deployment and hosting
These skills will further enhance your ability to create dynamic, interactive web applications.