Module 5 · Web Development with JavaScript
CSS layout and responsive design
Style the payment page with CSS, lay it out with flexbox and grid, design for phones first, and use a media query so it adapts to wider screens without separate pages.
About 15 minutes
The problem
Most of Tallybook's customers open invoices on a phone, from a link in an email or WhatsApp message. The old page was designed on a laptop: on a phone, the table ran off the edge, the buttons were tiny, and customers had to pinch and zoom to pay.
Responsive design means one page that works at every width, designed for the smallest screen first.
The concept
CSS rules
selector { property: value; }Select by element (button), class (.summary) or id (#amount), and set properties such as color, padding, font-size.
Layout
- Flexbox (
display: flex) lines items up in a row or column, with gaps and alignment. - Grid (
display: grid) places items in rows and columns.
Mobile first
Write the phone layout as the default. Then add media queries that change the layout when there's room:
@media (min-width: 700px) { /* rules for wider screens */ }Touch-friendly
Tap targets at least about 44 pixels tall, body text at least 16px (which also stops phones zooming into form fields), and enough contrast to read in daylight.
Example
Add a stylesheet to pay.html from lesson 4. Put this inside <head>, and wrap the table and the balance in <div class="layout"> with the balance in <section class="summary">:
HTML
<style>
:root { --ink: #1c1917; --muted: #57534e; --brand: #0f766e; }
* { box-sizing: border-box; }
body { margin: 0; font: 16px/1.5 system-ui, sans-serif; color: var(--ink); }
main { padding: 16px; max-width: 960px; margin: 0 auto; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 8px; border-bottom: 1px solid #e7e5e4; }
.layout { display: grid; gap: 24px; }
.summary { padding: 16px; border: 1px solid #e7e5e4; border-radius: 12px; }
form { display: flex; flex-direction: column; gap: 8px; }
input { font-size: 16px; padding: 12px; border: 1px solid var(--muted); border-radius: 8px; }
button { min-height: 48px; font-size: 16px; color: white; background: var(--brand); border: 0; border-radius: 8px; }
@media (min-width: 700px) {
.layout { grid-template-columns: 2fr 1fr; align-items: start; }
}
</style>On a phone, .layout is a single column: the invoice table, then the summary. From 700 pixels wide, the media query turns it into two columns, table on the left and summary on the right, with no change to the HTML. The inputs are 16px with generous padding, and the button is 48px tall, so it's easy to tap.
Walkthrough
- Add the styles and resize the browser window across 700 pixels. Watch the layout switch.
- In DevTools, turn on the device toolbar (Ctrl+Shift+M) and pick a phone. Is everything usable without zooming?
- Change the brand colour to a pale yellow. Use DevTools' contrast checker on the button: does it pass?
- Write a media query for very wide screens (the task below).
Practice
Task
6 minWrite CSS so that the payment form's fields sit side by side (amount and reference in one row) on screens at least 1000 pixels wide, but stay stacked on smaller screens. Use a media query and grid or flexbox.
Your work is checked for
- A min-width media query of 1000px
- Targets the form
- Uses grid or flex in a row
- No fixed pixel width on the page body
Check your understanding
Answer every question to check.