Skip to content
EzzyWeb

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.

Headings and paragraphs together
HTML
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>
The h1 introduces the whole page, while the h2 introduces a smaller section within it. Notice that each idea gets its own paragraph tag rather than being crammed together.

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.

Ordered and unordered lists
HTML
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>
The packing list uses ul because the order of items doesn't matter, while the steps use ol because they should be followed in sequence.

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.

A nested list and ordered-list attributes
HTML
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>
This list starts labeling at C (the third letter) because of start="3" and type="A", and its second item contains a nested ul with two sub-items.

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.

A link to another site
HTML
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>
The href attribute holds the destination URL, and the visible link text sits between the opening and closing a tags.

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.

Links that open, download, email, and call
HTML
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>
target="_blank" with rel="noopener" is the safe way to open a link in a new tab; download, mailto:, and tel: each change what clicking a link actually does.

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.

An image with descriptive alt text
HTML
1<img src="mountain-sunrise.jpg" alt="Sunrise over a mountain range with orange sky" />
Notice the img tag closes itself with a trailing slash and space, and the alt text describes what's in the picture rather than just naming the file.

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.

An image tuned for real-world performance
HTML
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/>
width and height reserve space to prevent layout jump, loading="lazy" defers offscreen images, and title adds an optional hover tooltip.

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.

Several inline tags in one small page
HTML
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>
Each inline tag changes what a piece of text means, not just how it looks: importance, emphasis, relevance, code, an aside, a line break, a thematic break, and two kinds of quotation.

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.

div for blocks, span for inline pieces
HTML
1<div class="card">2  <h2>Weather Today</h2>3  <p>It's <span class="highlight">72&deg;F</span> and sunny.</p>4</div>
The outer div groups a whole card of block content together for styling. The inner span wraps just a few words within a sentence so they can be styled without breaking the flow of the paragraph.

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.

Several attributes, annotated
HTML
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 above each line explain what that attribute contributes. disabled needs no value at all; its mere presence disables the 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 &amp; for an ampersand, &lt; for a less-than sign, &gt; for a greater-than sign, and &copy; for a copyright symbol.

Comments and entities in practice
HTML
1<!-- This paragraph explains our formula, written safely -->2<p>Use the formula a &lt; b &amp;&amp; b &lt; c to check the order.</p>3<p>&copy; 2024 Example Co.</p>
Without entities, the less-than signs and ampersand here would look like the start of a tag or a broken reference. Entities let you show those characters as plain text.

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.

Live preview

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.