Build a Product Landing Page
Build a responsive product landing page from scratch with HTML and CSS.
Introduction
30 Second Summary
Every website you visit is built from two languages: HTML for structure and CSS for styling. Understanding how they work turns you from someone who designs screens into someone who can bring those designs to life in a browser.
In this project, you will build a professional product landing page from scratch using only HTML and CSS. You'll create a responsive page for a fictional design tool called "DesignFlow" that looks polished on both desktop and mobile screens.
What You'll Build
A live landing page running in your browser that you can resize to any screen width, inspect with developer tools, and tweak in real time to see instant results.
By the end of this project, you'll have:
- A polished page with a header, hero section, feature cards, and footer that you built line by line from an empty file.
- A layout that snaps elements side-by-side using Flexbox, the CSS equivalent of Auto Layout in Figma.
- A page that automatically rearranges itself for phone-sized screens when you resize the browser window.
- Secret Mission: Add hover animations to buttons and cards, plus build a CSS-only FAQ accordion that opens and closes without any JavaScript.
Are there any prerequisites?
None. This project starts from zero and walks you through installing everything you need. All you need is a computer with VS Code installed.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters. Taking a moment to articulate the goal now makes every step that follows feel purposeful instead of random.
Set Up Your Coding Environment
In Figma, every change you make shows up instantly on the canvas. To get that same immediate feedback when writing code, you need a setup that refreshes your browser the moment you save a file.
In this step, you'll install a browser-refreshing tool inside VS Code, create your project folder, and write your very first line of HTML. By the end, you'll see your code running live.
In this step, get ready to:
- Install the Live Server extension in VS Code.
- Create a project folder and your first HTML file.
- See your code appear live in the browser.
Install the Live Server extension
Live Server is a VS Code extension that launches a local web server and auto-refreshes your browser every time you save. It gives you the same instant feedback loop you get in Figma when you nudge a layer and see the canvas update.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Visual Studio Code and press Enter to open it.
- Press Cmd+Shift+X (macOS) or Ctrl+Shift+X (Windows) to open the Extensions panel.
- Type Live Server in the search bar at the top of the panel.
- Find the one by Ritwick Dey (it has 80+ million installs) and click Install.
After a moment, the Install button changes to Disable and Uninstall buttons. That confirms the extension is active.
Don't see Live Server in search results?
Make sure you're in the Extensions panel (the icon looks like four squares in the left sidebar), not the file search bar. If you accidentally opened the file search, close it and press Cmd+Shift+X (macOS) or Ctrl+Shift+X (Windows) again.
help me find and install the Live Server extension
Create your project folder and HTML file
Every web project lives in its own folder. You'll create one on your Desktop so it's easy to find later.
- Open a terminal inside VS Code by pressing Ctrl+` (the backtick key, above Tab on your keyboard). A terminal panel appears at the bottom of VS Code.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir designflow-landing
cd designflow-landing
- Confirm the folder exists by running:
pwd
You should see a path ending in designflow-landing in the output.
- Now open this folder as your workspace. In VS Code, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the designflow-landing folder, and click Open.
VS Code reloads with designflow-landing shown in the Explorer sidebar on the left. The folder is empty for now.
- Create your first file by hovering over the DESIGNFLOW-LANDING heading in the Explorer sidebar and clicking the New File icon (it looks like a page with a small plus sign).
- Type index.html as the filename and press Enter.
The file opens in the editor area. This is the file your browser will display as a webpage.
Why index.html?
Web servers look for a file called index.html by default when someone visits a site. Naming your file this way means the server knows exactly which page to show first.
Write your first line of code and see it live
Time to prove the whole setup works. You'll type one line of HTML, save it, and watch it appear in your browser instantly.
- Click inside the empty index.html file in the editor and type the following code:
<h1>Hello, I am a designer who codes</h1>
What does this code do?
The <h1> tag tells the browser this text is a top-level heading. The browser makes it large and bold by default. The </h1> at the end closes the tag, like closing a bracket.
- Save the file by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Right-click the index.html file in the Explorer sidebar.
- Select Open with Live Server.
Before you look at the browser, what do you expect to see on the page?
Your default browser opens and displays the text "Hello, I am a designer who codes" as a large, bold heading. The URL bar shows http://127.0.0.1:5500. That address is your local computer acting as a tiny web server.
- Test the auto-refresh: go back to VS Code, change the word "designer" to "developer" in your index.html file, and save with Cmd+S (macOS) or Ctrl+S (Windows).
- Switch to your browser. The page updates automatically without you refreshing.
- Change the text back to "designer" and save again so your file matches the project code.
Browser didn't open?
Make sure you right-clicked index.html in the Explorer sidebar (not in the editor). Also check the bottom-right status bar in VS Code for a "Port: 5500" indicator, which confirms Live Server is running.
If you still don't see the option, make sure you installed the Live Server extension by Ritwick Dey and not a different extension with a similar name.
help me get Live Server working in VS Code
✔️ Awesome, I've got everything!
Great. Double check you've saved your file and that the text reads "Hello, I am a designer who codes" (with "designer", not "developer").
ⓧ I'd like to double check the full code
Your index.html should contain exactly this:
<h1>Hello, I am a designer who codes</h1>
Your coding environment is ready. You have VS Code, Live Server, and a live-updating browser window. Next up, you'll replace this single heading with the full structure of a real landing page.
Build the Page Structure with HTML
Right now your page shows a single line of text. A real landing page has distinct sections: a header, a hero area, feature highlights, and a footer.
HTML gives you the building blocks to define these sections. It is like creating frames and layers in Figma before you start styling them.
In this step, get ready to:
- Replace your single line of text with a full HTML document structure.
- Define four page sections using semantic HTML elements.
- See all your content displayed in the browser with default formatting.
Set up the document shell and header
Every HTML page needs a standard outer shell: a DOCTYPE declaration, a head section for metadata, and a body for visible content. You will build this shell and add the first visible section inside it.
- Select all the existing text in index.html by pressing Cmd+A (macOS) or Ctrl+A (Windows).
- Delete it and replace it with the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DesignFlow - Design Tool Landing Page</title>
</head>
<body>
<header class="header">
<div class="container">
<span class="logo">DesignFlow</span>
<nav class="nav">
<a href="#features">Features</a>
<a href="#pricing">Pricing</a>
<a href="#about">About</a>
</nav>
</div>
</header>
</body>
</html>
What does this code do?
The first three lines set up the page shell. <!DOCTYPE html> tells the browser this is an HTML5 page. The <head> section holds invisible settings like the page title and character encoding.
Inside the <body> you have your first visible section: a <header> containing the brand name "DesignFlow" and three navigation links. The <div class="container"> wrapper will help you center content later when you add CSS.
- Save the file by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Check your browser. You should see the text "DesignFlow" followed by three blue links: Features, Pricing, and About.
Don't see anything in the browser?
Make sure Live Server is still running. Look for the "Port: 5500" indicator in the VS Code status bar at the bottom. If it disappeared, right-click index.html in the Explorer sidebar and choose Open with Live Server.
If you see the old "Hello" text, make sure you deleted all previous content before pasting the new code.
Help me troubleshoot my Live Server setup
Add the hero section
The hero is the large, attention-grabbing area at the top of a landing page. It contains the main headline, a supporting paragraph, and a call-to-action button.
- In index.html, place your cursor on the blank line between the closing </header> tag and the closing </body> tag.
- Paste the following code there:
<section class="hero">
<div class="container">
<h1>Design beautiful interfaces without the complexity</h1>
<p>DesignFlow helps product teams go from idea to polished UI in minutes, not hours. Simple, fast, and built for collaboration.</p>
<a href="#" class="btn">Start Free Trial</a>
</div>
</section>
What does this code do?
The <section> element groups related content together. Inside it, the <h1> is the main headline, the <p> is supporting text, and the <a> with class btn is the call-to-action button.
Right now the button looks like a plain blue link. CSS will transform it into a proper button later.
- Save the file.
- Check your browser. Below the nav links you should now see a large heading, a paragraph of text, and a blue "Start Free Trial" link.
Add the features section and footer
The features section showcases three product benefits in separate cards. The footer closes out the page with a simple message.
- Place your cursor on the blank line between the hero's closing </section> tag and the closing </body> tag.
- Paste the following code there:
<section class="features" id="features">
<div class="container">
<h2>Why teams love DesignFlow</h2>
<div class="features-grid">
<div class="feature-card">
<h3>Lightning Fast</h3>
<p>Create layouts in seconds with smart auto-spacing and alignment guides that feel like magic.</p>
</div>
<div class="feature-card">
<h3>Real-Time Collaboration</h3>
<p>Work together with your team simultaneously. See cursors, comments, and changes as they happen.</p>
</div>
<div class="feature-card">
<h3>Developer Handoff</h3>
<p>Generate clean CSS and specs automatically. No more miscommunication between design and engineering.</p>
</div>
</div>
</div>
</section>
<footer class="footer">
<div class="container">
<p>Built with HTML and CSS by a designer who codes.</p>
</div>
</footer>
What does this code do?
The features section uses a <div class="features-grid"> to wrap three feature-card divs. Each card has an <h3> title and a <p> description. The id="features" attribute makes the "Features" nav link scroll to this section.
The <footer> is a semantic element that marks the bottom of the page. Browsers and screen readers recognize it as the closing section.
- Save the file.
- Check your browser. You should now see the three feature headings ("Lightning Fast", "Real-Time Collaboration", "Developer Handoff") with their descriptions, plus the footer text at the very bottom.
Seeing a jumbled mess or missing sections?
Make sure your closing tags match. Every <section> needs a </section>, and every <div> needs a </div>. A missing closing tag causes everything after it to nest incorrectly.
Check that you pasted the features section BETWEEN the hero's closing </section> and </body>. If it landed inside the hero section, your structure will be wrong.
Help me fix my HTML structure
Take a moment to look at what the browser is showing you. What do you think it looks like right now? A polished landing page, or something simpler?
The browser shows all your content, but it looks like a plain text document. The heading is big, links are blue and underlined, and everything stacks vertically with the browser's default font. This is HTML doing its job: defining structure and content, not appearance.
Why does it look so plain?
HTML only defines WHAT is on the page and how sections relate to each other. It is like setting up all your layers and text content in Figma before applying any fills, fonts, or spacing. The visual styling comes from CSS, which you will add in the next step.
✔️ Awesome, I've got everything!
Great. Make sure you have saved index.html and can see all four sections (header, hero, features, footer) in your browser.
ⓧ I'd like to double check the full code
Scroll up through your work and confirm these three blocks are present in your index.html, in this order:
- The document shell and header block (starting with <!DOCTYPE html>, containing the <header> element).
- The hero section block (starting with <section class="hero">, containing the headline, paragraph, and button link).
- The features and footer block (starting with <section class="features" id="features">, ending with </footer>).
The very last two lines of your file should be </body> and </html>.
Your page structure is complete. You have a header, hero, features section, and footer all defined in clean HTML. Next up, you will add a CSS file to transform this plain document into a visually polished landing page.
Style the Page with CSS
Your page has all the right content, but it looks like a plain text document from the 1990s. CSS is the layer that controls visual appearance: colors, fonts, spacing, sizes, and backgrounds.
Think of CSS as the code equivalent of the properties panel in Figma where you set fill color, font size, padding, and corner radius. In this step, you will transform your unstyled HTML into something that looks designed.
In this step, get ready to:
- Create a CSS file and connect it to your HTML.
- Style every section of the page with colors, fonts, and spacing.
- Observe how the page looks with styling but without layout control.
Create a CSS file and link it to your HTML
Before CSS can style anything, your HTML file needs to know the CSS file exists. You create that connection with a link tag.
- In the VS Code sidebar, right-click inside your designflow-landing folder and select New File.
- Name the file style.css and press Enter.
- Open index.html and find this line in the <head> section:
<title>DesignFlow - Design Tool Landing Page</title>
- Add this new line directly below it:
<link rel="stylesheet" href="style.css">
What does this line do?
The <link> tag tells the browser to load your CSS file and apply its styles to the page. Without this connection, style.css would sit in your folder doing nothing.
- Save index.html with Cmd+S (macOS) or Ctrl+S (Windows).
Now open style.css in the editor. This is where all your visual styling will live.
- Add the foundation styles to style.css by pasting the following code:
/* Remove default browser spacing and fix box model */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Set a clean system font for the whole page */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: #1a1a2e;
line-height: 1.6;
}
/* Center content and constrain width */
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 24px;
}
What does this code do?
The * selector targets every element on the page. Setting margin: 0 and padding: 0 removes the default spacing browsers add. box-sizing: border-box makes padding behave the way you expect from Figma: padding fits inside the element's width instead of adding to it.
The .container class constrains content to 1100px wide and centers it horizontally with margin: 0 auto. This is the same pattern every real website uses to keep content from stretching edge-to-edge on wide screens.
- Save style.css.
- Look at your browser. The font has changed from Times New Roman to a clean sans-serif, and all the default spacing around elements has collapsed.
Page still looks the same?
- Make sure you saved both index.html and style.css. A white dot on the file tab in VS Code means unsaved changes.
- Check that the <link> tag is inside the <head> section, not inside <body>.
- Confirm the filename is exactly style.css (all lowercase) and matches the href in your link tag.
Why isn't my CSS file connecting to my HTML?
Style each section of the page
Now you will style each section from top to bottom, starting with the header and working your way down to the footer.
- Add the header, logo, and navigation styles below your existing code in style.css:
/* Header bar with bottom border */
.header {
background-color: #ffffff;
border-bottom: 1px solid #e2e8f0;
padding: 16px 0;
}
/* Logo text in brand purple */
.logo {
font-size: 22px;
font-weight: 700;
color: #4f46e5;
}
/* Navigation links */
.nav a {
text-decoration: none;
color: #475569;
margin-left: 24px;
font-size: 15px;
}
What does this code do?
The .header gets a white background and a subtle gray bottom border to separate it from the content below. The .logo is styled in purple (#4f46e5) to stand out as the brand mark.
The .nav a selector targets only links inside the nav element. text-decoration: none removes the default blue underline that browsers add to links.
- Save style.css and check your browser.
- You should see a white header area with a thin gray line underneath it. The word "DesignFlow" appears in purple, and the nav links are no longer blue and underlined.
Header still looks unstyled?
- Make sure you pasted the new code below the existing .container block, not inside it.
- Check for missing closing braces } on the previous section. A missing brace breaks everything that follows.
Why aren't my header styles showing up?
- Add the hero section styles below your navigation code in style.css:
/* Hero section with light background */
.hero {
padding: 80px 0;
background-color: #f8fafc;
text-align: center;
}
/* Large bold headline */
.hero h1 {
font-size: 44px;
font-weight: 700;
color: #1a1a2e;
max-width: 700px;
margin: 0 auto 20px;
}
/* Supporting paragraph */
.hero p {
font-size: 18px;
color: #475569;
max-width: 550px;
margin: 0 auto 32px;
}
What does this code do?
The .hero section gets a light gray background (#f8fafc) and generous padding to create visual breathing room. text-align: center centers all the text inside it.
The max-width on the heading and paragraph keeps long lines from stretching too wide to read comfortably. margin: 0 auto centers those constrained elements within the section.
- Save style.css and check your browser.
- The hero section now has a light gray background with a large, bold, centered headline and a smaller paragraph beneath it.
- Add the call-to-action button styles below your hero code in style.css:
/* Call-to-action button */
.btn {
display: inline-block;
padding: 14px 28px;
background-color: #4f46e5;
color: #ffffff;
text-decoration: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
}
What does this code do?
The .btn class turns the link into a button shape. display: inline-block lets you set padding and dimensions on it (regular links ignore vertical padding). border-radius: 8px rounds the corners, just like corner radius in Figma.
- Save style.css and check your browser.
- A purple button with white text and rounded corners now appears below the hero paragraph.
- Add the features section and card styles below your button code in style.css:
/* Features section */
.features {
padding: 80px 0;
}
/* Section heading */
.features h2 {
text-align: center;
font-size: 32px;
margin-bottom: 48px;
color: #1a1a2e;
}
/* Individual feature cards */
.feature-card {
flex: 1;
padding: 32px;
background-color: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 12px;
}
.feature-card h3 {
font-size: 20px;
margin-bottom: 12px;
color: #1a1a2e;
}
.feature-card p {
font-size: 15px;
color: #64748b;
line-height: 1.7;
}
What does this code do?
Each .feature-card gets a white background, a subtle gray border, and rounded corners (border-radius: 12px). The padding: 32px creates internal spacing between the border and the text inside.
The flex: 1 property tells each card to share available space equally. This won't have a visible effect yet because the parent container isn't using Flexbox. You will activate it in the next step.
- Save style.css and check your browser.
- You should see three cards stacked vertically, each with a rounded border and internal padding. The section heading "Why teams love DesignFlow" appears centered above them.
- Add the footer styles below your feature card code in style.css:
/* Dark footer */
.footer {
padding: 24px 0;
background-color: #1a1a2e;
text-align: center;
}
.footer p {
color: #94a3b8;
font-size: 14px;
}
What does this code do?
The footer uses a dark navy background (#1a1a2e) with light gray text (#94a3b8). This high-contrast inversion signals the end of the page visually.
- Save style.css and check your browser.
- At the bottom of the page, you should see a dark bar with light gray text reading "Built with HTML and CSS by a designer who codes."
✔️ Awesome, I've got everything!
Great. Make sure you have saved both index.html and style.css.
ⓧ I'd like to double check the full code
Your style.css file should contain these sections in order. Scroll up and confirm each one is present:
- Universal reset (* selector with margin, padding, box-sizing).
- Body font stack and color.
- Container max-width and centering.
- Header background, border, and padding.
- Logo font size, weight, and purple color.
- Nav link styles (no underline, gray color, left margin).
- Hero section background, padding, and centered text.
- Hero h1 large font and hero p smaller font.
- Button with purple background, white text, and rounded corners.
- Features section padding and centered h2.
- Feature card border, border-radius, and padding.
- Feature card h3 and p text styles.
- Footer dark background and light gray text.
Your index.html should have this line inside the <head> section, below the <title> tag:
<link rel="stylesheet" href="style.css">
Notice what still needs fixing
Your page has colors, fonts, borders, and rounded corners. It looks designed. But take a closer look at two specific areas.
- Look at your header. Do you expect the logo and navigation links to be sitting side-by-side, or stacked on top of each other?
The logo "DesignFlow" and the navigation links are stacked vertically. They are not on the same row.
- Now look at the three feature cards. Are they sitting next to each other in a row, or stacked in one tall column?
The cards are stacked in a single column, one on top of the other. This is because HTML elements are "blocks" that take up the full width by default.
Why is everything stacking vertically?
By default, HTML block elements stack top-to-bottom. CSS colors, fonts, and spacing do not change this behavior. To arrange items side-by-side, you need a layout system.
That layout system is called Flexbox, and it works exactly like Auto Layout in Figma. You will add it in the next step.
Your page looks designed, but the layout is wrong. In the next step, you will use Flexbox to put items side-by-side and make this look like a real landing page.
Fix the Layout with Flexbox
Your page has colors, fonts, and spacing. It looks designed. But look at the header: the logo and nav links are stacking on top of each other instead of sitting side-by-side.
HTML elements are "blocks" by default, meaning each one takes up the full width and pushes the next element below it. Flexbox is the CSS tool that fixes this. It works exactly like Auto Layout in Figma: you set a direction, alignment, and spacing between items.
In this step, get ready to:
- Use Flexbox to put the header logo and nav links on the same row.
- Use Flexbox to arrange the three feature cards side-by-side with equal widths.
Add Flexbox to the header
Right now the .header has the logo and nav stacked vertically. You need to tell the container inside the header to lay out its children in a row.
- In style.css, find the .header rule (the one with background-color: #ffffff).
- Directly below that rule's closing brace, add this new rule:
.header .container {
display: flex;
justify-content: space-between;
align-items: center;
}
What does this code do?
This targets the .container div that lives inside .header. The three properties work together:
- display: flex switches the container from stacking children vertically to placing them on a single row.
- justify-content: space-between pushes the logo to one end and the nav to the other. In Figma, this is the "Space Between" distribution setting in Auto Layout.
- align-items: center vertically centers both items so they line up along their midpoints.
- Save style.css.
- Check your browser. The header now shows "DesignFlow" on the left and the three nav links on the right, all in one row.
Logo and nav still stacking?
- Make sure you wrote .header .container (with a space between them), not .header.container. The space means "a container inside the header."
- Check that this new rule is separate from the existing .header rule. They should be two distinct rule blocks, not combined into one.
- Confirm you saved the file. Live Server only updates your browser on save.
Still stuck? Why isn't my header Flexbox working?
Why Flexbox instead of floats or inline-block?
Older CSS techniques like float and display: inline-block can also place items side-by-side, but they require workarounds for alignment and spacing. Flexbox handles direction, alignment, and gap in a single, predictable system.
If you have used Auto Layout in Figma, you already understand Flexbox. Same mental model, different syntax.
Add Flexbox to the features grid
The three feature cards are still stacked in a tall column. The cards already have flex: 1 from the previous step, which tells them to share space equally. But that property only activates when the parent is a flex container.
- In style.css, find the .features h2 rule (the one with text-align: center).
- Directly below that rule's closing brace, add this new rule:
.features-grid {
display: flex;
gap: 24px;
}
What does this code do?
- display: flex turns .features-grid into a flex container, placing its three child cards in a row.
- gap: 24px adds 24 pixels of space between each card. This is like setting the spacing value in Figma Auto Layout.
- The flex: 1 already on each .feature-card now activates, making all three cards stretch to equal widths.
Before you save, predict what you expect to see. Will the three cards sit in a row with equal widths, or will something else happen?
- Save style.css.
- Check your browser. The three feature cards now sit side-by-side in a single row with equal spacing between them.
Your page now looks like a properly designed landing page. The header has the logo on the left and nav on the right. The feature cards are in a balanced row.
Cards still in a column?
- Check that your selector says .features-grid (with a hyphen). This must match the class name in your HTML exactly.
- Make sure the rule is its own block and not accidentally nested inside another rule's braces.
- Verify that your .feature-card rule still has flex: 1 in it. Without it, the cards will not stretch to equal widths.
Need help? Why aren't my feature cards appearing in a row?
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css and your browser is showing the updated layout.
ⓧ I'd like to double check the full code
Confirm these two new rules are in your style.css, in this order:
- A .header .container rule with display: flex, justify-content: space-between, and align-items: center. It should appear right after the .header rule.
- A .features-grid rule with display: flex and gap: 24px. It should appear right after the .features h2 rule.
Everything else in style.css and index.html stays unchanged from the previous step.
Your landing page looks polished on a full-width browser window. But try dragging the window to be very narrow, like a phone screen. The feature cards get crushed. Next up, you will make the page adapt to smaller screens.
Make It Responsive for Mobile
Your landing page looks polished on desktop. The header, hero, feature cards, and footer are all styled and positioned correctly.
But what happens when someone visits your page on their phone? Real products need to work on every screen size. In this step, you'll use a CSS media query to make your layout adapt to narrow screens.
In this step, get ready to:
- Open Chrome DevTools to preview your page at phone width and see the layout problem.
- Add a CSS media query that adapts the layout for small screens.
See the problem on small screens
In Figma, you create separate phone-sized frames to see how a design looks on mobile. Browsers have a similar tool built right into Chrome DevTools.
- Open Chrome DevTools by pressing Cmd+Option+I (macOS) or Ctrl+Shift+I (Windows).
- Click the device toolbar icon (a small phone/tablet icon) at the top of the DevTools panel, or press Cmd+Shift+M (macOS) or Ctrl+Shift+M (Windows).
- In the responsive toolbar at the top, set the width to 375 (iPhone width).
Before you look at the result, what do you think your page looks like at phone width? Do you think the three side-by-side cards will still fit?
The three feature cards are crushed into tiny unreadable columns. The headline text is far too large for the narrow screen. This is your page without any responsive rules.
What is responsive design?
Responsive design means your layout adapts to different screen sizes. In Figma, you create separate frames for desktop and mobile. In CSS, you use media queries to apply different styles depending on the screen width.
Add a media query for mobile screens
A media query tells the browser: "only apply these styles when the screen is this size or smaller." You'll add one that activates below 768px, the standard breakpoint for tablets and phones.
- In style.css, scroll to the very bottom of the file (below the .footer p rule) and add this media query:
@media (max-width: 768px) {
.hero h1 {
font-size: 30px;
}
.features-grid {
flex-direction: column;
}
}
What does this code do?
The @media (max-width: 768px) wrapper means everything inside only applies when the browser window is 768 pixels wide or less.
- font-size: 30px shrinks the hero heading from 44px to 30px so it fits on a phone screen.
- flex-direction: column switches the feature cards from a horizontal row to a vertical stack. This is like changing a Figma Auto Layout frame from horizontal to vertical.
- Save style.css.
- Look at your browser in DevTools responsive mode (still at 375px width). The feature cards now stack vertically and the heading is a comfortable, readable size.
- Click the device toolbar icon again to exit responsive mode and return to full desktop width. The cards snap back to their side-by-side row.
Cards still crushed at phone width?
- Make sure the media query is at the very bottom of style.css, after all other rules. CSS reads top-to-bottom, so the media query needs to come last to override earlier styles.
- Check that you have both opening { and closing } braces for the @media block AND for each rule inside it. Missing a brace is the most common cause.
- Confirm the responsive width in DevTools is set to 768 or narrower. At 769px and above, the media query won't activate.
Help me figure out why my media query isn't working.
✔️ Awesome, I've got everything!
Great. Make sure you've saved your file.
ⓧ I'd like to double check the full code
Your style.css is over 30 lines, so here's what to confirm:
- All your existing CSS rules (from the reset through to the footer styles) are unchanged.
- The @media (max-width: 768px) block is at the very bottom of the file, after the .footer p rule.
- Inside the media query, you have .hero h1 { font-size: 30px; } and .features-grid { flex-direction: column; }.
Your index.html is unchanged from the previous step.
Verify the page works at both sizes
Before you call this step done, what do you expect to see when you toggle between phone width and desktop width?
- In DevTools responsive mode, set the width to 375. Confirm the feature cards stack in a single column, the heading text is a readable size, and no content overflows the screen.
- Exit responsive mode (click the device toolbar icon again) to return to full desktop width. The cards return to their side-by-side row.
Your landing page now works on desktop and mobile. You've built a complete, responsive product page from scratch using only HTML and CSS. Next up, the Secret Mission challenges you to add hover animations and an interactive FAQ section.
Secret mission
Add Hover Animations and a CSS-Only FAQ
Your landing page looks polished, but it feels static. Real product pages respond to user interaction. In this secret mission, you will add smooth hover animations to your button and cards, plus build an expandable FAQ section that opens and closes without a single line of JavaScript.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
This project runs entirely locally, so there are no ongoing costs.
Resources you used:
- The designflow-landing folder on your Desktop (contains index.html and style.css).
- The Live Server extension installed in VS Code.
Keep everything running
No action needed. Choose this if you're still actively building or want to keep experimenting with your landing page.
- Your designflow-landing folder stays on your Desktop, ready to open anytime.
- The Live Server extension remains in VS Code for future projects.
Pause - I'll come back to this later
Stop the Live Server process to free up the port. Your files stay on disk for when you return.
- In VS Code, click the Port: 5500 button in the bottom status bar to stop Live Server. You can also press Cmd+L, Cmd+C (macOS) or Ctrl+L, Ctrl+C (Windows).
- Your project folder and files remain on your Desktop. Reopen the folder in VS Code and start Live Server again when you are ready to continue.
Delete - I don't want to use this again
Remove all project files and the Live Server extension to start completely fresh.
- Stop Live Server if it is still running (click the Port: 5500 button in the status bar).
- Delete the project folder by running this command in your terminal:
macOS
rm -rf ~/Desktop/designflow-landing
Windows
rmdir /s /q %USERPROFILE%\Desktop\designflow-landing
- To uninstall Live Server, open the Extensions panel in VS Code (Cmd+Shift+X on macOS or Ctrl+Shift+X on Windows). Find Live Server in your installed extensions, click the gear icon, and select Uninstall.
Nice Work!
Nice Work!
You just built a complete product landing page from an empty file using only HTML and CSS. That page is live in your browser right now, responding to hovers and adapting to different screen sizes.
Here's what you learned:
- Used HTML to define page structure (header, hero, features, footer) the same way you create frames and layers in Figma.
- Applied CSS for colors, fonts, spacing, and borders, translating design properties into code.
- Used Flexbox to arrange elements side-by-side and added a media query so the layout adapts to mobile screens.
- Created hover animations and built a CSS-only FAQ accordion using the HTML details/summary pattern, all without JavaScript (Secret Mission).
Ready to quiz yourself?