CPCODELAB
Practice

Practice CSS

You’ve read the lessons — now prove it. Take the quiz for instant feedback, then work the coding exercises. Try each one yourself before you reveal the solution.

Quick quiz

18 questions
Score: 0 / 18
0/18 answered
  1. 1

    Which CSS selector has the highest specificity?

  2. 2

    What does box-sizing: border-box do?

  3. 3

    Given margin: 10px 20px 30px, what is the left margin?

  4. 4

    Which value of position removes an element from normal document flow and positions it relative to the nearest positioned ancestor?

  5. 5

    What CSS property controls the stacking order of positioned elements?

  6. 6

    In a flex container with justify-content: space-between, where are the first and last items placed?

  7. 7

    What does flex: 1 expand to?

  8. 8

    Which CSS Grid property defines the number and size of columns?

  9. 9

    What unit is 1rem relative to?

  10. 10

    Which pseudo-class targets an element only when it receives keyboard focus?

  11. 11

    What does the CSS rule transition: opacity 0.3s ease do?

  12. 12

    Which media query activates styles for screens narrower than 768px?

  13. 13

    What does animation-fill-mode: both do?

  14. 14

    Which CSS function clamps a value between a minimum and maximum?

  15. 15

    What does filter: drop-shadow(...) do differently from box-shadow?

  16. 16

    What CSS property must you set on a parent element to make it a container query context?

  17. 17

    Inside calc(), which of the following is valid CSS?

  18. 18

    What is the purpose of @property in CSS?

🛠️

Coding exercises

8 tasks
1

Fluid Typography with clamp()

Medium

Write CSS so that .hero-title has a font size that is never smaller than `1.5rem` and never larger than `3.5rem`, scaling smoothly based on the viewport width. Use clamp() with a viewport-relative preferred value of 3vw + 1rem. Also set line-height: 1.15 and letter-spacing: -0.02em.

💡 Show hint

The syntax is clamp(min, preferred, max). Combine a vw unit with a rem inside the preferred value using calc() or the + operator directly inside clamp().

✅ Show solution
css
.hero-title {
  font-size: clamp(1.5rem, 3vw + 1rem, 3.5rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
}
2

Glassmorphism Card

Medium

Style a .glass-card element to look like frosted glass. It should have: a semi-transparent white background (rgba(255,255,255,0.15)), a light white border (1px solid rgba(255,255,255,0.25)), 16px border radius, 2rem padding, and a backdrop blur of 20px that blurs whatever is behind it. Include the -webkit- prefixed fallback.

💡 Show hint

Use backdrop-filter: blur(20px) and also add -webkit-backdrop-filter: blur(20px) for Safari support.

✅ Show solution
css
.glass-card {
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 16px;
  padding: 2rem;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
3

Container Query Card

Hard

Set up a .card-wrapper as a named container called "card" with inline-size containment. Inside it, write a @container rule so that when the wrapper is at least 420px wide, the .card switches from a single-column grid to a two-column grid with columns "100px 1fr" and a 1rem gap. By default .card should be display: grid; grid-template-columns: 1fr; gap: 1rem;.

💡 Show hint

Use container: card / inline-size on the wrapper, then write @container card (min-width: 420px) { .card { ... } }.

✅ Show solution
css
.card-wrapper {
  container: card / inline-size;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@container card (min-width: 420px) {
  .card {
    grid-template-columns: 100px 1fr;
    gap: 1rem;
  }
}
4

Style a Navigation Bar

Easy

Given an <ul> with class nav, write CSS to display the list items horizontally in a row with no bullets, a dark background (#1a1a2e), and white links. Each list item should have 16px horizontal padding.

Starter
css
/* Style the nav */
.nav {

}

.nav li {

}

.nav a {

}
💡 Show hint

Use display: flex on .nav and list-style: none to remove bullets. Set text-decoration: none on links.

✅ Show solution
css
.nav {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  background-color: #1a1a2e;
}

.nav li {
  padding: 0 16px;
}

.nav a {
  color: #ffffff;
  text-decoration: none;
  display: block;
  padding: 12px 0;
}
5

Centered Card with Box Model

Easy

Write CSS for a .card element that is 400px wide, has 24px padding, a 1px solid #e2e8f0 border, 8px border radius, and is horizontally centered on the page. Ensure padding does not add to the total width.

💡 Show hint

Use box-sizing: border-box to keep the total width at 400px. Use margin: 0 auto to center a block element.

✅ Show solution
css
.card {
  box-sizing: border-box;
  width: 400px;
  padding: 24px;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  margin: 0 auto;
}
6

Flexbox Holy Grail Layout

Medium

Create a classic holy grail layout with three columns using Flexbox. The .layout container holds .sidebar-left (200px wide), .main (takes all remaining space), and .sidebar-right (200px wide). All columns should stretch to the same height. Add 16px gap between columns.

Starter
css
.layout {

}

.sidebar-left,
.sidebar-right {

}

.main {

}
💡 Show hint

Set display: flex on .layout. Use flex: 1 on .main so it grows to fill available space. Use a fixed width or flex: 0 0 200px on the sidebars.

✅ Show solution
css
.layout {
  display: flex;
  align-items: stretch;
  gap: 16px;
}

.sidebar-left,
.sidebar-right {
  flex: 0 0 200px;
  width: 200px;
}

.main {
  flex: 1;
  min-width: 0;
}
7

Responsive Image Grid

Medium

Write CSS for a .gallery container that displays .gallery-item elements in a responsive grid. On screens wider than 768px, show 3 equal columns with 16px gap. On smaller screens, show 1 column. Each item should have a fixed height of 200px and the image inside (.gallery-item img) should cover the entire item without distortion.

💡 Show hint

Use grid-template-columns: repeat(3, 1fr) for the 3-column layout and a @media query for the 1-column fallback. Use object-fit: cover on the img.

✅ Show solution
css
.gallery {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.gallery-item {
  height: 200px;
  overflow: hidden;
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

@media (min-width: 768px) {
  .gallery {
    grid-template-columns: repeat(3, 1fr);
  }
}
8

Animated Tooltip with Pseudo-elements

Hard

Create a CSS-only tooltip for a .tooltip-trigger element. The tooltip text is stored in a data-tip attribute. When the user hovers over .tooltip-trigger, a tooltip box should appear above the element using ::before (the bubble) and ::after (a small arrow pointing down). The tooltip should fade in using a CSS transition (opacity from 0 to 1 over 0.2s). Use position: absolute for the tooltip and ensure .tooltip-trigger is the positioning context. Do not use JavaScript.

Starter
css
/* The trigger element already has position: relative */
.tooltip-trigger {
  position: relative;
  cursor: pointer;
  display: inline-block;
}

/* Tooltip bubble */
.tooltip-trigger::before {

}

/* Arrow */
.tooltip-trigger::after {

}

/* Show on hover */
.tooltip-trigger:hover::before,
.tooltip-trigger:hover::after {

}
💡 Show hint

Use content: attr(data-tip) on ::before to pull text from the attribute. Position both pseudo-elements with position: absolute; bottom: 100%. Start with opacity: 0 and pointer-events: none, then set opacity: 1 on hover. Use border tricks on ::after to create the arrow triangle.

✅ Show solution
css
.tooltip-trigger {
  position: relative;
  cursor: pointer;
  display: inline-block;
}

.tooltip-trigger::before {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background-color: #1a1a2e;
  color: #ffffff;
  padding: 6px 10px;
  border-radius: 4px;
  white-space: nowrap;
  font-size: 0.875rem;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 10;
}

.tooltip-trigger::after {
  content: "";
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-top-color: #1a1a2e;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 10;
}

.tooltip-trigger:hover::before,
.tooltip-trigger:hover::after {
  opacity: 1;
}