Build a Responsive Portfolio Website

Week 1 Weekend Project

Project Overview

Create a personal portfolio website that showcases your skills, projects, and contact information. This project combines everything you've learned this week: HTML structure, CSS styling, responsive design, and basic JavaScript interactivity.

Project Requirements

graph TD A[Portfolio Website] --> B[Header/Nav] A --> C[Hero Section] A --> D[About Me] A --> E[Projects] A --> F[Skills] A --> G[Contact] A --> H[Footer] B --> I[Logo] B --> J[Navigation Menu] B --> K[Mobile Menu] E --> L[Project Cards] L --> M[Image] L --> N[Description] L --> O[Links] G --> P[Contact Form] G --> Q[Social Links] style A fill:#f9f,stroke:#333,stroke-width:2px style E fill:#9cf,stroke:#333,stroke-width:2px style G fill:#fc9,stroke:#333,stroke-width:2px

Problem Solving Using Polya's Method

Step 1: Understand the Problem

What are we building? A responsive portfolio website that showcases our work and allows visitors to contact us.

Expected Input:

Expected Output:

Step 2: Devise a Plan

Simplified Whiteboard Plan:

  1. Create project structure (folders and files)
  2. Build HTML skeleton with semantic elements
  3. Add CSS for mobile-first styling
  4. Implement responsive design with media queries
  5. Create interactive navigation with JavaScript
  6. Build project showcase section
  7. Add contact form with validation
  8. Test on different devices and browsers

Project Structure

portfolio/
├── index.html
├── css/
│   └── styles.css
├── js/
│   └── main.js
├── images/
│   ├── profile.jpg
│   ├── project1.jpg
│   ├── project2.jpg
│   └── project3.jpg
└── assets/
    └── resume.pdf

Step 3: Carry Out the Plan

File: index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Portfolio website of John Doe, web developer">
    <title>John Doe | Web Developer Portfolio</title>
    <link rel="stylesheet" href="css/styles.css">
    <link rel="icon" href="images/favicon.png">
</head>
<body>
    <!-- Header with Navigation -->
    <header>
        <nav class="navbar">
            <div class="container">
                <a href="#home" class="logo">JD</a>
                <button class="nav-toggle" aria-label="Toggle navigation">
                    <span class="hamburger"></span>
                </button>
                <ul class="nav-menu">
                    <li><a href="#home">Home</a></li>
                    <li><a href="#about">About</a></li>
                    <li><a href="#projects">Projects</a></li>
                    <li><a href="#skills">Skills</a></li>
                    <li><a href="#contact">Contact</a></li>
                </ul>
            </div>
        </nav>
    </header>

    <main>
        <!-- Hero Section -->
        <section id="home" class="hero">
            <div class="container">
                <h1>John Doe</h1>
                <p class="tagline">Full Stack Web Developer</p>
                <a href="#contact" class="btn btn-primary">Get In Touch</a>
                <a href="assets/resume.pdf" class="btn btn-secondary" download>Download Resume</a>
            </div>
        </section>

        <!-- About Section -->
        <section id="about" class="about">
            <div class="container">
                <h2>About Me</h2>
                <div class="about-content">
                    <img src="images/profile.jpg" alt="John Doe" class="profile-img">
                    <div class="about-text">
                        <p>I'm a passionate web developer with experience in creating responsive, user-friendly websites and applications. I love turning complex problems into simple, beautiful solutions.</p>
                        <p>When I'm not coding, you can find me exploring new technologies, contributing to open-source projects, or hiking in the mountains.</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Projects Section -->
        <section id="projects" class="projects">
            <div class="container">
                <h2>Projects</h2>
                <div class="project-grid">
                    <article class="project-card">
                        <img src="images/project1.jpg" alt="E-commerce Website">
                        <div class="project-info">
                            <h3>E-commerce Website</h3>
                            <p>A fully responsive online store built with React and Node.js</p>
                            <div class="project-links">
                                <a href="#" class="btn btn-small">Live Demo</a>
                                <a href="#" class="btn btn-small btn-secondary">GitHub</a>
                            </div>
                        </div>
                    </article>
                    <!-- Add more project cards -->
                </div>
            </div>
        </section>

        <!-- Skills Section -->
        <section id="skills" class="skills">
            <div class="container">
                <h2>Skills</h2>
                <div class="skills-grid">
                    <div class="skill-category">
                        <h3>Frontend</h3>
                        <ul>
                            <li>HTML5</li>
                            <li>CSS3 / Sass</li>
                            <li>JavaScript (ES6+)</li>
                            <li>React.js</li>
                        </ul>
                    </div>
                    <div class="skill-category">
                        <h3>Backend</h3>
                        <ul>
                            <li>Node.js</li>
                            <li>Express.js</li>
                            <li>MongoDB</li>
                            <li>REST APIs</li>
                        </ul>
                    </div>
                    <div class="skill-category">
                        <h3>Tools</h3>
                        <ul>
                            <li>Git / GitHub</li>
                            <li>VS Code</li>
                            <li>Webpack</li>
                            <li>Docker</li>
                        </ul>
                    </div>
                </div>
            </div>
        </section>

        <!-- Contact Section -->
        <section id="contact" class="contact">
            <div class="container">
                <h2>Contact Me</h2>
                <form id="contact-form" class="contact-form">
                    <div class="form-group">
                        <label for="name">Name</label>
                        <input type="text" id="name" name="name" required>
                    </div>
                    <div class="form-group">
                        <label for="email">Email</label>
                        <input type="email" id="email" name="email" required>
                    </div>
                    <div class="form-group">
                        <label for="message">Message</label>
                        <textarea id="message" name="message" rows="5" required></textarea>
                    </div>
                    <button type="submit" class="btn btn-primary">Send Message</button>
                </form>
                <div class="social-links">
                    <a href="#" aria-label="GitHub">GitHub</a>
                    <a href="#" aria-label="LinkedIn">LinkedIn</a>
                    <a href="#" aria-label="Twitter">Twitter</a>
                </div>
            </div>
        </section>
    </main>

    <footer>
        <div class="container">
            <p>&copy; 2024 John Doe. All rights reserved.</p>
        </div>
    </footer>

    <script src="js/main.js"></script>
</body>
</html>

File: css/styles.css

/* Reset and Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

:root {
    --primary-color: #007bff;
    --secondary-color: #6c757d;
    --text-color: #333;
    --light-bg: #f8f9fa;
    --white: #ffffff;
    --spacing-unit: 1rem;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    color: var(--text-color);
}

.container {
    width: 90%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--spacing-unit);
}

/* Typography */
h1, h2, h3 {
    margin-bottom: var(--spacing-unit);
}

h1 {
    font-size: 2.5rem;
}

h2 {
    font-size: 2rem;
    text-align: center;
    margin-bottom: 2rem;
}

/* Navigation */
.navbar {
    background: var(--white);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    position: fixed;
    width: 100%;
    top: 0;
    z-index: 1000;
}

.navbar .container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
}

.logo {
    font-size: 1.5rem;
    font-weight: bold;
    color: var(--primary-color);
    text-decoration: none;
}

.nav-menu {
    display: none;
    list-style: none;
    gap: 1.5rem;
}

.nav-menu a {
    text-decoration: none;
    color: var(--text-color);
    transition: color 0.3s ease;
}

.nav-menu a:hover {
    color: var(--primary-color);
}

.nav-toggle {
    display: block;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.5rem;
}

.hamburger {
    display: block;
    width: 25px;
    height: 3px;
    background: var(--text-color);
    position: relative;
}

.hamburger::before,
.hamburger::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 3px;
    background: var(--text-color);
    left: 0;
}

.hamburger::before {
    top: -8px;
}

.hamburger::after {
    bottom: -8px;
}

/* Sections */
section {
    padding: 4rem 0;
}

.hero {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: var(--white);
    text-align: center;
    padding: 8rem 0 4rem;
    margin-top: 60px;
}

.tagline {
    font-size: 1.25rem;
    margin-bottom: 2rem;
}

/* Buttons */
.btn {
    display: inline-block;
    padding: 0.75rem 1.5rem;
    border-radius: 4px;
    text-decoration: none;
    transition: all 0.3s ease;
    margin: 0.5rem;
}

.btn-primary {
    background: var(--primary-color);
    color: var(--white);
}

.btn-primary:hover {
    background: #0056b3;
    transform: translateY(-2px);
}

.btn-secondary {
    background: transparent;
    color: var(--white);
    border: 2px solid var(--white);
}

.btn-secondary:hover {
    background: var(--white);
    color: var(--primary-color);
}

/* About Section */
.about-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2rem;
}

.profile-img {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    object-fit: cover;
}

/* Projects Section */
.project-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 2rem;
}

.project-card {
    background: var(--white);
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    transition: transform 0.3s ease;
}

.project-card:hover {
    transform: translateY(-5px);
}

.project-card img {
    width: 100%;
    height: 200px;
    object-fit: cover;
}

.project-info {
    padding: 1.5rem;
}

.project-links {
    margin-top: 1rem;
}

/* Skills Section */
.skills-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 2rem;
}

.skill-category {
    background: var(--light-bg);
    padding: 1.5rem;
    border-radius: 8px;
}

.skill-category ul {
    list-style: none;
}

.skill-category li {
    padding: 0.5rem 0;
    border-bottom: 1px solid #dee2e6;
}

/* Contact Section */
.contact {
    background: var(--light-bg);
}

.contact-form {
    max-width: 600px;
    margin: 0 auto;
}

.form-group {
    margin-bottom: 1.5rem;
}

.form-group label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 600;
}

.form-group input,
.form-group textarea {
    width: 100%;
    padding: 0.75rem;
    border: 1px solid #ced4da;
    border-radius: 4px;
    font-family: inherit;
}

.social-links {
    text-align: center;
    margin-top: 2rem;
}

.social-links a {
    display: inline-block;
    margin: 0 1rem;
    color: var(--primary-color);
    text-decoration: none;
}

/* Footer */
footer {
    background: var(--text-color);
    color: var(--white);
    text-align: center;
    padding: 1rem 0;
}

/* Responsive Design */
@media (min-width: 768px) {
    .nav-toggle {
        display: none;
    }
    
    .nav-menu {
        display: flex;
    }
    
    .about-content {
        flex-direction: row;
        text-align: left;
    }
    
    h1 {
        font-size: 3.5rem;
    }
}

File: js/main.js

// Mobile Navigation Toggle
const navToggle = document.querySelector('.nav-toggle');
const navMenu = document.querySelector('.nav-menu');

navToggle.addEventListener('click', () => {
    navMenu.classList.toggle('active');
    navToggle.classList.toggle('active');
});

// Smooth Scrolling for Navigation Links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function(e) {
        e.preventDefault();
        const target = document.querySelector(this.getAttribute('href'));
        
        if (target) {
            // Close mobile menu if open
            navMenu.classList.remove('active');
            navToggle.classList.remove('active');
            
            // Smooth scroll to target
            target.scrollIntoView({
                behavior: 'smooth',
                block: 'start'
            });
        }
    });
});

// Form Validation and Submission
const contactForm = document.getElementById('contact-form');

contactForm.addEventListener('submit', function(e) {
    e.preventDefault();
    
    // Get form values
    const name = document.getElementById('name').value.trim();
    const email = document.getElementById('email').value.trim();
    const message = document.getElementById('message').value.trim();
    
    // Basic validation
    if (!name || !email || !message) {
        alert('Please fill in all fields');
        return;
    }
    
    // Email validation
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
        alert('Please enter a valid email address');
        return;
    }
    
    // In a real application, you would send this data to a server
    console.log('Form submitted:', { name, email, message });
    alert('Thank you for your message! I will get back to you soon.');
    
    // Reset form
    contactForm.reset();
});

// Navbar background change on scroll
window.addEventListener('scroll', () => {
    const navbar = document.querySelector('.navbar');
    if (window.scrollY > 100) {
        navbar.style.background = '#fff';
        navbar.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
    } else {
        navbar.style.background = 'transparent';
        navbar.style.boxShadow = 'none';
    }
});

// Add animation on scroll
function revealOnScroll() {
    const elements = document.querySelectorAll('.project-card, .skill-category');
    
    elements.forEach(element => {
        const elementTop = element.getBoundingClientRect().top;
        const windowHeight = window.innerHeight;
        
        if (elementTop < windowHeight - 100) {
            element.style.opacity = '1';
            element.style.transform = 'translateY(0)';
        }
    });
}

// Initialize animation styles
document.querySelectorAll('.project-card, .skill-category').forEach(element => {
    element.style.opacity = '0';
    element.style.transform = 'translateY(20px)';
    element.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
});

window.addEventListener('scroll', revealOnScroll);
window.addEventListener('load', revealOnScroll);

Step 4: Look Back and Reflect

Testing Checklist

Enhancements and Extensions

Code Explanations

Mobile Navigation Implementation

The mobile navigation uses a hamburger menu that toggles visibility when clicked. Think of it like a drawer that slides in and out - when you click the button, the drawer opens, and when you click again (or select a menu item), it closes.

Smooth Scrolling

Smooth scrolling creates a pleasant user experience when navigating between sections. Instead of jumping instantly to a section, the page glides smoothly - like taking an elevator instead of teleporting between floors.

Form Validation

Form validation is like a security guard checking IDs at the door. It ensures that all required information is provided and in the correct format before allowing the form to be submitted.

Responsive Design

The responsive design uses CSS Grid and Flexbox with a mobile-first approach. Think of it like water that adapts to fill any container - the layout adjusts to fit any screen size while maintaining readability and usability.

Real World Applications

This portfolio website structure can be adapted for:

Advanced Enhancements

Dark Mode Implementation

// Add to main.js
function toggleDarkMode() {
    document.body.classList.toggle('dark-mode');
    localStorage.setItem('darkMode', document.body.classList.contains('dark-mode'));
}

// Check for saved preference
if (localStorage.getItem('darkMode') === 'true') {
    document.body.classList.add('dark-mode');
}

// Add to CSS
.dark-mode {
    --text-color: #f8f9fa;
    --light-bg: #343a40;
    --white: #212529;
    background: #212529;
}

.dark-mode .navbar {
    background: #343a40;
}

.dark-mode .project-card {
    background: #495057;
    color: #f8f9fa;
}

Project Filtering

// Add filter buttons to HTML
<div class="project-filters">
    <button class="filter-btn active" data-filter="all">All</button>
    <button class="filter-btn" data-filter="web">Web</button>
    <button class="filter-btn" data-filter="mobile">Mobile</button>
    <button class="filter-btn" data-filter="design">Design</button>
</div>

// Add to JavaScript
const filterButtons = document.querySelectorAll('.filter-btn');
const projectCards = document.querySelectorAll('.project-card');

filterButtons.forEach(button => {
    button.addEventListener('click', () => {
        // Remove active class from all buttons
        filterButtons.forEach(btn => btn.classList.remove('active'));
        button.classList.add('active');
        
        const filter = button.dataset.filter;
        
        projectCards.forEach(card => {
            if (filter === 'all' || card.dataset.category === filter) {
                card.style.display = 'block';
            } else {
                card.style.display = 'none';
            }
        });
    });
});

Further Learning Resources

Project Conclusion

Congratulations! You've built a complete, responsive portfolio website that showcases your new web development skills. This project demonstrates:

Remember to customize the content, add your own projects, and continue enhancing the site as you learn more advanced techniques throughout the course!