← Back to course

Final Mini Project: Responsive Landing Page

Final Mini Project: Responsive Landing Page

Welcome to the final lesson of this CSS course.

You made it.

Your browser survived.

Your CSS survived.

Probably.

In this lesson, we will combine everything you learned into one mini project.

We will build a responsive landing page.

It will include:

This is where CSS stops being random isolated properties and becomes a real website.

The little CSS pieces finally meet each other.

Like a frontend family dinner.

Hopefully with fewer arguments.

What You’ll Build

You will create a landing page for a fictional web service called FastSite Studio.

The page will have:

This project uses many things from previous lessons:

No new monster today.

Just putting the tools together.

Like assembling furniture, but with fewer mysterious screws.

Create the Project

Create a folder for the final project:

mkdir css-lesson10
cd css-lesson10
touch index.html
touch style.css

You should have:

css-lesson10/
  index.html
  style.css

Open the folder in your editor.

This is our final CSS playground.

No fear.

Only semicolons.

And maybe one dramatic refresh.

Write the HTML

Open index.html and add this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>FastSite Studio</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header class="hero">
    <nav class="navbar">
      <h1 class="logo">FastSite Studio</h1>

      <div class="nav-links">
        <a href="#">Home</a>
        <a href="#">Features</a>
        <a href="#">Pricing</a>
        <a href="#">Contact</a>
      </div>
    </nav>

    <section class="hero-content">
      <p class="eyebrow">Modern CSS Project</p>
      <h2>Build a Fast, Clean, Responsive Website</h2>
      <p>
        Practice CSS layout, responsive design, cards, buttons, shadows, and transitions in one complete mini project.
      </p>

      <div class="hero-actions">
        <a href="#" class="button primary-button">Start Building</a>
        <a href="#" class="button secondary-button">View Features</a>
      </div>
    </section>
  </header>

  <main>
    <section class="section intro-section">
      <div class="section-header">
        <p class="eyebrow dark">What You Practice</p>
        <h2>Everything Comes Together Here</h2>
        <p>
          This project combines the most important beginner CSS skills into a layout you can reuse for real websites.
        </p>
      </div>

      <div class="feature-grid">
        <article class="feature-card">
          <div class="icon">⚡</div>
          <h3>Fast Layout</h3>
          <p>Use Grid and Flexbox to create sections that are clean, structured, and easy to adjust.</p>
        </article>

        <article class="feature-card">
          <div class="icon">📱</div>
          <h3>Responsive Design</h3>
          <p>Make the page adapt to laptops, tablets, and phones without horizontal scrolling chaos.</p>
        </article>

        <article class="feature-card">
          <div class="icon">🎨</div>
          <h3>Polished Styling</h3>
          <p>Add colors, borders, shadows, spacing, and hover effects to make the page feel finished.</p>
        </article>
      </div>
    </section>

    <section class="section pricing-section">
      <div class="section-header">
        <p class="eyebrow dark">Pricing</p>
        <h2>Choose Your CSS Adventure</h2>
        <p>
          These pricing cards are just practice, but the layout pattern is used on real landing pages everywhere.
        </p>
      </div>

      <div class="pricing-grid">
        <article class="pricing-card">
          <h3>Basic</h3>
          <p class="price">€99</p>
          <p>Perfect for practicing layout basics.</p>
          <ul>
            <li>One-page layout</li>
            <li>Simple cards</li>
            <li>Basic responsive design</li>
          </ul>
          <a href="#" class="button card-button">Choose Basic</a>
        </article>

        <article class="pricing-card featured-card">
          <p class="badge">Popular</p>
          <h3>Standard</h3>
          <p class="price">€199</p>
          <p>Best for building a polished responsive page.</p>
          <ul>
            <li>Responsive sections</li>
            <li>Cards and buttons</li>
            <li>Hover transitions</li>
          </ul>
          <a href="#" class="button card-button">Choose Standard</a>
        </article>

        <article class="pricing-card">
          <h3>Premium</h3>
          <p class="price">€299</p>
          <p>For when your CSS is ready to wear a suit.</p>
          <ul>
            <li>Advanced layout</li>
            <li>Polished visual style</li>
            <li>Reusable structure</li>
          </ul>
          <a href="#" class="button card-button">Choose Premium</a>
        </article>
      </div>
    </section>
  </main>

  <footer class="site-footer">
    <p>Created with HTML, CSS, patience, and a few brave semicolons.</p>
  </footer>
</body>
</html>

This HTML gives us the full structure.

Now we need CSS.

At the moment, the page is just raw HTML.

Useful, but not charming.

Like pasta without sauce.

Technically food.

Emotionally unfinished.

Add Base Styles

Open style.css and add:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: Arial, sans-serif;
  background-color: #f3f4f6;
  color: #111827;
}

a {
  color: inherit;
  text-decoration: none;
}

ul {
  padding-left: 20px;
}

This gives us:

Good foundation.

A final project needs a stable foundation.

Otherwise CSS starts behaving like a shopping cart with one broken wheel.

Style the Hero

Add:

.hero {
  background: linear-gradient(135deg, #111827, #1e3a8a);
  color: white;
}

This creates the dark hero background.

Now style the navbar:

.navbar {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.logo {
  margin: 0;
  font-size: 24px;
}

.nav-links {
  display: flex;
  gap: 20px;
  font-weight: 700;
}

The navbar now uses Flexbox.

Logo on the left.

Links on the right.

Clean.

Simple.

Professional enough that CSS might ask for a LinkedIn profile.

Style the Hero Content

Add:

.hero-content {
  max-width: 850px;
  margin: 0 auto;
  padding: 90px 24px 110px;
  text-align: center;
}

.eyebrow {
  margin: 0 0 16px;
  color: #bfdbfe;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.hero-content h2 {
  margin: 0 0 20px;
  font-size: 58px;
  line-height: 1.1;
}

.hero-content p {
  margin: 0 auto;
  max-width: 700px;
  color: #dbeafe;
  font-size: 20px;
  line-height: 1.7;
}

Now the hero has:

This is visual hierarchy.

The user sees what matters first.

Heading first.

Text second.

Button next.

A good layout does not make the user hunt for meaning with a flashlight.

Style the Buttons

Add:

.hero-actions {
  display: flex;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 28px;
}

.button {
  display: inline-block;
  padding: 14px 22px;
  border-radius: 999px;
  font-weight: 700;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.button:hover {
  transform: translateY(-3px);
}

.primary-button {
  background-color: white;
  color: #1e3a8a;
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.22);
}

.secondary-button {
  border: 2px solid rgba(255, 255, 255, 0.5);
  color: white;
}

Now the hero has two buttons.

One primary.

One secondary.

The primary button is stronger.

The secondary button is quieter.

This is important.

Not every button should scream.

If every button screams, the page becomes a meeting where everyone talks at once.

Terrible.

Create Reusable Section Styles

Add:

.section {
  max-width: 1100px;
  margin: 0 auto;
  padding: 72px 24px;
}

.section-header {
  max-width: 760px;
  margin: 0 auto 36px;
  text-align: center;
}

.eyebrow.dark {
  color: #2563eb;
}

.section-header h2 {
  margin: 0 0 16px;
  font-size: 38px;
  line-height: 1.2;
}

.section-header p {
  color: #4b5563;
  font-size: 18px;
  line-height: 1.7;
}

Now sections have consistent spacing.

Consistency matters.

A website with random spacing feels nervous.

Like CSS is trying to remember where it parked the car.

Create Feature Cards

Add:

.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.feature-card {
  background-color: white;
  padding: 28px;
  border: 2px solid #e5e7eb;
  border-radius: 24px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.06);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.feature-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.1);
}

.icon {
  width: 52px;
  height: 52px;
  border-radius: 18px;
  background-color: #dbeafe;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  margin-bottom: 18px;
}

.feature-card h3 {
  margin: 0 0 12px;
  font-size: 24px;
}

.feature-card p {
  color: #4b5563;
  font-size: 18px;
  line-height: 1.7;
}

This uses CSS Grid for the cards.

Three columns on desktop.

Nice spacing.

Soft shadows.

Hover movement.

The page is starting to look like it knows what it is doing.

Dangerously professional.

Style the Pricing Section

Add:

.pricing-section {
  padding-top: 40px;
}

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.pricing-card {
  position: relative;
  background-color: white;
  padding: 32px;
  border: 2px solid #e5e7eb;
  border-radius: 28px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.06);
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.pricing-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.1);
  border-color: #2563eb;
}

.pricing-card h3 {
  margin: 0 0 12px;
  font-size: 26px;
}

.price {
  margin: 0 0 16px;
  font-size: 42px;
  font-weight: 800;
  color: #1e3a8a;
}

.pricing-card p {
  color: #4b5563;
  font-size: 18px;
  line-height: 1.6;
}

.pricing-card li {
  margin-bottom: 8px;
  color: #374151;
}

Now pricing cards look structured.

The price is big.

The text is readable.

The cards have depth.

A pricing card must be easy to scan.

Users should not need a treasure map to find the price.

Featured Pricing Card

Add:

.featured-card {
  border-color: #2563eb;
  background-color: #eff6ff;
}

.badge {
  display: inline-block;
  margin: 0 0 16px;
  background-color: #2563eb;
  color: white !important;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 14px !important;
  font-weight: 700;
}

The middle card now stands out.

It has a badge.

It has a blue border.

It has a soft blue background.

It says:

“Look here.”

Not:

“LOOK HERE OR I WILL START FLASHING.”

Good.

Card Buttons

Add:

.card-button {
  margin-top: 18px;
  background-color: #2563eb;
  color: white;
  text-align: center;
  width: 100%;
}

.card-button:hover {
  box-shadow: 0 12px 25px rgba(37, 99, 235, 0.3);
}

Now every pricing card has a full-width button.

This is common in pricing sections.

Easy to click.

Easy to understand.

No mystery.

Mystery is for detective novels.

Not pricing cards.

Footer

Add:

.site-footer {
  text-align: center;
  padding: 36px 24px;
  color: #6b7280;
}

Simple footer.

No drama.

Final projects do not need dramatic footers.

The footer is not the main character.

Make It Responsive

Now add media queries.

First for tablets:

@media (max-width: 850px) {
  .hero-content h2 {
    font-size: 44px;
  }

  .feature-grid,
  .pricing-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

Now cards become two columns on medium screens.

Next for phones:

@media (max-width: 600px) {
  .navbar {
    flex-direction: column;
    align-items: flex-start;
  }

  .nav-links {
    flex-direction: column;
    gap: 12px;
  }

  .hero-content {
    text-align: left;
    padding: 64px 20px 80px;
  }

  .hero-content h2 {
    font-size: 36px;
  }

  .hero-content p {
    font-size: 18px;
  }

  .hero-actions {
    justify-content: flex-start;
  }

  .section {
    padding: 56px 20px;
  }

  .section-header {
    text-align: left;
  }

  .section-header h2 {
    font-size: 30px;
  }

  .feature-grid,
  .pricing-grid {
    grid-template-columns: 1fr;
  }
}

Now the page works on phones.

The navbar stacks.

Cards become one column.

Text gets smaller.

Spacing becomes more compact.

This is responsive design doing its job.

No sideways scrolling.

No tiny unreadable cards.

No user rage.

Excellent.

Add Reduced Motion Support

Add this at the end:

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none;
  }
}

This helps users who prefer less motion.

It is a small detail.

But good websites care about details.

And users.

Mostly users.

CSS exists for people, not just for screenshots.

Complete CSS

Your style.css should look like this:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: Arial, sans-serif;
  background-color: #f3f4f6;
  color: #111827;
}

a {
  color: inherit;
  text-decoration: none;
}

ul {
  padding-left: 20px;
}

.hero {
  background: linear-gradient(135deg, #111827, #1e3a8a);
  color: white;
}

.navbar {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.logo {
  margin: 0;
  font-size: 24px;
}

.nav-links {
  display: flex;
  gap: 20px;
  font-weight: 700;
}

.hero-content {
  max-width: 850px;
  margin: 0 auto;
  padding: 90px 24px 110px;
  text-align: center;
}

.eyebrow {
  margin: 0 0 16px;
  color: #bfdbfe;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.hero-content h2 {
  margin: 0 0 20px;
  font-size: 58px;
  line-height: 1.1;
}

.hero-content p {
  margin: 0 auto;
  max-width: 700px;
  color: #dbeafe;
  font-size: 20px;
  line-height: 1.7;
}

.hero-actions {
  display: flex;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 28px;
}

.button {
  display: inline-block;
  padding: 14px 22px;
  border-radius: 999px;
  font-weight: 700;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.button:hover {
  transform: translateY(-3px);
}

.primary-button {
  background-color: white;
  color: #1e3a8a;
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.22);
}

.secondary-button {
  border: 2px solid rgba(255, 255, 255, 0.5);
  color: white;
}

.section {
  max-width: 1100px;
  margin: 0 auto;
  padding: 72px 24px;
}

.section-header {
  max-width: 760px;
  margin: 0 auto 36px;
  text-align: center;
}

.eyebrow.dark {
  color: #2563eb;
}

.section-header h2 {
  margin: 0 0 16px;
  font-size: 38px;
  line-height: 1.2;
}

.section-header p {
  color: #4b5563;
  font-size: 18px;
  line-height: 1.7;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.feature-card {
  background-color: white;
  padding: 28px;
  border: 2px solid #e5e7eb;
  border-radius: 24px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.06);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.feature-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.1);
}

.icon {
  width: 52px;
  height: 52px;
  border-radius: 18px;
  background-color: #dbeafe;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  margin-bottom: 18px;
}

.feature-card h3 {
  margin: 0 0 12px;
  font-size: 24px;
}

.feature-card p {
  color: #4b5563;
  font-size: 18px;
  line-height: 1.7;
}

.pricing-section {
  padding-top: 40px;
}

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.pricing-card {
  position: relative;
  background-color: white;
  padding: 32px;
  border: 2px solid #e5e7eb;
  border-radius: 28px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.06);
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.pricing-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.1);
  border-color: #2563eb;
}

.pricing-card h3 {
  margin: 0 0 12px;
  font-size: 26px;
}

.price {
  margin: 0 0 16px;
  font-size: 42px;
  font-weight: 800;
  color: #1e3a8a;
}

.pricing-card p {
  color: #4b5563;
  font-size: 18px;
  line-height: 1.6;
}

.pricing-card li {
  margin-bottom: 8px;
  color: #374151;
}

.featured-card {
  border-color: #2563eb;
  background-color: #eff6ff;
}

.badge {
  display: inline-block;
  margin: 0 0 16px;
  background-color: #2563eb;
  color: white !important;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 14px !important;
  font-weight: 700;
}

.card-button {
  margin-top: 18px;
  background-color: #2563eb;
  color: white;
  text-align: center;
  width: 100%;
}

.card-button:hover {
  box-shadow: 0 12px 25px rgba(37, 99, 235, 0.3);
}

.site-footer {
  text-align: center;
  padding: 36px 24px;
  color: #6b7280;
}

@media (max-width: 850px) {
  .hero-content h2 {
    font-size: 44px;
  }

  .feature-grid,
  .pricing-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .navbar {
    flex-direction: column;
    align-items: flex-start;
  }

  .nav-links {
    flex-direction: column;
    gap: 12px;
  }

  .hero-content {
    text-align: left;
    padding: 64px 20px 80px;
  }

  .hero-content h2 {
    font-size: 36px;
  }

  .hero-content p {
    font-size: 18px;
  }

  .hero-actions {
    justify-content: flex-start;
  }

  .section {
    padding: 56px 20px;
  }

  .section-header {
    text-align: left;
  }

  .section-header h2 {
    font-size: 30px;
  }

  .feature-grid,
  .pricing-grid {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none;
  }
}

Save the file.

Refresh the browser.

Resize the window.

Hover over the cards and buttons.

You now have a complete responsive landing page.

Congratulations.

This is no longer just CSS practice.

This is a reusable website structure.

You can use this pattern for:

Now your CSS has a job.

Finally.

What You Practiced

In this final project, you practiced:

That is a lot.

Do not pretend it is nothing.

CSS looks simple until it starts arguing with the screen size.

You handled that.

Good.

Common Mistakes

Trying to Make Everything Perfect Immediately

Do not try to make the page perfect on the first attempt.

Build in stages:

  1. HTML structure.
  2. Base CSS.
  3. Layout.
  4. Cards.
  5. Responsive design.
  6. Polish.

If you try to do everything at once, CSS will smell fear.

Forgetting Mobile

Always resize the browser.

Always test smaller screens.

A page that works only on desktop is not finished.

It is just pretending.

Adding Too Much Decoration

A clean page is better than a noisy page.

Use:

You do not need 19 gradients and a button that dances like it heard music.

Mini Challenge

Customize this project.

Change:

Then make it your own landing page.

You can turn it into:

This is how real web projects begin.

Simple structure.

Then customization.

Then improvement.

Then coffee.

Summary

You finished the CSS course.

You learned:

CSS is not just decoration.

CSS is layout.

Structure.

Readability.

Responsiveness.

User experience.

And sometimes emotional damage.

But now you are stronger.

Final Words

Keep practicing.

Take this project and rebuild it from memory.

Then change it.

Break it.

Fix it.

Make another one.

That is how CSS becomes natural.

Not by reading one thousand properties.

By building things until your fingers know where display: grid lives.

Congratulations.

Your CSS toolbox is ready.

Now go build something fast, clean, responsive, and slightly less chaotic than the internet deserves.