Level 1, Foundations, Chapter 2 of 24
HTML — Building the Skeleton
Why this matters
Nearly every web page you've ever visited, no matter how flashy or animated, is built on the same handful of structural building blocks: headings, paragraphs, lists, links, and images. Learning these well is like learning the alphabet before writing sentences. Once you're fluent in the basic tags, you'll be able to describe almost any piece of written content on the web, and every later chapter about styling and interactivity will build directly on top of this foundation.
Think about how much of your daily browsing is really just those five things in different arrangements: a news article is headings and paragraphs, a recipe site is a list of ingredients and steps, a portfolio is images and links. This chapter picks up exactly where the previous one left off, and then goes further: how to format text within a sentence, how attributes work in general, and the smaller details that separate a page that merely displays from one that's genuinely well built.
The lesson
Reviewing document structure
In the previous chapter you saw that every HTML page starts with a doctype declaration, followed by an html element containing a head and a body. The head holds information about the page that isn't shown directly to a visitor, like the page title and character encoding, while the body holds everything a visitor actually sees. From this point forward, we'll focus almost entirely on what goes inside the body, since that's where structure and content live.
Headings and text
HTML gives you six levels of headings, h1 through h6, ranked by importance rather than by size alone. h1 should be reserved for the single most important heading on a page, typically its main title, while h2 through h6 mark progressively less important section headings, similar to how a book has a title, then chapter titles, then subheadings within chapters. Regular text content goes inside paragraph tags, written as p. Browsers automatically add spacing between paragraphs, and you should never fake a paragraph break by pressing Enter multiple times inside your HTML; whitespace like that is collapsed and ignored, so line breaks must be described with actual tags.
1<h1>My Travel Journal</h1>2<p>Welcome to my collection of notes from recent trips.</p>34<h2>Visiting the Coast</h2>5<p>The drive along the coastline took most of the morning, but the views were worth every minute.</p>Lists for grouped information
Whenever you have a group of related items, an HTML list is almost always the right structural choice, and it's far more meaningful to browsers, search engines, and assistive technology than typing dashes inside a paragraph. There are two main kinds. An unordered list, written as ul, is for items where order doesn't matter, like a shopping list. An ordered list, written as ol, is for items where sequence matters, like numbered steps in a recipe. In both cases, each individual item inside the list is wrapped in an li (list item) tag, and li tags must always live inside a ul or ol, never on their own.
1<h2>Packing List</h2>2<ul>3 <li>Passport</li>4 <li>Phone charger</li>5 <li>Comfortable shoes</li>6</ul>78<h2>Steps Before Leaving</h2>9<ol>10 <li>Check the weather forecast</li>11 <li>Confirm the flight time</li>12 <li>Lock the front door</li>13</ol>Lists can also nest inside one another, which is useful when an item has its own sub-points, like a step with several smaller details. To nest a list, place a whole new ul or ol inside an li, after that item's own text. The ol tag also accepts a few attributes worth knowing: start changes which number the list begins counting from, reversed counts downward instead of up, and type swaps the numbering style, for example type="A" for capital letters or type="i" for lowercase Roman numerals.
1<ol start="3" type="A">2 <li>Preheat the oven</li>3 <li>4 Prepare the topping5 <ul>6 <li>Chop the herbs</li>7 <li>Grate the cheese</li>8 </ul>9 </li>10 <li>Bake for twenty minutes</li>11</ol>Links: connecting pages together
The web is called a web because pages link to one another, and that link is created with the anchor tag, written as a. An anchor tag needs an href attribute, short for hypertext reference, which tells the browser where the link should go. The text or content between the opening and closing a tags is what a visitor sees and clicks. Links can point to other websites entirely, to other pages on your own site, or even to a specific section within the same page.
1<p>2 You can learn more about web standards at the3 <a href="https://developer.mozilla.org">MDN Web Docs</a> site.4</p>A few more link attributes come up constantly in real pages. Adding target="_blank" opens the link in a new tab instead of navigating away from your page; whenever you use it, you should also add rel="noopener", because without it the new page gets limited access to the original tab's window object, which is both a small security risk and a performance cost. A download attribute turns a link into a file download instead of a navigation. And two special link protocols are worth knowing by heart: href="mailto:someone@example.com" opens the visitor's email app with a new message already addressed, and href="tel:+15551234567" starts a phone call on devices that can make one.
1<a href="https://developer.mozilla.org" target="_blank" rel="noopener">2 Open MDN in a new tab3</a>4<a href="handbook.pdf" download>Download the handbook</a>5<a href="mailto:hello@example.com">Email us</a>6<a href="tel:+15551234567">Call the front desk</a>Images and meaningful alt text
Images are added with the img tag, which works a little differently from the tags you've seen so far: it has no closing tag and no content between tags, because it doesn't wrap anything, it simply points to an image file. An img tag needs a src attribute pointing to the image's location, and it should almost always include an alt attribute describing the image in words. Alt text is read aloud by screen readers for visitors who can't see the image, and it's also displayed if the image fails to load, so writing clear, specific alt text is a real accessibility skill, not an optional extra.
1<img src="mountain-sunrise.jpg" alt="Sunrise over a mountain range with orange sky" />Two more attributes make images behave much better in practice. Setting width and height (in pixels) tells the browser the image's proportions before the file has even finished downloading, so it can reserve the right amount of space; without them, the page can visibly jump around as images pop in, a jarring effect known as layout shift. Adding loading="lazy" tells the browser it doesn't need to download that image until it's about to scroll into view, which speeds up pages with many images. A title attribute adds a small tooltip that appears on hover, which can supplement, but should never replace, a proper alt attribute.
1<img2 src="mountain-sunrise.jpg"3 alt="Sunrise over a mountain range with orange sky"4 width="800"5 height="500"6 loading="lazy"7 title="Taken from the eastern ridge trail"8/>Formatting text within a sentence
So far every tag you've used has wrapped a whole block of content, but HTML also has inline tags meant to sit inside a sentence and change the meaning of specific words. strong marks text as having strong importance, like a warning, and browsers happen to render it bold, but the meaning, not the boldness, is the point. em marks text with stress emphasis, the way you'd naturally emphasize a word if you were speaking it aloud, and browsers render it italic. mark highlights text as relevant to the current context, like a search match. code marks a short piece of computer code or a filename within a sentence. small marks side comments like fine print or disclaimers. br inserts a single line break within a block of text, useful for things like a mailing address, and unlike most tags it never wraps content. hr draws a thematic break between two sections, like a scene change in a story. blockquote marks a longer quotation set off as its own block, while q marks a short quotation inline within a sentence, and browsers usually add quotation marks around q content automatically.
1<p><strong>Warning:</strong> the trail is <em>closed</em> after dark.</p>2<p>Search results for <mark>lantern</mark> festivals near you:</p>3<p>Run the build with <code>npm run build</code>.</p>4<p><small>Prices may vary by location.</small></p>5<p>123 Main Street<br />Springfield</p>6<hr />7<blockquote>8 The mountains are calling, and I must go.9</blockquote>10<p>She simply said, <q>we made it.</q></p>Grouping content: div and span
Sometimes you need a container that doesn't carry any particular meaning, just to group things together, for example to style a group as a unit later. That's what div and span are for. A div is a block-level generic container: it starts on its own line and stretches to fill the width available to it, and it's meant to wrap other block-level content like paragraphs or headings. A span is an inline generic container: it doesn't start a new line and only takes up as much width as its content, and it's meant to wrap a small piece of text within a sentence, similar to strong or em but with no built-in meaning at all. The rule of thumb is to always reach for a semantic tag first when one describes your content, like using blockquote for a quotation rather than a div, and only fall back to div or span when nothing else fits, typically because you need a hook purely for styling or scripting.
1<div class="card">2 <h2>Weather Today</h2>3 <p>It's <span class="highlight">72°F</span> and sunny.</p>4</div>Attributes and values
You've now used attributes like href, src, alt, width, and target, so it's worth stopping to look at how attributes work in general. An attribute always lives inside an opening tag, written as name="value", with the value wrapped in quotes; attributes never appear on a closing tag, so </p class="x"> is invalid HTML and browsers will ignore or mishandle it. An element can carry several attributes at once, separated by spaces, and the order between them doesn't matter. A handful of attributes, called global attributes, work on nearly every HTML element: id gives an element a unique name you can target from CSS or JavaScript, class gives it one or more group names for styling, title adds a hover tooltip, lang marks a piece of content as being in a different language than the rest of the page, and hidden removes an element from the page entirely without deleting its HTML.
Some attributes, like disabled, required, and checked, are boolean attributes: their presence alone turns the behavior on, and their absence turns it off, so you don't write disabled="true", you either include the word disabled or leave it out entirely. This is different from a valued attribute like href or class, which is meaningless without a value. Two common mistakes to watch for: leaving a value unquoted, like alt=Sunrise over hills, which browsers may parse incorrectly once a space appears, and forgetting that attributes only belong in opening tags, never closing ones.
1<!-- id: a unique hook for this one button -->2<!-- class: a reusable style group -->3<!-- title: a hover tooltip -->4<!-- disabled: a boolean attribute, present means true -->5<button id="save-btn" class="btn primary" title="Save your changes" disabled>6 Save7</button>Comments and character entities
HTML comments, written <!-- like this -->, let you leave notes in your code or temporarily remove a piece of markup without deleting it; anything between the markers is completely ignored by the browser. Because HTML uses angle brackets to define tags, you can't simply type a literal less-than or greater-than sign, or an ampersand, in your text without confusing the parser; instead you use a character entity, a short code starting with an ampersand and ending with a semicolon. The most common ones are & for an ampersand, < for a less-than sign, > for a greater-than sign, and © for a copyright symbol.
1<!-- This paragraph explains our formula, written safely -->2<p>Use the formula a < b && b < c to check the order.</p>3<p>© 2024 Example Co.</p>Attributes and nesting, together
Attributes like href, src, and alt are extra pieces of information you attach to an opening tag, always written as name="value" pairs. You've now seen several examples of nesting too, where one tag lives inside another, like a link inside a paragraph. The rule to remember is that tags must close in the reverse order they opened, like nested parentheses: if you open a p and then an a inside it, you must close the a before you close the p. Getting nesting right is what keeps your structure predictable, and browsers will often try to guess and silently fix broken nesting in ways that produce confusing results, so it's worth checking your tags carefully as you write them.
Try it yourself
Build a tiny profile section using a heading, a paragraph with an inline strong and em, a nested list of interests, and a link that opens in a new tab.
Chapter boss project
Build a recipe page
Create a single HTML page for a favorite recipe. The page needs a main heading with the recipe's name, a short paragraph describing the dish, an unordered list of ingredients, and an ordered list of preparation steps, since the ingredients don't have a required order but the steps do.
Include at least one image representing the finished dish, with meaningful alt text, sensible width and height attributes, and loading="lazy". Include at least one link to an outside page, opened safely in a new tab with target="_blank" and rel="noopener".
Somewhere in your steps, nest a sub-list for a step that has smaller details, and use at least two inline tags (for example strong for a warning about oven temperature, or em to emphasize a technique). Use a div only if you need a container with no other tag would fit, and explain your choice in an HTML comment.
Pay close attention to nesting as you build this page: make sure every list item lives inside a ul or ol, every link's text is fully contained between its opening and closing a tags, and your tags close in the right order throughout.
- Start with the overall page skeleton from Chapter 1, then add your content inside the body.
- Use h1 once for the recipe title, and consider h2 for section labels like 'Ingredients' and 'Steps'.
- Remember the img tag doesn't need a closing tag, but it does need both src and alt, and benefits from width, height, and loading.
- Any time you use target="_blank", pair it with rel="noopener".
- If your page looks wrong in the browser, open developer tools and check the Elements panel to see how your tags actually nested.
Level-up checklist
Tick these off once each one is true for you.
