CSS Coding Problems & Solutions

Master CSS from selectors to Grid layouts with 150 hands-on coding problems. Each exercise shows a common mistake and the correct modern CSS solution. Click any problem to expand.

Module 1 – CSS Fundamentals

Learn proper CSS syntax, linking stylesheets, colour values, units of measurement, and basic property declarations.

Problem 1: Link an external stylesheet correctly

Use a <link> element with the correct rel attribute. A <style> tag imports CSS inline, not from an external file.

Common Mistake
<style src="styles.css"></style>
Correct Solution
<link rel="stylesheet" href="styles.css">
Problem 2: Use correct CSS property syntax

CSS declarations use colons between property and value, and semicolons to terminate each declaration.

Common Mistake
h1 {
  color = blue
  font-size = 24px
}
Correct Solution
h1 {
  color: blue;
  font-size: 24px;
}
Problem 3: Use modern colour formats

Prefer HSL or hex values over named colours for precise brand consistency across browsers.

Common Mistake
.btn {
  background-color: red;
  color: darkblue;
}
Correct Solution
.btn {
  background-color: hsl(0, 84%, 60%);
  color: #1e3a5f;
}
Problem 4: Use rem units instead of px for scalable typography

Pixel units don't scale with user font preferences. Use rem for font sizing to respect accessibility settings.

Common Mistake
body { font-size: 16px; }
h1 { font-size: 32px; }
p { font-size: 14px; }
Correct Solution
html { font-size: 100%; } /* 16px default */
h1 { font-size: 2rem; }   /* 32px equivalent */
p { font-size: 0.875rem; } /* 14px equivalent */

Module 2 – Selectors & Specificity

Master CSS selectors, class vs ID targeting, pseudo-classes, combinators, and the specificity cascade hierarchy.

Problem 1: Avoid using IDs for styling

ID selectors have extremely high specificity, making them hard to override. Use classes for styling and reserve IDs for JavaScript hooks.

Common Mistake
#main-button {
  background: blue;
  padding: 10px 20px;
}
Correct Solution
.btn-primary {
  background: blue;
  padding: 10px 20px;
}
Problem 2: Use pseudo-classes for interactive states

Apply :hover, :focus, and :active pseudo-classes instead of JavaScript class toggles for basic interaction states.

Common Mistake
.link {
  color: blue;
}
.link-hovered {
  color: darkblue;
  /* Requires JavaScript to add this class */
}
Correct Solution
.link {
  color: blue;
  transition: color 0.2s ease;
}
.link:hover,
.link:focus {
  color: darkblue;
}
Problem 3: Avoid over-qualified selectors

Deeply nested selectors increase specificity unnecessarily and create brittle CSS. Keep selectors flat and descriptive.

Common Mistake
body div.container section.hero div.content h1.title {
  font-size: 2rem;
}
Correct Solution
.hero-title {
  font-size: 2rem;
}
Problem 4: Use :nth-child() for pattern-based styling

Instead of adding classes like .odd and .even manually, leverage CSS structural pseudo-classes.

Common Mistake
<tr class="odd">...</tr>
<tr class="even">...</tr>
<tr class="odd">...</tr>
Correct Solution
tr:nth-child(even) {
  background-color: #f9fafb;
}
tr:nth-child(odd) {
  background-color: #ffffff;
}

Module 3 – Box Model & Layout

Understand margin, padding, border, box-sizing, display modes, and the document flow model for pixel-perfect layouts.

Problem 1: Set box-sizing to border-box globally

Without border-box, padding and border add to the element's width, breaking layouts unexpectedly.

Common Mistake
.card {
  width: 300px;
  padding: 20px;
  border: 2px solid #ccc;
  /* Total rendered width: 344px, not 300px! */
}
Correct Solution
*, *::before, *::after {
  box-sizing: border-box;
}
.card {
  width: 300px;
  padding: 20px;
  border: 2px solid #ccc;
  /* Total rendered width: 300px exactly */
}
Problem 2: Collapsing margins between siblings

Vertical margins between adjacent block elements collapse to the larger value. Use padding or gap instead when spacing needs to be exact.

Common Mistake
.section-a { margin-bottom: 40px; }
.section-b { margin-top: 30px; }
/* Gap between them is 40px, not 70px — margins collapse! */
Correct Solution
.sections-wrapper {
  display: flex;
  flex-direction: column;
  gap: 40px; /* Flex gap doesn't collapse */
}
Problem 3: Centre a div horizontally

Horizontal centring requires margin: 0 auto plus a defined width, or use Flexbox for more control.

Common Mistake
.container {
  text-align: center; /* Only centres inline content, not the div itself */
}
Correct Solution
.container {
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
}

Module 4 – Flexbox

Build flexible, one-dimensional layouts using Flexbox alignment, distribution, wrapping, and ordering properties.

Problem 1: Centre content both horizontally and vertically

The classic centring problem is solved cleanly with three Flexbox properties on the parent container.

Common Mistake
.hero {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* Works but creates positioning context issues */
}
Correct Solution
.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
Problem 2: Create a responsive card row with flex-wrap

Without flex-wrap, children overflow the container on small screens. Always enable wrapping for responsive card grids.

Common Mistake
.card-row {
  display: flex;
  /* Items overflow on mobile — no wrapping! */
}
.card { width: 300px; }
Correct Solution
.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
}
.card {
  flex: 1 1 300px; /* Grow, shrink, min 300px */
}
Problem 3: Push an element to the far right with margin-left auto

Use margin-left: auto on a flex child to push it to the end without adding spacer elements or using float.

Common Mistake
.nav {
  display: flex;
}
.nav-cta {
  float: right; /* Float doesn't work inside flex */
}
Correct Solution
.nav {
  display: flex;
  align-items: center;
}
.nav-cta {
  margin-left: auto;
}

Module 5 – CSS Grid

Create complex two-dimensional page layouts using CSS Grid template areas, fractional units, auto-fit, and minmax functions.

Problem 1: Create a responsive grid without media queries

Combine auto-fit with minmax() to create grids that automatically reflow without breakpoints.

Common Mistake
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  /* Breaks on mobile — always 3 columns! */
}
Correct Solution
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}
Problem 2: Use grid-template-areas for semantic layouts

Named grid areas make complex layouts readable and maintainable compared to line-number positioning.

Common Mistake
.header { grid-column: 1 / 4; grid-row: 1; }
.sidebar { grid-column: 1; grid-row: 2 / 4; }
.main { grid-column: 2 / 4; grid-row: 2; }
Correct Solution
.page {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main main"
    "footer footer footer";
  grid-template-columns: 250px 1fr 1fr;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
Problem 3: Use gap instead of margins for grid spacing

Using margins creates uneven spacing at edges. The gap property provides consistent gutters between grid items only.

Common Mistake
.grid-item {
  margin: 12px;
  /* Creates 24px gap between items but also 12px around edges */
}
Correct Solution
.grid {
  display: grid;
  gap: 24px; /* Only between items, not at edges */
}

Module 6 – Responsive Design

Build mobile-first layouts using media queries, fluid typography, responsive images, and modern viewport units.

Problem 1: Write mobile-first media queries

Start with mobile styles as defaults, then layer on complexity for larger screens using min-width breakpoints.

Common Mistake
/* Desktop-first — styles break on mobile */
.grid { display: grid; grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 768px) {
  .grid { grid-template-columns: 1fr; }
}
Correct Solution
/* Mobile-first — single column default */
.grid { display: grid; gap: 24px; }
@media (min-width: 768px) {
  .grid { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1024px) {
  .grid { grid-template-columns: 1fr 1fr 1fr; }
}
Problem 2: Use clamp() for fluid typography

The clamp() function creates smoothly scaling font sizes without media query breakpoints.

Common Mistake
h1 { font-size: 24px; }
@media (min-width: 768px) { h1 { font-size: 36px; } }
@media (min-width: 1200px) { h1 { font-size: 48px; } }
Correct Solution
h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
  /* Min: 24px, scales with viewport, max: 48px */
}
Problem 3: Make images responsive

Images with fixed width overflow their containers on small screens. Always constrain with max-width.

Common Mistake
img {
  width: 800px;
  height: 600px;
}
Correct Solution
img {
  max-width: 100%;
  height: auto;
  display: block;
}

Module 7 – Animations & Transitions

Add smooth transitions, keyframe animations, hover effects, and performance-optimised motion to your elements.

Problem 1: Use transition on the base state, not the hover state

Transitions declared on :hover only animate in, not out. Place them on the base selector for both directions.

Common Mistake
.card:hover {
  transform: translateY(-8px);
  transition: transform 0.3s ease;
  /* Snaps back instantly on mouse-out! */
}
Correct Solution
.card {
  transition: transform 0.3s ease;
}
.card:hover {
  transform: translateY(-8px);
}
Problem 2: Only animate GPU-accelerated properties

Animating width, height, top, or left causes layout thrashing. Use transform and opacity for smooth 60fps animations.

Common Mistake
.slide-in {
  animation: slideIn 0.5s ease;
}
@keyframes slideIn {
  from { left: -100%; }
  to { left: 0; }
}
Correct Solution
.slide-in {
  animation: slideIn 0.5s ease;
}
@keyframes slideIn {
  from { transform: translateX(-100%); }
  to { transform: translateX(0); }
}
Problem 3: Respect user motion preferences

Some users have vestibular disorders. Always provide a prefers-reduced-motion media query to disable animations.

Best Practice
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

Module 8 – CSS Variables & Best Practices

Use CSS custom properties for theming, implement a consistent design system, and follow maintainable coding standards.

Problem 1: Define a design system with CSS custom properties

Hard-coded colour values scattered across files create inconsistency. Define variables on :root for a single source of truth.

Common Mistake
.header { background: #1e3a8a; }
.footer { background: #1e3a8a; }
.btn { background: #1e3a8a; }
/* Same colour repeated — hard to update globally */
Correct Solution
:root {
  --color-primary: #1e3a8a;
  --color-primary-light: #3b82f6;
  --radius-md: 12px;
  --shadow-sm: 0 2px 8px rgba(0,0,0,0.08);
}
.header { background: var(--color-primary); }
.btn { background: var(--color-primary); }
.btn:hover { background: var(--color-primary-light); }
Problem 2: Implement dark mode with CSS variables

Override custom properties inside a prefers-color-scheme media query to implement dark mode with zero duplication.

Best Practice
:root {
  --bg: #ffffff;
  --text: #1f2937;
  --surface: #f9fafb;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #111827;
    --text: #f9fafb;
    --surface: #1f2937;
  }
}
body {
  background: var(--bg);
  color: var(--text);
}
Problem 3: Avoid using !important

Using !important is almost always a sign of a specificity problem. Fix the cascade instead of forcing overrides.

Common Mistake
.nav-link {
  color: red !important;
  font-size: 18px !important;
  padding: 10px !important;
  /* Can't be overridden easily in future */
}
Correct Solution
/* Use a more specific selector or reorder stylesheets */
.site-header .nav-link {
  color: red;
  font-size: 18px;
  padding: 10px;
}