CSS Tutorial
CSS Responsive
Fluid widths, flexible type, and media queries make one stylesheet work on a phone and a desk.
One sheet, many viewports
Responsive CSS is not a separate language. It is a handful of habits: the layout uses fluid widths instead of a locked 960px canvas, images cannot overflow, type can scale, and media queries rearrange when a single column is the honest layout. Harbor studio’s site is the same HTML on a phone in a queue and on a desk in the print shop.
The HTML side of this story is the viewport meta tag — width=device-width — so the phone does not pretend the page is 980 pixels wide. This chapter is the stylesheet that then uses that real width.
Start with the viewport
Without the meta tag, your careful min-width queries never see a 360-pixel viewport. The phone scales a fake desktop down. Always include the tag on a real page. In the live preview it is already in the wrapper around your snippet.
| Piece | Job |
|---|---|
| Viewport meta | Layout width follows the device |
| Fluid widths | max-width and percent, not a fixed page width |
| Fluid images | max-width: 100%; height: auto |
clamp() | Type that scales between a floor and a ceiling |
| Media queries | Change columns when fluid is not enough |
Do not lock zoom with user-scalable=no. Responsive includes letting people enlarge the page. Practice these snippets at /css/try and drag the preview narrower.
Fluid images
A photo whose intrinsic width is 1400 pixels will blow out a 360-pixel column. The usual rule is: never wider than the parent, keep the aspect ratio, and still put width and height in HTML so the browser can reserve space.
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
img {
max-width: 100%;
height: auto;
display: block;
border-radius: 0.5rem;
}
h1 { color: #0d9488; font-size: 1.25rem; }
</style>
<h1>Harbor studio</h1>
<p>The banner shrinks with the column. It never forces a sideways scroll.</p>
<img
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1400' height='360'%3E%3Crect fill='%230284c7' width='1400' height='360'/%3E%3Ctext x='50%25' y='50%25' fill='%23fff' font-size='42' text-anchor='middle' dominant-baseline='middle'%3EPier gallery%3C/text%3E%3C/svg%3E"
alt="Wide pier gallery banner"
width="1400"
height="360"
>clamp for flexible type
clamp(min, preferred, max) picks the middle value, then floors and caps it. A heading can grow with the viewport without becoming a poster on a television or a whisper on a phone. The preferred value is often a vw expression plus a rem offset.
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
h1 {
color: #0d9488;
font-size: clamp(1.35rem, 0.8rem + 2.4vw, 2.4rem);
line-height: 1.2;
margin: 0 0 0.5rem;
}
p {
max-width: 42ch;
line-height: 1.6;
}
</style>
<h1>Harbor studio print shop</h1>
<p>
Resize the preview. The heading scales between 1.35rem and 2.4rem. The paragraph stays a readable
42ch measure.
</p>Read the three arguments as: never smaller than 1.35rem, prefer this viewport-tied size, never larger than 2.4rem. Test at the smallest phone and the widest window. If the heading clips or looks timid, move the floor or the ceiling — not the HTML.
A fluid page shell
Cap the main column with max-width, center it with margin-inline: auto, and let width be 100% minus padding. That shell plus fluid images plus a min-width query for a sidebar is enough for most brochure pages.
Example
<style>
* { box-sizing: border-box; }
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 0;
}
.wrap {
width: min(100% - 2rem, 42rem);
margin-inline: auto;
padding: 1.25rem 0 2rem;
}
.layout {
display: grid;
gap: 1rem;
}
header {
padding: 0.85rem 1rem;
background: #0ea5e9;
color: #fff;
border-radius: 0.5rem;
}
main, aside {
padding: 1rem;
border-radius: 0.5rem;
}
main { background: #fff; border: 1px solid #bae6fd; }
aside { background: #ccfbf1; }
h1, h2 { margin: 0 0 0.35rem; }
h1 { font-size: clamp(1.2rem, 1rem + 1.2vw, 1.6rem); }
p { margin: 0; line-height: 1.55; }
@media (min-width: 40rem) {
.layout { grid-template-columns: 1fr 10rem; }
header { grid-column: 1 / -1; }
}
</style>
<div class="wrap">
<div class="layout">
<header><h1>Harbor studio</h1></header>
<main>
<h2>Visit</h2>
<p>The wrap is never wider than 42rem. From 40rem, hours sit beside the article.</p>
</main>
<aside><p>Open 8–16</p></aside>
</div>
</div>width: min(100% - 2rem, 42rem) is fluid and capped in one line: full width minus gutters, until 42rem. It needs the modern min() function, which every current browser has. Media queries then rearrange, they do not invent a second site.
Worked examples
The short listings above show one property. These sheets paint documents you would actually ship: a lab dashboard, a clinic form, a marks table, a nav bar.
CSS does not invent meaning. HTML already said what the pieces are. Cascade, specificity, and the box model decide how they look. The numbers are classroom values — current, pH, pulse, 3-4-5 — so the style has something real to sit on.
Preview them in the CSS editor at /css/try. Change one property and watch the page paint. The tags stay the same.
Biology
A heading that clamps
clamp(min, preferred, max) is fluid type: 1.2rem on a small phone, 4vw in the middle, 2rem cap on a desk. Pair with a viewport meta in HTML.
Images: max-width 100%; height auto. That is the whole “flexible image” lesson in one rule.
Example
<style>
h1 { font-size: clamp(1.2rem, 4vw, 2rem); color: #9f1239; }
</style>
<h1>Fever protocol</h1>Physics
A photo that cannot overflow
A 480 px still on a 320 px preview overflows unless max-width: 100%. The alt still describes the drop test.
Example
<style>
img { max-width: 100%; height: auto; }
</style>
<img src="https://picsum.photos/seed/widedrop/480/160" alt="Strobe still of a falling mass">