By the end of this lesson you will be able to
- Explain why a page must adapt to different screen sizes.
- Add the viewport meta tag and write a media query with a breakpoint.
- Make a layout change from one column to several as the screen widens.
- Style hover and focus states for links and buttons.
- Explain why removing the focus outline harms keyboard users.
People read your page on a phone in a queue, on a laptop at home and on a big screen at work. A page that looks fine on one can be unreadable on another. Responsive design means writing one page that adapts to the space it has. The second half of this lesson is about states: how a button or link looks when the pointer is over it or when a keyboard user has landed on it, which is a matter of comfort for some and of access for others.
One page, many screens
Responsive design means a page changes its layout to suit the width of the screen. The approach most people recommend is mobile first: write the simple, one-column layout for a phone first, then add rules for larger screens. A phone layout is the hardest to get right, and starting there keeps pages fast and readable.
Two things make this work. First, the viewport tag in the head, <meta name="viewport" content="width=device-width, initial-scale=1">. Without it, many phones pretend the screen is much wider and shrink the whole page to fit, so text becomes tiny. Second, flexible sizes: use max-width: 100% for images, rem for text and a grid or flex layout that can wrap, rather than fixed pixel widths.
img {
max-width: 100%;
height: auto;
}Media queries and breakpoints
A Media query is a conditional CSS block: the rules inside apply only when the condition is true. The most common condition is a minimum width. The query @media (min-width: 40rem) { ... } means "when the viewport is at least 40rem (about 640 pixels) wide, apply these rules". The width at which the layout changes is called a breakpoint. Choose breakpoints where your content starts to look wrong, not at the sizes of particular devices.
.cards {
display: grid;
gap: 12px;
}
@media (min-width: 40rem) {
.cards {
grid-template-columns: 1fr 1fr 1fr;
}
}Read it as a story. By default, the cards are in a grid with no column rule, so each sits on its own row, which is the phone layout. When the screen reaches 40rem, the media query switches on and the same grid gets three equal columns. You write the small version first and only add what changes.
- Is the screen at least 40rem wide?
- YesDo thisThree columns (laptop)
- NoDo thisOne column (phone)
Read this figure as text
A yes or no tree asking whether the screen is at least 40rem wide and showing one column or three columns.
Start with the question: is the screen at least 40rem wide? If no, the browser uses the default rules and shows the cards in one column, the phone layout. If yes, the browser also applies the media query rules and shows the cards in three columns, the laptop layout. The browser checks again whenever the window is resized.
- Menu links stacked
- One column of cards
- Big touch-friendly buttons
- Same HTML
- Menu links in a row
- Three columns of cards
- More space around text
- Same HTML
Read this figure as text
Two columns comparing the layout of one page on a phone screen and on a laptop screen.
Left column, Phone, narrow screen: menu links stacked, one column of cards, large touch-friendly buttons, text size unchanged. Right column, Laptop, wide screen: menu links in a row, three columns of cards, more space around the text. The HTML is identical in both; only the CSS rules that apply are different.
Hover and focus states
Elements can have states, and CSS reaches them with a colon and a keyword called a pseudo-class. :hover applies while the mouse pointer is over an element. :focus applies while an element has keyboard focus, for example after someone presses the Tab key to reach a link or a form field. :focus-visible applies focus styles only when the browser decides a visible indicator is needed, which is mainly for keyboard use. :active applies while a button is being pressed.
.button {
background-color: #1b5e20;
color: #ffffff;
padding: 10px 16px;
border-radius: 6px;
text-decoration: none;
}
.button:hover {
background-color: #2e7d32;
}
.button:focus-visible {
outline: 3px solid #ffb300;
outline-offset: 2px;
}The hover rule is a nice touch, but on a phone there is no pointer, so never hide important information behind hover. The focus rule matters more. A keyboard user, or anyone who cannot use a mouse, relies on the focus outline to know where they are on the page, as you can only see where you are by seeing the highlight. Browsers draw a default outline, and the common mistake is to remove it with outline: none; and put nothing in its place.
Normal
Hover and focus (shown here)
Read this figure as text
Two live mini pages showing the same button in its normal appearance and with hover and focus styling.
Two live pages. Before: a plain dark green button called Join us with no extra styling. After: the same button with a lighter green background to show the hover state and a thick amber outline to show keyboard focus. The outline lets someone using the Tab key see which control is selected.
Other things to design for: make tap targets at least about 44 pixels high so thumbs can hit them, give users a way to enlarge text without breaking the layout, and consider a prefers-reduced-motion media query if you ever add animation. Media queries can ask about more than width; they can also notice a reader's preference for reduced motion or a dark colour scheme.
Try it in the live editor
Step 1: Start narrow
Create three div boxes in a container with
display: grid; gap: 10px;.You should see: The boxes stack in a single column.
Step 2: Add a breakpoint
Add
@media (min-width: 30rem) { .container { grid-template-columns: 1fr 1fr 1fr; } }.You should see: If the preview is wide enough, the boxes form three columns.
Step 3: Add hover
Give each box
.box:hover { background-color: #fff3cd; }.You should see: A box changes colour when the pointer is over it.
Step 4: Test the keyboard
Add a link in the page, click in the preview, then press Tab and look for the focus outline.
You should see: A visible outline appears around the link.
Common mistakes
✖ Instead of: Leaving out the viewport meta tag and wondering why the phone shows a tiny page.
✔ Do this: Always include
<meta name="viewport" content="width=device-width, initial-scale=1">in the head.✖ Instead of: Writing
outline: none;to remove the focus ring.✔ Do this: Replace the default with your own clear
:focus-visibleoutline.✖ Instead of: Hiding important information so that it appears only on hover.
✔ Do this: Touch screens have no hover. Make important content visible without it.
✖ Instead of: Choosing breakpoints for specific phone models.
✔ Do this: Let your content decide: resize and add a breakpoint where the layout starts to look wrong.
If something goes wrong
- My media query seems to do nothing.
- Check the brackets and the units inside the query, and that the rules are inside the curly brackets of the
@mediablock. Test with the window wider than the breakpoint. - On my phone the page is tiny but on my laptop it is fine.
- The viewport meta tag is probably missing or misspelled. Add it to the head exactly as shown.
- The page scrolls sideways on narrow screens.
- Something is wider than the screen, usually an image or fixed pixel width. Use
max-width: 100%for images and avoid fixed widths for containers. - Hover styles stick on a touch screen.
- Touch devices have no true hover. Use hover only as a bonus and ensure the page works without it.
Key terms
- Responsive design
- Building a web page so its layout adapts to the size of the screen it is shown on.
- Media query
- A CSS block whose rules apply only when a condition, such as the screen being wide enough, is true.
Practise it for real
Reading is not the same as being able to do it. Complete these on your own computer, then tick only what you have actually done. These ticks are your own honest record: nothing checks them for you.
A responsive card layout
In the live editor, build three fictional cards (for example Seeds, Tools and Water). Make them stack on a narrow preview and sit in three columns when the width is at least 40rem. Check both layouts by resizing the preview or the browser window.
Test the keyboard on a real page
On your laptop, open any page you have made (or a simple trusted site) in the browser and press Tab repeatedly without using the mouse. Count how many controls you can reach and note whether you can always see where the focus is. Write one sentence on what you would fix.
Challenge: an accessible button
Style a link so it looks like a button with strong contrast between text and background, a hover colour change and a clearly visible focus-visible outline. Then add a media query that makes the button wider on phones. Explain why you did not use outline: none.
Knowledge check
6 questions. You need 80% to pass. Mistakes here are part of learning, and you can retry as often as you like.
Summary
- Responsive design lets one page adapt to different screen widths.
- Include the viewport meta tag and use flexible sizes, such as `max-width: 100%` and rem.
- A media query applies rules above or below a breakpoint; write the small layout first.
- Use :hover, :focus and :focus-visible to show state.
- Never remove the focus outline without replacing it.
Checklist: can you do these?
Marking a lesson as read does not prove you can do it. Skills count as demonstrated when you pass the quiz (not yet) and complete the practical tasks (not yet).
Related lessons
References and further reading
Official sources for details that can change between versions.
- Responsive design (MDN Web Docs)
- Using media queries (MDN Web Docs)
- Understanding focus visible (W3C Web Accessibility Initiative)