Himanshu SharmaSoftware engineer
Let’s talk

CSS · Lesson 29 of 29

Project: style a landing page

Put the whole CSS course into practice by styling a responsive landing page with variables, Flexbox, Grid, media queries, gradients and gentle motion.

30 minProjectUpdated 18 October 2026

By the end of this lessonStyle a complete, responsive landing page from plain HTML using variables, Flexbox, Grid, media queries and transitions, and check it on small and large screens.

What you will build

A landing page is a one-page website that introduces a product, a service or a person and invites a visitor to take one action: sign up, buy, call. You will take plain HTML and make it responsive and polished using what the course taught:

  • CSS variables for colours, spacing and shape
  • box-sizing, a simple reset and readable typography
  • a header with Flexbox
  • a hero with a gradient background and a call to action
  • a features section with a responsive Grid
  • a call-to-action band, and a footer
  • a media query for wider screens
  • transitions for hover and focus

The content here is a made-up "Sunrise Bakery" so you can focus on CSS. Change the words to your own project afterwards.

Step 1: the HTML

Start with clean semantic HTML and no styling. Paste this into the editor below:

html
<header class="site-header">
  <a class="logo" href="#">Sunrise Bakery</a>
  <nav aria-label="Main">
    <a href="#menu">Menu</a>
    <a href="#about">About</a>
    <a href="#order" class="btn">Order now</a>
  </nav>
</header>

<main>
  <section class="hero">
    <h1>Fresh bread, baked before sunrise</h1>
    <p>Stone-ground flour, slow fermentation and nothing artificial.</p>
    <a class="btn" href="#order">Order for pickup</a>
  </section>

  <section class="features" id="menu">
    <h2>Why people love us</h2>
    <div class="grid">
      <article class="card"><h3>Slow fermented</h3><p>24 hours for deeper flavour and easier digestion.</p></article>
      <article class="card"><h3>Local grain</h3><p>Flour milled within 50 km of the bakery.</p></article>
      <article class="card"><h3>Baked daily</h3><p>Warm loaves on the counter from 6 a.m.</p></article>
    </div>
  </section>

  <section class="cta" id="order">
    <h2>Ready for tomorrow's loaf?</h2>
    <a class="btn" href="#">Place an order</a>
  </section>
</main>

<footer class="site-footer"><p>&copy; 2026 Sunrise Bakery, 12 Market Road</p></footer>

Step 2: variables and base styles

css
:root {
  --brand: #c2410c;
  --brand-dark: #9a3412;
  --ink: #1f2937;
  --paper: #fffaf5;
  --card: #ffffff;
  --space: 1rem;
  --radius: 14px;
  --shadow: 0 6px 20px rgb(0 0 0 / .08);
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
}
img { max-width: 100%; height: auto; }
h1, h2, h3 { line-height: 1.2; }

Step 3: header, buttons and hero

css
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space);
  padding: var(--space) calc(var(--space) * 1.5);
}
.logo { font-weight: 800; font-size: 1.25rem; color: var(--brand-dark); text-decoration: none; }
.site-header nav { display: flex; align-items: center; gap: var(--space); }
.site-header nav a { color: var(--ink); text-decoration: none; }

.btn {
  display: inline-block;
  padding: 0.7rem 1.4rem;
  border-radius: 999px;
  background: var(--brand);
  color: white !important;
  font-weight: 700;
  text-decoration: none;
  transition: background-color .2s ease, transform .2s ease;
}
.btn:hover { background: var(--brand-dark); transform: translateY(-2px); }
.btn:focus-visible { outline: 3px solid #fdba74; outline-offset: 3px; }

.hero {
  padding: 4rem calc(var(--space) * 1.5);
  text-align: center;
  color: white;
  background:
    linear-gradient(rgb(0 0 0 / .35), rgb(0 0 0 / .35)),
    linear-gradient(135deg, #f59e0b, #c2410c);
}
.hero h1 { font-size: clamp(2rem, 6vw, 3.5rem); margin: 0 0 .5rem; }
.hero p { max-width: 36rem; margin: 0 auto 1.5rem; font-size: 1.15rem; }

Notice clamp(2rem, 6vw, 3.5rem): a heading that scales smoothly between a minimum and maximum with the screen width, with no media query. The dark overlay layer keeps the white text readable on the bright gradient.

Step 4: the responsive features grid

css
.features { padding: 3rem calc(var(--space) * 1.5); max-width: 70rem; margin-inline: auto; }
.features h2 { text-align: center; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: calc(var(--space) * 1.5);
}
.card {
  background: var(--card);
  padding: calc(var(--space) * 1.5);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: transform .2s ease, box-shadow .2s ease;
}
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 28px rgb(0 0 0 / .12); }
.card h3 { margin-top: 0; color: var(--brand-dark); }
css
.cta {
  text-align: center;
  padding: 3rem calc(var(--space) * 1.5);
  background: #ffedd5;
}
.site-footer { padding: var(--space); text-align: center; font-size: .9rem; background: #1f2937; color: #e5e7eb; }

Step 6: wider screens and motion

Everything so far works on a phone. Add a layer for larger screens, and respect reduced motion:

css
@media (min-width: 48rem) {
  .hero { padding: 7rem 2rem; }
  .cta { display: flex; align-items: center; justify-content: center; gap: 2rem; }
  .cta h2 { margin: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .btn, .card { transition: none; }
}

The finished page

Put it all together here and experiment: change --brand and watch the whole page recolour.

html
<style>
  :root { --brand:#c2410c; --brand-dark:#9a3412; --ink:#1f2937; --paper:#fffaf5; --card:#fff; --space:1rem; --radius:14px; --shadow:0 6px 20px rgb(0 0 0/.08); }
  *,*::before,*::after{box-sizing:border-box}
  body{margin:0;font-family:system-ui,sans-serif;line-height:1.6;color:var(--ink);background:var(--paper)}
  .site-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--space);padding:var(--space) 1.5rem}
  .logo{font-weight:800;color:var(--brand-dark);text-decoration:none}
  .site-header nav{display:flex;align-items:center;gap:var(--space)}
  .site-header nav a{color:var(--ink);text-decoration:none}
  .btn{display:inline-block;padding:.7rem 1.4rem;border-radius:999px;background:var(--brand);color:#fff!important;font-weight:700;text-decoration:none;transition:background-color .2s,transform .2s}
  .btn:hover{background:var(--brand-dark);transform:translateY(-2px)}
  .hero{padding:3rem 1.5rem;text-align:center;color:#fff;background:linear-gradient(rgb(0 0 0/.35),rgb(0 0 0/.35)),linear-gradient(135deg,#f59e0b,#c2410c)}
  .hero h1{font-size:clamp(1.8rem,6vw,3rem);margin:0 0 .5rem}
  .hero p{max-width:36rem;margin:0 auto 1.2rem}
  .features{padding:2rem 1.5rem;max-width:70rem;margin-inline:auto}
  .features h2{text-align:center}
  .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));gap:1.5rem}
  .card{background:var(--card);padding:1.5rem;border-radius:var(--radius);box-shadow:var(--shadow);transition:transform .2s}
  .card:hover{transform:translateY(-4px)}
  .card h3{margin-top:0;color:var(--brand-dark)}
  .cta{text-align:center;padding:2rem 1.5rem;background:#ffedd5}
  .site-footer{padding:var(--space);text-align:center;font-size:.9rem;background:#1f2937;color:#e5e7eb}
  @media (min-width:48rem){.cta{display:flex;align-items:center;justify-content:center;gap:2rem}.cta h2{margin:0}}
  @media (prefers-reduced-motion:reduce){.btn,.card{transition:none}}
</style>
<header class="site-header"><a class="logo" href="#">Sunrise Bakery</a><nav aria-label="Main"><a href="#menu">Menu</a><a href="#about">About</a><a href="#order" class="btn">Order now</a></nav></header>
<main>
  <section class="hero"><h1>Fresh bread, baked before sunrise</h1><p>Stone-ground flour, slow fermentation and nothing artificial.</p><a class="btn" href="#order">Order for pickup</a></section>
  <section class="features" id="menu"><h2>Why people love us</h2><div class="grid">
    <article class="card"><h3>Slow fermented</h3><p>24 hours for deeper flavour.</p></article>
    <article class="card"><h3>Local grain</h3><p>Flour milled within 50 km.</p></article>
    <article class="card"><h3>Baked daily</h3><p>Warm loaves from 6 a.m.</p></article>
  </div></section>
  <section class="cta" id="order"><h2>Ready for tomorrow's loaf?</h2><a class="btn" href="#">Place an order</a></section>
</main>
<footer class="site-footer">&copy; 2026 Sunrise Bakery, 12 Market Road</footer>

Check your work

  1. Narrow first: drag the preview narrow. Is everything readable with no sideways scroll?
  2. Wide: does the layout use the space sensibly? Do the cards reflow?
  3. Keyboard: Tab through the links and buttons. Is the focus ring always visible?
  4. Contrast: check the text against its backgrounds (white on the hero, the brand colour on the buttons) with the DevTools contrast checker. Aim for 4.5:1.
  5. Zoom to 200 per cent. Nothing should overlap.
  6. Reduced motion: confirm the page works with transitions turned off.
  7. Validate your HTML and CSS using the W3C validators.

Common mistakes

  • Starting with desktop and fighting to squeeze it onto phones.
  • Hard-coding every colour instead of using variables.
  • Skipping the overlay on the hero and ending up with unreadable text.
  • Fixed pixel widths for the grid.
  • Forgetting focus styles because the mouse looks fine.
  • Copying a template you do not understand, then being unable to change it.

Exercise

Add a "Testimonials" section between the features and the call to action: two quote cards in a two-column Grid on wide screens and one column on narrow ones, using the same variables.

Show one possible answer
html
<style>
  .quotes { padding: 3rem 1.5rem; max-width: 70rem; margin-inline: auto; }
  .quotes .grid { display: grid; gap: 1.5rem; }
  @media (min-width: 48rem) { .quotes .grid { grid-template-columns: 1fr 1fr; } }
  blockquote { margin: 0; padding: 1.5rem; background: var(--card); border-left: 5px solid var(--brand); border-radius: var(--radius); box-shadow: var(--shadow); }
</style>
<section class="quotes">
  <h2>What neighbours say</h2>
  <div class="grid">
    <blockquote>"The best crust in the city." <footer>Asha</footer></blockquote>
    <blockquote>"We order every Saturday." <footer>Kabir</footer></blockquote>
  </div>
</section>

Use real, permitted quotes on a real site, never invented ones.

You have finished the CSS course. Next, put your pages online and keep practising by rebuilding pages you admire from scratch.

Key points

  • The project combines the course - variables, box-sizing, Flexbox, Grid, media queries, backgrounds and transitions.
  • Build it mobile-first - style the narrow layout first, then add rules for wider screens.
  • Define your colours, spacing and radius as variables before writing any component styles.
  • Check contrast, keyboard focus and reduced motion before you call the page finished.
  • A small page you finish and understand is worth more than a big template you copied.

Check yourself

1. Where should you start styling this page?
2. Why define colours and spacing as variables first?
3. Which layout tool suits the three feature cards that should reflow on their own?
4. What must you check before finishing?

Free tools for this lesson

Final exam and certificate

Finish all 29 lessons to unlock a 15-question exam on CSS. Pass it and you get a certificate with a public link you can share.

Sign in to take the exam