01. The Brand Button
We have a variable --brand-pink defined globally.
Update this boring grey button to use the brand color variable.
background-color: ;
}
var() function. Syntax: var(--variable-name)
CSS custom properties (a.k.a. variables) let you store a value once and reuse it everywhere. You define one with two dashes — usually on :root so the whole page can see it: --brand-pink: #ec4899;. To use it, wrap the name in var(). Change the value in one place and every element that references it updates automatically — that's how design systems stay consistent.
02. Soften the Edges
Design wants consistent rounded corners. Use the variable --card-radius
to round the corners of this sharp card.
border-radius: ;
}
border-radius. The variable is --card-radius.
border-radius rounds an element's corners. The value can be pixels (12px), a percentage (50% turns a square into a circle), or — like here — a variable so every card shares the exact same curve. Pulling it from --card-radius means you can re-tune roundness across the whole site by editing one line.
Hello World
I am currently very sharp.
03. Variable Size
This profile picture is too small. We have a variable --avatar-size (which is 80px).
Apply it to both width and height.
width: ;
height: ;
}
var(--avatar-size).
width and height set an element's box size. When you feed both the same variable, the element stays a perfect square no matter what value the variable holds. That's why avatars use a single --avatar-size token: you can resize every avatar across the site by changing one number.
04. The Background Video
We want this video to act like a background. It needs to play automatically, loop forever, and be silent.
></video>
autoplay, loop, and muted.
HTML media is configured with attributes, not CSS. autoplay starts playback immediately, loop restarts it endlessly, and muted kills the sound. The gotcha: modern browsers block autoplay unless the video is also muted — so background videos always need all three together.
HERO TITLE
05. The Podcast Player
This audio file is invisible! Add the attribute to let users see the play/pause buttons.
></audio>
controls.
An <audio> (or <video>) element renders nothing visible on its own. Adding the boolean attribute controls tells the browser to draw its built-in play / pause / volume UI. Boolean attributes don't need a value — the word alone switches them on.
06. Fix the Squish
We forced this image into a square, and now it looks terrible. Use CSS to make it fill the box without distortion.
width: 200px; height: 200px;
object-fit: ;
}
cover or contain. Which one fills the box?
When an image is forced into a box that doesn't match its proportions, the default behavior squishes it. object-fit fixes that: cover fills the whole box and crops the overflow (no distortion), while contain shrinks the image until it fits entirely (may leave gaps). For thumbnails and hero images you almost always want cover.
07. Smooth Navigation
When hovering this link, the color snaps instantly. Add a transition to make it fade over 0.5 seconds.
color: gray;
transition: ;
}
color 0.5s (or all 0.5s).
By default, CSS changes happen instantly. transition animates them over time so they feel smooth. The shorthand is property duration — color 0.5s fades the color over half a second, or all 0.5s animates every property that changes. Note: it lives on the element's normal state, not the :hover — the transition describes how to get to and from the hover.
08. The Heartbeat
Make the heart grow bigger when hovered. Use transform to make it 1.2x size.
transform: ;
}
scale(). For example: scale(1.5)
transform lets you visually scale, rotate, or move an element without affecting the layout around it. scale(1.2) grows it to 120% of its size, out from the center. Put it on :hover and pair it with a transition for that satisfying grow-on-hover effect.
09. Spin to Refresh
Make the refresh icon spin 180 degrees when hovered.
transform: ;
}
rotate() with an angle in degrees: rotate(180deg).
rotate() is a transform function that spins an element around its center. The angle is measured in degrees: rotate(180deg) is a half turn, rotate(360deg) a full spin. Combine it with a transition so the rotation animates instead of snapping.
10. The Lift Off
Make this Submit button move UP by 5 pixels when hovered to create a 3D "lift" effect.
transform: ;
}
translateY(-10px)
translate() moves an element from where it sits. translateY() handles vertical motion, and because the Y axis points down, a negative value moves the element up — translateY(-5px) lifts it 5px. Unlike changing margin or top, transforms don't disturb neighboring elements, which makes them perfect for hover lifts.