From object to iframe — other embedding technologies - Learn web development

From object to iframe — other embedding technologies
====================================================

* Previous
* Overview: Multimedia and embedding
* Next

By now you should really be getting the hang of embedding things into your web pages, including images, video and audio. At this point we'd like to take somewhat of a sideways step, looking at some elements that allow you to embed a wide variety of content types into your webpages: the `<iframe>`, `<embed>` and `<object>` elements. `<iframe>`s are for embedding other web pages, and the other two allow you to embed external resources such as PDF files.

|  |  |
| --- | --- |
| Prerequisites: | Basic software installed, basic knowledge of
 working with files, familiarity with HTML fundamentals (as covered in
 Getting started with HTML) and the previous articles in this module.
  |
| Objective: |
 To learn how to embed items into web pages using
 `<object>`, `<embed>`, and
 `<iframe>`, like PDF documents and other webpages.
  |

A short history of embedding
----------------------------

A long time ago on the Web, it was popular to use **frames** to create websites — small parts of a website stored in individual HTML pages. These were embedded in a master document called a **frameset**, which allowed you to specify the area on the screen that each frame filled, rather like sizing the columns and rows of a table. These were considered the height of coolness in the mid to late 90s, and there was evidence that having a webpage split up into smaller chunks like this was better for download speeds — especially noticeable with network connections being so slow back then. They did however have many problems, which far outweighed any positives as network speeds got faster, so you don't see them being used anymore.

A little while later (late 90s, early 2000s), plugin technologies became very popular, such as Java Applets and Flash — these allowed web developers to embed rich content into webpages such as videos and animations, which just weren't available through HTML alone. Embedding these technologies was achieved through elements like `<object>`, and the lesser-used `<embed>`, and they were very useful at the time. They have since fallen out of fashion due to many problems, including accessibility, security, file size, and more. These days major browsers have stopped supporting plugins such as Flash.

Finally, the `<iframe>` element appeared (along with other ways of embedding content, such as `<canvas>`, `<video>`, etc.) This provides a way to embed an entire web document inside another one, as if it were an `<img>` or other such element, and is used regularly today.

With the history lesson out of the way, let's move on and see how to use some of these.

Active learning: classic embedding uses
---------------------------------------

In this article we are going to jump straight into an active learning section, to immediately give you a real idea of just what embedding technologies are useful for. The online world is very familiar with YouTube, but many people don't know about some of the sharing facilities it has available. Let's look at how YouTube allows us to embed a video in any page we like using an `<iframe>`.

1. First, go to YouTube and find a video you like.
2. Below the video, you'll find a *Share* button — select this to display the sharing options.
3. Select the *Embed* button and you'll be given some `<iframe>` code — copy this.
4. Insert it into the *Input* box below, and see what the result is in the *Output*.

For bonus points, you could also try embedding a Google Map in the example:

1. Go to Google Maps and find a map you like.
2. Click on the "Hamburger Menu" (three horizontal lines) in the top left of the UI.
3. Select the *Share or embed map* option.
4. Select the Embed map option, which will give you some `<iframe>` code — copy this.
5. Insert it into the *Input* box below, and see what the result is in the *Output*.

If you make a mistake, you can always reset it using the *Reset* button. If you get really stuck, press the *Show solution* button to see an answer.
```

<h2>Live output</h2>

<div class="output" style="min-height: 250px;"></div>

<h2>Editable code</h2>
<p class="a11y-label">
  Press Esc to move focus away from the code area (Tab inserts a tab character).
</p>

<textarea
 id="code"
 class="input"
 style="width: 95%;min-height: 100px;"></textarea>

<div class="playable-buttons">
  <input id="reset" type="button" value="Reset" />
  <input id="solution" type="button" value="Show solution" />
</div>
```

```
html {
  font-family: sans-serif;
}

h2 {
  font-size: 16px;
}

.a11y-label {
  margin: 0;
  text-align: right;
  font-size: 0.7rem;
  width: 98%;
}

body {
  margin: 10px;
  background: #f5f9fa;
}
```

```
const textarea = document.getElementById("code");
const reset = document.getElementById("reset");
const solution = document.getElementById("solution");
const output = document.querySelector(".output");
let code = textarea.value;
let userEntry = textarea.value;

function updateCode() {
  output.innerHTML = textarea.value;
}

reset.addEventListener("click", function () {
  textarea.value = code;
  userEntry = textarea.value;
  solutionEntry = htmlSolution;
  solution.value = "Show solution";
  updateCode();
});

solution.addEventListener("click", function () {
  if (solution.value === "Show solution") {
    textarea.value = solutionEntry;
    solution.value = "Hide solution";
  } else {
    textarea.value = userEntry;
    solution.value = "Show solution";
  }
  updateCode();
});

const htmlSolution =
  '<iframe width="420" height="315" src="https://www.youtube.com/embed/QH2-TGUlwu4" frameborder="0" allowfullscreen>\n</iframe>\n\n<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d37995.65748333395!2d-2.273568166412784!3d53.473310471916975!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x487bae6c05743d3d%3A0xf82fddd1e49fc0a1!2sThe+Lowry!5e0!3m2!1sen!2suk!4v1518171785211" width="600" height="450" frameborder="0" style="border:0" allowfullscreen>\n</iframe>';
let solutionEntry = htmlSolution;

textarea.addEventListener("input", updateCode);
window.addEventListener("load", updateCode);

// stop tab key tabbing out of textarea and
// make it write a tab at the caret position instead

textarea.onkeydown = function (e) {
  if (e.keyCode === 9) {
    e.preventDefault();
    insertAtCaret("\t");
  }

  if (e.keyCode === 27) {
    textarea.blur();
  }
};

function insertAtCaret(text) {
  const scrollPos = textarea.scrollTop;
  let caretPos = textarea.selectionStart;

  const front = textarea.value.substring(0, caretPos);
  const back = textarea.value.substring(
    textarea.selectionEnd,
    textarea.value.length,
  );
  textarea.value = front + text + back;
  caretPos += text.length;
  textarea.selectionStart = caretPos;
  textarea.selectionEnd = caretPos;
  textarea.focus();
  textarea.scrollTop = scrollPos;
}

// Update the saved userCode every time the user updates the text area code

textarea.onkeyup = function () {
  // We only want to save the state when the user code is being shown,
  // not the solution, so that solution is not saved over the user code
  if (solution.value === "Show solution") {
    userEntry = textarea.value;
  } else {
    solutionEntry = textarea.value;
  }

  updateCode();
};
```

iframes in detail
-----------------

So, that was easy and fun, right? `<iframe>` elements are designed to allow you to embed other web documents into the current document. This is great for incorporating third-party content into your website that you might not have direct control over and don't want to have to implement your own version of — such as video from online video providers, commenting systems like Disqus, maps from online map providers, advertising banners, etc. Even the live editable examples you've been using through this course are implemented using `<iframe>`s.

 Before diving into using `<iframe>` elements, there are some security concerns to be aware of.
 Say you wanted to include the MDN glossary on one of your web pages using the `<iframe>` element, you might try something like the next code example.
 If you were to add the code below into one of your pages, you might be surprised to see an error message instead of the glossary page:

```html
<head>
  <style>
 iframe {
 border: none;
 }
 </style>
</head>
<body>
  <iframe
 src="https://developer.mozilla.org/en-US/docs/Glossary"
 width="100%"
 height="500"
 allowfullscreen
 sandbox>
    <p>
      <a href="/en-US/docs/Glossary">
        Fallback link for browsers that don't support iframes
      </a>
    </p>
  </iframe>
</body>
```

If you have a look at your browser's console, you'll see an error message like the following:
```

Refused to display 'https://developer.mozilla.org/' in a frame because it set 'X-Frame-Options' to 'deny'.
```

The Security section below goes into more detail about why you see this error, but first, let's have a look at what our code is doing.

The example includes the bare essentials needed to use an `<iframe>`:

`border: none`

If used, the `<iframe>` is displayed without a surrounding border. Otherwise, by default, browsers display the `<iframe>` with a surrounding border (which is generally undesirable).

`allowfullscreen`

If set, the `<iframe>` is able to be placed in fullscreen mode using the Fullscreen API (somewhat beyond the scope of this article.)

`src`

This attribute, as with `<video>`/`<img>`, contains a path pointing to the URL of the document to be embedded.

`width` and `height`

These attributes specify the width and height you want the iframe to be.

`sandbox`

This attribute, which works in slightly more modern browsers than the rest of the `<iframe>` features (e.g. IE 10 and above) requests heightened security settings; we'll say more about this in the next section.

**Note:** In order to improve speed, it's a good idea to set the iframe's `src` attribute with JavaScript after the main content is done with loading. This makes your page usable sooner and decreases your official page load time (an important SEO metric.)

### Security concerns

Above we mentioned security concerns — let's go into this in a bit more detail now. We are not expecting you to understand all of this content perfectly the first time; we just want to make you aware of this concern, and provide a reference to come back to as you get more experienced and start considering using `<iframe>`s in your experiments and work. Also, there is no need to be scared and not use `<iframe>`s — you just need to be careful. Read on…

Browser makers and Web developers have learned the hard way that iframes are a common target (official term: **attack vector**) for bad people on the Web (often termed **hackers**, or more accurately, **crackers**) to attack if they are trying to maliciously modify your webpage, or trick people into doing something they don't want to do, such as reveal sensitive information like usernames and passwords. Because of this, spec engineers and browser developers have developed various security mechanisms for making `<iframe>`s more secure, and there are also best practices to consider — we'll cover some of these below.

**Note:** Clickjacking is one kind of common iframe attack where hackers embed an invisible iframe into your document (or embed your document into their own malicious website) and use it to capture users' interactions. This is a common way to mislead users or steal sensitive data.

A quick example first though — try loading the previous example we showed above into your browser — you can find it live on GitHub (see the source code too.) Instead of the page you expected, you'll probably see some kind of message to the effect of "I can't open this page", and if you look at the *Console* in the browser developer tools, you'll see a message telling you why. In Firefox, you'll get told something like *The loading of "https://developer.mozilla.org/en-US/docs/Glossary" in a frame is denied by "X-Frame-Options" directive set to "DENY"*. This is because the developers that built MDN have included a setting on the server that serves the website pages to disallow them from being embedded inside `<iframe>`s (see Configure CSP directives, below.) This makes sense — an entire MDN page doesn't really make sense to be embedded in other pages unless you want to do something like embed them on your site and claim them as your own — or attempt to steal data via clickjacking, which are both really bad things to do. Plus if everybody started to do this, all the additional bandwidth would start to cost Mozilla a lot of money.

#### Only embed when necessary

Sometimes it makes sense to embed third-party content — like youtube videos and maps — but you can save yourself a lot of headaches if you only embed third-party content when completely necessary. A good rule for web security is *"You can never be too cautious. If you made it, double-check it anyway. If someone else made it, assume it's dangerous until proven otherwise."*

Besides security, you should also be aware of intellectual property issues. Most content is copyrighted, offline and online, even content you might not expect (for example, most images on Wikimedia Commons). Never display content on your webpage unless you own it or the owners have given you written, unequivocal permission. Penalties for copyright infringement are severe. Again, you can never be too cautious.

If the content is licensed, you must obey the license terms. For example, the content on MDN is licensed under CC-BY-SA. That means, you must credit us properly when you quote our content, even if you make substantial changes.

#### Use HTTPS

HTTPS is the encrypted version of HTTP. You should serve your websites using HTTPS whenever possible:

1. HTTPS reduces the chance that remote content has been tampered with in transit.
2. HTTPS prevents embedded content from accessing content in your parent document, and vice versa.

HTTPS-enabling your site requires a special security certificate to be installed. Many hosting providers offer HTTPS-enabled hosting without you needing to do any setup on your own to put a certificate in place. But if you *do* need to set up HTTPS support for your site on your own, Let's Encrypt provides tools and instructions you can use for automatically creating and installing the necessary certificate — with built-in support for the most widely-used web servers, including the Apache web server, Nginx, and others. The Let's Encrypt tooling is designed to make the process as easy as possible, so there's really no good reason to avoid using it or other available means to HTTPS-enable your site.

**Note:** GitHub pages allow content to be served via HTTPS by default.
 If you are using a different hosting provider you should check what support they provide for serving content with HTTPS.

#### Always use the `sandbox` attribute

You want to give attackers as little power as you can to do bad things on your website, therefore you should give embedded content *only the permissions needed for doing its job.* Of course, this applies to your own content, too. A container for code where it can be used appropriately — or for testing — but can't cause any harm to the rest of the codebase (either accidental or malicious) is called a sandbox.

Content that's not sandboxed may be able to execute JavaScript, submit forms, trigger popup windows, etc. By default, you should impose all available restrictions by using the `sandbox` attribute with no parameters, as shown in our previous example.

If absolutely required, you can add permissions back one by one (inside the `sandbox=""` attribute value) — see the `sandbox` reference entry for all the available options. One important note is that you should *never* add both `allow-scripts` and `allow-same-origin` to your `sandbox` attribute — in that case, the embedded content could bypass the Same-origin policy that stops sites from executing scripts, and use JavaScript to turn off sandboxing altogether.

**Note:** Sandboxing provides no protection if attackers can fool people into visiting malicious content directly (outside an `iframe`). If there's any chance that certain content may be malicious (e.g., user-generated content), please serve it from a different domain to your main site.

#### Configure CSP directives

CSP stands for **content security policy** and provides a set of HTTP Headers (metadata sent along with your web pages when they are served from a web server) designed to improve the security of your HTML document. When it comes to securing `<iframe>`s, you can *configure your server to send an appropriate `X-Frame-Options` header.* This can prevent other websites from embedding your content in their web pages (which would enable clickjacking and a host of other attacks), which is exactly what the MDN developers have done, as we saw earlier on.

**Note:** You can read Frederik Braun's post On the X-Frame-Options Security Header for more background information on this topic. Obviously, it's rather out of scope for a full explanation in this article.

The <embed> and <object> elements
---------------------------------

The `<embed>` and `<object>` elements serve a different function to `<iframe>` — these elements are general purpose embedding tools for embedding external content, such as PDFs.

However, you are unlikely to use these elements very much. If you need to display PDFs, it's usually better to link to them, rather than embedding them in the page.

Historically these elements have also been used for embedding content handled by browser plugins such as Adobe Flash, but this technology is now obsolete and is not supported by modern browsers.

If you find yourself needing to embed plugin content, this is the kind of information you'll need, at a minimum:

|  | `<embed>` | `<object>` |
| --- | --- | --- |
| URL of the embedded content | `src` | `data` |
| *accurate* media type
 of the embedded content
  | `type` | `type` |
| height and width (in CSS pixels) of the box controlled by the plugin | `height``width` | `height``width` |
| names and values, to feed the plugin as parameters | ad hoc attributes with those names and values |
 single-tag `<param>` elements, contained within
 `<object>` |
| independent HTML content as fallback for an unavailable resource | not supported (`<noembed>` is obsolete) |
 contained within `<object>`, after
 `<param>` elements
  |

Let's look at an `<object>` example that embeds a PDF into a page (see the live example and the source code):

```html
<object data="mypdf.pdf" type="application/pdf" width="800" height="1200">
  <p>
    You don't have a PDF plugin, but you can
    <a href="mypdf.pdf">download the PDF file. </a>
  </p>
</object>
```

PDFs were a necessary stepping stone between paper and digital, but they pose many accessibility challenges and can be hard to read on small screens. They do still tend to be popular in some circles, but it is much better to link to them so they can be downloaded or read on a separate page, rather than embedding them in a webpage.

Test your skills!
-----------------

You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: Multimedia and embedding.

Summary
-------

The topic of embedding other content in web documents can quickly become very complex, so in this article, we've tried to introduce it in a simple, familiar way that will immediately seem relevant, while still hinting at some of the more advanced features of the involved technologies. To start with, you are unlikely to use embedding for much beyond including third-party content like maps and videos on your pages. As you become more experienced, however, you are likely to start finding more uses for them.

There are many other technologies that involve embedding external content besides the ones we discussed here. We saw some in earlier articles, such as `<video>`, `<audio>`, and `<img>`, but there are others to discover, such as `<canvas>` for JavaScript-generated 2D and 3D graphics, and `<svg>` for embedding vector graphics. We'll look at SVG in the next article of the module.

* Previous
* Overview: Multimedia and embedding
* Next


Test your skills: Multimedia and embedding - Learn web development

Test your skills: Multimedia and embedding
==========================================

The aim of this skill test is to assess whether you understand how to embed video and audio content in HTML, also using object, iframe and other embedding technologies.

**Note:** You can try solutions in the interactive editors on this page or in an online editor such as CodePen, JSFiddle, or Glitch.

If you get stuck, you can reach out to us in one of our communication channels.

Task 1
------

In this task, we want you to embed a simple audio file onto the page. You need to:

* Add the path to the audio file to an appropriate attribute to embed it on the page. The audio is called `audio.mp3`, and it is in a folder inside the current folder called `media`.
* Add an attribute to make browsers display some default controls.
* Add some appropriate fallback text for browsers that don't support `<audio>`.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.

Task 2
------

In this task, we want you to mark up a slightly more complex video player, with multiple sources, subtitles, and other features besides. You need to:

* Add an attribute to make browsers display some default controls.
* Add some appropriate fallback text for browsers that don't support `<video>`.
* Add multiple sources, containing the paths to the video files. The files are called `video.mp4` and `video.webm`, and are in a folder inside the current folder called `media`.
* Let the browser know in advance what video formats the sources point to, so it can make an informed choice of which one to download ahead of time.
* Give the `<video>` a width and height equal to its intrinsic size (320 by 240 pixels).
* Make the video muted by default.
* Display the text tracks contained in the `media` folder, in a file called `subtitles_en.vtt`, when the video is playing. You must explicitly set the type as subtitles, and the subtitle language to English.
* Make sure the readers can identify the subtitle language when they use the default controls.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.

Task 3
------

In this task, we want you to:

* Embed a PDF into the page. The PDF is called `mypdf.pdf`, and is contained in the `media` folder.
* Go to a sharing site like YouTube or Google Maps, and embed a video or other media item into the page.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.


Test your skills: HTML images - Learn web development

Test your skills: HTML images
=============================

The aim of this skill test is to assess whether you understand images and how to embed them in HTML.

**Note:** You can try solutions in the interactive editors on this page or in an online editor such as CodePen, JSFiddle, or Glitch.

If you get stuck, you can reach out to us in one of our communication channels.

Task 1
------

In this task, we want you to embed a simple image of some Blueberries into the page. You need to:

* Add the path to the image to an appropriate attribute to embed it on the page. The image is called `blueberries.jpg`, and it is in a folder inside the current folder called `images`.
* Add some alternative text to an appropriate attribute to describe the image, for people that cannot see it.
* Give the `<img>` element an appropriate `width` and `height` so that it displays at the correct aspect ratio, and enough space is left on the page to display it. The image's intrinsic size is 615 x 419 pixels.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.

Task 2
------

In this task, you already have a full-featured image, but we'd like you to add a tooltip that appears when the image is moused over. You should put some appropriate information into the tooltip.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.

Task 3
------

In this task, you are provided with both a full-featured image and some caption text. What you need to do here is add elements that will associate the image with the caption.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.


Tips for authoring fast-loading HTML pages - Learn web development

Tips for authoring fast-loading HTML pages
==========================================

These tips are based on common knowledge and experimentation.

An optimized web page not only provides for a more responsive site for your visitors but also reduces the load on your web servers and internet connection. This can be crucial for high volume sites or sites which have a spike in traffic due to unusual circumstances such as breaking news stories.

Optimizing page load performance is not just for content which will be viewed by narrowband dial-up or mobile device visitors. It is just as important for broadband content and can lead to dramatic improvements even for your visitors with the fastest connections.

Tips
----

### Reduce page weight

Page weight is by far the most important factor in page-load performance.

Reducing page weight through the elimination of unnecessary whitespace and comments, commonly known as minimization, and by moving inline script and CSS into external files, can improve download performance with minimal need for other changes in the page structure.

Tools such as HTML Tidy can automatically strip leading whitespace and extra blank lines from valid HTML source. Other tools can "compress" JavaScript by reformatting the source or by obfuscating the source and replacing long identifiers with shorter versions.

### Minimize the number of files

Reducing the number of files referenced in a web page lowers the number of HTTP connections required to download a page, thereby reducing the time for these requests to be sent, and for their responses to be received.

Depending on a browser's cache settings, it may send a request with the `If-Modified-Since` header for each referenced file, asking whether the file has been modified since the last time it was downloaded. Too much time spent querying the last modified time of the referenced files can delay the initial display of the web page, since the browser must check the modification time for each of these files, before rendering the page.

If you use background images a lot in your CSS, you can reduce the number of HTTP lookups needed by combining the images into one, known as an image sprite. Then you just apply the same image each time you need it for a background and adjust the x/y coordinates appropriately. This technique works best with elements that will have limited dimensions, and will not work for every use of a background image. However, the fewer HTTP requests and single image caching can help reduce page-load time.

### Use a Content Delivery Network (CDN)

For the purposes of this article, a CDN is a means to reduce the physical distance between your server and your visitor. As the distance between your server origin and visitor increases, the load times will increase. Suppose your website server is located in the United States and it has a visitor from India; the page load time will be much higher for the Indian visitor compared to a visitor from the US.

A CDN is a geographically distributed network of servers that work together to shorten the distance between the user and your website. CDNs store cached versions of your website and serve them to visitors via the network node closest to the user, thereby reducing latency.

Further reading:

* Understanding CDNs
### Reduce domain lookups

Since each separate domain costs time in a DNS lookup, the page load time will grow along with the number of separate domains appearing in CSS link(s) and JavaScript and image src(es).

This may not always be practical; however, you should always take care to use only the minimum necessary number of different domains in your pages.

### Cache reused content

Make sure that any content that can be cached, is cached, and with appropriate expiration times.

In particular, pay attention to the `Last-Modified` header. It allows for efficient page caching; by means of this header, information is conveyed to the user agent about the file it wants to load, such as when it was last modified. Most web servers automatically append the `Last-Modified` header to static pages (e.g. `.html`, `.css`), based on the last-modified date stored in the file system. With dynamic pages (e.g. `.php`, `.aspx`), this, of course, can't be done, and the header is not sent.

So, in particular, for pages which are generated dynamically, a little research on this subject is beneficial. It can be somewhat involved, but it will save a lot in page requests on pages which would normally not be cacheable.

More information:

1. HTTP Conditional Get for RSS Hackers
2. HTTP 304: Not Modified
3. HTTP ETag on Wikipedia
4. Caching in HTTP
### Optimally order the components of the page

Download page content first, along with any CSS or JavaScript that may be required for its initial display, so that the user gets the quickest apparent response during the page loading. This content is typically text, and can, therefore, benefit from text compression in transit, thus providing an even quicker response to the user.

Any dynamic features that require the page to complete loading before being used, should be initially disabled, and then only enabled after the page has loaded. This will cause the JavaScript to be loaded after the page contents, which will improve the overall appearance of the page load.

### Reduce the number of inline scripts

Inline scripts can be expensive for page loading since the parser must assume that an inline script could modify the page structure while parsing is in progress. Reducing the use of inline scripts in general, and reducing the use of `document.write()` to output content in particular, can improve overall page loading. Use DOM APIs to manipulate page content, rather than `document.write()`.

### Use modern CSS and valid markup

Use of modern CSS reduces the amount of markup, can reduce the need for (spacer) images, in terms of layout, and can very often replace images of stylized text — that "cost" much more than the equivalent text-and-CSS.

Using valid markup has other advantages. First, browsers will have no need to perform error-correction when parsing the HTML (this is aside from the philosophical issue of whether to allow format variation in user input and then programmatically "correct" or normalize it; or whether, instead, to enforce a strict, no-tolerance input format).

Moreover, valid markup allows for the free use of other tools that can *pre-process* your web pages. For example, HTML Tidy can remove whitespace and optional ending tags; however, it will refuse to run on a page with serious markup errors.

### Chunk your content

Tables for layouts are a legacy method that should not be used anymore. Layouts utilizing floats, positioning, flexbox, or grids should be used instead.

Tables are still considered valid markup but should be used for displaying tabular data. To help the browser render your page quicker, you should avoid nesting your tables.

Rather than deeply nesting tables as in:

```html
<table>
  <table>
    <table>
      …
    </table>
  </table>
</table>
```

use non-nested tables or divs as in

```html
<table>
  …
</table>
<table>
  …
</table>
<table>
  …
</table>
```

See also: CSS Flexible Box Layout and CSS Grid Layout specifications.

### Minify and compress SVG assets

SVG produced by most drawing applications often contains unnecessary metadata which can be removed. Configure your servers, apply gzip compression for SVG assets.

### Minify and compress your images

Large images cause your page to take more time to load. Consider compressing your images before adding them to your page, using compression features built into image-manipulation tools such as Photoshop, or using a specialized tool such as Compress Jpeg or Tiny PNG.

### Specify sizes for images and tables

If the browser can immediately determine the height and/or width of your images and tables, it will be able to display a web page without having to reflow the content. This not only speeds the display of the page but prevents annoying changes in a page's layout when the page completes loading. For this reason, `height` and `width` should be specified for images, whenever possible.

Tables should use the CSS selector: property combination:

```css
table-layout: fixed;
```

and should specify widths of columns using the `<col>` and the `<colgroup>` elements.

### Use lazy loading for images

By default, images are loaded **eagerly**; that is, the image is fetched and rendered as soon as it's processed in the HTML. All eagerly loaded images are rendered before the window's `load` event is sent. Switching to lazy loading of images tells the browser to hold off on loading images until they're about to be needed to draw the visual viewport.

To mark an image for lazy loading, specify its `loading` attribute with a value of `lazy`. With this set, the image will only be loaded when it's needed.

```html
<img src="./images/footerlogo.jpg" loading="lazy" alt="MDN logo" />
```

Note that lazily-loaded images may not be available when the `load` event is fired. You can determine if a given image is loaded by checking to see if the value of its Boolean `complete` property is `true`.

### Choose your user-agent requirements wisely

To achieve the greatest improvements in page design, make sure that reasonable user-agent requirements are specified for projects. Do not require your content to appear pixel-perfect in all browsers, especially not in down-version browsers.

Ideally, your basic minimum requirements should be based on the consideration of modern browsers that support the relevant standards. This can include recent versions of Firefox, Google Chrome, Opera, and Safari.

Note, however, that many of the tips listed in this article are common-sense techniques which apply to any user agent, and can be applied to any web page, regardless of browser-support requirements.

### Use async and defer, if possible

Make the JavaScript scripts such that they are compatible with both the async and the defer attributes, and use async whenever possible, especially if you have multiple script elements.

With that, the page can stop rendering while JavaScript is still loading. Otherwise, the browser will not render anything that is after the script elements that do not have these attributes.

Note: Even though these attributes do help a lot the first time a page is loaded, you should use them but not assume they will work in all browsers. If you already follow all JavaScript best practices, there is no need to change your code.

Example page structure
----------------------

* ``<html>``
    + ``<head>``
        - ``<link>``
         CSS files required for page appearance. Minimize the number of files for performance while keeping unrelated CSS in separate files for maintenance.
        - ``<script>``
         JavaScript files for functions **required** during the loading of the page, but not any interaction related JavaScript that can only run after page loads.
         Minimize the number of files for performance while keeping unrelated JavaScript in separate files for maintenance.
    + ``<body>``
     User visible page content in small chunks (``<header>``/ ``<main>`/` ``<table>``) that can be displayed without waiting for the full page to download.
        - ``<script>``
         Any scripts which will be used to perform interactivity. Interaction scripts typically can only run after the page has completely loaded and all necessary objects have been initialized. There is no need to load these scripts before the page content. That only slows down the initial appearance of the page load.
         Minimize the number of files for performance while keeping unrelated JavaScript in separate files for maintenance.
See also
--------

* Book: "Speed Up Your Site" by Andy King
* The excellent and very complete Best Practices for Speeding Up Your Website (Yahoo!)
* Tools for analyzing and optimizing performance: Google PageSpeed Tools


Add a hitmap on top of an image - Learn web development

Add a hitmap on top of an image
===============================

Here we go over how to set up an image map, and some downsides to consider first.

Here are some things you need to know| Prerequisites: |
 You should already know how to
 create a basic HTML document
 and how to
 add accessible images to a webpage. |
| Objective: |
 Learn how to make different regions of one image link to different
 pages.
  |

**Warning:** This article discusses client-side image maps only. Do not use server-side image maps, which require the user to have a mouse.

Image maps, and their drawbacks
-------------------------------

When you nest an image inside `<a>`, the entire image links to one webpage. An image map, on the other hand, contains several active regions (called "hotspots") that each link to a different resource.

Formerly, image maps were a popular navigation device, but it's important to thoroughly consider their performance and accessibility ramifications.

Text links (perhaps styled with CSS) are preferable to image maps for several reasons: text links are lightweight, maintainable, often more SEO-friendly, and support accessibility needs (e.g., screen readers, text-only browsers, translation services).

How to insert an image map, properly
------------------------------------

### Step 1: The image

Not just any image is acceptable.

* The image must make it clear what happens when people follow image links. `alt` text is mandatory, of course, but many people never see it.
* The image must clearly indicate where hotspots begin and end.
* Hotspots must be large enough to tap comfortably, at any viewport size. How large is large enough? 72 × 72 CSS pixels is a good minimum, with additional generous gaps between touch targets. The map of the world at 50languages.com (as of time of writing) illustrates the problem perfectly. It's much easier to tap Russia or North America than Albania or Estonia.

You insert your image much the same way as always (with an `<img>` element and `alt` text). If the image is only present as a navigation device, you may write `alt=""`, provided you furnish appropriate `alt` text in the `<area>` elements later on.

You will need a special `usemap` attribute. Come up with a unique name, containing no spaces, for your image map. Then assign that name (preceded by a hash) as the value for the `usemap` attribute:

```html
<img src="image-map.png" alt="" usemap="#example-map-1" />
```

### Step 2: Activate your hotspots

In this step, put all your code inside a `<map>` element. `<map>` only needs one attribute, the same map `name` as you used in your `usemap` attribute above:

```html
<map name="example-map-1"> </map>
```

Inside the `<map>` element, we need `<area>` elements. An `<area>` element corresponds to a single hotspot. To keep keyboard navigation intuitive, make sure the source order of `<area>` elements corresponds to the visual order of hotspots.

`<area>` elements are void elements, but do require four attributes:

`shape`

`coords`

`shape` takes one of four values: `circle`, `rect`, `poly`, and `default`. (An `<area>` whose `shape` is `default` occupies the entire image, minus any other hotspots you've defined.) The shape you choose determines the coordinate information you'll need to provide in `coords`.

* For a circle, provide the center's x and y coordinates, followed by the length of the radius.
* For a rectangle, provide the x/y coordinates of the upper-left and bottom-right corners.
* For a polygon, to provide the x/y coordinates of each corner (so, at least six values).

Coordinates are given in CSS pixels.

In case of overlap, source order carries the day.

`href`

The URL of the resource you're linking to. You may leave this attribute blank if you *don't* want the current area to link anywhere (say, if you're making a hollow circle.)

`alt`

A mandatory attribute, telling people where the link goes or what it does. `alt` text only displays when the image is unavailable. Please refer to our guidelines for writing accessible link text.

You may write `alt=""` if the `href` attribute is blank *and* the entire image already has an `alt` attribute.

```html
<map name="example-map-1">
  <area
 shape="circle"
 coords="200,250,25"
 href="page-2.html"
 alt="circle example" />

  <area
 shape="rect"
 coords="10, 5, 20, 15"
 href="page-3.html"
 alt="rectangle example" />
</map>
```

### Step 3: Make sure it works for everybody

You aren't done until you test image maps rigorously on many browsers and devices. Try following links with your keyboard alone. Try turning images off.

If your image map is wider than about 240px, you'll need to make further adjustments to make your website responsive. It's not enough to resize the image for small screens, because the coordinates stay the same and no longer match the image.

If you must use image maps, you may want to look into Matt Stow's jQuery plugin. Alternatively, Dudley Storey demonstrates a way to use SVG for an image map effect, along with a subsequent combined SVG-raster hack for bitmap images.

Learn more
----------

* `<img>`
* `<map>`
* `<area>`
* Online image map editor


Define terms with HTML - Learn web development

Define terms with HTML
======================

HTML provides several ways to convey description semantics, whether inline or as structured glossaries. In this article, we'll cover how to properly mark up keywords when you're defining them.

|  |  |
| --- | --- |
| Prerequisites: |
 You need to be familiar with how to
 create a basic HTML document.
  |
| Objective: | Learn how to introduce new keywords and how to build description lists. |

When you need a term defined, you probably go straight to a dictionary or glossary. Dictionaries and glossaries *formally* associate keywords with one or more descriptions, as in this case:

>
>
> Blue (*Adjective*)
>
>
>  Of a color like the sky in a sunny day.
>  *"The clear blue sky"*
>
>
>
>
>
>

But we're constantly defining keywords informally, as here:

>
> **Firefox** is the web browser created by the Mozilla Foundation.
>
>
>

To deal with these use cases, HTML provides tags to mark descriptions and words described, so that your meaning gets across properly to your readers.

How to mark informal description
--------------------------------

In textbooks, the first time a keyword occurs, it's common to put the keyword in bold and define it right away.

We do that in HTML too, except HTML is not a visual medium and so we don't use bold. We use `<dfn>`, which is a special element just for marking the first occurrence of keywords. Note that `<dfn>` tags go around the *word to be defined,* not the definition (the definition consists of the entire paragraph):

```html
<p><dfn>Firefox</dfn> is the web browser created by the Mozilla Foundation.</p>
```

**Note:** Another use for bold is to emphasize content. Bold itself is a concept foreign to HTML, but there are tags for indicating emphasis.

### Special case: Abbreviations

It's best to mark abbreviations specially with `<abbr>`, so that screen readers read them appropriately and so that you can operate on all abbreviations uniformly. Just as with any new keyword, you should define your abbreviations the first time they occur.

```html
<p>
  <dfn><abbr>HTML</abbr> (hypertext markup language)</dfn>
  is a description language used to structure documents on the web.
</p>
```

**Note:** The HTML spec does indeed set aside the `title` attribute for expanding the abbreviation. However, this is not an acceptable alternative for providing an inline expansion. The contents of `title` are completely hidden from your users, unless they're using a mouse and they happen to hover over the abbreviation. The spec duly acknowledges this as well.

### Improve accessibility

`<dfn>` marks the keyword defined, and indicates that the current paragraph defines the keyword. In other words, there's an implicit relationship between the `<dfn>` element and its container. If you want a more formal relationship, or your definition consists of only one sentence rather than the whole paragraph, you can use the `aria-describedby` attribute to associate a term more formally with its definition:

```html
<p>
  <span id="ff">
    <dfn aria-describedby="ff">Firefox</dfn>
    is the web browser created by the Mozilla Foundation.
  </span>
  You can download it at <a href="https://www.mozilla.org">mozilla.org</a>
</p>
```

Assistive technology can often use this attribute to find a text alternative to a given term. You can use `aria-describedby` on any tag enclosing a keyword to be defined (not just the `<dfn>` element). `aria-describedby` references the `id` of the element containing the description.

How to build a description list
-------------------------------

Description lists are just what they claim to be: a list of terms and their matching descriptions (e.g., definition lists, dictionary entries, FAQs, and key-value pairs).

**Note:** Description lists are not suitable for marking up dialog, because conversation does not directly describe the speakers. Here are recommendations for marking up dialog.

The terms described go inside `<dt>` elements. The matching description follows immediately, contained within one or more `<dd>` elements. Enclose the whole description list with a `<dl>` element.

### A simple example

Here's a simple example describing kinds of food and drink:

```html
<dl>
  <dt>jambalaya</dt>
  <dd>
    rice-based entree typically containing chicken, sausage, seafood, and spices
  </dd>

  <dt>sukiyaki</dt>
  <dd>
    Japanese specialty consisting of thinly sliced meat, vegetables, and
    noodles, cooked in sake and soy sauce
  </dd>

  <dt>chianti</dt>
  <dd>dry Italian red wine originating in Tuscany</dd>
</dl>
```

**Note:** The basic pattern, as you can see, is to alternate `<dt>` terms with `<dd>` descriptions. If two or more terms occur in a row, the following description applies to all of them. If two or more descriptions occur in a row, they all apply to the last given term.

### Improving the visual output

Here's how a graphical browser displays the foregoing list:

If you want the keywords to stand out better, you could try bolding them. Remember, HTML is not a visual medium; we need CSS for all visual effects. The CSS `font-weight` property is what you need here:

```css
dt {
  font-weight: bold;
}
```

This produces the slightly more readable result below:

Learn more
----------

* `<dfn>`
* `<dl>`
* `<dt>`
* `<dd>`
* How to use the aria-describedby attribute


Use JavaScript within a webpage - Learn web development

Use JavaScript within a webpage
===============================

Take your webpages to the next level by harnessing JavaScript. Learn in this article how to trigger JavaScript right from your HTML documents.

|  |  |
| --- | --- |
| Prerequisites: |
 You need to be familiar with how to
 create a basic HTML document.
  |
| Objective: |
 Learn how to trigger JavaScript in your HTML file, and learn the most
 important best practices for keeping JavaScript accessible.
  |

About JavaScript
----------------

JavaScript is a programming language mostly used client-side to make webpages interactive. You *can* create amazing webpages without JavaScript, but JavaScript opens up a whole new level of possibilities.

**Note:** In this article we're going over the HTML code you need to make JavaScript take effect. If you want to learn JavaScript itself, you can start with our JavaScript basics article. If you already know something about JavaScript or if you have a background with other programming languages, we suggest you jump directly into our JavaScript Guide.

How to trigger JavaScript from HTML
-----------------------------------

Within a browser, JavaScript doesn't do anything by itself. You run JavaScript from inside your HTML webpages. To call JavaScript code from within HTML, you need the `<script>` element. There are two ways to use `script`, depending on whether you're linking to an external script or embedding a script right in your webpage.

### Linking an external script

Usually, you'll be writing scripts in their own .js files. If you want to execute a .js script from your webpage, just use `<script>` with an `src` attribute pointing to the script file, using its URL:

```html
<script src="path/to/my/script.js"></script>
```

### Writing JavaScript within HTML

You may also add JavaScript code between `<script>` tags rather than providing an `src` attribute.

```html
<script>
 window.addEventListener("load", () => {
 console.log("This function is executed once the page is fully loaded");
 });
</script>
```

That's convenient when you just need a small bit of JavaScript, but if you keep JavaScript in separate files you'll find it easier to

* focus on your work
* write self-sufficient HTML
* write structured JavaScript applications
Use scripting accessibly
------------------------

Accessibility is a major issue in any software development. JavaScript can make your website more accessible if you use it wisely, or it can become a disaster if you use scripting without care. To make JavaScript work in your favor, it's worth knowing about certain best practices for adding JavaScript:

* **Make all content available as (structured) text.** Rely on HTML for your content as much as possible. For example, if you've implemented a nice JavaScript progress bar, make sure to supplement it with matching text percentages inside the HTML. Likewise, your drop-down menus should be structured as unordered lists of links.
* **Make all functionality accessible from the keyboard.**
    + Let users Tab through all controls (e.g., links and form input) in a logical order.
    + If you use pointer events (like mouse events or touch events), duplicate the functionality with keyboard events.
    + Test your site using a keyboard only.
* **Don't set nor even guess time limits.** It takes extra time to navigate with the keyboard or hear content read out. You can hardly ever predict just how long it will take for users or browsers to complete a process (especially asynchronous actions such as loading resources).
* **Keep animations subtle and brief with no flashing.** Flashing is annoying and can cause seizures. Additionally, if an animation lasts more than a couple seconds, give the user a way to cancel it.
* **Let users initiate interactions.** That means, don't update content, redirect, or refresh automatically. Don't use carousels or display popups without warning.
* **Have a plan B for users without JavaScript.** People may have JavaScript turned off to improve speed and security, and users often face network issues that prevent loading scripts. Moreover, third-party scripts (ads, tracking scripts, browser extensions) might break your scripts.
    + At a minimum, leave a short message with `<noscript>` like this: `<noscript>To use this site, please enable JavaScript.</noscript>`
    + Ideally, replicate the JavaScript functionality with HTML and server-side scripting when possible.
    + If you're only looking for simple visual effects, CSS can often get the job done even more intuitively.
    + *Since almost everybody **does** have JavaScript enabled, `<noscript>` is no excuse for writing inaccessible scripts.*
Learn more
----------

* `<script>`
* `<noscript>`
* James Edwards' introduction to using JavaScript accessibly
* Accessibility guidelines from W3C


Using data attributes - Learn web development

Using data attributes
=====================

HTML is designed with extensibility in mind for data that should be associated with a particular element but need not have any defined meaning. `data-*` attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, or extra properties on DOM.

HTML syntax
-----------

The syntax is simple. Any attribute on any element whose attribute name starts with `data-` is a data attribute. Say you have an article and you want to store some extra information that doesn't have any visual representation. Just use `data` attributes for that:

```html
<article
 id="electric-cars"
 data-columns="3"
 data-index-number="12314"
 data-parent="cars">
  …
</article>
```

JavaScript access
-----------------

Reading the values of these attributes out in JavaScript is also very simple. You could use `getAttribute()` with their full HTML name to read them, but the standard defines a simpler way: a `DOMStringMap` you can read out via a `dataset` property.

To get a `data` attribute through the `dataset` object, get the property by the part of the attribute name after `data-` (note that dashes are converted to camel case).

```js
const article = document.querySelector("#electric-cars");
// The following would also work:
// const article = document.getElementById("electric-cars")

article.dataset.columns; // "3"
article.dataset.indexNumber; // "12314"
article.dataset.parent; // "cars"
```

Each property is a string and can be read and written. In the above case setting `article.dataset.columns = 5` would change that attribute to `"5"`.

CSS access
----------

Note that, as data attributes are plain HTML attributes, you can even access them from CSS. For example to show the parent data on the article you can use generated content in CSS with the `attr()` function:

```css
article::before {
  content: attr(data-parent);
}
```

You can also use the attribute selectors in CSS to change styles according to the data:

```css
article[data-columns="3"] {
  width: 400px;
}
article[data-columns="4"] {
  width: 600px;
}
```

You can see all this working together in this JSBin example.

Data attributes can also be stored to contain information that is constantly changing, like scores in a game. Using the CSS selectors and JavaScript access here this allows you to build some nifty effects without having to write your own display routines. See this screencast for an example using generated content and CSS transitions (JSBin example).

Data values are strings. Number values must be quoted in the selector for the styling to take effect.

Issues
------

Do not store content that should be visible and accessible in data attributes, because assistive technology may not access them. In addition, search crawlers may not index data attributes' values.

See also
--------

* This article is adapted from Using data attributes in JavaScript and CSS on hacks.mozilla.org.
* Custom attributes are also supported in SVG 2; see `HTMLElement.dataset` and `data-\*` for more information.
* How to use HTML data attributes (Sitepoint)


HTML table basics - Learn web development

HTML table basics
=================

* Overview: Tables
* Next

This article gets you started with HTML tables, covering the very basics such as rows, cells, headings, making cells span multiple columns and rows, and how to group together all the cells in a column for styling purposes.

|  |  |
| --- | --- |
| Prerequisites: |
 The basics of HTML (see
 Introduction to HTML).
  |
| Objective: | To gain basic familiarity with HTML tables. |

What is a table?
----------------

A table is a structured set of data made up of rows and columns (**tabular data**). A table allows you to quickly and easily look up values that indicate some kind of connection between different types of data, for example a person and their age, or a day of the week, or the timetable for a local swimming pool.

![A sample table showing names and ages of some people - Chris 38, Dennis 45, Sarah 29, Karen 47.](/en-US/docs/Learn/HTML/Tables/Basics/numbers-table.png)

![A swimming timetable showing a sample data table](/en-US/docs/Learn/HTML/Tables/Basics/swimming-timetable.png)

Tables are very commonly used in human society, and have been for a long time, as evidenced by this US Census document from 1800:

![A very old parchment document; the data is not easily readable, but it clearly shows a data table being used.](/en-US/docs/Learn/HTML/Tables/Basics/1800-census.jpg)

It is therefore no wonder that the creators of HTML provided a means by which to structure and present tabular data on the web.

### How does a table work?

The point of a table is that it is rigid. Information is easily interpreted by making visual associations between row and column headers. Look at the table below for example and find a Jovian gas giant with 62 moons. You can find the answer by associating the relevant row and column headers.
```

<table>
  <caption>
    Data about the planets of our solar system (Source:
    <a href="https://nssdc.gsfc.nasa.gov/planetary/factsheet/"
 >Nasa's Planetary Fact Sheet - Metric</a
 >).
  </caption>
  <thead>
    <tr>
      <td colspan="2"></td>
      <th scope="col">Name</th>
      <th scope="col">Mass (10<sup>24</sup>kg)</th>
      <th scope="col">Diameter (km)</th>
      <th scope="col">Density (kg/m<sup>3</sup>)</th>
      <th scope="col">Gravity (m/s<sup>2</sup>)</th>
      <th scope="col">Length of day (hours)</th>
      <th scope="col">Distance from Sun (10<sup>6</sup>km)</th>
      <th scope="col">Mean temperature (°C)</th>
      <th scope="col">Number of moons</th>
      <th scope="col">Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th colspan="2" rowspan="4" scope="rowgroup">Terrestrial planets</th>
      <th scope="row">Mercury</th>
      <td>0.330</td>
      <td>4,879</td>
      <td>5427</td>
      <td>3.7</td>
      <td>4222.6</td>
      <td>57.9</td>
      <td>167</td>
      <td>0</td>
      <td>Closest to the Sun</td>
    </tr>
    <tr>
      <th scope="row">Venus</th>
      <td>4.87</td>
      <td>12,104</td>
      <td>5243</td>
      <td>8.9</td>
      <td>2802.0</td>
      <td>108.2</td>
      <td>464</td>
      <td>0</td>
      <td></td>
    </tr>
    <tr>
      <th scope="row">Earth</th>
      <td>5.97</td>
      <td>12,756</td>
      <td>5514</td>
      <td>9.8</td>
      <td>24.0</td>
      <td>149.6</td>
      <td>15</td>
      <td>1</td>
      <td>Our world</td>
    </tr>
    <tr>
      <th scope="row">Mars</th>
      <td>0.642</td>
      <td>6,792</td>
      <td>3933</td>
      <td>3.7</td>
      <td>24.7</td>
      <td>227.9</td>
      <td>-65</td>
      <td>2</td>
      <td>The red planet</td>
    </tr>
    <tr>
      <th rowspan="4" scope="rowgroup">Jovian planets</th>
      <th rowspan="2" scope="rowgroup">Gas giants</th>
      <th scope="row">Jupiter</th>
      <td>1898</td>
      <td>142,984</td>
      <td>1326</td>
      <td>23.1</td>
      <td>9.9</td>
      <td>778.6</td>
      <td>-110</td>
      <td>67</td>
      <td>The largest planet</td>
    </tr>
    <tr>
      <th scope="row">Saturn</th>
      <td>568</td>
      <td>120,536</td>
      <td>687</td>
      <td>9.0</td>
      <td>10.7</td>
      <td>1433.5</td>
      <td>-140</td>
      <td>62</td>
      <td></td>
    </tr>
    <tr>
      <th rowspan="2" scope="rowgroup">Ice giants</th>
      <th scope="row">Uranus</th>
      <td>86.8</td>
      <td>51,118</td>
      <td>1271</td>
      <td>8.7</td>
      <td>17.2</td>
      <td>2872.5</td>
      <td>-195</td>
      <td>27</td>
      <td></td>
    </tr>
    <tr>
      <th scope="row">Neptune</th>
      <td>102</td>
      <td>49,528</td>
      <td>1638</td>
      <td>11.0</td>
      <td>16.1</td>
      <td>4495.1</td>
      <td>-200</td>
      <td>14</td>
      <td></td>
    </tr>
    <tr>
      <th colspan="2" scope="rowgroup">Dwarf planets</th>
      <th scope="row">Pluto</th>
      <td>0.0146</td>
      <td>2,370</td>
      <td>2095</td>
      <td>0.7</td>
      <td>153.3</td>
      <td>5906.4</td>
      <td>-225</td>
      <td>5</td>
      <td>
        Declassified as a planet in 2006, but this
        <a
 href="https://www.usatoday.com/story/tech/2014/10/02/pluto-planet-solar-system/16578959/"
 >remains controversial</a
 >.
      </td>
    </tr>
  </tbody>
</table>
```

```
table {
  border-collapse: collapse;
  border: 2px solid black;
}

th,
td {
  padding: 5px;
  border: 1px solid black;
}
```

When implemented correctly, HTML tables are handled well by accessibility tools such as screen readers, so a successful HTML table should enhance the experience of sighted and visually impaired users alike.

### Table styling

You can also have a look at the live example on GitHub! One thing you'll notice is that the table does look a bit more readable there — this is because the table you see above on this page has minimal styling, whereas the GitHub version has more significant CSS applied.

Be under no illusion; for tables to be effective on the web, you need to provide some styling information with CSS, as well as good solid structure with HTML. In this module we are focusing on the HTML part; to find out about the CSS part you should visit our Styling tables article after you've finished here.

We won't focus on CSS in this module, but we have provided a minimal CSS stylesheet for you to use that will make your tables more readable than the default you get without any styling. You can find the stylesheet here, and you can also find an HTML template that applies the stylesheet — these together will give you a good starting point for experimenting with HTML tables.

### When should you NOT use HTML tables?

HTML tables should be used for tabular data — this is what they are designed for. Unfortunately, a lot of people used to use HTML tables to lay out web pages, e.g. one row to contain the header, one row to contain the content columns, one row to contain the footer, etc. You can find more details and an example at Page Layouts in our Accessibility Learning Module. This was commonly used because CSS support across browsers used to be terrible; table layouts are much less common nowadays, but you might still see them in some corners of the web.

In short, using tables for layout rather than CSS layout techniques is a bad idea. The main reasons are as follows:

1. **Layout tables reduce accessibility for visually impaired users**: screen readers, used by blind people, interpret the tags that exist in an HTML page and read out the contents to the user. Because tables are not the right tool for layout, and the markup is more complex than with CSS layout techniques, the screen readers' output will be confusing to their users.
2. **Tables produce tag soup**: As mentioned above, table layouts generally involve more complex markup structures than proper layout techniques. This can result in the code being harder to write, maintain, and debug.
3. **Tables are not automatically responsive**: When you use proper layout containers (such as `<header>`, `<section>`, `<article>`, or `<div>`), their width defaults to 100% of their parent element. Tables on the other hand are sized according to their content by default, so extra measures are needed to get table layout styling to effectively work across a variety of devices.
Active learning: Creating your first table
------------------------------------------

We've talked table theory enough, so, let's dive into a practical example and build up a simple table.

1. First of all, make a local copy of blank-template.html and minimal-table.css in a new directory on your local machine.
2. The content of every table is enclosed by these two tags: **`<table></table>`**. Add these inside the body of your HTML.
3. The smallest container inside a table is a table cell, which is created by a **`<td>`** element ('td' stands for 'table data'). Add the following inside your table tags:

```html
<td>Hi, I'm your first cell.</td>
```

4. If we want a row of four cells, we need to copy these tags three times. Update the contents of your table to look like so:

```html
<td>Hi, I'm your first cell.</td>
<td>I'm your second cell.</td>
<td>I'm your third cell.</td>
<td>I'm your fourth cell.</td>
```

As you will see, the cells are not placed underneath each other, rather they are automatically aligned with each other on the same row. Each `<td>` element creates a single cell and together they make up the first row. Every cell we add makes the row grow longer.

To stop this row from growing and start placing subsequent cells on a second row, we need to use the **`<tr>`** element ('tr' stands for 'table row'). Let's investigate this now.

1. Place the four cells you've already created inside `<tr>` tags, like so:

```html
<tr>
  <td>Hi, I'm your first cell.</td>
  <td>I'm your second cell.</td>
  <td>I'm your third cell.</td>
  <td>I'm your fourth cell.</td>
</tr>
```

2. Now you've made one row, have a go at making one or two more — each row needs to be wrapped in an additional `<tr>` element, with each cell contained in a `<td>`.
### Result

This should result in a table that looks something like the following:
```

<table>
  <tr>
    <td>Hi, I'm your first cell.</td>
    <td>I'm your second cell.</td>
    <td>I'm your third cell.</td>
    <td>I'm your fourth cell.</td>
  </tr>

  <tr>
    <td>Second row, first cell.</td>
    <td>Cell 2.</td>
    <td>Cell 3.</td>
    <td>Cell 4.</td>
  </tr>
</table>
```

```
table {
  border-collapse: collapse;
}
td,
th {
  border: 1px solid black;
  padding: 10px 20px;
}
```

**Note:** You can also find this on GitHub as simple-table.html (see it live also).

Adding headers with <th> elements
---------------------------------

Now let's turn our attention to table headers — special cells that go at the start of a row or column and define the type of data that row or column contains (as an example, see the "Person" and "Age" cells in the first example shown in this article). To illustrate why they are useful, have a look at the following table example. First the source code:

```html
<table>
  <tr>
    <td> </td>
    <td>Knocky</td>
    <td>Flor</td>
    <td>Ella</td>
    <td>Juan</td>
  </tr>
  <tr>
    <td>Breed</td>
    <td>Jack Russell</td>
    <td>Poodle</td>
    <td>Streetdog</td>
    <td>Cocker Spaniel</td>
  </tr>
  <tr>
    <td>Age</td>
    <td>16</td>
    <td>9</td>
    <td>10</td>
    <td>5</td>
  </tr>
  <tr>
    <td>Owner</td>
    <td>Mother-in-law</td>
    <td>Me</td>
    <td>Me</td>
    <td>Sister-in-law</td>
  </tr>
  <tr>
    <td>Eating Habits</td>
    <td>Eats everyone's leftovers</td>
    <td>Nibbles at food</td>
    <td>Hearty eater</td>
    <td>Will eat till he explodes</td>
  </tr>
</table>
```

```
table {
  border-collapse: collapse;
}
td,
th {
  border: 1px solid black;
  padding: 10px 20px;
}
```

Now the actual rendered table:

The problem here is that, while you can kind of make out what's going on, it is not as easy to cross reference data as it could be. If the column and row headings stood out in some way, it would be much better.

### Active learning: table headers

Let's have a go at improving this table.

1. First, make a local copy of our dogs-table.html and minimal-table.css files in a new directory on your local machine. The HTML contains the same Dogs example as you saw above.
2. To recognize the table headers as headers, both visually and semantically, you can use the **`<th>`** element ('th' stands for 'table header'). This works in exactly the same way as a `<td>`, except that it denotes a header, not a normal cell. Go into your HTML, and change all the `<td>` elements surrounding the table headers into `<th>` elements.
3. Save your HTML and load it in a browser, and you should see that the headers now look like headers.

**Note:** You can find our finished example at dogs-table-fixed.html on GitHub (see it live also).

### Why are headers useful?

We have already partially answered this question — it is easier to find the data you are looking for when the headers clearly stand out, and the design just generally looks better.

**Note:** Table headings come with some default styling — they are bold and centered even if you don't add your own styling to the table, to help them stand out.

Tables headers also have an added benefit — along with the `scope` attribute (which we'll learn about in the next article), they allow you to make tables more accessible by associating each header with all the data in the same row or column. Screen readers are then able to read out a whole row or column of data at once, which is pretty useful.

Allowing cells to span multiple rows and columns
------------------------------------------------

Sometimes we want cells to span multiple rows or columns. Take the following simple example, which shows the names of common animals. In some cases, we want to show the names of the males and females next to the animal name. Sometimes we don't, and in such cases we just want the animal name to span the whole table.

The initial markup looks like this:

```html
<table>
  <tr>
    <th>Animals</th>
  </tr>
  <tr>
    <th>Hippopotamus</th>
  </tr>
  <tr>
    <th>Horse</th>
    <td>Mare</td>
  </tr>
  <tr>
    <td>Stallion</td>
  </tr>
  <tr>
    <th>Crocodile</th>
  </tr>
  <tr>
    <th>Chicken</th>
    <td>Hen</td>
  </tr>
  <tr>
    <td>Rooster</td>
  </tr>
</table>
```

```
table {
  border-collapse: collapse;
}
td,
th {
  border: 1px solid black;
  padding: 10px 20px;
}
```

But the output doesn't give us quite what we want:

We need a way to get "Animals", "Hippopotamus", and "Crocodile" to span across two columns, and "Horse" and "Chicken" to span downwards over two rows. Fortunately, table headers and cells have the `colspan` and `rowspan` attributes, which allow us to do just those things. Both accept a unitless number value, which equals the number of rows or columns you want spanned. For example, `colspan="2"` makes a cell span two columns.

Let's use `colspan` and `rowspan` to improve this table.

1. First, make a local copy of our animals-table.html and minimal-table.css files in a new directory on your local machine. The HTML contains the same animals example as you saw above.
2. Next, use `colspan` to make "Animals", "Hippopotamus", and "Crocodile" span across two columns.
3. Finally, use `rowspan` to make "Horse" and "Chicken" span across two rows.
4. Save and open your code in a browser to see the improvement.

**Note:** You can find our finished example at animals-table-fixed.html on GitHub (see it live also).

Providing common styling to columns
-----------------------------------

### Styling without <col>

There is one last feature we'll tell you about in this article before we move on. HTML has a method of defining styling information for an entire column of data all in one place — the **`<col>`** and **`<colgroup>`** elements. These exist because it can be a bit annoying and inefficient having to specify styling on columns — you generally have to specify your styling information on *every* `<td>` or `<th>` in the column, or use a complex selector such as `:nth-child`.

**Note:** Styling columns like this is limited to a few properties: `border`, `background`, `width`, and `visibility`. To set other properties you'll have to either style every `<td>` or `<th>` in the column, or use a complex selector such as `:nth-child`.

Take the following simple example:

```html
<table>
  <tr>
    <th>Data 1</th>
    <th style="background-color: yellow">Data 2</th>
  </tr>
  <tr>
    <td>Calcutta</td>
    <td style="background-color: yellow">Orange</td>
  </tr>
  <tr>
    <td>Robots</td>
    <td style="background-color: yellow">Jazz</td>
  </tr>
</table>
```

```
table {
  border-collapse: collapse;
}
td,
th {
  border: 1px solid black;
  padding: 10px 20px;
}
```

Which gives us the following result:

This isn't ideal, as we have to repeat the styling information across all three cells in the column (we'd probably have a `class` set on all three in a real project and specify the styling in a separate stylesheet).

### Styling with <col>

Instead of doing this, we can specify the information once, on a `<col>` element. `<col>` elements are specified inside a `<colgroup>` container just below the opening `<table>` tag. We could create the same effect as we see above by specifying our table as follows:

```html
<table>
  <colgroup>
    <col />
    <col style="background-color: yellow" />
  </colgroup>
  <tr>
    <th>Data 1</th>
    <th>Data 2</th>
  </tr>
  <tr>
    <td>Calcutta</td>
    <td>Orange</td>
  </tr>
  <tr>
    <td>Robots</td>
    <td>Jazz</td>
  </tr>
</table>
```

Effectively we are defining two "style columns", one specifying styling information for each column. We are not styling the first column, but we still have to include a blank `<col>` element — if we didn't, the styling would just be applied to the first column.

If we wanted to apply the styling information to both columns, we could just include one `<col>` element with a span attribute on it, like this:

```html
<colgroup>
  <col style="background-color: yellow" span="2" />
</colgroup>
```

Just like `colspan` and `rowspan`, `span` takes a unitless number value that specifies the number of columns you want the styling to apply to.

**Note:** When the table, a column, and table cells in that column are all styled separately then styles applied to the cells are painted on top of column styles which are painted on top of the table. This is because the table layer is rendered first, then the columns' layer is rendered, with the cells' layer rendered on top of all the other table layers.

### Active learning: colgroup and col

Now it's time to have a go yourself.

Below you can see the timetable of a languages teacher. On Friday she has a new class teaching Dutch all day, but she also teaches German for a few periods on Tuesday and Thursdays. She wants to highlight the columns containing the days she is teaching.

Recreate the table by following the steps below.

1. First, make a local copy of our timetable.html file in a new directory on your local machine. The HTML contains the same table you saw above, minus the column styling information.
2. Add a `<colgroup>` element at the top of the table, just underneath the `<table>` tag, in which you can add your `<col>` elements (see the remaining steps below).
3. The first two columns need to be left unstyled.
4. Add a background color to the third column. The value for your `style` attribute is `background-color:#97DB9A;`
5. Set a separate width on the fourth column. The value for your `style` attribute is `width: 42px;`
6. Add a background color to the fifth column. The value for your `style` attribute is `background-color: #97DB9A;`
7. Add a different background color plus a border to the sixth column, to signify that this is a special day and she's teaching a new class. The values for your `style` attribute are `background-color:#DCC48E; border:4px solid #C1437A;`
8. The last two days are free days, so just set them to no background color but a set width; the value for the `style` attribute is `width: 42px;`

See how you get on with the example. If you get stuck, or want to check your work, you can find our version on GitHub as timetable-fixed.html (see it live also).

Summary
-------

That just about wraps up the basics of HTML tables. In the next article, we'll look at some slightly more advanced table features, and start to think how accessible they are for visually impaired people.

* Overview: Tables
* Next


Structuring planet data - Learn web development

Structuring planet data
=======================

* Previous
* Overview: Tables

In our table assessment, we provide you with some data on the planets in our solar system, and get you to structure it into an HTML table.

|  |  |
| --- | --- |
| Prerequisites: |
 Before attempting this assessment you should have already worked through
 all the articles in this module.
  |
| Objective: | To test comprehension of HTML tables and associated features. |

Starting point
--------------

To start the assessment, make local copies of blank-template.html, minimal-table.css, and planets-data.txt in a new directory in your local computer.

**Note:** You can try solutions in your code editor or in an online editor such as CodePen, JSFiddle, or Glitch.

If you get stuck, you can reach out to us in one of our communication channels.

Project brief
-------------

You are working at a school; currently your students are studying the planets of our solar system, and you want to provide them with an easy-to-follow set of data to look up facts and figures about the planets. An HTML data table would be ideal — you need to take the raw data you have available and turn it into a table, following the steps below.

### Steps to complete

The following steps describe what you need to do to complete the table example. All the data you'll need is contained in the `planets-data.txt` file. If you have trouble visualizing the data, look at the live example below, or try drawing a diagram.

1. Open your copy of `blank-template.html`, and start the table off by giving it an outer container, a table header, and a table body. You don't need a table footer for this example.
2. Add the provided caption to your table.
3. Add a row to the table header containing all the column headers.
4. Create all the content rows inside the table body, remembering to make all the row headings into headings semantically.
5. Ensure all the content is placed into the right cells — in the raw data, each row of planet data is shown next to its associated planet.
6. Add attributes to make the row and column headers unambiguously associated with the rows, columns, or rowgroups that they act as headings for.
7. Add a black border just around the column that contains all the planet name row headers.
Hints and tips
--------------

* The first cell of the header row needs to be blank, and span two columns.
* The group row headings (e.g. *Jovian planets*) that sit to the left of the planet name row headings (e.g. *Saturn*) are a little tricky to sort out — you need to make sure each one spans the correct number of rows and columns.
* One way of associating headers with their rows/columns is a lot easier than the other way.
Example
-------

The finished table should look like this:

![Complex table has a caption above it. The top row cells are column headers. There are three columns of headers. The first two columns have merged cells, with the third column being individual headers for each row. All the text is centered. The headers and every other row have a slight background color.](/en-US/docs/Learn/HTML/Tables/Structuring_planet_data/assessment-table.png)

You can also see the example live here (no looking at the source code — don't cheat!)

* Previous
* Overview: Tables


HTML table advanced features and accessibility - Learn web development

HTML table advanced features and accessibility
==============================================

* Previous
* Overview: Tables
* Next

In the second article in this module, we look at some more advanced features of HTML tables — such as captions/summaries and grouping your rows into table head, body and footer sections — as well as looking at the accessibility of tables for visually impaired users.

|  |  |
| --- | --- |
| Prerequisites: |
 The basics of HTML (see
 Introduction to HTML).
  |
| Objective: |
 To learn about more advanced HTML table features, and the accessibility
 of tables.
  |

Adding a caption to your table with <caption>
---------------------------------------------

You can give your table a caption by putting it inside a `<caption>` element and nesting that inside the `<table>` element. You should put it just below the opening `<table>` tag.

```html
<table>
  <caption>
    Dinosaurs in the Jurassic period
  </caption>

  …
</table>
```

As you can infer from the brief example above, the caption is meant to contain a description of the table contents. This is useful for all readers wishing to get a quick idea of whether the table is useful to them as they scan the page, but particularly for blind users. Rather than have a screen reader read out the contents of many cells just to find out what the table is about, the user can rely on a caption and then decide whether or not to read the table in greater detail.

A caption is placed directly beneath the `<table>` tag.

**Note:** The `summary` attribute can also be used on the `<table>` element to provide a description — this is also read out by screen readers. We'd recommend using the `<caption>` element instead, however, as `summary` is deprecated and can't be read by sighted users (it doesn't appear on the page).

### Active learning: Adding a caption

Let's try this out, revisiting an example we first met in the previous article.

1. Open up your language teacher's school timetable from the end of HTML Table Basics, or make a local copy of our timetable-fixed.html file.
2. Add a suitable caption for the table.
3. Save your code and open it in a browser to see what it looks like.

**Note:** You can find our version on GitHub — see timetable-caption.html (see it live also).

Adding structure with <thead>, <tfoot>, and <tbody>
---------------------------------------------------

As your tables get a bit more complex in structure, it is useful to give them more structural definition. One clear way to do this is by using `<thead>`, `<tfoot>`, and `<tbody>`, which allow you to mark up a header, footer, and body section for the table.

These elements don't make the table any more accessible to screen reader users, and don't result in any visual enhancement on their own. They are however very useful for styling and layout — acting as useful hooks for adding CSS to your table. To give you some interesting examples, in the case of a long table you could make the table header and footer repeat on every printed page, and you could make the table body display on a single page and have the contents available by scrolling up and down.

To use them:

* The `<thead>` element must wrap the part of the table that is the header — this is usually the first row containing the column headings, but this is not necessarily always the case. If you are using `<col>`/`<colgroup>` element, the table header should come just below those.
* The `<tfoot>` element needs to wrap the part of the table that is the footer — this might be a final row with items in the previous rows summed, for example. You can include the table footer right at the bottom of the table as you'd expect, or just below the table header (the browser will still render it at the bottom of the table).
* The `<tbody>` element needs to wrap the other parts of the table content that aren't in the table header or footer. It will appear below the table header or sometimes footer, depending on how you decided to structure it.

**Note:** `<tbody>` is always included in every table, implicitly if you don't specify it in your code. To check this, open up one of your previous examples that doesn't include `<tbody>` and look at the HTML code in your browser developer tools — you will see that the browser has added this tag for you. You might wonder why you ought to bother including it at all — you should, because it gives you more control over your table structure and styling.

### Active learning: Adding table structure

Let's put these new elements into action.

1. First of all, make a local copy of spending-record.html and minimal-table.css in a new folder.
2. Try opening it in a browser — You'll see that it looks OK, but it could stand to be improved. The "SUM" row that contains a summation of the spent amounts seems to be in the wrong place, and there are some details missing from the code.
3. Put the obvious headers row inside a `<thead>` element, the "SUM" row inside a `<tfoot>` element, and the rest of the content inside a `<tbody>` element.
4. Save and refresh, and you'll see that adding the `<tfoot>` element has caused the "SUM" row to go down to the bottom of the table.
5. Next, add a `colspan` attribute to make the "SUM" cell span across the first four columns, so the actual number appears at the bottom of the "Cost" column.
6. Let's add some simple extra styling to the table, to give you an idea of how useful these elements are for applying CSS. Inside the head of your HTML document, you'll see an empty `<style>` element. Inside this element, add the following lines of CSS code:

```css
tbody {
  font-size: 95%;
  font-style: italic;
}

tfoot {
  font-weight: bold;
}
```

7. Save and refresh, and have a look at the result. If the `<tbody>` and `<tfoot>` elements weren't in place, you'd have to write much more complicated selectors/rules to apply the same styling.

**Note:** We don't expect you to fully understand the CSS right now. You'll learn more about this when you go through our CSS modules (Introduction to CSS is a good place to start; we also have an article specifically on styling tables).

Your finished table should look something like the following:

**Note:** You can also find it on GitHub as spending-record-finished.html.

Nesting Tables
--------------

It is possible to nest a table inside another one, as long as you include the complete structure, including the `<table>` element. This is generally not really advised, as it makes the markup more confusing and less accessible to screen reader users, and in many cases you might as well just insert extra cells/rows/columns into the existing table. It is however sometimes necessary, for example if you want to import content easily from other sources.

The following markup shows a simple nested table:

```html
<table id="table1">
  <tr>
    <th>title1</th>
    <th>title2</th>
    <th>title3</th>
  </tr>
  <tr>
    <td id="nested">
      <table id="table2">
        <tr>
          <td>cell1</td>
          <td>cell2</td>
          <td>cell3</td>
        </tr>
      </table>
    </td>
    <td>cell2</td>
    <td>cell3</td>
  </tr>
  <tr>
    <td>cell4</td>
    <td>cell5</td>
    <td>cell6</td>
  </tr>
</table>
```

The output of which looks something like this:
```

table {
  border-collapse: collapse;
}
td,
th {
  border: 1px solid black;
  padding: 10px 20px;
}
```

Tables for visually impaired users
----------------------------------

Let's recap briefly on how we use data tables. A table can be a handy tool, for giving us quick access to data and allowing us to look up different values. For example, it takes only a short glance at the table below to find out how many rings were sold in Gent during August 2016. To understand its information we make visual associations between the data in this table and its column and/or row headers.

Items Sold August 2016|  | Clothes | Accessories |
| Trousers | Skirts | Dresses | Bracelets | Rings |
| Belgium | Antwerp | 56 | 22 | 43 | 72 | 23 |
| Gent | 46 | 18 | 50 | 61 | 15 |
| Brussels | 51 | 27 | 38 | 69 | 28 |
| The Netherlands | Amsterdam | 89 | 34 | 69 | 85 | 38 |
| Utrecht | 80 | 12 | 43 | 36 | 19 |

But what if you cannot make those visual associations? How then can you read a table like the above? Visually impaired people often use a screen reader that reads out information on web pages to them. This is no problem when you're reading plain text but interpreting a table can be quite a challenge for a blind person. Nevertheless, with the proper markup we can replace visual associations by programmatic ones.

**Note:** There are around 253 Million people living with Visual Impairment according to WHO data in 2017.

This section of the article provides further techniques for making tables as accessible as possible.

### Using column and row headers

Screen readers will identify all headers and use them to make programmatic associations between those headers and the cells they relate to. The combination of column and row headers will identify and interpret the data in each cell so that screen reader users can interpret the table similarly to how a sighted user does.

We already covered headers in our previous article — see Adding headers with <th> elements.

### The scope attribute

A new topic for this article is the `scope` attribute, which can be added to the `<th>` element to tell screen readers exactly what cells the header is a header for — is it a header for the row it is in, or the column, for example? Looking back to our spending record example from earlier on, you could unambiguously define the column headers as column headers like this:

```html
<thead>
  <tr>
    <th scope="col">Purchase</th>
    <th scope="col">Location</th>
    <th scope="col">Date</th>
    <th scope="col">Evaluation</th>
    <th scope="col">Cost (€)</th>
  </tr>
</thead>
```

And each row could have a header defined like this (if we added row headers as well as column headers):

```html
<tr>
  <th scope="row">Haircut</th>
  <td>Hairdresser</td>
  <td>12/09</td>
  <td>Great idea</td>
  <td>30</td>
</tr>
```

screen readers will recognize markup structured like this, and allow their users to read out the entire column or row at once, for example.

`scope` has two more possible values — `colgroup` and `rowgroup`. These are used for headings that sit over the top of multiple columns or rows. If you look back at the "Items Sold August 2016" table at the start of this section of the article, you'll see that the "Clothes" cell sits above the "Trousers", "Skirts", and "Dresses" cells. All of these cells should be marked up as headers (`<th>`), but "Clothes" is a heading that sits over the top and defines the other three subheadings. "Clothes" therefore should get an attribute of `scope="colgroup"`, whereas the others would get an attribute of `scope="col"`.

### The id and headers attributes

An alternative to using the `scope` attribute is to use `id` and `headers` attributes to create associations between headers and cells. The way they are used is as follows:

1. You add a unique `id` to each `<th>` element.
2. You add a `headers` attribute to each `<td>` element. Each `headers` attribute has to contain a list of the `id`s of all the `<th>` elements that act as a header for that cell, separated by spaces.

This gives your HTML table an explicit definition of the position of each cell in the table, defined by the header(s) for each column and row it is part of, kind of like a spreadsheet. For it to work well, the table really needs both column and row headers.

Returning to our spending costs example, the previous two snippets could be rewritten like this:

```html
<thead>
  <tr>
    <th id="purchase">Purchase</th>
    <th id="location">Location</th>
    <th id="date">Date</th>
    <th id="evaluation">Evaluation</th>
    <th id="cost">Cost (€)</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th id="haircut">Haircut</th>
    <td headers="location haircut">Hairdresser</td>
    <td headers="date haircut">12/09</td>
    <td headers="evaluation haircut">Great idea</td>
    <td headers="cost haircut">30</td>
  </tr>

  …
</tbody>
```

**Note:** This method creates very precise associations between headers and data cells but it uses **a lot** more markup and does not leave any room for errors. The `scope` approach is usually enough for most tables.

### Active learning: playing with scope and headers

1. For this final exercise, we'd like you to first make local copies of items-sold.html and minimal-table.css, in a new directory.
2. Now try adding in the appropriate `scope` attributes to make this table more appropriate.
3. Finally, try making another copy of the starter files, and this time make the table more accessible using `id` and `headers` attributes.

**Note:** You can check your work against our finished examples — see items-sold-scope.html (also see this live) and items-sold-headers.html (see this live too).

Summary
-------

There are a few other things you could learn about tables in HTML, but this is all you need to know for now. Next, you can test yourself with our HTML tables assessment. Have fun!

If you are already learning CSS and have done well on the assessment, you can move on and learn about styling HTML tables — see Styling tables.

If you want to get started with learning CSS, check out the CSS Learning Area!

* Previous
* Overview: Tables
* Next


Marking up a letter - Learn web development

Marking up a letter
===================

* Previous
* Overview: Introduction to HTML
* Next

We all learn to write a letter sooner or later; it is also a useful example to test our text formatting skills. In this assignment, you'll have a letter to mark up as a test for your HTML text formatting skills, as well as hyperlinks and proper use of the HTML `<head>` element.

|  |  |
| --- | --- |
| Prerequisites: |
 Before attempting this assessment you should have already worked through
 Getting started with HTML,
 What's in the head? Metadata in HTML,
 HTML text fundamentals,
 Creating hyperlinks, and
 Advanced text formatting.
  |
| Objective: |
 Test basic and advanced HTML text formatting, use of hyperlinks, and use
 of HTML <head>.
  |

Starting point
--------------

 To begin, get the raw text you need to mark up, and the CSS to style the HTML.
 Create a new `.html` file using your text editor or use an online editor such as CodePen, JSFiddle, or Glitch.

**Note:** If you get stuck, you can reach out to us in one of our communication channels.

Project brief
-------------

For this project, your task is to mark up a letter that needs to be hosted on a university intranet. The letter is a response from a research fellow to a prospective PhD student concerning their application to the university.

### Block/structural semantics

* Use appropriate document structure including doctype, and `<html>`, `<head>` and `<body>` elements.
* In general, the letter should be marked up as an organization of headings and paragraphs, with the following exception. There is one top level heading (the "Re:" line) and three second level headings.
* Use an appropriate list type to mark up the semester start dates, study subjects, and exotic dances.
* Put the two addresses inside `<address>` elements. Each line of the address should sit on a new line, but not be in a new paragraph.
### Inline semantics

* The names of the sender and receiver (and *Tel* and *Email*) should be marked up with strong importance.
* The four dates in the document should have appropriate elements containing machine-readable dates.
* The first address and first date in the letter should have a class attribute value of *sender-column*. The CSS you'll add later will cause these to be right aligned, as it should be in the case in a classic letter layout.
* Mark up the following five acronyms/abbreviations in the main text of the letter — "PhD," "HTML," "CSS," "BC," and "Esq." — to provide expansions of each one.
* The six sub/superscripts should be marked up appropriately — in the chemical formulae, and the numbers 103 and 104 (they should be 10 to the power of 3 and 4, respectively).
* Try to mark up at least two appropriate words in the text with strong importance/emphasis.
* There are two places where the letter should have a hyperlink. Add appropriate links with titles. For the location that the links point to, you may use `http://example.com` as the URL.
* Mark up the university motto quote and citation with appropriate elements.
### The head of the document

* The character set of the document should be set as utf-8 using the appropriate meta tag.
* The author of the letter should be specified in an appropriate meta tag.
* The provided CSS should be included inside an appropriate tag.
Hints and tips
--------------

* Use the W3C HTML validator to validate your HTML. Award yourself bonus points if it validates.
* You don't need to know any CSS to do this assignment. You just need to put the provided CSS inside an HTML element.
Example
-------

The following screenshot shows an example of what the letter might look like after being marked up.

![Example](/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter/letter-update.png)

* Previous
* Overview: Introduction to HTML
* Next