CSS Tutorial
CSS Forms
Style labels, inputs, and buttons so a form is readable. Keep :focus visible.
A form is a reading task
People fill a booking form in a hurry, often on a phone. CSS should make the label obvious, the field easy to tap, the button clearly the submit, and the focus ring impossible to miss. Harbor studio’s “book a desk” form does not need a novel look. It needs contrast, spacing, and a visible :focus style.
Browsers ship a default look for input and button. You will override font, size, padding, and border so the fields match the page. You should not remove the focus outline without replacing it.
Labels sit with their fields
A label with a matching for / id pair is already clickable: click the words, the field focuses. CSS then stacks them with a small grid or flex column so the label is above the control, not lost to the left on a narrow screen.
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
form {
max-width: 22rem;
display: grid;
gap: 0.85rem;
}
.field {
display: grid;
gap: 0.3rem;
}
label {
font-weight: 650;
font-size: 0.9rem;
}
input[type="text"],
input[type="email"] {
font: inherit;
padding: 0.55rem 0.7rem;
border: 1px solid #7dd3fc;
border-radius: 0.4rem;
background: #fff;
color: #0c4a6e;
}
</style>
<h1>Harbor studio</h1>
<form action="#" method="get">
<div class="field">
<label for="guest">Name</label>
<input id="guest" name="guest" type="text" autocomplete="name">
</div>
<div class="field">
<label for="mail">Email</label>
<input id="mail" name="mail" type="email" autocomplete="email">
</div>
</form>Inherit the page font on inputs. Some browsers default fields to a system serif or a tiny size.font: inherit plus padding makes the tap target closer to 44px high. Try the form at/css/try.
Keep :focus visible
Keyboard users tab from field to field. If you set outline: none and stop there, they cannot tell where they are. Replace the outline with a ring they can see against both the sky page and the white field — a teal offset, for example.
| Selector | When it matches |
|---|---|
:focus | The field is focused, including mouse click |
:focus-visible | Focus the browser thinks should be advertised (usually keyboard) |
:focus-within | The element or a descendant is focused — useful on a field wrapper |
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
input[type="text"] {
font: inherit;
width: 16rem;
max-width: 100%;
padding: 0.55rem 0.7rem;
border: 1px solid #38bdf8;
border-radius: 0.4rem;
background: #fff;
}
input[type="text"]:focus {
outline: 3px solid #0d9488;
outline-offset: 2px;
border-color: #0d9488;
}
label { display: block; font-weight: 650; margin-bottom: 0.3rem; }
</style>
<form action="#" method="get">
<label for="desk">Desk name</label>
<input id="desk" name="desk" type="text" value="Tide">
</form>Click the field. The teal ring should be obvious. Never rely on a 1px border-color change alone — it is easy to miss next to a sky border. Outline plus offset sits outside the box and does not shift layout.
Buttons that look like buttons
A submit control should contrast with the fields. Full teal background, white text, enough padding, and a hover/focus state. Disabled buttons need lower contrast and cursor: not-allowed, and they still must not be the only way to explain why submit is blocked — put that in text too.
Example
<style>
body {
font-family: system-ui, sans-serif;
color: #0c4a6e;
background: #f0f9ff;
margin: 1.25rem;
}
form {
display: grid;
gap: 0.75rem;
max-width: 20rem;
}
label { font-weight: 650; font-size: 0.9rem; }
input {
font: inherit;
padding: 0.5rem 0.65rem;
border: 1px solid #7dd3fc;
border-radius: 0.4rem;
}
input:focus {
outline: 3px solid #0d9488;
outline-offset: 2px;
}
button[type="submit"] {
font: inherit;
font-weight: 700;
padding: 0.6rem 1rem;
border: 0;
border-radius: 0.45rem;
background: #0d9488;
color: #fff;
cursor: pointer;
}
button[type="submit"]:hover {
background: #0f766e;
}
button[type="submit"]:focus-visible {
outline: 3px solid #0284c7;
outline-offset: 2px;
}
.field { display: grid; gap: 0.3rem; }
</style>
<h1>Book a desk</h1>
<form action="#" method="get">
<div class="field">
<label for="when">Date</label>
<input id="when" name="when" type="text" placeholder="19 Aug">
</div>
<button type="submit">Request slot</button>
</form>A few practical defaults
- Set
box-sizing: border-boxso padding does not overflow awidth: 100%field. - Use
max-width: 100%on inputs so they cannot force a horizontal scroll. - Group a checkbox with its label on one line: flex,
gap,align-items: center. appearancecan strip native styling on some controls; if you do that, restyle focus and disabled yourself.
Placeholder text is not a label. It disappears as the user types and is often paler than body copy. Keep a real label, then use placeholder for an example format only.
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 field that shows focus
Inputs need padding, a visible border, and :focus outline. Placeholder is not a label. colour contrast on the value matters more than a trendy hairline border.
Buttons should look like buttons. Disabled is a state with opacity or grey — and aria if you script it.
Example
<style>
input { border: 1px solid #0d9488; padding: 0.4rem 0.6rem; }
input:focus { outline: 2px solid teal; }
</style>
<label>Email <input type="email" name="email" placeholder="you@clinic.test"></label>Chemistry
A mass field on a bench laptop
tabular-nums and a decent font-size stop 18.0 looking like 180. min-width on the input helps a gloved user hit the target.
Example
<style>
input { font-size: 1.1rem; font-variant-numeric: tabular-nums; min-width: 8ch; }
</style>
<label>Mass / g <input type="number" name="g" value="18.0"></label>