CSS Exercises
Practise what you've learned. Type the missing piece into each highlighted gap and press Check. Further down are styling challenges with live editors and model solutions.
Fill in the blanks
Syntax and selectors
Link an external stylesheet from the HTML head.
<link ="stylesheet" href="styles.css">
rel="stylesheet" tells the browser what the linked file is (lesson 02).
Select every element with the class "note".
{ color: #565d72; }
A dot selects by class (lesson 03).
Select the element with the id "header".
{ padding: 1rem; }
A hash selects by id (lesson 03).
Select only paragraphs that are direct children of an article.
article p { margin-top: 0; }
> is the child combinator (lesson 04).
Select links whose href starts with "https".
a[href"https"] { color: green; }
^= means "starts with" (lesson 04).
Style a button when the mouse is over it.
button: { background: #164c91; }
:hover is a user-action pseudo-class (lesson 05).
Select every odd row of a table.
tr:nth-child() { background: #f4f6fa; }
odd and 2n+1 are equivalent (lesson 05).
Insert generated content before each item.
li:: { content: "→ "; }
::before needs a content property (lesson 06).
Values and colour
Size the text relative to the root font size.
h1 { font-size: 2.5; }
rem respects the user's font-size settings (lesson 09).
Make a semi-transparent black using the modern rgb() syntax.
.overlay { background: rgb(0 0 0 50%); }
The slash separates the alpha value (lesson 10).
Create a gradient that goes from left to right.
.bar { background: (to right, #1a5fb4, #d6336c); }
Gradients are images, so they go in background (lesson 12).
Use the custom property --brand.
a { color: (--brand); }
var() reads a custom property (lesson 13).
Make the heading size fluid, between 1.5rem and 3rem.
h1 { font-size: (1.5rem, 1rem + 3vw, 3rem); }
clamp(min, preferred, max) (lesson 14).
Boxes and text
Make width include padding and border.
*, *::before, *::after { box-sizing: ; }
The most common line in any reset (lesson 17).
Centre a block horizontally.
.container { max-width: 60rem; margin-inline: ; }
Auto margins share the free space (lesson 15).
Round the corners of a card.
.card { : 12px; }
(lesson 18)
Add a soft shadow.
.card { : 0 4px 12px rgb(0 0 0 / 15%); }
offset-x, offset-y, blur, colour (lesson 18).
Show an ellipsis when text overflows one line.
.title { white-space: nowrap; overflow: hidden; text-overflow: ; }
All three declarations are needed (lesson 17).
Keep text visible while a web font loads.
@font-face { font-family: "Inter"; src: url("inter.woff2") format("woff2"); font-display: ; }
swap shows fallback text immediately (lesson 20).
Layout
Turn the container into a flex container.
.nav { display: ; gap: 1rem; }
(lesson 27)
Push flex items to opposite ends of the main axis.
.header { display: flex; justify-content: ; }
(lesson 27)
Let a flex item grow to fill the remaining space.
.search { flex: ; }
flex: 1 means grow 1, shrink 1, basis 0 (lesson 28).
Create three equal grid columns.
.grid { display: grid; grid-template-columns: repeat(3, 1); }
fr shares the free space (lesson 29).
Make as many 200px-minimum columns as fit.
.cards { display: grid; grid-template-columns: repeat(, minmax(200px, 1fr)); }
A responsive grid with no media queries (lesson 29).
Centre a child both ways inside a grid container.
.box { display: grid; : center; }
Shorthand for align-items and justify-items (lesson 31).
Keep the header at the top while scrolling.
.header { position: ; top: 0; }
Sticky needs an offset like top (lesson 24).
Apply styles only on screens at least 768px wide.
@media () { .sidebar { display: block; } }
Both syntaxes work in current browsers (lesson 32).
Make the card a size container.
.card-wrap { : inline-size; }
Required before @container queries can match (lesson 33).
Effects and modern CSS
Animate the colour change over 0.3 seconds.
a { transition: 0.3s ease; }
(lesson 37)
Define the keyframes for the "spin" animation.
@ spin { to { rotate: 1turn; } }
(lesson 38)
Crop an image to fill its box without distortion.
img { width: 100%; height: 200px; object-fit: ; }
(lesson 41)
Style a card that contains an image.
.card:(img) { border-color: #1a5fb4; }
:has() is the parent selector (lesson 43).
Write a zero-specificity selector for base styles.
:(.card) p { color: #565d72; }
(lesson 43)
Refer to the parent selector in a nested rule.
.btn { :hover { background: #164c91; } }
(lesson 44)
Declare the order of cascade layers.
reset, base, components, utilities;
Later layers win (lesson 45).
Give a colour different values in light and dark mode.
body { color: (#10131c, #e8eaf2); }
Requires color-scheme: light dark (lesson 46).
Show a focus ring only for keyboard focus.
button: { outline: 3px solid #1a5fb4; }
(lesson 48)
Styling challenges
1. A profile card
Style the card: centred with a maximum width of 280px, rounded corners, a shadow, a circular avatar, and a button that changes colour on hover.
Show a model solution
.profile {
max-width: 280px;
margin: 2rem auto;
padding: 1.5rem;
text-align: center;
font-family: system-ui, sans-serif;
border-radius: 16px;
box-shadow: 0 6px 20px rgb(0 0 0 / 12%);
}
.avatar {
width: 96px;
height: 96px;
border-radius: 50%;
object-fit: cover;
}
.profile h2 {
margin: 0.5rem 0 0;
}
.profile p {
margin: 0.25rem 0 1rem;
color: #565d72;
}
.follow {
display: inline-block;
padding: 0.5em 1.4em;
border-radius: 999px;
background: #1a5fb4;
color: white;
text-decoration: none;
transition: background 0.2s;
}
.follow:hover {
background: #164c91;
}
2. A navigation bar
Lay out the logo on the left and the links on the right with Flexbox. Remove the list bullets, add space between links, and on screens narrower than 500px stack everything vertically.
Show a model solution
.site-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
background: #10131c;
font-family: system-ui, sans-serif;
}
.site-header a {
color: white;
text-decoration: none;
}
.logo {
font-weight: 800;
}
.links {
display: flex;
gap: 1.25rem;
margin: 0;
padding: 0;
list-style: none;
}
@media (width < 500px) {
.site-header,
.links {
flex-direction: column;
gap: 0.5rem;
}
}
3. A photo grid
Create a responsive grid where each column is at least 150px wide, images are square and cropped neatly, and the first image spans two columns and two rows.
Show a model solution
.photos {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
grid-auto-flow: dense;
gap: 8px;
}
.photos img {
width: 100%;
height: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 8px;
}
.photos img:first-child {
grid-column: span 2;
grid-row: span 2;
}
4. A themed alert with an entrance animation
Style the alerts with a coloured left border driven by a custom property, different colours for success and error, and a short slide-in animation that is turned off for users who prefer reduced motion.
Show a model solution
.alert {
--tone: #1a5fb4;
margin-bottom: 8px;
padding: 10px 14px;
border-inline-start: 5px solid var(--tone);
border-radius: 6px;
background: color-mix(in oklch, var(--tone), white 90%);
font-family: system-ui, sans-serif;
animation: slide-in 0.4s ease-out;
}
.alert.success {
--tone: #1e6b3c;
}
.alert.error {
--tone: #a12222;
}
@keyframes slide-in {
from {
opacity: 0;
translate: -20px 0;
}
}
@media (prefers-reduced-motion: reduce) {
.alert {
animation: none;
}
}