Build an Animated Landing Page
Build a responsive, animated landing page with CSS keyframes and hover effects.
Introduction
30 Second Summary
Think about the last website that impressed you. Chances are it had smooth animations, hover effects, and elements that responded to your mouse.
In this project, you will build a professional animated landing page for a fictional export-import business called "GlobalTrade Solutions" using only HTML and CSS. You will create entrance animations, a pulsing button, a hover dropdown menu, and a layout that adapts to mobile screens.
What You'll Build
Open the finished page in your browser and watch the hero headline slide into view with a smooth fade, a call-to-action button pulse with a subtle glow, and a dropdown menu reveal itself when you hover over "Services."
By the end of this project, you'll have:
- A sticky navigation bar with a hover-activated dropdown menu that reveals business services without any JavaScript.
- A hero section with CSS keyframe entrance animations that fade and slide content into view on page load, plus a pulsing call-to-action button.
- A set of service cards that respond to hover by lifting up and casting deeper shadows, and a fully responsive layout that stacks gracefully on mobile screens.
- Secret Mission: a gradient background animation on the hero section and staggered entrance delays on service cards.
Are there any prerequisites?
None. This guide includes setup for all required tools. You just need a computer with a web browser.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters.
Set Up Your Project
Every animated landing page starts with a foundation. You need a folder to hold your code, files to write in, and a way to preview changes instantly in the browser.
In this step, you'll set up your workspace with a live-reloading development server. Every time you save a file, the browser will refresh automatically so you can see your changes immediately.
In this step, get ready to:
- Install the Live Server extension for instant browser previews.
- Create your project folder and starter files.
- Write the HTML boilerplate and confirm it displays in the browser.
Install the Live Server extension
Live Server is a VS Code extension that launches a local development server. It watches your files and automatically refreshes the browser whenever you save a change.
- In VS Code, press Cmd+Shift+X (macOS) or Ctrl+Shift+X (Windows) to open the Extensions panel.
- Type Live Server in the search bar.
- Find the result by Ritwick Dey and click Install.
- Wait for the install to finish. The button changes from Install to a gear icon when it's done.
Don't see Live Server in search results?
Make sure you're in the Extensions panel (the icon with four squares on the left sidebar) and not the file search. Check your spelling matches exactly: Live Server.
Help me find Live Server in VS Code
Create your project folder and files
You need a dedicated folder to hold your landing page files. Creating it on your Desktop makes it easy to find later.
- Open the integrated terminal in VS Code by pressing Cmd+` (macOS) or Ctrl+` (Windows).
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir globaltrade-landing
cd globaltrade-landing
- In VS Code, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the globaltrade-landing folder, and click Open.
VS Code reloads with the folder name in the sidebar header.
- In the Explorer sidebar, hover over the GLOBALTRADE-LANDING heading and click the New File icon (a page with a plus sign).
- Type index.html and press Enter.
- Click the New File icon again, type style.css, and press Enter.
You should now see both index.html and style.css listed in the Explorer sidebar.
Don't see the New File icon?
The icon only appears when you hover over the folder heading in the Explorer sidebar. If the sidebar isn't visible, press Cmd+Shift+E (macOS) or Ctrl+Shift+E (Windows) to open it.
Help me create a new file in VS Code
Add the HTML boilerplate and launch Live Server
Every web page needs a basic HTML skeleton that tells the browser what kind of document it's reading. This boilerplate also connects your CSS stylesheet so styles apply when you write them later.
- Click on index.html in the Explorer sidebar to open it in the editor.
- Paste the following code into the file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlobalTrade Solutions</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
</body>
</html>
What does this code do?
- <!DOCTYPE html> tells the browser this is a modern HTML5 document.
- The viewport meta tag ensures the page scales correctly on mobile devices.
- <link rel="stylesheet" href="style.css"> connects your CSS file so any styles you write there will apply to this page.
- The <body> is empty for now. You'll add all your visible content here in the next step.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Right-click index.html 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 browser opens a new tab showing a completely blank white page. Check the browser tab title at the top. It should read GlobalTrade Solutions.
Seeing a directory listing instead of a blank page?
This means Live Server opened the folder instead of the file. Make sure you right-clicked index.html specifically (not the folder or style.css).
If the page is blank but the tab title says localhost instead of GlobalTrade Solutions, double-check that you saved index.html after pasting the boilerplate.
Help me troubleshoot Live Server
✔️ Awesome, I've got everything!
Great. Double check you've saved index.html and your browser shows the blank page with the correct title.
ⓧ I'd like to double check the full code
Here is the complete index.html file so far. Your style.css file should be empty at this point.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GlobalTrade Solutions</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
</body>
</html>
Your workspace is ready and Live Server is watching for changes. Next up, you'll fill that empty page with all the content for your landing page.
Build the Page Structure
Your project folder is ready and Live Server is watching for changes. Now you need actual content in the browser before you can style anything.
In this step, you will build the full HTML5 structure of the landing page. Even without any CSS, seeing your raw text content proves the HTML is valid and gives you something tangible to style next.
In this step, get ready to:
- Build a navigation bar with a dropdown menu for business services.
- Add a hero section with a headline, tagline, and call-to-action button.
- Create service cards and a footer to complete the page layout.
Build the header with navigation
The navigation bar is the first thing visitors interact with on any website. Your header will include a logo, main links, and a dropdown menu that reveals sub-items for the Services category.
- In VS Code, open index.html from the Explorer sidebar.
- Find the empty <body> tags and add the following code between them:
<!-- Navigation bar with logo and links -->
<header>
<nav>
<div class="logo">GlobalTrade</div>
<!-- Main navigation links -->
<ul class="nav-links">
<li><a href="#">Home</a></li>
<!-- Dropdown parent with nested menu -->
<li class="dropdown">
<a href="#">Services</a>
<ul class="dropdown-menu">
<li><a href="#">Import Services</a></li>
<li><a href="#">Export Services</a></li>
<li><a href="#">Logistics</a></li>
<li><a href="#">Customs Clearance</a></li>
</ul>
</li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
</header>
What does this code do?
- <header> and <nav> are semantic HTML elements that tell the browser (and screen readers) this area is navigation.
- The .dropdown list item wraps the Services link and a nested .dropdown-menu list. Later, CSS will hide this nested list and reveal it on hover.
- Each href="#" is a placeholder link. It keeps the page from navigating anywhere when clicked.
- Save index.html (Cmd+S on macOS, Ctrl+S on Windows).
- Check your browser. You should see "GlobalTrade" followed by a list of links (Home, Services, Import Services, Export Services, Logistics, Customs Clearance, About, Contact) in plain black text.
Don't see any text in the browser?
- Make sure you pasted the code between the opening <body> and closing </body> tags, not inside the <head>.
- Confirm Live Server is still running. Look for "Port: 5500" in the VS Code status bar at the bottom. If not, right-click index.html and select Open with Live Server.
Why isn't my HTML showing in the browser?
Build the hero section
The hero is the large, attention-grabbing area at the top of the page. It holds the main headline, a supporting tagline, and a call-to-action button that invites visitors to act.
- In index.html, place your cursor on the blank line after the closing </header> tag.
- Add the hero section by pasting this code below it:
<!-- Hero section with headline and call to action -->
<section class="hero">
<h1>Global Import & Export Solutions</h1>
<p class="hero-tagline">Connecting businesses across borders with reliable trade services</p>
<a href="#" class="cta-button">Get a Free Quote</a>
</section>
What does this code do?
- <section class="hero"> groups the hero content into a named section. The class name gives CSS a hook to style it later.
- The .cta-button is an anchor link styled as a button. This is a common pattern for call-to-action elements that link somewhere.
- &amp; is the HTML entity for the & character. Browsers display it as a normal ampersand.
- Save index.html.
- Check your browser. Below the navigation links, you should now see "Global Import & Export Solutions" as a large heading, the tagline text, and "Get a Free Quote" as a blue link.
Hero text not appearing below the nav links?
- Check that the hero section code is placed after the closing </header> tag, not inside it.
- Make sure you have a closing </section> tag at the end of the hero block.
Help me figure out why my hero section isn't showing up.
Build the services section and footer
The services section showcases what the business offers using a grid of cards. A footer rounds out the page with copyright information.
- In index.html, place your cursor on the blank line after the hero's closing </section> tag.
- Add the services section and footer by pasting this code below it:
<!-- Services section with card grid -->
<section class="services">
<h2>Our Services</h2>
<div class="services-grid">
<div class="service-card">
<h3>Import Solutions</h3>
<p>Streamlined import processes with customs handling, documentation, and door-to-door delivery from any country.</p>
</div>
<div class="service-card">
<h3>Export Management</h3>
<p>End-to-end export services including compliance, packaging, and international shipping coordination.</p>
</div>
<div class="service-card">
<h3>Logistics & Shipping</h3>
<p>Reliable freight forwarding by sea, air, and land with real-time tracking and competitive rates.</p>
</div>
</div>
</section>
<!-- Page footer -->
<footer>
<p>© 2026 GlobalTrade Solutions. All rights reserved.</p>
</footer>
What does this code do?
- .services-grid is a wrapper div that holds the three cards. CSS will turn this into a flexible row layout in a later step.
- Each .service-card div groups a heading and description together. These class names give CSS precise targets for hover effects later.
- &copy; renders as the copyright symbol (©) in the browser.
Before you save, take a moment to predict: what do you think the full page will look like right now, with no CSS at all?
- Save index.html.
Your browser auto-refreshes and shows all of your content as plain, unstyled black text on a white background. The navigation links appear at the top, with the Services dropdown items visible as a nested bullet list. Below that, you see the hero headline, tagline, and link. Then the service cards as headings with body text, and finally the footer copyright line.
Seeing broken text or missing sections?
- Check for missing closing tags. Every <section> needs a matching </section>, and every <div> needs a matching </div>.
- Make sure the three code chunks are in order: header first, then hero, then services and footer. None of them should overlap or be nested inside each other.
- If you see raw HTML tags instead of rendered text, make sure you are viewing the page through Live Server (the URL starts with http://127.0.0.1:5500) and not opening the file directly.
My HTML page is showing broken content or missing sections. Help me debug.
✔️ Awesome, I've got everything!
Great. Double check you have saved index.html and all your text content is visible in the browser.
ⓧ I'd like to double check the full code
Your index.html should contain the original boilerplate (DOCTYPE, head, meta tags, title, stylesheet link) plus three chunks you added inside the body, in this order:
- The header/nav block with the logo, nav-links list, and the dropdown menu inside the Services list item.
- The hero section with the h1 headline, the .hero-tagline paragraph, and the .cta-button anchor.
- The services section with the h2, the .services-grid div containing three .service-card divs, followed by the footer.
Scroll up and confirm each chunk is present in your file, in that order. Nothing should overlap or be nested inside another section.
Your HTML skeleton is complete. Every piece of content is on the page, ready to be transformed. Next up, you will style the navigation bar and make that dropdown menu appear only on hover.
Style the Navigation with a Hover Dropdown
Your HTML structure is complete and the browser is showing all your content. Right now it looks like an unstyled document from the 1990s.
The navigation bar is the first interactive element visitors touch on any website. In this step, you'll transform it into a professional sticky nav with a hover-activated dropdown menu. The best part: you'll do it entirely with CSS, no JavaScript needed.
In this step, get ready to:
- Style the header as a sticky nav bar with a Flexbox layout.
- Hide the dropdown menu by default and reveal it smoothly on hover.
- Add color transitions to navigation links for hover interactivity.
Style the base layout
Every CSS file starts with a reset. Browsers apply their own default margins and padding to elements, which creates inconsistent spacing. A reset zeroes those out so you're working from a clean slate.
- In VS Code, open style.css and add the CSS reset, body styles, and header layout by pasting the following code:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', sans-serif;
line-height: 1.6;
color: #333;
}
/* Header and Navigation */
header {
background-color: #1a1a2e;
padding: 15px 40px;
position: sticky;
top: 0;
z-index: 100;
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
}
What does this code do?
The * selector targets every element on the page and removes default margins and padding. box-sizing: border-box makes padding count toward an element's total width instead of adding to it.
The header gets a dark navy background and position: sticky so it stays pinned to the top of the page as the user scrolls. The nav uses display: flex with justify-content: space-between to push the logo to the left and links to the right.
- Save style.css.
- Check your browser. You should see the header turn dark navy, and the navigation text (logo and links) should now sit on a single horizontal line inside that dark bar.
Still seeing unstyled text?
- Confirm that your index.html has <link rel="stylesheet" href="style.css"> in the <head> section.
- Check that style.css is in the same folder as index.html. If they are in different folders, the link won't work.
- Make sure Live Server is still running. Look for the port number in the VS Code status bar at the bottom.
Why isn't my CSS styling the page?
The header has its dark background but the nav links still look plain. Let's style the logo, links, and add the hover color change.
- Add the logo and nav link styles below the code you just pasted in style.css:
.logo {
color: #e94560;
font-size: 1.8rem;
font-weight: 700;
}
.nav-links {
display: flex;
list-style: none;
gap: 30px;
}
.nav-links a {
color: #ffffff;
text-decoration: none;
font-size: 1rem;
padding: 10px 5px;
transition: color 0.3s ease;
}
.nav-links a:hover {
color: #e94560;
}
What does this code do?
The .logo gets a coral-red color (#e94560) that contrasts against the navy header. .nav-links uses display: flex to lay out the links horizontally with even spacing.
The transition: color 0.3s ease property tells the browser to animate the color change over 0.3 seconds instead of switching instantly. When a user hovers over a link, it smoothly fades to #e94560.
- Save style.css and check the browser.
- You should see a red "GlobalTrade" logo on the left, white navigation links on the right, and hovering any link turns it red with a smooth fade.
Links not changing color on hover?
- Check that the .nav-links a:hover rule comes after .nav-links a in your file. Order matters in CSS.
- Make sure you have a closing } for every opening {. A missing brace breaks everything below it.
My CSS hover effect isn't working, can you help?
Why CSS :hover instead of JavaScript?
Many interactive effects (like dropdowns and color changes) can be achieved purely with CSS pseudo-classes like :hover. The browser handles the event detection for you, so there's no scripting to write, load, or debug.
This makes the page faster and simpler. For a landing page where mouse interaction is the primary input, CSS-only hover effects are the perfect fit.
Position the dropdown
Right now the dropdown items (Import Services, Export Services, etc.) are visible in the nav bar, pushing everything around. You need to position the dropdown menu so it floats below its parent link and stays hidden until the user hovers.
- Add the dropdown positioning styles below your existing code in style.css:
/* Dropdown */
.dropdown {
position: relative;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
background-color: #16213e;
list-style: none;
min-width: 200px;
border-radius: 4px;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
What does this code do?
Setting .dropdown to position: relative creates an anchor point. The .dropdown-menu then uses position: absolute to float freely relative to that anchor, appearing directly below it (top: 100%).
The menu starts invisible with opacity: 0 and visibility: hidden. Using both together ensures screen readers ignore it AND it can transition smoothly (unlike display: none which can't be animated).
- Save style.css and check the browser.
- The dropdown items (Import Services, Export Services, Logistics, Customs Clearance) should have disappeared from the nav bar. They're still in the HTML, just hidden by the CSS.
Dropdown items still showing?
- Check that the class name in your CSS (.dropdown-menu) matches exactly what's in your HTML (class="dropdown-menu"). CSS class names are case-sensitive.
- Verify that opacity: 0 and visibility: hidden are both present inside the .dropdown-menu rule. You need both for the menu to disappear completely.
Help me figure out why my dropdown menu is still visible.
Reveal the dropdown on hover
The dropdown is hidden. Now you need to bring it back when the user hovers over the "Services" link. One CSS rule makes this happen.
- Add the hover reveal and dropdown item styles below your existing code in style.css:
.dropdown:hover .dropdown-menu {
opacity: 1;
visibility: visible;
}
.dropdown-menu li a {
display: block;
padding: 12px 20px;
color: #ffffff;
text-decoration: none;
transition: background-color 0.3s ease;
}
.dropdown-menu li a:hover {
background-color: #1a1a2e;
}
What does this code do?
The selector .dropdown:hover .dropdown-menu means "when the user hovers over the dropdown container, target the dropdown-menu inside it." It flips opacity and visibility back to fully visible.
Because you already added a transition on .dropdown-menu in the previous chunk, the browser animates between hidden and visible over 0.3 seconds. The individual link styles add padding and a background highlight to make each item feel clickable.
- Save style.css.
Before you test, what do you think will happen when you hover over "Services" in the nav bar?
- Hover your mouse over the "Services" link in the nav bar.
- You should see a darker panel smoothly fade in below it, showing four items: Import Services, Export Services, Logistics, and Customs Clearance.
- Move your mouse away and the dropdown fades out.
- Hover over individual dropdown items and you'll see a subtle background highlight on each one.
Dropdown appears but snaps instead of fading?
- Go back to your .dropdown-menu rule and check that it includes transition: opacity 0.3s ease, visibility 0.3s ease;. Without the transition, the change is instant.
- Make sure there's no display: none anywhere on the dropdown menu. display: none cannot be transitioned, which is why we use opacity and visibility instead.
My dropdown transition isn't smooth, can you help?
✔️ Awesome, I've got everything!
Great. Double check you've saved style.css and the dropdown is fading in smoothly on hover.
ⓧ I'd like to double check the full code
Your style.css should contain three sections you built above, in this order:
- The CSS reset (* selector), body styles, header, and nav flexbox layout.
- The .logo, .nav-links, .nav-links a, and .nav-links a:hover styles.
- The dropdown section: .dropdown, .dropdown-menu (hidden state), .dropdown:hover .dropdown-menu (reveal), and .dropdown-menu li a item styles.
Scroll up and confirm each code block is present in your file, in order. If anything is missing, copy it from the relevant chunk above.
Your navigation is styled and interactive. You have a sticky header, smooth hover effects on links, and a dropdown that fades in on demand. Next up, you'll bring the hero section to life with entrance animations and give the service cards a satisfying hover lift.
Animate the Hero Section and Style the Service Cards
Your navigation is interactive, but the rest of the page is still a wall of unstyled text. Static pages feel lifeless.
In this step, you will add entrance animations that make the hero section slide into view, a pulsing call-to-action button, and hover effects on your service cards. These techniques transform a plain document into something that feels polished and professional.
In this step, get ready to:
- Create a CSS keyframe animation that fades and slides content into view.
- Build an infinitely pulsing button using a second keyframe animation.
- Style service cards with hover effects that lift and cast shadows.
Style and animate the hero section
The hero is the first thing visitors see. A dark gradient background, centered white text, and a smooth entrance animation will draw their eye immediately.
You will create a @keyframes animation called fadeInUp that starts elements invisible and shifted downward, then brings them up into position with a fade.
- In style.css, add the following CSS below your existing dropdown styles:
/* Hero Section */
.hero {
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: #ffffff;
text-align: center;
padding: 120px 20px;
}
.hero h1 {
font-size: 3rem;
margin-bottom: 20px;
animation: fadeInUp 0.8s ease both;
}
.hero-tagline {
font-size: 1.2rem;
margin-bottom: 30px;
opacity: 0.9;
animation: fadeInUp 0.8s ease 0.2s both;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
What does this code do?
- .hero creates a dark diagonal gradient background and centers everything with generous padding.
- @keyframes fadeInUp defines the animation: start at invisible and 30px below, end at fully visible in the correct position.
- animation: fadeInUp 0.8s ease both applies the animation over 0.8 seconds. The both keyword keeps elements hidden before the animation starts and visible after it ends.
- The tagline has a 0.2s delay so it appears slightly after the headline, creating a cascading entrance.
What is animation-fill-mode?
The both value for animation-fill-mode ensures the element applies styles from the first keyframe before the animation starts (when there is a delay) and retains styles from the last keyframe after it ends.
Without it, the tagline would flash visible before its 0.2s delay kicks in, then disappear, then animate. That flicker would ruin the smooth entrance.
- Save style.css.
- Refresh your browser (or let Live Server auto-refresh). You should see the hero section with a dark gradient background. The headline "Global Import & Export Solutions" slides up and fades in, followed by the tagline a split second later.
Don't see the animation?
- The animation only plays on page load. Try a hard refresh with Cmd+Shift+R (macOS) or Ctrl+Shift+R (Windows) to see it replay.
- Check that your @keyframes fadeInUp block is placed after the .hero-tagline rule, not inside another selector.
- help me debug my fadeInUp animation
Add the pulsing CTA button
A static button is easy to miss. A subtle pulse draws the visitor's eye without being annoying. You will create a second @keyframes animation that runs infinitely, gently scaling the button and adding a glow.
- Add the following CSS below your @keyframes fadeInUp block:
/* CTA Button */
.cta-button {
display: inline-block;
background-color: #e94560;
color: #ffffff;
padding: 15px 35px;
text-decoration: none;
border-radius: 30px;
font-size: 1.1rem;
font-weight: 600;
animation: pulse 2s infinite ease-in-out;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
box-shadow: 0 0 0 rgba(233, 69, 96, 0);
}
50% {
transform: scale(1.05);
box-shadow: 0 0 20px rgba(233, 69, 96, 0.4);
}
}
What does this code do?
- .cta-button styles the link as a rounded pill-shaped button with a bold coral background.
- animation: pulse 2s infinite ease-in-out makes the pulse animation repeat forever, cycling every 2 seconds.
- At the 50% mark, the button grows to 1.05x its size and gains a soft red glow. At 0% and 100%, it returns to normal. This creates a breathing rhythm.
- Save style.css and check your browser.
- You should see a coral-red "Get a Free Quote" button that gently pulses with a glowing shadow. The pulse never stops.
Button not pulsing?
- Make sure @keyframes pulse is placed outside any other selector block. It must be a top-level rule.
- Confirm the animation name in .cta-button matches the name after @keyframes exactly (case-sensitive).
- help me fix my CSS pulse animation
Style the services section layout
Below the hero, the services section needs a clean layout. CSS Flexbox will arrange the three cards in a horizontal row with even spacing.
- Add the following CSS below your @keyframes pulse block:
/* Services Section */
.services {
padding: 80px 20px;
text-align: center;
background-color: #f8f9fa;
}
.services h2 {
font-size: 2.2rem;
margin-bottom: 40px;
color: #1a1a2e;
}
.services-grid {
display: flex;
gap: 30px;
max-width: 1200px;
margin: 0 auto;
justify-content: center;
}
What does this code do?
- .services gives the section a light grey background to visually separate it from the dark hero above.
- .services-grid uses display: flex to place the three cards side by side. The gap: 30px adds even spacing between them.
- Save style.css and check your browser.
- You should see the three service cards now arranged in a horizontal row on a light grey background, with the "Our Services" heading centered above them.
The cards are in a row, but they are plain text on a flat background. Next you will give them shape, hover interactions, and style the footer.
- Add the following CSS below your .services-grid block:
.service-card {
background-color: #ffffff;
padding: 40px 30px;
border-radius: 10px;
flex: 1;
max-width: 350px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.service-card:hover {
transform: translateY(-8px);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
}
.service-card h3 {
font-size: 1.4rem;
margin-bottom: 15px;
color: #1a1a2e;
}
.service-card p {
color: #666;
font-size: 0.95rem;
}
/* Footer */
footer {
background-color: #1a1a2e;
color: #ffffff;
text-align: center;
padding: 25px 20px;
font-size: 0.9rem;
}
What does this code do?
- Each .service-card gets a white background, rounded corners, and a soft shadow to create a card look.
- transition: transform 0.3s ease, box-shadow 0.3s ease tells the browser to smoothly animate any changes to those properties over 0.3 seconds.
- .service-card:hover lifts the card 8px upward and deepens the shadow, creating a satisfying "pick up" effect when you hover.
- The footer matches the header's navy color to bookend the page.
What are CSS transitions?
A CSS transition smoothly interpolates between CSS values when a state change occurs (like :hover). Without a transition, the card would jump instantly to its new position. With it, the card glides upward over 0.3 seconds.
- Save style.css.
Before you check the browser, what do you think will happen when you hover over a service card?
- Hover your mouse over each service card. Each card should lift upward and cast a deeper shadow as your cursor enters it. Move your cursor away and it settles back down smoothly.
- Scroll down to confirm the footer appears as a dark navy bar with white centered text.
Cards not lifting on hover?
- Make sure the transition property is on .service-card (the base state), not on .service-card:hover. The transition must be declared before the state change.
- Check that .service-card:hover appears immediately after .service-card and is not accidentally nested inside another rule's curly braces.
- help me debug my service card hover effect
Now do a final check of the full page by hard-refreshing with Cmd+Shift+R (macOS) or Ctrl+Shift+R (Windows). You should see the hero headline and tagline slide up and fade in over about one second, the CTA button pulsing, and the service cards lifting when you hover them.
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css and all your animations are playing.
ⓧ I'd like to double check the full code
Your style.css is now quite long. Scroll through and confirm you have each of these sections in order:
- The CSS reset (* selector and body styles).
- Header and Navigation (header, nav, .logo, .nav-links).
- Dropdown (.dropdown, .dropdown-menu, .dropdown:hover .dropdown-menu).
- Hero Section (.hero, .hero h1, .hero-tagline, @keyframes fadeInUp).
- CTA Button (.cta-button, @keyframes pulse).
- Services Section (.services, .services h2, .services-grid, .service-card, .service-card:hover).
- Footer (footer).
Your page looks polished on a full-width browser window. But try something: drag the edge of your browser to make it narrower. The nav items squish together, cards overflow sideways, and text gets cramped. That is the problem you will fix in the next step with responsive design.
Make It Responsive
Your landing page now has smooth animations, glowing buttons, and interactive card effects. But how does it look on a phone?
CSS media queries let you write rules that only apply when the browser window is below a certain width. In this step, you will add a media query that transforms your desktop layout into a mobile-friendly one.
In this step, get ready to:
- Add a media query that restructures the navigation for mobile.
- Stack the hero and service cards vertically on narrow screens.
- Test the layout at both wide and narrow viewport widths.
Before writing any responsive CSS, take a look at how your page currently handles a narrow viewport.
- Drag the right edge of your browser window inward until the window is about half your screen width.
What do you think will happen to the navigation links and the service cards at this narrow width?
The nav items squish together or wrap awkwardly. The service cards overflow sideways, forcing horizontal scrolling. The hero headline gets cramped. This is the gap that media queries close.
Add the media query for navigation
A media query wraps CSS rules in a condition. The rules inside only apply when the viewport matches that condition.
- In style.css, scroll to the very bottom of the file (after the footer styles).
- Add the following responsive navigation rules:
/* Responsive Design */
@media (max-width: 768px) {
nav {
flex-direction: column;
gap: 15px;
}
.nav-links {
flex-direction: column;
align-items: center;
gap: 10px;
}
.dropdown-menu {
position: static;
opacity: 1;
visibility: visible;
background-color: transparent;
min-width: auto;
text-align: center;
}
.dropdown-menu li a {
padding: 5px 10px;
font-size: 0.9rem;
}
}
What does this code do?
The @media (max-width: 768px) wrapper means everything inside only applies when the browser is 768 pixels wide or narrower.
- nav and .nav-links switch from horizontal (row) to vertical (column) layout so links stack on top of each other.
- .dropdown-menu becomes position: static and permanently visible. On mobile, hover does not exist (no mouse), so the dropdown items display inline instead of hiding behind a hover.
- The dropdown link padding and font size shrink slightly to fit the narrower space.
- Save style.css.
- Make sure your browser window is still narrow (about half your screen width). The navigation should now stack vertically with the dropdown items visible below "Services".
Navigation still squished horizontally?
- Confirm your media query starts with @media (max-width: 768px) { and has a matching closing } at the very end. A missing brace silently breaks everything inside.
- Make sure this code is at the very bottom of style.css, after the footer styles. If it is placed above other rules, the desktop styles may override it.
- Check that your browser window is actually narrow enough. Drag it until it is clearly less than half your monitor width.
Why isn't my media query changing the navigation layout?
Stack the hero and services content
The navigation stacks correctly now, but the hero text is still oversized and the service cards still sit in a row. These need the same responsive treatment.
- In style.css, find the closing } of your media query (the very last line of the file).
- Add the following rules just above that closing brace, inside the media query:
.hero {
padding: 80px 20px;
}
.hero h1 {
font-size: 2rem;
}
.hero-tagline {
font-size: 1rem;
}
.services-grid {
flex-direction: column;
align-items: center;
}
.service-card {
max-width: 100%;
}
What does this code do?
- .hero padding is reduced from 120px to 80px so the section does not dominate the smaller screen.
- The headline drops from 3rem to 2rem and the tagline from 1.2rem to 1rem so text fits without overflowing.
- .services-grid switches to flex-direction: column so cards stack vertically instead of sitting side by side.
- .service-card gets max-width: 100% so each card stretches to fill the available width on mobile.
- Save style.css.
- With your browser still narrow, the service cards should now stack in a single column and the hero headline should fit comfortably without overflow.
Cards still in a row or text overflowing?
- Make sure these new rules are inside the @media (max-width: 768px) { } block. If they are outside, they will apply at all widths.
- Check you did not accidentally add a second closing } that ends the media query too early. The media query should have exactly one opening and one closing brace wrapping all the mobile rules.
My service cards won't stack vertically in the media query. Help me debug.
Test both views
The real test of responsive CSS is switching back and forth between wide and narrow to confirm nothing breaks in either direction.
- Drag your browser window back to full width. The desktop layout should return: horizontal nav, three-column card row, dropdown hidden until hover.
- Now drag the window narrow again (below 768px). The navigation should stack vertically, dropdown items should appear inline, and cards should stack in a single column.
- Confirm there is no horizontal scrollbar at any width.
Before you call this done, predict: if you hover over "Services" while the window is narrow, will you see the dropdown animation or not?
You will not see any animation. The media query sets the dropdown to always visible with opacity: 1 and position: static, so there is nothing to reveal on hover. The items are already showing.
Why make the dropdown always visible on mobile?
Mobile devices do not have a mouse cursor, so :hover does not work reliably on touchscreens. By making dropdown items permanently visible at narrow widths, every link stays accessible without JavaScript.
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css and your browser shows both layouts correctly.
ⓧ I'd like to double check the full code
Your style.css is too long to show in one block. Scroll through your file and confirm these sections appear in order:
- CSS reset (* { margin: 0; ... }) and body font styles at the top.
- Header, nav, logo, and nav-links styles.
- Dropdown styles (.dropdown, .dropdown-menu, .dropdown:hover .dropdown-menu).
- Hero section styles with @keyframes fadeInUp.
- CTA button styles with @keyframes pulse.
- Services section, services-grid, and service-card styles.
- Footer styles.
- The @media (max-width: 768px) block at the very bottom containing nav, nav-links, dropdown-menu, hero, and services-grid overrides.
Your index.html has not changed in this step.
Your landing page is now fully responsive. It looks polished on a wide desktop monitor and stacks gracefully on a narrow phone screen. You have built a complete, professional page using only HTML and CSS. Next up, a secret mission to push your animation skills even further.
Secret mission
Add a Gradient Animation and Staggered Card Entrances
Your landing page already has entrance animations and hover effects. But what if the hero background itself was alive, slowly shifting between colors? And what if the service cards appeared one after another in a wave instead of all at once? This secret mission layers on advanced CSS animation techniques to make your page feel truly cinematic.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally in your browser, so there are no ongoing costs or cloud resources to worry about.
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- The globaltrade-landing project folder on your Desktop (containing index.html and style.css).
- The Live Server extension installed in VS Code.
Keep everything running
No action needed. Choose this if you are still actively building or want to continue experimenting with your landing page.
- Your project folder is on your Desktop. Open index.html anytime to view your page.
- Right-click index.html in VS Code and select Open with Live Server to resume live editing.
- The Live Server extension stays installed in VS Code and is useful for any future HTML/CSS project.
Pause - I'll come back to this later
Stop the Live Server process to free up the port, but keep your files for later.
- In VS Code, click Port: 5500 in the bottom status bar to stop Live Server. Alternatively, press Ctrl+Shift+P (Windows) or Cmd+Shift+P (macOS), type Live Server: Stop Live Server, and press Enter.
- Close the browser tab that was displaying your page.
- Your globaltrade-landing folder remains on your Desktop. Reopen it in VS Code whenever you want to continue.
Delete - I don't want to use this again
Remove all project files and optionally uninstall the Live Server extension.
- Stop Live Server if it is still running (click Port: 5500 in the VS Code status bar).
- Close the project in VS Code.
- Delete the project folder. On macOS/Linux, open your terminal and run:
rm -rf ~/Desktop/globaltrade-landing
On Windows, open PowerShell and run:
rmdir /s /q "$HOME\Desktop\globaltrade-landing"
- To uninstall Live Server: open the Extensions panel in VS Code (Ctrl+Shift+X on Windows or Cmd+Shift+X on macOS), find Live Server in your installed list, and click Uninstall.
Nice Work!
Nice Work!
Nice work! You just built a professional, animated landing page for an export-import business using nothing but HTML and CSS.
You've learned how to:
- Write CSS @keyframes animations for entrance effects (fadeInUp) and infinite effects (pulse) that bring a static page to life.
- Create a hover-activated CSS dropdown navigation and hover transitions on service cards without writing a single line of JavaScript.
- Implement responsive design with a CSS media query that adapts your layout for mobile screens.
- Secret Mission: Added a gradient background animation and staggered card entrance delays using animation-delay and :nth-child selectors.
Ready to quiz yourself?