Intermediate50 minProjectCSS Polish

BSB Part 4B: Polish and Refine

Apply cascade cleanup, detail selectors, pseudo-elements, and restrained motion to bring the Black Swan Bistro site to a polished finish.

Learning Objectives

By the end of this lesson, you'll be able to:

  • Audit and simplify CSS specificity across a multi-page site
  • Use pseudo-classes and pseudo-elements to refine interactive and decorative details
  • Add restrained transitions and transforms to interactive components
  • Guard all motion with the prefers-reduced-motion media query
  • Apply Apply a structured polish workflow that can carry forward to future projects

Why This Matters:

Polish is not about adding more CSS. It is about making existing CSS clearer, more intentional, and more responsive to user interaction. This pass teaches a repeatable refinement workflow.

Before You Start:

You should be familiar with:

Tutorial Introduction

This tutorial is a structured polish pass. You will work through the Black Swan Bistro site in four focused passes, each building on the last:

  1. Cascade cleanup — audit specificity and simplify selectors
  2. Detail selectors — add hover states, focus styles, and decorative pseudo-elements
  3. Restrained motion — add transitions and transforms to interactive moments
  4. Final review — check accessibility, reduced motion, and overall feel

Each pass is short and focused. You are not rewriting the site. You are making targeted improvements that show you understand the tools from the last two tutorials well enough to apply them to a real project.

Keep the scope small: a polish pass is not a redesign. If you find yourself wanting to restructure HTML or rethink the layout, note it for later. This pass is about CSS refinement only.

What Polish Means in CSS

Polish is the difference between a page that works and a page that feels considered. It shows up in small details:

  • Links that respond smoothly to hover instead of snapping to a new colour
  • Cards that lift slightly when interactive, signalling that they lead somewhere
  • Navigation that shows focus states for keyboard users
  • Decorative touches with pseudo-elements instead of extra HTML
  • A stylesheet that is easy to read and change because specificity is low and selectors are clear

None of these changes are large on their own. Together, they signal care and intention. And the process of adding them teaches restraint — knowing when a detail helps and when it just adds noise.

Pass 1: Cascade Cleanup

Before adding any new CSS, clean up what you have. High specificity and unnecessary selector chains make every future change harder. This pass makes the stylesheet easier to work with.

Audit Specificity

Open DevTools on each page and look for crossed-out styles in the Styles panel. Each crossed-out rule is a specificity conflict. Ask:

  • Is the winning selector more specific than it needs to be?
  • Are there ID selectors that could be replaced with classes?
  • Are there long descendant chains like .hero .container .section-title that could be a single class?

Write down each problem you find. You do not need to fix everything at once — just build a clear picture before changing anything.

Simplify Selectors

For each problem in your audit, rewrite the selector to be as simple as possible while keeping the same visual result. The pattern is usually the same:

  • Replace ID selectors with class selectors
  • Replace long descendant chains with a single purpose-named class
  • Remove !important by fixing the specificity conflict underneath

After each change, check the page in the browser. If it looks the same, the simplification worked. If something breaks, you have found a specificity dependency worth understanding.

Pass 2: Detail Selectors

With a cleaner stylesheet, you can now add interactive and decorative detail with confidence that new rules will not fight old ones.

Pseudo-classes for Interaction

Review every interactive element on the site — links, buttons, cards that contain links, and navigation items. Each one should have clear :hover and :focus-visible states.

  • Navigation links: a colour or underline shift on hover, plus a visible focus ring
  • Buttons: a background or shadow change that signals interactivity
  • Cards with links: consider styling the whole card on :hover and :focus-within

The key rule: every interactive element should look different in its hovered and focused state. If it looks the same regardless of interaction, the user has no feedback.

Pseudo-elements for Decoration

Pseudo-elements let you add decorative detail without touching the HTML. Use them for:

  • Section dividers between content areas
  • Subtle accent lines under headings
  • Decorative marks next to the active navigation link

Keep pseudo-element decoration modest. One or two well-placed touches improve the feel. Five or six make the page feel noisy.

/* Example: accent line under section titles */
.section-title::after {
    content: '';
    display: block;
    width: 3rem;
    height: 2px;
    background-color: var(--color-golden-orange);
    margin-top: 0.5rem;
}

Pass 3: Restrained Motion

Motion draws attention. Used well, it signals that the page is responding to the user. Used carelessly, it makes the page feel slow or distracting.

Transitions on Interactive Elements

Add transitions to the interactive states you created in Pass 2. The rules are simple:

  • Only transition the properties you are changing — never use transition: all
  • Keep durations between 0.15s and 0.3s for interactive feedback
  • Use ease or ease-out for most hover transitions
/* Navigation link transition */
.site-nav__link {
    transition: color 0.2s ease;
}

/* Button transition */
.button {
    transition: background-color 0.2s ease, box-shadow 0.2s ease;
}

Transforms for Subtle Depth

A small translateY on card hover gives a sense of lift without physically moving content around the page. Pair it with a soft box-shadow change for depth:

.menu-card {
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.menu-card:hover,
.menu-card:focus-within {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

Restraint matters here. A 2px lift is enough to signal interactivity. More than 4px starts to feel like the card is jumping off the page.

Guarding with prefers-reduced-motion

Every transition and transform you add needs a reduced-motion fallback. Place this at the end of your stylesheet:

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

This is not a nice-to-have. It is an accessibility requirement. Users with motion sensitivity, vestibular disorders, or a preference for calm interfaces depend on this media query working correctly.

Test it: in macOS, go to System Settings → Accessibility → Display → Reduce motion. In DevTools, open the Rendering panel and emulate prefers-reduced-motion: reduce. Every transition on the site should effectively disappear.

Pass 4: Final Review

The last pass is a full walkthrough. Open each page and check:

  1. Consistency: do hover states, focus styles, and card lifts feel the same across all pages?
  2. Reduced motion: enable the preference and verify all motion stops
  3. Keyboard navigation: tab through every page and check that focus-visible styles appear on every interactive element
  4. Specificity: open DevTools one more time and confirm there are no unnecessary overrides left
  5. Feel: does the site feel considered, or does it feel over-decorated?

If something feels like too much, remove it. The best polish passes end with fewer lines of CSS than you expected, not more.

⏸️ Pause & Check: Do You Understand?

Before moving forward, can you answer these?

  1. Why should you audit specificity before adding new selectors or transitions?
  2. When is a transition helpful, and when does it get in the way?
  3. What does the prefers-reduced-motion media query protect against?
Check Your Answers
  1. High-specificity selectors make future changes harder because each new rule has to fight the existing ones. Cleaning up specificity first gives you a stable foundation so the motion and detail work you add next stays predictable and easy to maintain.
  2. A transition is helpful when it gives the user a clear signal that something responded to their action, like a button hover or a card lift. It gets in the way when it slows down navigation, distracts from content, or runs on every property change including layout shifts.
  3. It protects users who experience motion sensitivity, vestibular disorders, or simply prefer a calmer interface. When this preference is active, your CSS should disable or reduce transitions, transforms, and animations so the site stays comfortable and accessible.

How confident are you with this concept?

😕 Still confused | 🤔 Getting there | 😊 Got it! | 🎉 Could explain it to a friend!

Polish the BSB Homepage

Work through these four steps on the BSB homepage. Each step corresponds to one of the four passes.

Audit one page for specificity problems

Open DevTools on the BSB homepage. Find one element where a style is being overridden. Check the Styles panel to see which selector wins and why.

If the winning selector uses an ID or a long chain like .hero .container .section-title, rewrite it using a single class. Confirm the visual result stays the same.

💡 Need a hint?
Look for crossed-out styles in the Styles panel — those are the losing rules.
A single class like .hero-title is almost always better than a long chain of descendant selectors.

Add a hover transition to navigation links

In your shared stylesheet, find the .site-nav__link rule. Add a colour or border-bottom change on hover, with a transition:

.site-nav__link {
  transition: color 0.2s ease;
}

.site-nav__link:hover {
  color: var(--color-golden-orange);
}

Check that the active link still looks distinct from the hover state.

💡 Need a hint?
Keep the transition under 0.3s — navigation should feel instant, not sluggish.
Only transition the property you are changing. Avoid transition: all.

Add a subtle card lift on hover

Find your .menu-card component rule. Add a transform and box-shadow on hover:

.menu-card {
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.menu-card:hover,
.menu-card:focus-within {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

The lift should be small — just enough to signal interactivity.

💡 Need a hint?
translateY(-2px) is subtle. More than -4px starts to look jumpy.
Test with your keyboard too — :hover alone does not help keyboard users. Consider adding :focus-within if the card contains a link.

Wrap motion in a reduced-motion guard

At the end of your stylesheet, add a media query that removes or reduces all transitions and transforms when the user prefers reduced motion:

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

Test by enabling "Reduce motion" in your operating system accessibility settings or in DevTools under Rendering.

💡 Need a hint?
Setting duration to 0.01ms instead of 0s avoids breaking JavaScript that listens for transitionend events.
In macOS: System Settings → Accessibility → Display → Reduce motion. In DevTools: Rendering panel → Emulate CSS media feature prefers-reduced-motion.

You know it is working when:

  • ☐ At least one specificity problem is identified and fixed
  • ☐ Navigation links have a visible hover transition
  • ☐ Menu cards lift subtly on hover with transform and box-shadow
  • ☐ A prefers-reduced-motion query disables all transitions and transforms
  • ☐ The page looks and feels the same as before, but interactions are smoother

💪 Independent Challenge

Now try this on your own without hints!

Your Task:

Apply the same four-pass polish workflow to the remaining BSB pages (menu, about, and contact). Since they share the same stylesheet, some of your homepage changes will already apply. Focus on any page-specific elements that still need hover states, focus styles, or decorative touches.
Requirements:
  • Every interactive element on every page has a visible :hover and :focus-visible state
  • At least one pseudo-element adds a decorative detail that improves visual hierarchy
  • All transitions use specific properties (not transition: all) and stay under 0.3s
  • The prefers-reduced-motion query covers every transition and animation on the site
  • Keyboard navigation works on every page with visible focus indicators
Stretch Goals (Optional):
  • Add a ::before or ::after accent to the active navigation link that shows only on the current page
  • Use :first-child or :last-child to remove border or margin from the first/last card in a grid
  • Add a subtle scale transform to buttons on :active so they feel like they press inward

Success Criteria:

CriteriaYou've succeeded if...
Specificity cleanupNo unnecessary ID selectors or long descendant chains remain in the shared stylesheet.
Interaction statesEvery link, button, and interactive card has visually distinct hover and focus states.
Motion restraintTransitions are fast, purposeful, and limited to specific properties.
Accessibilityprefers-reduced-motion disables all motion. Focus-visible styles work on every interactive element.
Overall feelThe site feels considered and professional without being over-decorated.

Recap

In this tutorial, you applied a structured polish workflow to the Black Swan Bistro site:

  1. Cascade cleanup made the stylesheet easier to work with by removing specificity conflicts
  2. Detail selectors added hover, focus, and decorative refinements
  3. Restrained motion gave interactive elements smooth, purposeful transitions
  4. Final review checked accessibility, consistency, and overall feel

This four-pass structure is not specific to the bistro. You can apply it to any project when the layout is working but the experience is not yet polished.

Lesson Complete: What You Learned

Key Takeaways:

  • Polish is deliberate refinement, not decoration — every change should solve a real problem or improve a real interaction.
  • Cascade cleanup comes first because high-specificity CSS makes every future change harder.
  • Pseudo-classes and pseudo-elements add detail without adding HTML clutter.
  • Transitions and transforms should be restrained: fast, purposeful, and limited to interactive moments.
  • The prefers-reduced-motion query is not optional — it is an accessibility requirement for any site with motion.
  • A Polish Pass is something you can repeat with every project: audit, detail, motion, review.

Learning Objectives Review:

Look back at what you set out to learn. Can you now:

  • ✅ Audit and simplify CSS specificity across a multi-page site Check!
  • ✅ Use pseudo-classes and pseudo-elements to refine interactive and decorative details Got it!
  • ✅ Add restrained transitions and transforms to interactive components Can explain it!
  • ✅ Guard all motion with the prefers-reduced-motion media query Could teach this!
  • ✅ Apply a structured polish workflow that can carry forward to future projects Check!

If you can confidently answer "yes" to most of these, you're ready to move on!

Think & Reflect:

Cascade Thinking

  • Which specificity problem was the most surprising when you audited your stylesheet?
  • How did simplifying selectors change how easy it was to add the hover and motion work?

Detail and Motion

  • Which transition or pseudo-element made the biggest difference for the smallest amount of CSS?
  • Where did you decide not to add motion, and why?

Looking Ahead

  • How would you apply this same four-pass polish workflow to a different project?
  • What parts of the BSB site would benefit from JavaScript interaction that CSS alone cannot provide?

Recommended Next Steps

Continue Learning

Ready to move forward? Continue with the next tutorial in this series:

Black Swan Bistro — Part 5 (Prepare for Deployment)

Progress tracking is disabled. Enable it in to track your completed tutorials.