jefftml's HTML & CSS Boilerplate
A modern, minimal 2026 starting point for webpages.
This boilerplate is deliberately tiny. It isn't a framework or a reset; it's a sensible, opinionated foundation that gives you comfortable typography, native dark mode, and a readable layout before you write a single line of your own CSS. Everything here is standards-based and ships in every current browser (with one tiny exception).
Table of Contents
Why this exists
Most "boilerplates" are either bloated (a whole CSS reset plus a grid system you didn't ask for) or too bare (a blank <html> with nothing to make text readable). This one aims for the middle: a handful of well-chosen modern CSS features that make a page look intentional and read comfortably on any device, with nothing to install and nothing to tear out later.
It also leans on newer platform features, logical properties, clamp(), color-scheme, text-wrap, hanging-punctuation, so the defaults are future-friendly and internationalization-ready out of the box.
Features at a glance
| Feature | What it does | Why it helps |
|---|---|---|
| Single file, zero dependencies | All CSS lives in an inline <style> block | Nothing to download, no build tooling, instant first paint |
| Native light & dark mode | color-scheme: light dark | Respects the user's OS preference automatically; form controls and scrollbars adapt too |
| Fluid typography | clamp()-based font size | Text scales smoothly between mobile and desktop with no media queries |
| Optimal reading measure | min(68ch, 100%) content width | Caps line length at a comfortable ~68 characters for readability |
| Logical properties | inline-size, margin-inline, padding-block | Works correctly in right-to-left and vertical writing modes |
| Comfortable line spacing | line-height: 1.7 | Easier, less cramped reading of long-form text |
| Smarter body line breaks | text-wrap: pretty | Avoids orphaned single words at the end of paragraphs |
| Balanced headings | text-wrap: balance on h1–h6 | Multi-line headings wrap into even, tidy blocks instead of a long line plus a stray word |
| Hanging punctuation | hanging-punctuation: first last | Cleaner typographic alignment where supported |
| iOS zoom fix | -webkit-text-size-adjust: 100% | Stops mobile Safari from inflating text on rotation |
| System font stack | font-family: sans-serif | No web-font request, so text renders instantly with no layout shift |
| Semantic, accessible base | lang, <main>, proper meta tags | Better SEO and screen-reader behavior from the start |
Getting started
- Copy the boilerplate into a new
index.html. - Replace the
<h1>and<p>placeholders with your content. - Open it in a browser. That's it, there's no step 4.
When your styles outgrow the inline block, uncomment the stylesheet link in the <head> and move your CSS into a style.css file:
<link rel="stylesheet" href="style.css">
Anatomy
The <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jefftml’s HTML & CSS Boilerplate</title>
<meta name="description" content="A 2026 starting point for webpages.">
lang="en"on the<html>element tells browsers and assistive technology which language the page is in, improving screen-reader pronunciation and search indexing.charset="UTF-8"declares Unicode encoding so every character, including emoji and non-Latin scripts, renders correctly. It's placed first so the browser knows the encoding before parsing anything else.viewportmakes the page responsive by mapping the layout to the device's actual width instead of a zoomed-out desktop view.meta descriptionprovides the summary search engines and social previews can use.’in the title uses a proper typographic curly apostrophe (’) rather than a straight quote, a small detail that signals the same typographic care found throughout the CSS.
The CSS
:root {
color-scheme: light dark;
}
Declares that the page supports both light and dark color schemes. The browser then renders its default UI (text color, backgrounds, form controls, scrollbars) to match the visitor's system preference, giving you automatic dark mode with a single line and no JavaScript.
html {
font-family: sans-serif;
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
line-height: 1.7;
-webkit-text-size-adjust: 100%;
text-wrap: pretty;
hanging-punctuation: first last;
}
font-family: sans-serifuses the reader's default sans-serif face. There's no web font to download, so text appears immediately with zero layout shift and no privacy or performance cost.font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem)is fluid typography. The size never drops below1rem(16px) or rises above1.125rem(18px), and in between it grows gently with the viewport (0.95rem + 0.25vw). You get responsive text without writing breakpoints.line-height: 1.7is a generous, unitless line height that keeps paragraphs airy and comfortable for extended reading. Being unitless, it scales correctly with any font size.-webkit-text-size-adjust: 100%prevents mobile WebKit browsers from auto-enlarging text when the device rotates, so your intended sizes are respected.text-wrap: prettyasks the browser to spend a little extra effort on line breaking in body text. Its headline benefit is eliminating orphans, a final line left with one lonely word, by pulling a word down from the line above; it also reduces long runs of consecutive hyphenated lines. Set onhtmlso it inherits to every paragraph on the page.hanging-punctuation: first lastlets opening quotes and similar marks hang slightly into the margin, keeping the left edge of text optically aligned. It degrades gracefully, browsers that don't support it simply ignore it.
main {
inline-size: min(68ch, 100%);
margin-inline: auto;
padding-block: 2rem;
}
inline-size: min(68ch, 100%)sets the content width to whichever is smaller: 68 characters or the full available space. Thechunit ties the measure to the font itself, capping line length around the ~45–75 character sweet spot that's easiest to read, while100%ensures it never overflows on narrow screens.margin-inline: autocenters the content horizontally using a logical property, so it behaves correctly regardless of text direction.padding-block: 2remadds breathing room above and below the content, again via a logical property, so "block" means the flow direction rather than a hard-coded top/bottom.
Note on logical properties:
inline-size,margin-inline, andpadding-blockare direction-aware equivalents ofwidth, horizontalmargin, and verticalpadding. They automatically adapt to right-to-left languages (like Arabic or Hebrew) and vertical writing modes, making the layout internationalization-ready with no extra work.
h1, h2, h3, h4, h5, h6 {
text-wrap: balance;
}
text-wrap: balanceevens out the line lengths of a heading that wraps to more than one line, so it forms a tidy block rather than a full-width first line with a single stranded word beneath it. It's the sibling ofprettyabove, whereprettyoptimizes how a passage ends,balancedistributes text across all of its lines, and this rule overrides the inheritedprettyfor headings only.- It's scoped to
h1–h6deliberately: browsers capbalanceat a small number of lines (commonly ~4–6) to keep it cheap, and the payoff is most visible on short, large, high-contrast text. Applying it to long paragraphs would mostly do nothing.
Note on
text-wrap: both values are purely cosmetic. Browsers that don't support them fall back to ordinary line breaking, nothing shifts, overflows, or breaks.
Customizing
- Swap the font: replace
sans-serifwith your own stack, e.g.font-family: "Inter", system-ui, sans-serif; - Adjust the measure: change
68chto taste, lower for narrower columns, higher for wider ones. - Tune the fluid range: edit the three values in
clamp()to set your own minimum, growth rate, and maximum text size. - Force a single theme: change
color-schemeto justlightordarkif you don't want it to follow the OS. - Balance more than headings: add other short, display-sized text, blockquotes, figure captions, card titles, to the
text-wrap: balanceselector list. - Opt out of pretty wrapping: set
text-wrap: wrapon any element where you'd rather have plain, maximally fast line breaking. - Go external: uncomment the
<link rel="stylesheet">and move the styles intostyle.cssonce the project grows.
Browser support
Every feature here works in current versions of Chrome, Edge, Firefox, and Safari, and the whole file is built so that anything unsupported fails silently rather than breaking the layout.
The progressive enhancements, hanging-punctuation, color-scheme, and the two text-wrap values, simply do nothing in browsers that lack them: readers get standard punctuation, the default light rendering, and ordinary line breaks. text-wrap: balance and text-wrap: pretty in particular have landed on different timelines across engines, so treat them as a bonus for readers on newer browsers rather than something to rely on. Everything else (clamp(), logical properties, min(), ch units) is broadly supported across modern browsers.
License
Use it, change it, ship it. No attribution required.