Before starting, you should be able to write semantic HTML, connect an external stylesheet, use selectors, inspect computed styles, and work with the box model, intrinsic sizing, typography, backgrounds, borders, and visible focus. Complete Modules 1–9 first.
This lesson begins layout by studying what the browser already does. It does not use Flexbox, Grid, positioning, floats, media queries, or fixed coordinates. Those tools should solve a real layout problem, not replace a useful default.
Create this structure:
repair-cafe/
├── index.html
└── styles.css
Create index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Riverside repair café</title>
<meta name="description" content="Practical information for the free Riverside repair café.">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<div class="wrapper">
<p class="site-name">Riverside repair café</p>
</div>
</header>
<main class="wrapper">
<h1>Bring one household item for a free repair check</h1>
<p class="intro">Volunteer repairers will examine small electrical items, clothing, bicycles, and toys.</p>
<section aria-labelledby="visit-heading">
<h2 id="visit-heading">Plan your visit</h2>
<p>Sessions run on the first Saturday of each month from 10:00 to 14:00 at Riverside Library.</p>
<p><strong>Important:</strong> a repair cannot be guaranteed, and unsafe items may be declined.</p>
<a class="action-link" href="#booking-instructions">Read the booking instructions</a>
</section>
<section id="booking-instructions" aria-labelledby="bring-heading">
<h2 id="bring-heading">What to bring</h2>
<ul>
<li>The item and every loose part.</li>
<li>A charger, power cable, or instruction booklet when relevant.</li>
<li>Details of any access adjustment you need at the venue.</li>
</ul>
</section>
</main>
<footer class="site-footer">
<div class="wrapper">
<p>Run by Riverside Library and local volunteers.</p>
</div>
</footer>
</body>
</html>
Create styles.css:
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
color: #172b3a;
background-color: #f3f7f8;
font-family: system-ui, sans-serif;
font-size: 1rem;
line-height: 1.6;
}
h1,
h2,
p {
margin-top: 0;
}
h1 {
font-size: 2rem;
line-height: 1.15;
}
h2 {
margin-top: 2rem;
font-size: 1.4rem;
line-height: 1.25;
}
Run the folder through a local server. Read the page from top to bottom before adding layout rules. That order is the foundation: site name, page heading, introduction, visit information, action, preparation information, and footer.
Normal flow is the default system the browser uses to place boxes when they are not floated, positioned out of flow, or made part of a Flexbox or Grid layout. It is not “no layout”. It is a capable, content-aware layout.
Block-level boxes in ordinary horizontal writing usually begin on a new line and are placed one after another in the block direction. A block box with automatic inline size generally uses the available width of its containing block. That is why the headings, paragraphs, sections, list, and landmarks already form one readable column.
Inline-level boxes participate in lines of text. The <strong> element and the text inside the link sit within line boxes and can wrap with surrounding text. An inline box does not behave like a separate full-width row.
These are layout roles, not statements about meaning. <main> is meaningful HTML and normally produces a block box, but display: block itself does not create a main landmark. Keep semantic HTML responsible for meaning and CSS responsible for presentation.
In Developer Tools, select a paragraph and the <strong> element. Check their computed display values. Browser defaults commonly expose the paragraph as block and strong as inline. Then disable CSS: the document should still be understandable because the HTML order and elements remain sound.
Conceptually, display describes two jobs:
The familiar single-keyword values combine these ideas. display: block produces a block-level box whose children use ordinary flow. display: inline produces an inline-level box whose contents use inline layout. display: inline-block produces an inline-level box on the outside and a block formatting context on the inside.
You do not need to rewrite every browser default. Add display only when you want a different result. Repeating display: block on every heading and paragraph adds noise without solving a problem.
Add this rule:
.wrapper {
width: 92%;
max-width: 68rem;
margin-inline: auto;
}
The repeated .wrapper <div> elements group content only for sizing. There is no more specific semantic element for “this shared width constraint”, so a div is appropriate.
width: 92% leaves space at the inline edges when the viewport is narrow. max-width prevents excessive growth on a wide screen. margin-inline: auto shares leftover inline space between the two sides when the wrapper is narrower than its containing block. None of these rules fixes the height. Each wrapper grows in the block direction as its content wraps or expands.
Do not add a wrapper around every element. One wrapper can constrain a group. Excess wrappers make the document tree and selectors harder to understand.
Add these rules:
.site-header,
.site-footer {
padding-block: 1rem;
color: #ffffff;
background-color: #174f5b;
}
.site-name,
.site-footer p {
margin-bottom: 0;
}
main.wrapper {
padding-block: 2rem 3rem;
}
.intro {
max-width: 60ch;
font-size: 1.15rem;
}
section {
padding-block-end: 1rem;
border-block-end: 0.0625rem solid #78909c;
}
Padding creates space inside the header, main region, footer, and sections. The browser calculates their final block sizes from content, line wrapping, padding, and borders. There is no height to clip translated text or create empty space when a paragraph is short.
The ch constraint limits the introduction’s line measure without assigning a fixed physical width. It is a maximum, so the paragraph can still become narrower with its container.
The logical properties padding-block, padding-block-end, border-block-end, and margin-inline describe relationships to writing directions. This lesson still uses English horizontal text, but the property names express the layout intention more accurately than physical top, bottom, left, and right names.
Add these rules:
.action-link {
display: inline-block;
margin-block: 0.5rem 1rem;
padding: 0.65rem 0.9rem;
color: #ffffff;
background-color: #075985;
border: 0.125rem solid #075985;
border-radius: 0.4rem;
font-weight: 700;
}
.action-link:hover {
background-color: #064b6f;
}
.action-link:focus-visible {
outline: 0.1875rem solid #101828;
outline-offset: 0.1875rem;
}
The link stays inline-level relative to surrounding content, so it does not automatically fill a row. Its inline-block box accepts predictable padding and margins and remains one box when its label fits. The browser may still wrap a long link label as needed inside the box.
This styling does not change the link into a button. It still navigates to booking.html, so <a href> is correct. A control that performs an in-page action would need a real <button> and, often, JavaScript beyond this course.
If CSS fails, the destination remains a normal link. If inline-block were unsupported—which is not a realistic concern in the course’s modern-browser baseline—the content and link would remain available in ordinary inline layout.
The completed index.html is unchanged from the starting file. The complete styles.css is:
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
color: #172b3a;
background-color: #f3f7f8;
font-family: system-ui, sans-serif;
font-size: 1rem;
line-height: 1.6;
}
h1,
h2,
p {
margin-top: 0;
}
h1 {
font-size: 2rem;
line-height: 1.15;
}
h2 {
margin-top: 2rem;
font-size: 1.4rem;
line-height: 1.25;
}
.wrapper {
width: 92%;
max-width: 68rem;
margin-inline: auto;
}
.site-header,
.site-footer {
padding-block: 1rem;
color: #ffffff;
background-color: #174f5b;
}
.site-name,
.site-footer p {
margin-bottom: 0;
}
main.wrapper {
padding-block: 2rem 3rem;
}
.intro {
max-width: 60ch;
font-size: 1.15rem;
}
section {
padding-block-end: 1rem;
border-block-end: 0.0625rem solid #78909c;
}
.action-link {
display: inline-block;
margin-block: 0.5rem 1rem;
padding: 0.65rem 0.9rem;
color: #ffffff;
background-color: #075985;
border: 0.125rem solid #075985;
border-radius: 0.4rem;
font-weight: 700;
}
.action-link:hover {
background-color: #064b6f;
}
.action-link:focus-visible {
outline: 0.1875rem solid #101828;
outline-offset: 0.1875rem;
}
The wrapper still fills the full width. Check that the class is on the intended element, the stylesheet path resolves, and max-width is not being overridden. At narrow widths, width: 92% should still be the active constraint.
The wrapper is not centred. Inspect the computed inline margins. Auto margins share free space only when the box is narrower than its containing block.
Padding appears to make a box too wide. Confirm that the global box-sizing: border-box rule applies. Then inspect width, padding, borders, and the containing block separately.
A link fills the whole row. Check whether it accidentally received display: block or a width. The solution uses inline-block.
Long text overlaps the next section. Remove fixed height, negative margins, and positioning. Let the box’s content determine its block size.
Use the sequence: reproduce the problem, inspect the selected box, identify its display role and containing block, check computed size and overflow, change one rule, and retest long and short content.
Create a two-file page for a public reading group. It must contain a site header, main, two labelled sections, and a footer. Add one .page-width wrapper inside each full-width region. The main wrapper must use width: 90%, max-width: 64rem, and automatic inline margins. Style a “View the reading list” link as inline-block with padding and a visible focus outline. Do not use Flexbox, Grid, positioning, media queries, or fixed heights.
Test with this longer heading: “Join the monthly public reading and discussion group”. Record whether it wraps without overlap at a narrow width.
index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Public reading group</title>
<meta name="description" content="Meeting details for a free public reading group.">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<div class="page-width"><p>Northside Library</p></div>
</header>
<main class="page-width">
<h1>Join the monthly public reading and discussion group</h1>
<section aria-labelledby="meeting-heading">
<h2 id="meeting-heading">Next meeting</h2>
<p>Meet in the community room on Thursday at 18:00.</p>
<a class="reading-link" href="#reading-list">View the reading list</a>
</section>
<section id="reading-list" aria-labelledby="list-heading">
<h2 id="list-heading">Reading list</h2>
<p>Borrow the selected title from the library desk or request an accessible edition.</p>
</section>
</main>
<footer class="site-footer">
<div class="page-width"><p>Participation is free.</p></div>
</footer>
</body>
</html>
styles.css:
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
color: #1d2d35;
background-color: #f6f8f7;
font-family: system-ui, sans-serif;
line-height: 1.6;
}
.page-width {
width: 90%;
max-width: 64rem;
margin-inline: auto;
}
.site-header,
.site-footer {
padding-block: 1rem;
color: #ffffff;
background-color: #305a48;
}
.site-header p,
.site-footer p {
margin: 0;
}
main {
padding-block: 2rem 3rem;
}
section {
padding-block-end: 1rem;
border-block-end: 0.0625rem solid #718278;
}
.reading-link {
display: inline-block;
padding: 0.65rem 0.9rem;
color: #ffffff;
background-color: #164e63;
border: 0.125rem solid #164e63;
border-radius: 0.35rem;
font-weight: 700;
}
.reading-link:focus-visible {
outline: 0.1875rem solid #111827;
outline-offset: 0.1875rem;
}
The solution was checked as a complete two-file document structure. Its wrappers have flexible widths and maximum constraints, its link has an inline-block role and visible focus rule, and it contains no Flexbox, Grid, positioning, media queries, or fixed heights. Browser rendering and narrow-width behaviour still require manual testing.