Capstone: Building a Responsive Landing Page
Project Overview
Welcome to the capstone lesson of the CSS course. In this comprehensive project, you will build a complete, production-quality responsive landing page from scratch, applying every technique you have learned throughout the course. This is not a simple exercise -- it is a full project that combines CSS resets, custom properties, Flexbox navigation, Grid layouts, background images with gradient overlays, hover transitions, dark mode support, accessibility best practices, and mobile-first responsive design into a single cohesive page.
The landing page you will build includes seven distinct sections: a responsive header with navigation, a hero section with a background image and gradient overlay, a features section with Grid cards, a testimonials section, a pricing table, a call-to-action section, and a multi-column footer. Each section introduces specific CSS patterns and techniques that you will encounter in real-world projects.
Step 1: Project Setup -- Reset, Custom Properties, and Base Styles
Every professional project starts with a solid foundation. We begin by resetting browser defaults, defining our design tokens as CSS custom properties, and establishing base typography and layout styles. This setup ensures consistency across browsers and makes the entire design easy to maintain and modify.
CSS Reset and Custom Properties
/* ============================================
CSS RESET -- Normalize browser defaults
============================================ */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
scroll-behavior: smooth;
-webkit-text-size-adjust: 100%;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: var(--text-primary);
background-color: var(--bg-primary);
transition: background-color 0.3s ease, color 0.3s ease;
}
img {
max-width: 100%;
height: auto;
display: block;
}
a {
text-decoration: none;
color: inherit;
}
ul, ol {
list-style: none;
}
button {
font: inherit;
cursor: pointer;
border: none;
background: none;
}
/* ============================================
DESIGN TOKENS -- Custom Properties
============================================ */
:root {
/* Primary palette */
--color-primary: #4f46e5;
--color-primary-light: #818cf8;
--color-primary-dark: #3730a3;
/* Neutral palette */
--color-white: #ffffff;
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db;
--color-gray-500: #6b7280;
--color-gray-700: #374151;
--color-gray-800: #1f2937;
--color-gray-900: #111827;
/* Semantic colors (Light mode defaults) */
--bg-primary: var(--color-white);
--bg-secondary: var(--color-gray-50);
--bg-card: var(--color-white);
--text-primary: var(--color-gray-900);
--text-secondary: var(--color-gray-500);
--text-heading: var(--color-gray-800);
--border-color: var(--color-gray-200);
/* Accent */
--color-accent: #f59e0b;
--color-success: #10b981;
--color-danger: #ef4444;
/* Spacing scale */
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2rem;
--space-2xl: 3rem;
--space-3xl: 4rem;
--space-4xl: 6rem;
/* Typography scale */
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
--text-5xl: 3rem;
/* Layout */
--container-max: 1200px;
--header-height: 72px;
--border-radius: 8px;
--border-radius-lg: 16px;
/* Shadows */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.12);
--shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.15);
/* Transitions */
--transition-fast: 150ms ease;
--transition-base: 300ms ease;
--transition-slow: 500ms ease;
}
/* ============================================
BASE UTILITY CLASSES
============================================ */
.container {
width: 100%;
max-width: var(--container-max);
margin: 0 auto;
padding: 0 var(--space-lg);
}
.section-title {
font-size: var(--text-3xl);
font-weight: 700;
color: var(--text-heading);
text-align: center;
margin-bottom: var(--space-md);
}
.section-subtitle {
font-size: var(--text-lg);
color: var(--text-secondary);
text-align: center;
max-width: 600px;
margin: 0 auto var(--space-3xl);
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.75rem;
font-size: var(--text-base);
font-weight: 600;
border-radius: var(--border-radius);
transition: transform var(--transition-fast),
box-shadow var(--transition-fast),
background-color var(--transition-fast);
}
.btn:active {
transform: translateY(1px) scale(0.98);
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-white);
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}
.btn-outline {
border: 2px solid var(--color-primary);
color: var(--color-primary);
background: transparent;
}
.btn-outline:hover {
background-color: var(--color-primary);
color: var(--color-white);
transform: translateY(-2px);
}
Step 2: Responsive Header and Navigation with Flexbox
The header uses Flexbox to align the logo and navigation links horizontally. On mobile devices, the navigation collapses into a hamburger menu toggled by a checkbox hack (pure CSS, no JavaScript required). The header also uses a sticky position so it remains visible as the user scrolls.
HTML: Header Structure
<header class="header">
<div class="container header__inner">
<a href="#" class="header__logo">
<span class="logo-icon"></></span>
<span class="logo-text">DevLand</span>
</a>
<!-- Checkbox hack for mobile menu toggle -->
<input type="checkbox" id="nav-toggle" class="nav-toggle" aria-hidden="true">
<label for="nav-toggle" class="nav-toggle-label" aria-label="Toggle navigation">
<span class="hamburger"></span>
</label>
<nav class="header__nav" aria-label="Main navigation">
<ul class="nav-list">
<li><a href="#features" class="nav-link">Features</a></li>
<li><a href="#testimonials" class="nav-link">Testimonials</a></li>
<li><a href="#pricing" class="nav-link">Pricing</a></li>
<li><a href="#cta" class="nav-link nav-link--cta">Get Started</a></li>
</ul>
</nav>
</div>
</header>
CSS: Header and Navigation
/* ============================================
HEADER -- Sticky navigation with Flexbox
============================================ */
.header {
position: sticky;
top: 0;
z-index: 1000;
height: var(--header-height);
background-color: var(--bg-primary);
border-bottom: 1px solid var(--border-color);
/* Glassmorphism effect for modern browsers */
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
background-color: rgba(255, 255, 255, 0.85);
}
.header__inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
}
/* Logo styling */
.header__logo {
display: flex;
align-items: center;
gap: var(--space-sm);
font-size: var(--text-xl);
font-weight: 700;
color: var(--text-heading);
z-index: 10; /* Stay above mobile nav overlay */
}
.logo-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background-color: var(--color-primary);
color: var(--color-white);
border-radius: var(--border-radius);
font-size: var(--text-sm);
font-family: monospace;
}
/* Desktop navigation */
.nav-list {
display: flex;
align-items: center;
gap: var(--space-xl);
}
.nav-link {
font-size: var(--text-base);
font-weight: 500;
color: var(--text-secondary);
transition: color var(--transition-fast);
position: relative;
}
.nav-link::after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
width: 0;
height: 2px;
background-color: var(--color-primary);
transition: width var(--transition-base);
}
.nav-link:hover {
color: var(--color-primary);
}
.nav-link:hover::after {
width: 100%;
}
/* CTA button in navigation */
.nav-link--cta {
background-color: var(--color-primary);
color: var(--color-white) !important;
padding: 0.5rem 1.25rem;
border-radius: var(--border-radius);
transition: background-color var(--transition-fast),
transform var(--transition-fast);
}
.nav-link--cta::after {
display: none; /* No underline for button */
}
.nav-link--cta:hover {
background-color: var(--color-primary-dark);
transform: translateY(-1px);
}
/* Hamburger menu -- hidden on desktop */
.nav-toggle {
display: none; /* Hide the checkbox */
}
.nav-toggle-label {
display: none; /* Hidden on desktop, shown on mobile */
cursor: pointer;
z-index: 10;
}
.hamburger,
.hamburger::before,
.hamburger::after {
display: block;
width: 24px;
height: 2px;
background-color: var(--text-primary);
transition: transform var(--transition-base),
opacity var(--transition-fast);
}
.hamburger {
position: relative;
}
.hamburger::before,
.hamburger::after {
content: '';
position: absolute;
left: 0;
}
.hamburger::before { top: -7px; }
.hamburger::after { top: 7px; }
/* ============================================
MOBILE NAVIGATION (max-width: 768px)
============================================ */
@media (max-width: 768px) {
.nav-toggle-label {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
}
.header__nav {
position: fixed;
top: var(--header-height);
left: 0;
width: 100%;
height: calc(100vh - var(--header-height));
background-color: var(--bg-primary);
transform: translateX(100%);
transition: transform var(--transition-base);
}
.nav-list {
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-2xl);
height: 100%;
padding: var(--space-2xl);
}
.nav-link {
font-size: var(--text-2xl);
}
/* When checkbox is checked, show the mobile nav */
.nav-toggle:checked ~ .header__nav {
transform: translateX(0);
}
/* Animate hamburger to X when open */
.nav-toggle:checked ~ .nav-toggle-label .hamburger {
background-color: transparent;
}
.nav-toggle:checked ~ .nav-toggle-label .hamburger::before {
top: 0;
transform: rotate(45deg);
}
.nav-toggle:checked ~ .nav-toggle-label .hamburger::after {
top: 0;
transform: rotate(-45deg);
}
}
<input type="checkbox"> paired with a <label> to create a toggle mechanism without JavaScript. The CSS sibling selector .nav-toggle:checked ~ .header__nav targets the navigation element when the checkbox is checked. This is a widely used pattern for accessible mobile menus. The aria-label on the label ensures screen readers announce the toggle purpose.Step 3: Hero Section with Background Image and Gradient Overlay
The hero section creates a dramatic first impression using a full-width background image with a semi-transparent gradient overlay. The content is centered both vertically and horizontally using Flexbox. The gradient overlay ensures text remains readable regardless of the background image.
HTML: Hero Section
<section class="hero">
<div class="hero__overlay"></div>
<div class="container hero__content">
<h1 class="hero__title">Build Beautiful Websites with Confidence</h1>
<p class="hero__subtitle">
Master modern CSS techniques and create stunning,
responsive web experiences that delight users.
</p>
<div class="hero__actions">
<a href="#pricing" class="btn btn-primary btn--lg">Start Learning</a>
<a href="#features" class="btn btn-outline btn--lg">See Features</a>
</div>
</div>
</section>
CSS: Hero Section
/* ============================================
HERO SECTION -- Full-width with gradient overlay
============================================ */
.hero {
position: relative;
min-height: calc(100vh - var(--header-height));
display: flex;
align-items: center;
justify-content: center;
/* Background image with fallback color */
background: var(--color-gray-900) url('https://images.unsplash.com/photo-1517134191118-9d595e4c8c2b?w=1920&q=80')
center / cover no-repeat;
overflow: hidden;
}
/* Gradient overlay for text readability */
.hero__overlay {
position: absolute;
inset: 0; /* Shorthand for top/right/bottom/left: 0 */
background: linear-gradient(
135deg,
rgba(17, 24, 39, 0.92) 0%,
rgba(79, 70, 229, 0.75) 100%
);
z-index: 1;
}
/* Content sits above the overlay */
.hero__content {
position: relative;
z-index: 2;
text-align: center;
padding: var(--space-4xl) 0;
max-width: 800px;
}
.hero__title {
font-size: var(--text-5xl);
font-weight: 800;
color: var(--color-white);
line-height: 1.1;
margin-bottom: var(--space-lg);
/* Subtle text shadow for depth */
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
}
.hero__subtitle {
font-size: var(--text-xl);
color: var(--color-gray-300);
margin-bottom: var(--space-2xl);
line-height: 1.7;
}
.hero__actions {
display: flex;
gap: var(--space-md);
justify-content: center;
flex-wrap: wrap;
}
.btn--lg {
padding: 1rem 2.25rem;
font-size: var(--text-lg);
}
/* Hero-specific button overrides */
.hero .btn-outline {
border-color: var(--color-white);
color: var(--color-white);
}
.hero .btn-outline:hover {
background-color: var(--color-white);
color: var(--color-primary);
}
/* Responsive hero text */
@media (max-width: 768px) {
.hero__title {
font-size: var(--text-3xl);
}
.hero__subtitle {
font-size: var(--text-base);
}
.hero__content {
padding: var(--space-2xl) 0;
}
}
Step 4: Features Section with CSS Grid Cards
The features section uses CSS Grid to arrange feature cards in a responsive layout. The grid automatically adapts from three columns on desktop to a single column on mobile using the auto-fit keyword with minmax(). Each card includes hover effects with smooth transitions.
HTML: Features Section
<section class="features" id="features">
<div class="container">
<h2 class="section-title">Powerful Features</h2>
<p class="section-subtitle">
Everything you need to build modern, responsive websites.
</p>
<div class="features__grid">
<article class="feature-card">
<div class="feature-card__icon">⚡</div>
<h3 class="feature-card__title">Lightning Fast</h3>
<p class="feature-card__desc">Optimized performance with modern CSS techniques that ensure smooth 60fps animations and minimal repaints.</p>
</article>
<article class="feature-card">
<div class="feature-card__icon">📱</div>
<h3 class="feature-card__title">Fully Responsive</h3>
<p class="feature-card__desc">Mobile-first design that looks stunning on every device, from small phones to large desktop monitors.</p>
</article>
<article class="feature-card">
<div class="feature-card__icon">⚛</div>
<h3 class="feature-card__title">Accessible</h3>
<p class="feature-card__desc">Built with accessibility in mind, including proper focus management, contrast ratios, and screen reader support.</p>
</article>
<article class="feature-card">
<div class="feature-card__icon">🎨</div>
<h3 class="feature-card__title">Beautiful Design</h3>
<p class="feature-card__desc">Carefully crafted visual design with consistent spacing, typography, and color that delights users.</p>
</article>
<article class="feature-card">
<div class="feature-card__icon">🔒</div>
<h3 class="feature-card__title">Secure by Default</h3>
<p class="feature-card__desc">Follow industry best practices for web security with proper content security policies and safe CSS patterns.</p>
</article>
<article class="feature-card">
<div class="feature-card__icon">🚀</div>
<h3 class="feature-card__title">Easy to Deploy</h3>
<p class="feature-card__desc">Ship with confidence using clean, maintainable CSS that any team member can understand and extend.</p>
</article>
</div>
</div>
</section>
CSS: Features Grid and Cards
/* ============================================
FEATURES SECTION -- Grid layout with cards
============================================ */
.features {
padding: var(--space-4xl) 0;
background-color: var(--bg-secondary);
}
.features__grid {
display: grid;
/* Auto-responsive grid: 3 columns on desktop, adapts down */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--space-xl);
}
.feature-card {
background-color: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-lg);
padding: var(--space-2xl);
text-align: center;
transition: transform var(--transition-base),
box-shadow var(--transition-base);
}
/* Card hover: lift effect */
.feature-card:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-lg);
}
.feature-card__icon {
font-size: 2.5rem;
margin-bottom: var(--space-lg);
/* Circular icon background */
display: inline-flex;
align-items: center;
justify-content: center;
width: 72px;
height: 72px;
border-radius: 50%;
background-color: rgba(79, 70, 229, 0.1);
}
.feature-card__title {
font-size: var(--text-xl);
font-weight: 700;
color: var(--text-heading);
margin-bottom: var(--space-sm);
}
.feature-card__desc {
font-size: var(--text-base);
color: var(--text-secondary);
line-height: 1.7;
}
/* Smaller cards on small screens */
@media (max-width: 640px) {
.features__grid {
grid-template-columns: 1fr;
}
}
Step 5: Testimonials Section
The testimonials section uses Flexbox to arrange customer quotes in a scrollable row on desktop and a stacked column on mobile. Each testimonial card uses subtle styling and a quotation mark decorative element created with a pseudo-element.
HTML: Testimonials Section
<section class="testimonials" id="testimonials">
<div class="container">
<h2 class="section-title">What Our Students Say</h2>
<p class="section-subtitle">
Hear from developers who transformed their skills.
</p>
<div class="testimonials__grid">
<blockquote class="testimonial-card">
<p class="testimonial-card__text">This course completely changed how I approach CSS. The systematic debugging methodology alone was worth the entire investment.</p>
<footer class="testimonial-card__author">
<div class="author-avatar">SK</div>
<div>
<cite class="author-name">Sarah K.</cite>
<span class="author-role">Frontend Developer</span>
</div>
</footer>
</blockquote>
<blockquote class="testimonial-card">
<p class="testimonial-card__text">I went from fighting with CSS daily to actually enjoying writing styles. Grid and Flexbox finally clicked for me thanks to the hands-on projects.</p>
<footer class="testimonial-card__author">
<div class="author-avatar">MR</div>
<div>
<cite class="author-name">Marco R.</cite>
<span class="author-role">Fullstack Engineer</span>
</div>
</footer>
</blockquote>
<blockquote class="testimonial-card">
<p class="testimonial-card__text">The accessibility and performance sections were exceptional. I now build sites that are faster and more inclusive by default.</p>
<footer class="testimonial-card__author">
<div class="author-avatar">AL</div>
<div>
<cite class="author-name">Aisha L.</cite>
<span class="author-role">UX Engineer</span>
</div>
</footer>
</blockquote>
</div>
</div>
</section>
CSS: Testimonials
/* ============================================
TESTIMONIALS SECTION
============================================ */
.testimonials {
padding: var(--space-4xl) 0;
background-color: var(--bg-primary);
}
.testimonials__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--space-xl);
}
.testimonial-card {
background-color: var(--bg-secondary);
border-radius: var(--border-radius-lg);
padding: var(--space-2xl);
position: relative;
transition: transform var(--transition-base);
}
.testimonial-card:hover {
transform: translateY(-4px);
}
/* Decorative quotation mark */
.testimonial-card::before {
content: '\201C'; /* Left double quotation mark */
position: absolute;
top: var(--space-md);
left: var(--space-xl);
font-size: 4rem;
line-height: 1;
color: var(--color-primary-light);
opacity: 0.3;
font-family: Georgia, serif;
}
.testimonial-card__text {
font-size: var(--text-base);
color: var(--text-primary);
line-height: 1.8;
margin-bottom: var(--space-xl);
padding-top: var(--space-lg);
font-style: italic;
}
.testimonial-card__author {
display: flex;
align-items: center;
gap: var(--space-md);
}
.author-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background-color: var(--color-primary);
color: var(--color-white);
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: var(--text-sm);
flex-shrink: 0;
}
.author-name {
display: block;
font-style: normal;
font-weight: 600;
color: var(--text-heading);
}
.author-role {
font-size: var(--text-sm);
color: var(--text-secondary);
}
Step 6: Pricing Table with Grid and Hover Effects
The pricing section is one of the most complex components. It uses CSS Grid to align three pricing tiers, with the middle "popular" tier visually emphasized by scaling, a colored border, and a badge. Each card responds to hover with a subtle lift and shadow enhancement.
HTML: Pricing Section
<section class="pricing" id="pricing">
<div class="container">
<h2 class="section-title">Simple, Transparent Pricing</h2>
<p class="section-subtitle">
Choose the plan that works best for your learning goals.
</p>
<div class="pricing__grid">
<div class="pricing-card">
<h3 class="pricing-card__name">Starter</h3>
<div class="pricing-card__price">
<span class="price-currency">$</span>
<span class="price-amount">29</span>
<span class="price-period">/month</span>
</div>
<ul class="pricing-card__features">
<li>All CSS lessons</li>
<li>5 practice projects</li>
<li>Community access</li>
<li class="feature--disabled">1-on-1 mentoring</li>
<li class="feature--disabled">Certificate</li>
</ul>
<a href="#" class="btn btn-outline pricing-card__btn">Get Started</a>
</div>
<div class="pricing-card pricing-card--popular">
<span class="pricing-card__badge">Most Popular</span>
<h3 class="pricing-card__name">Professional</h3>
<div class="pricing-card__price">
<span class="price-currency">$</span>
<span class="price-amount">59</span>
<span class="price-period">/month</span>
</div>
<ul class="pricing-card__features">
<li>All CSS lessons</li>
<li>15 practice projects</li>
<li>Community access</li>
<li>Weekly mentoring</li>
<li class="feature--disabled">Certificate</li>
</ul>
<a href="#" class="btn btn-primary pricing-card__btn">Get Started</a>
</div>
<div class="pricing-card">
<h3 class="pricing-card__name">Enterprise</h3>
<div class="pricing-card__price">
<span class="price-currency">$</span>
<span class="price-amount">99</span>
<span class="price-period">/month</span>
</div>
<ul class="pricing-card__features">
<li>All CSS lessons</li>
<li>Unlimited projects</li>
<li>Private community</li>
<li>Daily mentoring</li>
<li>Certificate</li>
</ul>
<a href="#" class="btn btn-outline pricing-card__btn">Contact Sales</a>
</div>
</div>
</div>
</section>
CSS: Pricing Table
/* ============================================
PRICING SECTION -- Grid with featured card
============================================ */
.pricing {
padding: var(--space-4xl) 0;
background-color: var(--bg-secondary);
}
.pricing__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-xl);
align-items: start;
}
.pricing-card {
background-color: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-lg);
padding: var(--space-2xl);
text-align: center;
position: relative;
transition: transform var(--transition-base),
box-shadow var(--transition-base);
}
.pricing-card:hover {
transform: translateY(-6px);
box-shadow: var(--shadow-lg);
}
/* Popular card emphasis */
.pricing-card--popular {
border: 2px solid var(--color-primary);
transform: scale(1.05);
box-shadow: var(--shadow-xl);
z-index: 1;
}
.pricing-card--popular:hover {
transform: scale(1.05) translateY(-6px);
box-shadow: var(--shadow-xl);
}
.pricing-card__badge {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--color-primary);
color: var(--color-white);
font-size: var(--text-sm);
font-weight: 600;
padding: 0.25rem 1rem;
border-radius: 50px;
white-space: nowrap;
}
.pricing-card__name {
font-size: var(--text-xl);
font-weight: 600;
color: var(--text-heading);
margin-bottom: var(--space-md);
}
.pricing-card__price {
margin-bottom: var(--space-xl);
display: flex;
align-items: baseline;
justify-content: center;
gap: 2px;
}
.price-currency {
font-size: var(--text-xl);
font-weight: 600;
color: var(--text-secondary);
}
.price-amount {
font-size: var(--text-5xl);
font-weight: 800;
color: var(--text-heading);
line-height: 1;
}
.price-period {
font-size: var(--text-base);
color: var(--text-secondary);
}
.pricing-card__features {
margin-bottom: var(--space-xl);
text-align: left;
}
.pricing-card__features li {
padding: 0.6rem 0;
color: var(--text-primary);
border-bottom: 1px solid var(--border-color);
font-size: var(--text-base);
}
.pricing-card__features li::before {
content: '\2713'; /* Checkmark */
margin-right: var(--space-sm);
color: var(--color-success);
font-weight: 700;
}
.pricing-card__features li.feature--disabled {
color: var(--text-secondary);
text-decoration: line-through;
opacity: 0.5;
}
.pricing-card__features li.feature--disabled::before {
content: '\2717'; /* Cross mark */
color: var(--text-secondary);
}
.pricing-card__btn {
width: 100%;
}
/* Responsive pricing: stack on tablet and below */
@media (max-width: 900px) {
.pricing__grid {
grid-template-columns: 1fr;
max-width: 450px;
margin: 0 auto;
}
.pricing-card--popular {
transform: scale(1);
order: -1; /* Move popular card to top on mobile */
}
.pricing-card--popular:hover {
transform: translateY(-6px);
}
}
Step 7: Call-to-Action Section with Gradient Background
The CTA section uses a bold gradient background to draw attention and encourage conversion. The layout is simple and focused, using Flexbox to center the content.
HTML: CTA Section
<section class="cta" id="cta">
<div class="container cta__content">
<h2 class="cta__title">Ready to Master CSS?</h2>
<p class="cta__text">
Join thousands of developers who have leveled up their skills.
Start your journey today with our comprehensive curriculum.
</p>
<a href="#pricing" class="btn btn-white btn--lg">Get Started Now</a>
</div>
</section>
CSS: CTA Section
/* ============================================
CALL-TO-ACTION SECTION -- Gradient background
============================================ */
.cta {
padding: var(--space-4xl) 0;
background: linear-gradient(
135deg,
var(--color-primary-dark) 0%,
var(--color-primary) 50%,
var(--color-primary-light) 100%
);
text-align: center;
}
.cta__content {
max-width: 700px;
}
.cta__title {
font-size: var(--text-4xl);
font-weight: 800;
color: var(--color-white);
margin-bottom: var(--space-md);
}
.cta__text {
font-size: var(--text-lg);
color: rgba(255, 255, 255, 0.85);
margin-bottom: var(--space-2xl);
line-height: 1.7;
}
.btn-white {
background-color: var(--color-white);
color: var(--color-primary);
font-weight: 700;
}
.btn-white:hover {
background-color: var(--color-gray-100);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
@media (max-width: 768px) {
.cta__title {
font-size: var(--text-2xl);
}
}
Step 8: Footer with Multi-Column CSS Grid
The footer uses CSS Grid to create a multi-column layout with a logo column, navigation links, and social links. On mobile, the grid collapses into a stacked layout.
HTML: Footer
<footer class="footer">
<div class="container">
<div class="footer__grid">
<div class="footer__brand">
<a href="#" class="header__logo">
<span class="logo-icon"></></span>
<span class="logo-text">DevLand</span>
</a>
<p class="footer__desc">Helping developers master modern CSS and build beautiful, accessible web experiences.</p>
</div>
<div class="footer__col">
<h4 class="footer__heading">Product</h4>
<ul class="footer__links">
<li><a href="#">Features</a></li>
<li><a href="#">Pricing</a></li>
<li><a href="#">Tutorials</a></li>
<li><a href="#">Changelog</a></li>
</ul>
</div>
<div class="footer__col">
<h4 class="footer__heading">Company</h4>
<ul class="footer__links">
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Careers</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
<div class="footer__col">
<h4 class="footer__heading">Legal</h4>
<ul class="footer__links">
<li><a href="#">Privacy Policy</a></li>
<li><a href="#">Terms of Service</a></li>
<li><a href="#">Cookie Policy</a></li>
</ul>
</div>
</div>
<div class="footer__bottom">
<p>© 2025 DevLand. All rights reserved.</p>
</div>
</div>
</footer>
CSS: Footer
/* ============================================
FOOTER -- Multi-column Grid layout
============================================ */
.footer {
padding: var(--space-4xl) 0 var(--space-xl);
background-color: var(--color-gray-900);
color: var(--color-gray-300);
}
.footer__grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: var(--space-2xl);
margin-bottom: var(--space-3xl);
}
.footer__brand {
max-width: 300px;
}
.footer__brand .header__logo {
margin-bottom: var(--space-md);
}
.footer__brand .logo-text {
color: var(--color-white);
}
.footer__desc {
font-size: var(--text-sm);
line-height: 1.7;
color: var(--color-gray-500);
}
.footer__heading {
font-size: var(--text-base);
font-weight: 600;
color: var(--color-white);
margin-bottom: var(--space-lg);
}
.footer__links li {
margin-bottom: var(--space-sm);
}
.footer__links a {
font-size: var(--text-sm);
color: var(--color-gray-500);
transition: color var(--transition-fast);
}
.footer__links a:hover {
color: var(--color-white);
}
.footer__bottom {
padding-top: var(--space-xl);
border-top: 1px solid rgba(255, 255, 255, 0.1);
text-align: center;
font-size: var(--text-sm);
color: var(--color-gray-500);
}
/* Responsive footer */
@media (max-width: 768px) {
.footer__grid {
grid-template-columns: 1fr 1fr;
gap: var(--space-2xl);
}
.footer__brand {
grid-column: 1 / -1;
max-width: 100%;
}
}
@media (max-width: 480px) {
.footer__grid {
grid-template-columns: 1fr;
}
}
Step 9: Dark Mode with Custom Properties
Dark mode is implemented by redefining the semantic custom properties inside a [data-theme="dark"] selector. Because the entire design uses custom properties for colors, switching themes requires changing only the variable values. The structural CSS remains completely untouched.
CSS: Dark Mode Theme
/* ============================================
DARK MODE -- Override semantic variables
============================================ */
[data-theme="dark"] {
--bg-primary: var(--color-gray-900);
--bg-secondary: var(--color-gray-800);
--bg-card: var(--color-gray-800);
--text-primary: var(--color-gray-100);
--text-secondary: var(--color-gray-500);
--text-heading: var(--color-white);
--border-color: rgba(255, 255, 255, 0.1);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
--shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.6);
}
/* Dark mode header glassmorphism override */
[data-theme="dark"] .header {
background-color: rgba(17, 24, 39, 0.85);
}
/* Dark mode feature card icon background */
[data-theme="dark"] .feature-card__icon {
background-color: rgba(129, 140, 248, 0.15);
}
/* Respect system preference with prefers-color-scheme */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg-primary: var(--color-gray-900);
--bg-secondary: var(--color-gray-800);
--bg-card: var(--color-gray-800);
--text-primary: var(--color-gray-100);
--text-secondary: var(--color-gray-500);
--text-heading: var(--color-white);
--border-color: rgba(255, 255, 255, 0.1);
}
}
/* Theme toggle button (add to header) */
.theme-toggle {
width: 44px;
height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--text-xl);
transition: transform var(--transition-fast),
background-color var(--transition-fast);
}
.theme-toggle:hover {
background-color: var(--bg-secondary);
transform: rotate(15deg);
}
Step 10: Accessibility Best Practices
Accessibility is not an optional add-on; it is a fundamental requirement of professional web development. The following CSS patterns ensure your landing page is usable by everyone, including people who navigate with keyboards, use screen readers, or have motion sensitivities.
CSS: Accessibility Enhancements
/* ============================================
ACCESSIBILITY -- Focus, motion, contrast
============================================ */
/* Visible focus styles for keyboard navigation */
*:focus-visible {
outline: 3px solid var(--color-primary);
outline-offset: 2px;
border-radius: 2px;
}
/* Remove outline for mouse users (focus without focus-visible) */
*:focus:not(:focus-visible) {
outline: none;
}
/* Skip navigation link for screen readers */
.skip-link {
position: absolute;
top: -100%;
left: var(--space-md);
padding: var(--space-sm) var(--space-md);
background-color: var(--color-primary);
color: var(--color-white);
font-weight: 600;
border-radius: var(--border-radius);
z-index: 9999;
transition: top var(--transition-fast);
}
.skip-link:focus {
top: var(--space-md);
}
/* Respect reduced motion preferences */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Ensure sufficient contrast on interactive elements */
.nav-link:focus-visible {
color: var(--color-primary);
background-color: rgba(79, 70, 229, 0.1);
padding: 0.25rem 0.5rem;
border-radius: var(--border-radius);
}
/* Screen reader only utility class */
.sr-only {
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 support */
@media (forced-colors: active) {
.btn-primary,
.btn-outline,
.btn-white {
border: 2px solid ButtonText;
}
.pricing-card--popular {
border: 3px solid Highlight;
}
}
:focus-visible pseudo-class is essential for modern web accessibility. It applies focus styles only when the user is navigating with a keyboard (Tab key), not when clicking with a mouse. This gives keyboard users clear visual indicators of where they are on the page without adding distracting outlines to every mouse click. Combined with prefers-reduced-motion: reduce, these two features form the minimum accessibility baseline every website should include.Step 11: Performance Best Practices
A well-crafted landing page must also perform well. The following CSS practices ensure fast loading, smooth animations, and efficient rendering.
CSS: Performance Optimizations
/* ============================================
PERFORMANCE -- Efficient CSS patterns
============================================ */
/* Use will-change sparingly, only on elements that animate */
.feature-card,
.pricing-card,
.testimonial-card {
will-change: transform;
}
/* Use content-visibility for below-the-fold sections */
.features,
.testimonials,
.pricing,
.cta {
content-visibility: auto;
contain-intrinsic-size: 0 600px;
}
/* Prefer transform and opacity for animations (GPU-accelerated) */
/* AVOID animating: width, height, top, left, margin, padding */
/* PREFER animating: transform, opacity, filter */
/* Efficient hover states using translate instead of margin */
.feature-card:hover {
/* GOOD: GPU-accelerated, no layout recalculation */
transform: translateY(-8px);
}
/* Font display swap to prevent invisible text during loading */
/* (This goes in your @font-face declaration) */
/*
@font-face {
font-family: 'Inter';
src: url('inter.woff2') format('woff2');
font-display: swap;
}
*/
/* Reduce paint area with contain */
.feature-card {
contain: layout style;
}
/* Efficient background images with image-rendering */
.hero {
image-rendering: auto;
/* Avoid loading huge images on mobile */
}
@media (max-width: 768px) {
.hero {
/* Use a smaller background image on mobile */
background-image: url('hero-mobile.jpg');
}
}
Complete HTML Document Structure
Here is the complete HTML document that ties all the sections together with proper semantic elements, meta tags, and the skip navigation link for accessibility.
Complete HTML Structure
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Master modern CSS and build beautiful responsive websites">
<title>DevLand - Master Modern CSS</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header class="header">
<!-- ... Header content from Step 2 ... -->
</header>
<main id="main-content">
<section class="hero">
<!-- ... Hero content from Step 3 ... -->
</section>
<section class="features" id="features">
<!-- ... Features content from Step 4 ... -->
</section>
<section class="testimonials" id="testimonials">
<!-- ... Testimonials content from Step 5 ... -->
</section>
<section class="pricing" id="pricing">
<!-- ... Pricing content from Step 6 ... -->
</section>
<section class="cta" id="cta">
<!-- ... CTA content from Step 7 ... -->
</section>
</main>
<footer class="footer">
<!-- ... Footer content from Step 8 ... -->
</footer>
</body>
</html>
<header>, <main>, <section>, <article>, <nav>, <footer>, <blockquote>, and <cite>. These elements convey meaning to screen readers and search engines. The aria-label attributes on the navigation and toggle button provide additional context for assistive technologies. The skip link allows keyboard users to jump past the navigation directly to the main content.Capstone Exercise
Build this entire landing page from scratch by following the steps in this lesson. Type every line of CSS yourself to build muscle memory. After completing the base implementation, extend the project with the following challenges: (1) Add a smooth scroll-triggered fade-in animation for each section using @keyframes and animation (respect prefers-reduced-motion). (2) Create a theme toggle button in the header that switches between light and dark mode by toggling the data-theme attribute on the <html> element. (3) Add a "back to top" floating button that appears when the user scrolls past the hero section, using position: fixed and a smooth translate transition. (4) Create a mobile-friendly off-canvas sidebar variation of the navigation using CSS transforms. (5) Add a subtle parallax scrolling effect to the hero background image using background-attachment: fixed. (6) Implement a CSS-only accordion FAQ section below the pricing table. (7) Test the complete page in Chrome, Firefox, and Safari DevTools, verifying the Grid and Flexbox layouts with their respective inspectors, checking all color contrast ratios, and confirming animations run at 60fps using the Performance panel. (8) Run a Lighthouse audit and optimize until you score above 95 on Accessibility and Performance. Document every design decision and the CSS techniques you used for each section.