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
- Responsive design (mobile-first approach)
- Semantic HTML structure
- CSS styling with Flexbox/Grid
- JavaScript for interactivity
- Accessible and SEO-friendly
- Cross-browser compatible
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:
- User interactions (clicks, form submissions)
- Different screen sizes (mobile, tablet, desktop)
- Browser compatibility requirements
Expected Output:
- A fully functional, responsive website
- Smooth navigation and transitions
- Contact form that validates input
- Accessible content for all users
Step 2: Devise a Plan
Simplified Whiteboard Plan:
- Create project structure (folders and files)
- Build HTML skeleton with semantic elements
- Add CSS for mobile-first styling
- Implement responsive design with media queries
- Create interactive navigation with JavaScript
- Build project showcase section
- Add contact form with validation
- 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>© 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
- ✓ Test on different devices (mobile, tablet, desktop)
- ✓ Check all navigation links work correctly
- ✓ Verify form validation
- ✓ Test in different browsers
- ✓ Check accessibility with screen readers
- ✓ Validate HTML and CSS
- ✓ Test page load speed
Enhancements and Extensions
- Add loading animations
- Implement dark mode toggle
- Add project filtering functionality
- Integrate with a backend for form submissions
- Add testimonials section
- Implement lazy loading for images
- Add blog section with recent posts
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:
- Freelance Developers: Showcase projects and attract clients
- Job Seekers: Stand out in job applications
- Agencies: Display services and case studies
- Artists/Designers: Create online galleries
- Small Businesses: Professional web presence
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
- MDN Web Docs: Comprehensive web development documentation
- CSS-Tricks: Advanced CSS techniques and tutorials
- JavaScript.info: In-depth JavaScript tutorials
- Web.dev: Google's web development best practices
- A11y Project: Accessibility guidelines and resources
Project Conclusion
Congratulations! You've built a complete, responsive portfolio website that showcases your new web development skills. This project demonstrates:
- Semantic HTML structure
- Modern CSS techniques (Flexbox, Grid, custom properties)
- Responsive design principles
- JavaScript interactivity
- Form validation
- Accessibility considerations
Remember to customize the content, add your own projects, and continue enhancing the site as you learn more advanced techniques throughout the course!