# Learn

# Learn Accessibility

Digital accessibility, commonly abbreviated a11y, is about designing and
building websites and web apps that disabled people can interact with in
a meaningful and equivalent way.

This course is created for beginner and advanced web developers.
You can go through the series from start to finish
to get a general understanding of accessibility practices and testing,
or you can use it as a reference for specific subjects. If you read an
unfamiliar term, refer to our [glossary](/learn/accessibility/glossary).
For those new to web development overall, check out the
[Learn HTML](/learn/html) courses for fundamentals with markup and
[Learn CSS](/learn/css) courses for styling fundamentals.

**This is not a complete reference**. Each section introduces the section topic, provides context and examples. There will be links to topic references, such as [MDN](https://developer.mozilla.org) and
[WCAG](https://www.w3.org/WAI/standards-guidelines/) specifications, and other
[web.dev](/learn) articles. Each section will have a short assessment to help
people confirm their understanding.

Some accessibility best practices differ, based on the disability you're
addressing. It's important to understand your users and to
listen to people with disabilities when they tell you what they need.

We are open to your feedback! [Open a GitHub issue](https://github.com/GoogleChrome/web.dev/issues/new/choose)
and give as much information as you can so we can address it.

Here's what you'll learn:

{% include 'partials/course-index.njk' %}

So, are you ready to learn accessibility? [Let's get started](/learn/accessibility/why).

{% Aside %}
This course was written by [Carie Fisher](https://cariefisher.com/)
([Twitter](https://twitter.com/cariefisher) and
[LinkedIn](https://linkedin.com/in/cariefisher)), with input and review from
[Alexandra White](https://heyawhite.com)
([Twitter](https://twitter.com/heyawhite)), and
[Rachel Andrew](https://rachelandrew.co.uk/)
([Twitter](https://twitter.com/rachelandrew)). Special thanks to
[Mark Steadman](https://twitter.com/Steady5063) for providing additional support
for the [JavaScript module](/learn/accessibility/javascript/), and 
[Aaron Forinton](https://github.com/aaronforinton) for supporting the publication process.
{% endAside %}

# ARIA and HTML

Most developers are familiar with the standard markup language of our modern
web, [HyperText Markup Language (HTML)](https://developer.mozilla.org/docs/Web/HTML).
However, you may be less familiar with
[Accessible Rich Internet Applications (ARIA)](https://developer.mozilla.org/docs/Web/Accessibility/ARIA)
(formally called WAI-ARIA): what it is, how it is used, and when&mdash;and when _not_&mdash;to use it.

HTML and ARIA play important roles in making digital products accessible,
especially when it comes to assistive technology (AT) such as screen readers.
Both are used to convert content into an alternate format, such as Braille or
Text-to-Speech (TTS).

Let's review a short history of ARIA, why it is important, and when and how
best to use it.

## Introduction to ARIA

ARIA was first developed in 2008 by the
[Web Accessibility Initiative (WAI)](https://www.w3.org/WAI/) group&mdash;a
subset of the overarching World Wide Web Consortium (W3C), which governs and
regulates the internet.

ARIA is not a true programming language but a set of attributes you can add to
HTML elements to increase their accessibility. These attributes communicate
role, state, and property to assistive technologies via accessibility APIs
found in modern browsers. This communication happens through the accessibility
tree.

<blockquote>
  <p>
    "<a href="https://www.w3.org/WAI/standards-guidelines/aria/">WAI-ARIA</a>, 
    the Accessible Rich Internet Applications Suite, defines a way to make web
    content and web applications more accessible to people with disabilities. It
    especially helps with dynamic content and advanced user interface controls
    developed with HTML, JavaScript, and related technologies."
  </p>
  <cite>
    <a href="https://www.w3.org/WAI/">The WAI group</a>
  </cite>
</blockquote>

### The accessibility tree

ARIA modifies incorrect or incomplete code to create a better experience for
those using AT by changing, exposing, and augmenting parts of the accessibility
tree. 

The accessibility tree is created by the browser and based on the standard
Document Object Model (DOM) tree. Like the DOM tree, the accessibility tree
contains objects representing all the markup elements, attributes, and text
nodes. The accessibility tree is also used by platform-specific accessibility
APIs to provide a representation that assistive technologies can understand.

<figure>
{% Img
  src="image/T4FyVKpzu4WKF1kBNvXepbi08t52/G1IWcJBT9tfZq4xCKTqq.jpg",
  alt="The ARIA augmented accessibility tree.", 
  width="575",
  height="383"
%}
</figure>

ARIA on its own doesn't change an element's functionality or visual appearance.
That means only AT users will notice differences between a digital product with
ARIA and one without it. That also means that developers alone are responsible
for making the appropriate code and styling changes to make an element as
accessible as possible.

The three main features of ARIA are roles, properties, and states/values.

_Roles_ define what an element is or does on the page or app.

```html
<div role="button">Self-destruct</div>
```

_Properties_ express characteristics or relationships to an object.

```html
<div role="button" aria-describedby="more-info">Self-destruct</div>

<div id="more-info">This page will self-destruct in 10 seconds.</div>
```

_States/values_ define the current conditions or data values associated with the element.

```html
<div role="button" aria-describedby="more-info" aria-pressed="false">
  Self-destruct
</div>

<div id="more-info">
  This page will self-destruct in 10 seconds.
</div>
```

While all three elements of ARIA can be used in one line of code, it's not
required. Instead, layer ARIA roles, properties, and states/values until you've
accomplished your final accessibility goal. Correctly incorporating ARIA into
your code base ensures that AT users will have all the information they need to
use your website, app, or other digital product successfully and equitably.

Recently, Chrome DevTools has created a way to
[see the full accessibility tree](https://developer.chrome.com/blog/full-accessibility-tree/)
making it easier for developers to understand how their code impacts
accessibility.

## When to use ARIA

In 2014, the W3C officially published the HTML5 recommendation. With it came
some big changes, including the addition of landmark elements such as `<main>`,
`<header>`, `<footer>`, `<aside>`, `<nav>`, and attributes like `hidden` and
`required`. With these new HTML5 elements and attributes, coupled with
increased browser support, certain parts of ARIA are now less critical.

When the browser supports an HTML tag with an implicit role with an ARIA
equivalent, there is usually no need to add ARIA to the element. However, ARIA
still includes many roles, states, and properties that aren't available in any
version of HTML. Those attributes remain useful for now.

This brings us to the ultimate question: When should you use ARIA? Thankfully
the WAI group has developed the
[five rules of ARIA](https://www.w3.org/TR/using-aria/) to help you decide how
to make elements accessible.

### Rule 1: Don't use ARIA

Yes, you read that right. Adding ARIA to an element does not inherently make it
more accessible. The [WebAIM Million annual accessibility report](https://webaim.org/projects/million/)
found that home pages with ARIA
present averaged 70% more detected errors than those without ARIA, primarily
due to the improper implementation of the ARIA attributes.

There are exceptions to this rule. ARIA is required when an HTML element
doesn't have accessibility support. This could be because the design doesn't
allow for a specific HTML element or the wanted feature/behavior isn't
available in HTML. However, these situations should be scarce.

<div class="switcher">
{% Compare 'worse' %}
```html
<a role="button">Submit</a>
```
{% endCompare %}

{% Compare 'better' %}
```html
<button>Submit</button>
```
{% endCompare %}
</div>

When in doubt, use [semantic HTML elements](/learn/html/semantic-html/).

### Rule 2: Don't add (unnecessary) ARIA to HTML

In most circumstances, HTML elements work well out of the box and do not need additional ARIA added to them. In fact, developers using ARIA often have to add additional code to make the elements functional in the case of interactive elements.

<div class="switcher">
{% Compare 'worse' %}
```html
<h2 role="tab">Heading tab</h2>
```
{% endCompare %}

{% Compare 'better' %}
```html
<div role="tab"><h2>Heading tab</h2></div>
```
{% endCompare %}
</div>

Do less work and have better-performing code when you use HTML elements as
intended.

### Rule 3: Always support keyboard navigation

All interactive (not disabled) ARIA controls must be keyboard accessible. You
can add tabindex= "0" to any element that needs a focus that doesn't normally
receive keyboard focus. Avoid [using tab indexes with positive
integers](https://www.scottohara.me/blog/2019/05/25/tabindex.html)
whenever possible to prevent potential keyboard focus order issues.

<div class="switcher">
{% Compare 'worse' %}
```html
<span role="button" tabindex="1">Submit</span>
```
{% endCompare %}

{% Compare 'better' %}
```html
<span role="button" tabindex="0">Submit</span>
```

{% CompareCaption %}
Of course, if you can, use a real `<button>` element in this case.
{% endCompareCaption %}

{% endCompare %}
</div>

{% Aside 'caution' %}
Remember, people with and without visual impairments use keyboard navigation. Don't add unnecessary tab stops to headings and paragraphs, as these can add additional challenges for some users who navigate by keyboard alone.
{% endAside %}

### Rule 4: Don't hide focusable elements

Don't add `role= "presentation"` or `aria-hidden= "true"` to elements that need
to have focus&mdash;including elements with a `tabindex= "0"`. When you add
these roles/states to elements, it sends a message to the AT that these
elements are not important and to skip over them. This can lead to confusion or
disrupt users attempting to interact with an element.

<div class="switcher">
{% Compare 'worse' %}
```html
<div aria-hidden="true"><button>Submit</button></div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<div><button>Submit</button></div>
```
{% endCompare %}
</div>

### Rule 5: Use accessible names for interactive elements

The purpose of an interactive element needs to be conveyed to a user before
they know how to interact with it. Ensure that all elements have an
[accessible name](https://www.w3.org/TR/accname-1.1/) for people using AT
devices. 

Accessible names can be the content surrounded by an element (in the case of an
`<a>`), alternative text, or a label.

For each of the following code samples, the accessible name is "Red leather
boots."

```html
<!-- A plain link with text between the link tags. -->
<a href="shoes.html">Red leather boots</a>

<!-- A linked image, where the image has alt text. -->
<a href="shoes.html"><img src="shoes.png" alt="Red leather boots"></a>

<!-- A checkbox input with a label. -->
<input type="checkbox" id="shoes">
<label for="shoes">Red leather boots</label>
```

There are many ways to check an element's accessible name, including inspecting the accessibility tree using [Chrome DevTools](https://developer.chrome.com/blog/full-accessibility-tree/) or testing it with a screen reader.

{% Aside %}
Coming soon: read more about screen reader testing in the Assistive Technology module.
{% endAside %}

## ARIA in HTML

While using HTML elements on their own is best practice, ARIA elements can be
added in certain situations. For example, you may pair ARIA with HTML in
patterns that need a higher level of AT support because of environmental
constraints or as a fall-back method for HTML elements that aren't fully
supported by all browsers.

Of course, there are recommendations for implementing [ARIA in
HTML](https://www.w3.org/TR/html-aria/). Most importantly: don't override
default HTML roles, reduce redundancy, and be aware of unintended side effects.

Let's look at some examples.

{% Compare 'worse' %}
```html
<a role="heading">Read more</a>
```

{% CompareCaption %}
Assigned the wrong role.
{% endCompareCaption %}

{% endCompare %}

{% Compare 'better' %}
```html
<a aria-label="Read more about some awesome article title">Read More</a>
```

{% CompareCaption %}
Correct role and an extra link description.
{% endCompareCaption %}

{% endCompare %}

<hr />

{% Compare 'worse' %}
```html
<ul role="list">...</ul>
```

{% CompareCaption %}
Redundant role.
{% endCompareCaption %}

{% endCompare %}

{% Compare 'better' %}
```html
<ul>...</ul>
```

{% CompareCaption %}
Redundancy removed
{% endCompareCaption %}

{% endCompare %}

<hr />

{% Compare 'worse' %}
```html
<details>
  <summary role="button">more information</summary>
  ...
</details>
```

{% CompareCaption %}
Potential side effects.
{% endCompareCaption %}

{% endCompare %}

{% Compare 'better' %}
```html
<details>
  <summary>more information</summary>
  ...
</details>
```

{% CompareCaption %}
No unintended side effects.
{% endCompareCaption %}

{% endCompare %}

{% Aside %}
One place in particular where ARIA can be useful is in forms. Check out the [Learn Forms accessibility module](/learn/forms/accessibility/).
{% endAside %}

## Complexities of ARIA

ARIA is complex, and you should always use caution when using it. While the
code examples in this lesson are fairly straightforward, creating accessible
custom patterns can quickly get complicated. 

There are many things to pay attention to, including but not limited to:
keyboard interactions, touch interfaces, AT/browser support, translation needs,
environmental constraints, legacy code, and user preferences. A little bit of
coding knowledge can be detrimental&mdash;or just plain annoying&mdash;if used
incorrectly. Remember to keep your code simple.

Those warnings aside, digital accessibility is not an all-or-nothing
situation&mdash;it's a spectrum that allows for some gray areas like this.
Multiple coding solutions can be seen as "correct," depending on the situation.
What is important is that you keep learning, testing, and trying to make our
digital world more open to all.

{% Assessment 'aria' %}

# Color and contrast

Have you ever tried to read text on a screen and found it difficult to read due
to the color scheme or struggled to see the screen in a very bright or
low-light environment? Or maybe you are someone with a more permanent color
vision issue, like the estimated [300 million people with color blindness](https://www.colourblindawareness.org/colour-blindness/)
or the [253 million people with low vision](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5820628/)? 

As a designer or developer, you need to understand how people perceive color
and contrast, whether temporary, situationally, or permanently. This will help
you best support their visual needs.

This module will introduce you to some accessible color and contrast fundamentals.

## Perceiving color

Did you know that objects do not possess color but reflect wavelengths of 
light? When you see color, your eyes receive and process those wavelengths and 
convert them to colors.

<figure>
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/cXQwXdc8J77KegJZtDD6.png", alt="An eye viewing the color wheel.", width="600", height="350"
%}
</figure>

When it comes to digital accessibility, we talk about these wavelengths in
terms of hue, saturation, and lightness (HSL). The HSL model was created as an
alternative to the RGB color model and more closely aligns with how a human
perceives color.

{% Aside %}
In CSS, a color can be specified in many ways, such as using color names, RGB,
RGBa, HEX, HSL, HSLa, HSV, or HSVa values. HSLa is similar to HSL, only an
alpha value has been added. Alpha is a measurement of opacity and is defined as
a number between 0.0 (fully transparent) and 1.0 (fully opaque).
{% endAside %}

_Hue_ is a qualitative way to describe a color, such as red, green, or blue,
where each hue has a specific spot on the color spectrum with values ranging
from 0 to 360, with red at 0, green at 120, and blue at 240.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'eYrEZqE',
 height: 350,
 theme: 'auto',
 tab: 'result',
 allow: ['geolocation']
} %}

Saturation is the intensity of a color, measured in percentages ranging from 0%
to 100%. A color with full saturation (100%) would be very vivid, while a color
with no saturation (0%) would be grayscale or black and white.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'vYjJKBP',
 height: 350,
 theme: 'auto',
 tab: 'result',
 allow: ['geolocation']
} %}

Lightness is a color's light or dark character, measured in percentages ranging
from 0% (black) to 100% (white). 

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'poVrboR',
 height: 350,
 theme: 'auto',
 tab: 'result',
 allow: ['geolocation']
} %}

## Measuring color contrast

To help support people with various visual disabilities, the WAI group created a
[color contrast formula](https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio) to
ensure [enough contrast exists](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html)
between the text and its background. When these color contrast ratios are
followed, people with moderately low vision can read text on the background
without needing contrast-enhancing assistive technology.

Let's look at images with a vibrant color palette and compare how that image
would appear to those with specific forms of color blindness.

<div class="switcher">
<figure>
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/Tan7yQpVFXDwUFxta05Z.jpg", alt="Original rainbow sand.", width="640", height="427"
    %}
    <figcaption>
      Photo by Alexander Grey on <a href="https://unsplash.com/photos/QGQz-IBBl5w">Unsplash</a>.
    </figcaption>
</figure>
<figure>
    {% Img
      src="image/VbsHyyQopiec0718rMq2kTE1hke2/3T6ZA4XYZA4sdCUZluNT.jpg", alt="Original rainbow pattern.", width="640", height="427"
      %}
      <figcaption>        
        Photo by Clark Van Der Beken on <a href="https://unsplash.com/photos/xFdrt8YIoJc">Unsplash</a>.
      </figcaption>
</figure>
</div>

On the left, the image shows rainbow sand with purple, red, orange, yellow, aqua green, light blue, and dark blue colors. On the right is a brighter, multicolored rainbow pattern.

### Deuteranopia

<div class="switcher">
<figure>
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/MmstWzPwC5oEZiy3ltXJ.jpg", alt="Rainbow sand, as seen by a person with deuteranopia.", width="450", height="300" %}
</figure>
<figure>
     {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/i9uQOQaWkyjUv0p2EqTI.jpg", alt="Rainbow pattern, as seen by a person with deuteranopia.", width="450", height="300" %}
</figure>
</div>

[Deuteranopia](https://www.color-blindness.com/deuteranopia-red-green-color-blindness/)
(commonly known as green blind) occurs in 1% to 5% of males, 0.35% to 0.1% of
females.

People with Deuteranopia have a reduced sensitivity to green light. This color blindness filter simulates what this type of color blindness might look like.

### Protanopia

<div class="switcher">
<figure>
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/hj9QDGzaCx7Fd9g5oJBr.jpg", alt="Rainbow sand, as seen by a person with protanopia.", width="450", height="300" %}  
</figure>
<figure>
     {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/o2Tu1YwNNgX3FYnCSocq.jpg", alt="Rainbow pattern, as seen by a person with protanopia.", width="450", height="300" %}
</figure>
</div>

[Protanopia](https://www.color-blindness.com/protanopia-red-green-color-blindness/)
(commonly known as red blind) occurs in 1.01% to 1.08% of males and 0.02% of
0.03% of females.

People with Protanopia have a reduced sensitivity to red light. This color blindness filter simulates what this type of color blindness might look like.

### Achromatopsia or Monochromatism

<div class="switcher">
<figure>
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/R372C4rw8c4bb3PKialX.jpg", alt="Rainbow sand, as seen by a person with achromatopsia.", width="450", height="300"  %}
</figure>
<figure>
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/41D6WgI6mnv2tgYhtLzt.jpg", alt="Rainbow pattern, as seen by a person with achromatopsia.", width="450", height="300"  %}
</figure>
</div>

[Achromatopsia or Monochromatism](https://www.color-blindness.com/2007/07/20/monochromacy-complete-color-blindness/) (or complete color blindness) occurs very, very rarely.

People with Achromatopsia or Monochromatism have almost no perception of red,
green, or blue light. This color blindness filter simulates what this type of
color blindness might look like.

### Calculate color contrast

The color contrast formula uses the
[relative luminance](https://www.w3.org/TR/WCAG/#dfn-relative-luminance) of
colors to help determine contrast, which can range from 1 to 21. This formula
is often shortened to `[color value]:1`. For example, pure black against pure
white has the largest color contrast ratio at `21:1`.

```text
(L1 + 0.05) / (L2 + 0.05)
L1 is the relative luminance of the lighter color
L2 is the relative luminance of the darker colors
```

Regular-sized text, including images of text, must have a color contrast ratio
of `4.5:1` to pass the
[minimum WCAG requirements for color](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html).
Large-sized text and essential icons must have a color contrast ratio of `3:1`.
Large-sized text is characterized by being at least 18pt / 24px or 14pt /
18.5px bolded. Logos and decorative elements are exempt from these color
contrast requirements.

Thankfully, no advanced math is required as there are a lot of tools that will
do the color contrast calculations for you. Tools like
[Adobe Color](https://color.adobe.com/create/color-accessibility),
[Color Contrast Analyzer](https://www.tpgi.com/color-contrast-checker/),
[Leonardo](https://leonardocolor.io/), and
[Chrome's DevTools color picker](https://developer.chrome.com/docs/devtools/accessibility/reference/#contrast)
can quickly tell you the color contrast ratios and offer suggestions to help
create the most inclusive color pairs and palettes.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'PoeKzWq',
 height: 450,
 theme: 'auto',
 tab: 'result'
} %}

## Using color

Without good color contrast levels in place, words, icons, and other graphical
elements are [hard to discover](https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html),
and the design can quickly become inaccessible. But it's also important to pay
attention to [how the color is used](https://www.w3.org/WAI/WCAG21/Understanding/use-of-color.html)
on the screen, as you cannot use color alone to convey information, actions, or
distinguish a visual element.

For example, if you say, "[click the green button to continue](https://www.w3.org/WAI/WCAG22/Understanding/sensory-characteristics.html),"
but omit any additional content or identifiers to the button, it would be
difficult for people with certain types of colorblindness to know which button
to click. Similarly, many graphs, charts, and tables use color alone to convey
information. Adding another identifier, like a pattern, text, or icon, is
crucial to help people understand the content.

Reviewing your digital products in grayscale is a good way to detect potential color issues quickly.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'rNvzLmd',
 height: 500,
 theme: 'auto',
 tab: 'result'
} %}

## Color-focused media queries

Beyond checking for color contrast ratios and the use of color on your screen,
you should consider applying the increasingly popular and supported
[media queries](/learn/design/media-features/#preferences) that offer the users
more control over what is displayed on the screen.

For example, using the [`@prefers-color-scheme`](https://drafts.csswg.org/mediaqueries-5/#descdef-media-prefers-color-scheme) media query, you can create a dark theme, which can be helpful to people with [photophobia](https://w3c.github.io/low-vision-a11y-tf/requirements.html#light-and-glare-sensitivity) or light sensitivity. You could also build a high contrast theme with [`@prefers-contrast`](https://drafts.csswg.org/mediaqueries-5/#descdef-media-prefers-contrast), which supports people with color deficiencies and [contrast sensitivity](https://w3c.github.io/low-vision-a11y-tf/requirements.html#contrast-sensitivity).

{% Aside %}
There are additional media queries and OS settings to consider for color
accessibility, but they are far less supported than the two listed in this
module. See the article [Operating System and Browser Accessibility Display Modes](https://www.a11yproject.com/posts/operating-system-and-browser-accessibility-display-modes/)
for more information on the various OS accessibility settings.
{% endAside %}

### Prefers color scheme

{% BrowserCompat 'css.at-rules.media.prefers-color-scheme' %}

The media query `@prefers-color-scheme` allows users to choose a light or
dark-themed version of the website or app they are visiting. You can see this
theme change in action by changing your light/dark preference settings and
navigating to a browser that supports this media query. Review the
[Mac](https://support.apple.com/en-us/HT208976) and
[Windows](https://blogs.windows.com/windowsexperience/2016/08/08/windows-10-tip-personalize-your-pc-by-enabling-the-dark-theme/) instructions for dark mode.

<figure>
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/Xl1Rw2thm1lf0aVDFYmv.png",
  alt="Mac settings UI",
  width="800", height="336"
%}
<figcaption>macOS general settings for appearance.</figcaption>
</figure>

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'ExLvNOw',
 height: 300,
 theme: 'auto',
 tab: 'css,result',
 allow: ['geolocation']
} %}

{% Details %}

{% DetailsSummary %}
Compare light and dark mode.
{% endDetailsSummary %}

<div class="switcher">
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/wDeiH1l9XfzJZz1wxBZg.png", alt="Code example in light mode.", width="600", height="186" %}
    <figcaption>Light mode.</figcaption>
  </figure>
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/6F0bSF5fQyxkkqEcRF4q.png", alt="Code example in dark mode.", width="600", height="186" %}
    <figcaption>Dark mode.</figcaption>
  </figure>
</div>

{% endDetails %}

### Prefers contrast

{% BrowserCompat 'css.at-rules.media.prefers-contrast' %}

The [`@prefers-contrast`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-contrast)
media query checks the user's OS settings to see if high contrast is toggled on
or off. You can see this theme change in action by changing your contrast
preference settings and navigating to a browser that supports this media query
([Mac](https://support.apple.com/lv-lv/guide/mac-help/unac089/mac) and [Windows](https://support.microsoft.com/windows/change-color-contrast-in-windows-fedc744c-90ac-69df-aed5-c8a90125e696) contrast mode settings).

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'bGMrgNV',
 height: 300,
 theme: 'auto',
 tab: 'css,result',
 allow: ['geolocation']
} %}

{% Details %}
{% DetailsSummary %}
Compare regular and high contrast.
{% endDetailsSummary %}

<div class="switcher">
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/wDeiH1l9XfzJZz1wxBZg.png", alt="Code example in light mode with no contrast preference.", width="600", height="186" %}
    <figcaption>Light mode, no contrast preference.</figcaption>
  </figure>
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/vKrSleRSunOTlwLlZMbR.png", alt="Code example in dark mode with high contrast preference.", width="600", height="186" %}
    <figcaption>Dark mode, high contrast preference.</figcaption>
  </figure>
</div>

{% endDetails %}

### Layering media queries

You can use multiple color-focused media queries to give your users even more
choices. In this example, we stacked `@prefers-color-scheme` and
`@prefers-contrast` together.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'wvjqgaK',
 height: 300,
 theme: 'auto',
 tab: 'css,result',
 allow: ['geolocation']
} %}

{% Details %}
{% DetailsSummary %}
Compare both color and contrast.
{% endDetailsSummary %}

<div class="switcher">
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/wDeiH1l9XfzJZz1wxBZg.png", alt="Light mode, regular contrast.", width="600", height="186" %}
    <figcaption>Light mode, no contrast preference.</figcaption>
  </figure>
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/6F0bSF5fQyxkkqEcRF4q.png", alt="Dark mode, regular contrast.", width="600", height="186" %}
    <figcaption>Dark mode, no contrast preference.</figcaption>
  </figure>
</div>

<div class="switcher">
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/vn8QJND0mRMg9rrn1JrK.png", alt="Light mode, high contrast.", width="600", height="186" %}
    <figcaption>Light mode, high contrast preference.</figcaption>
  </figure>
  <figure>
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/vKrSleRSunOTlwLlZMbR.png", alt="Dark mode, high contrast.", width="600", height="186" %}
    <figcaption>Dark mode, high contrast preference.</figcaption>
  </figure>
</div>

{% endDetails %}

{% Assessment 'color' %}

# Conclusion and next steps

Congratulations, you've made it through Learn Accessibility! At this point,
you've learned a lot of best practices for accessibility and gone through
multiple rounds of accessibility testing. You may have learned some new
terminology or refreshed your memory in our
[glossary](/learn/accessibility/glossary/).

We hope you are confident applying these lessons to your websites and web
applications.

## Additional resources

To continue building your accessibility knowledge, we recommend the following
resources:

* [Web Accessibility Initiative (WAI)](https://www.w3.org/WAI)
* [Web Content Accessibility Guidelines (WCAG) from the W3C](https://www.w3.org/WAI/standards-guidelines/)
* [WCAG Quick Reference Guide](https://www.w3.org/WAI/WCAG21/quickref)
* [Accessibility on MDN](https://developer.mozilla.org/docs/Web/Accessibility)
* [Deque University Digital Accessibility Courses & Accessibility Reference Library](https://dequeuniversity.com/)
* [Global web accessibility laws](https://www.w3.org/WAI/policies/)
* [A11y talks](https://a11ytalks.com/)
* [List of accessible patterns from Smashing Magazine](https://www.smashingmagazine.com/the-smashing-newsletter/smashing-newsletter-issue-289/)
* [How to fund accessibility work](https://pleasefunda11y.com/)
* [A11y automation tracker](https://a11y-automation.dev/)
* Google developer documentation style guide
    * [Write accessible documentation](https://developers.google.com/style/accessibility)
    * [Write inclusive documentation](https://developers.google.com/style/inclusive-documentation)

More resources can be found throughout the modules, as related to each topic.

## Community highlights

We conducted several interviews with accessibility practitioners in 2022. Read about their journey to accessibility and best practices:

* [Melanie Sumner](/community-highlight-melanie/) told us about her journey
  into engineering, accessible design, Ember.js, and the importance of funding
  these efforts.
* [Olutimilehin Olushuyi](/community-highlight-shuyi/) told us about his
  transition from the law to web development, building accessible community,
  and creating accessible layouts.
* [Albert Kim](/community-highlight-albert-kim/) told us about mental health 
  awareness, building for invisible disabilities, the  COGA Accessibility
  Community Group, and more practical wisdom.
* [Elisa Bandy](/community-highlight-elisa/) told us about her work for
  Google's internal documentation, how to prioritize use cases, and building
  expertise.

## Brought to you by

{% include 'partials/authors-stack.njk' %}

### Special thanks

Thank you to Aaron Forinton for supporting the publication of several modules
and assessments.

# Design and user experience

Think about your favorite website or app—what makes it your favorite? Now, think about a website or app you dislike—what
do you not like about it? How users interact with your design and their experience on your website and app can vary.

That experience can change based on the time of day, the type of device used, if they've had enough sleep the night before,
if they are unwell, if they're using assistive technology, and so much more. With close to eight billion people worldwide,
the possibilities of how people use and experience your designs are limitless.

## Inclusive design

How can we address all of the potential user needs at once? Enter inclusive design. Inclusive design utilizes a human-centered
approach that weaves together inclusivity, usability, and accessibility into one.

<figure data-float="right">
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/VqMZDtfUQpH0At8n2PF8.png",
  alt="A venn diagram where accessibility, inclusivity, and usability all meet in the middle as inclusive design.",
  width="400", height="390"
%}
</figure>

And unlike universal design, which focuses on a single design that as many people can use as possible, inclusive design principles
center on designing for a specific individual or use case, and then extending that design to others.

There are seven accessibility-focused [inclusive design principles](https://inclusivedesignprinciples.org):

1. *Provide comparable experience*: Ensure your interface provides an equal experience for all, so people can accomplish tasks in a way that suits their needs without undermining the quality of the content.
1. *Consider the situation*: Make sure your interface delivers a valuable experience to people, regardless of their circumstances.
1. *Be consistent*: Use familiar conventions and apply them in a logical manner.
1. *Give control*: Ensure people can access and interact with content in their preferred way.
1. *Offer choice*: Consider providing different ways for people to complete tasks, especially those that are complex or non-standard.
1. *Prioritize content*: Help users focus on core tasks, features, and information by arranging these elements in the preferred order within the content and layout.
1. *Add value*: Consider the purpose and significance of features and how they improve the experience for different users.

## Personas

When developing a new design or feature, many teams rely on user [personas](https://www.nngroup.com/articles/persona/) to guide them through
the process. Personas are fictitious characters that use your digital products, often based on quantitative and qualitative user research.

Personas also offer a quick and inexpensive way to test and prioritize those features throughout the design and development process.
They help to focus decisions surrounding site components by adding a layer of real-world consideration to the conversation to help align
strategy and create goals focused on specific user groups.

### Incorporating disabilities

<figure data-float="right">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/SmtiiRRpAImfG7MI6ku4.png", alt="Disabilities may be permanent, temporary, or situational. These disabilities can affect touch, seeing, hearing, and speaking.", width="350", height="573" %}
<figcaption>The Persona Spectrum from <a href="https://www.microsoft.com/design/inclusive/">Microsoft's Inclusive 101 Toolkit</a>.</figcaption>
</figure>

<blockquote>
  <p>"People are all different. I can only speak from my experience. When you meet one Deaf person, then you've met one Deaf person—not all of us."</p>
  <cite>
    Meryl Evans from the ID24 talk <a href="https://youtu.be/yrwKWtJdZ_c/">Deaf Tech: Travel Through Time from Past to Future</a>.
  </cite>
</blockquote>

Personas can be used as an inclusive design tool when you incorporate people with disabilities into your personas. There are many different ways
to do this. You may create [disability-specific personas](https://accessibility.blog.gov.uk/2016/09/02/dos-and-donts-on-designing-for-accessibility),
add disabilities to existing user personas, or even create a persona spectrum to reflect the dynamic reality of situational, temporary, and permanent disabilities.

No matter how you incorporate people with disabilities into your personas, they should not be based on real people or stereotypes. And personas are never a substitute for user testing.

{% Details %}
{% DetailsSummary %}
Persona: Jane Bennet
Check out an example of a persona that supports specific use cases.
{% endDetailsSummary %}

<figure data-float="right">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/ysBmXtLrbxScFwocWF8f.png", alt="Jane Smith is tall with long dark hair, wearing a gray long sleeve shirt and jeans", width="150", height="362" %}
</figure>

* **Name**: Jane Bennet
* **Age**: 57 years old
* **Location**: Essex, United Kingdom
* **Occupation**: UX engineer
* **Disability**: Hand tremor from Young Onset Parkinson's disease (YOPD)
* **Goals**: use speech-to-text input to make adding code suggestions easier; find biking equipment online with minimal keystrokes.
* **Frustrations**: websites lacking keyboard-only support; apps for design with small areas for touch interaction.

As a UX engineer, Jane designs and builds pages that are vital to keeping her
company's site relevant. She supports a lot of team members throughout the day.
She's the queen of putting out technical fires, and everyone's go-to in the
department when anything goes down unexpectedly.

Losing her fine motor skills to tremors is making it increasingly difficult for her to use a mouse. She's been steadily relying on
the keyboard more and more to navigate the web. Jane has always been dedicated to her physical fitness. She loves road racing and BMX.
This made it all the more of a blow when she was diagnosed with Young Onset Parkinson's disease last year.

{% endDetails %}

### Disability simulators

Use extreme caution when using disability simulators to [emulate or supplement your personas](https://accessibility.blog.gov.uk/2019/02/11/using-persona-profiles-to-test-accessibility/).

Disability simulators are a double-edged sword in that they can build sympathy or empathy—it can depend on the individual,
the context in which the simulator is used, and many other uncontrollable factors. Many accessibility advocates are [against using
disability simulator tools](https://sheribyrnehaber.medium.com/simulating-disabilities-d03986e05c1b) and recommend seeking out movies,
demos, tutorials, and other content created by people with disabilities, and learning about their experiences first-hand.

<blockquote>
  <p>"I think we need to be completely honest that any simulation activity does not impact some of the most important understandings we want the sighted to know in their heart and their head. Blindness is not the characteristic that defines us, that the misunderstandings and low expectations about blindness are our biggest obstacle.</p><p>Those misunderstandings create artificial barriers that prevent us from fully participating, and those false limitations build into something that holds us back."</p>
  <cite>
    <a href="https://nfb.org/sites/default/files/images/nfb/publications/bm/bm17/bm1704/bm170402.htm">Mark Riccobono</a>, President of the National Federation of the Blind
  </cite>
</blockquote>

## Accessibility heuristics

Consider adding [heuristics](https://www.nngroup.com/articles/how-to-conduct-a-heuristic-evaluation/) into your workflow as you
build your personas and designs. Heuristics are simple rules for interaction design, introduced in 1990 by Jakob Nielsen and Rolf Molich.
These ten principles were developed based on years of experience in the field of usability engineering, and have been used in design and human-computer
interaction programs ever since.

Fast-forward to 2019, and the design team at Deque created and shared a new set of [heuristics focused on digital accessibility](https://www.deque.com/blog/supporting-the-design-phase-with-accessibility-heuristics-evaluations/).
According to their research, up to 67% of all accessibility bugs for a website or app can be avoided when accessibility is part
of the design process. That's a huge impact that can be made before even one line of code is written.

Similar to the original set of heuristics, there are ten accessibility heuristics to consider when planning your design.

1. *Interaction methods and modalities*: Users can efficiently interact with the system using the input method of their choosing (such as a mouse, keyboard, touch, etc.).
1. *Navigation and wayfinding*: Users can easily navigate, find content, and determine where they are at all times within the system.
1. *Structure and semantics*: Users can make sense of the structure of the content on each page and understand how to operate within the system.
1. *Error prevention and states*: Interactive controls have persistent, meaningful instructions to help prevent mistakes, and provide users with clear error states which indicate what the problems are and how to fix them whenever errors are returned.
1. *Contrast and legibility*: Users can easily distinguish and read text and other meaningful information.
1. *Language and readability*: Users can easily read and understand the content.
1. *Predictability and consistency*: Users can predict each element's purpose. It's clear how each element relates to the system as a whole.
1. *Timing and preservation*: Users are given enough time to complete their tasks and do not lose information if their time (i.e., a session) runs out.
1. *Movement and flashing*: Users can stop elements on the page that move, flash, or are animated. Users should not be distracted or otherwise harmed by these elements.
1. *Visual and auditory alternatives*: Users can access text-based alternatives for any visual or auditory content which conveys information.

Once you have a basic understanding of these accessibility heuristics, you can
apply it to a persona or design using the accessibility heuristics worksheet
and by following the instructions provided. This exercise is more enlightening
when you gather multiple perspectives.

An example accessibility heuristic review for the navigation and wayfinding
checkpoint could look like the following:

<div class="table-wrapper scrollbar">
<table>
<thead>
  <tr>
    <th>Checkpoints for navigation and wayfinding</th>
    <th>Excels (+2 pt)</th>
    <th>Passes (+1 pt)</th>
    <th>Fails (-1 pt)</th>
    <th>N/A (0 pt)</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>Is a clear, visible indicator set on all active elements as they receive focus?</td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
    <td></td>
    <td></td>
    <td class="tg-0lax"></td>
  </tr>
  <tr>
    <td>Does the page have meaningful title text, with page-specific information first?</td>
    <td></td>
    <td></td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
    <td class="tg-0lax"></td>
  </tr>
  <tr>
    <td>Are the page title element and H1 the same or similar?</td>
    <td></td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>Are there meaningful headings for each major section?</td>
    <td></td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>Is the links' purpose defined from the link text alone or its immediate context?</td>
    <td></td>
    <td></td>
    <td></td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
  </tr>
  <tr>
    <td>Is a skip link provided at the very top of the page and is it revealed on focus?</td>
    <td></td>
    <td></td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
    <td></td>
  </tr>
  <tr>
    <td>Does the organization of navigational elements facilitate wayfinding?</td>
    <td><span role="img" aria-label="yes">&#9989;</span></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</tbody>
</table>
</div>

After everyone on the team looks at the page or component and conducts their
accessibility heuristic review, the totals are tallied up for each checkpoint.
At this point, you can decide how to remedy any found issues or
correct any omissions that are paramount to supporting digital accessibility.

## Accessibility annotations

Before you hand off your design to the development team, you should consider
adding [accessibility annotations](https://stephaniewalter.design/blog/a-designers-guide-to-documenting-accessibility-user-interactions/).
Annotations, in general, are used to explain creative choices and describe
different aspects of the design. Accessibility annotations focus on areas where
developers can make more accessible programmatic choices with the guidance of
the design team or an accessibility-focused specialist.

Accessibility annotations can be applied during any stage of the design
process, from wireframes to high-fidelity mock-ups. They can include user
flows, conditional states, and functionality. They often utilize symbols and
labels to streamline the process and keep the design as the main focus.

The following design illustrations examples are from [Indeed.com's accessibility annotations kit](https://www.figma.com/community/file/953682768192596304) for Figma.

<div class="auto-grid">
 <figure>
    {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/C365JZBXSoqHkSq068sy.png",
    alt="Design illustration of visual modifications used for various possible button states.",
    width="350", height="232"
    %}
   <figcaption>
     Action button design differs based on state: default, focus, hover, active, and disabled.
   </figcaption>
 </figure>
 <figure>
    {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/sRwFc6CeeqXVbY8XT7k6.png",
    alt="Design illustration of three different icons used on a job posting card.",
    width="350", height="232"
    %}
   <figcaption>
     Three icons have alt text highlighted. The icons for "save job" and "not interested" act as buttons, therefore the alt text is critical to understanding action. The icon next to "Apply with your Indeed resume" is purely decorative and therefore doesn't need alt text.
   </figcaption>
 </figure>
 <figure>
    {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/Xvw23qkfel5KeqQoh7cE.png",
    alt="Illustration of the relationship the form labels should have on their related inputs for month and year. ",
    width="350", height="232"
    %}
   <figcaption>
     Multiple input labels can be associated with each input, to help users understand context.
   </figcaption>
 </figure>
</div>

Depending on your design program, you should have multiple
[accessibility annotation starter kits](https://www.figma.com/community/tag/a11y/popular)
to choose from. Or, if you prefer, you can create your own set. In either case,
you should decide which information needs to be communicated to
the hand-off team and what format works best.

Some areas to consider for accessibility annotations include:

* **Color**: include contrast ratios of all of the different combinations of colors in the palette.
* **Buttons and links**: identify default, hover, active, focus, and disabled states.
* **Skip links**: highlight the hidden/visible design aspects and where they link to on the page.
* **Images and icons**: add alternative text recommendations for essential images/icons.
* **Audio and video**: highlight areas/links for captions, transcripts, and audio descriptions.
* **Headings**: add programmatic levels and include everything that looks like a heading.
* **Landmarks**: highlight the different sections of the design with HTML or ARIA.
* **Interactive components**: identify clickable elements, hover effects, focus area.
* **Keyboard**: identify where the focus should start (alpha stop) and the following tab order.
* **Forms**: add field labels, helper text, error messages, and success messages.
* **Accessible names**: identify how assistive technology should recognize the element.

# Keyboard focus

Many people use a keyboard—or other software/hardware that mimics the
functionality of a keyboard, such as a switch device—as their primary means of
navigation. People with temporary physical limitations such as sprained wrist
or fine motor disabilities like carpal tunnel, as well as some people without
disabilities, may choose to use a keyboard to navigate a page due to personal
preference, efficiency, or broken hardware.

Low-vision or blind users may use a keyboard for navigation combined with
their magnification or screen reader software. However, they may use different
keyboard shortcut commands to navigate a screen than a sighted user would.

Keyboard support for all of these disabilities and circumstances is critical. A
large part of keyboard accessibility is centered around
[focus](/focus). Focus refers to which element on the screen
currently receives input from the keyboard.

In this module, we concentrate on HTML structure and CSS styling for
keyboard and focusable elements. The
[JavaScript module](/learn/accessibility/javascript/) includes more
information on focus management and keystrokes for interactive elements.

## Focus order

The elements that a keyboard user can navigate to are called focusable
elements. [Focus order](https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html),
also called tab or navigation order, is the order in which elements receive
focus. The default focus order must be logical, intuitive, and match the visual
order of a page.

For most languages, the focus order starts at the top of the page and ends at the bottom, traveling from left to right. However, some languages are read right to left, so the primary language of the page may warrant a different focus order.

By default, focus order includes naturally focusable HTML elements, such as
links, checkboxes, and text inputs. Naturally focusable HTML elements include
built-in tab order support and basic keyboard event handling.

You can update the focus order to include any elements that don't normally
receive focus, such as non-interactive HTML elements, custom components, or
elements with [ARIA](/learn/accessibility/glossary/#aria) that overrides the
natural focus semantics.

{% Aside %}
Your `tab` key moves the keyboard focus up the
[DOM](https://developer.mozilla.org/docs/Glossary/DOM). `shift + tab` moves the
focus down the DOM.
{% endAside %}

### Tabindex

The focus order begins with elements that have a positive
[tabindex](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/tabindex)
attribute (if there are any) and moves from the smallest positive number to the
largest (such as 1, 2, 3). It then proceeds through elements with a tabindex of
zero according to their order in the DOM. Any elements with a negative tabindex
are removed from the natural focus order.

When a [tabindex](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/tabindex)
of zero (`tabindex="0"`) is applied to normally unfocusable elements, they are
added into the natural focus order of the page according to the way they appear
in the DOM. However, unlike naturally focusable HTML elements, you must
[provide additional keyboard support](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/)
for them to be fully accessible.

Similarly, if you have an element that normally is focusable but is
inactive—such as a button that is inoperative until an input field is filled
in—you should add a negative tabindex (`tabindex="-1"`) to this element. Adding
a negative tabindex signals to assistive technologies and keyboards that this
button should be removed from the natural focus order. But don't worry—you can
use JavaScript to add the focus back to the element when needed. 

In this example, a `tabindex` attribute was added to elements that do not
naturally receive focus. The order of the elements was manipulated using
`tabindex` to illustrate the power it can have on focus order. This is an
example of what not to do!

<div class="switcher">
<figure>

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'QWxWwNM',
 height: 300,
 theme: 'dark',
 tab: 'html'
} %}

</figure>

<figure>
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/CMwbHhLmPO3aO0AB4KBy.gif", alt="New focus order reflects the HTML.", width="800", height="450"
   %}
   <figcaption>
     Watch as a keyboard user tabs through the CodePen HTML.
   </figcaption>
</figure>
</div>

{% Aside 'caution' %}
As a general rule, you should avoid positive tabindexes. Giving focus to
non-interactive elements and disrupting the normal focus order may confuse and
frustrate your users. It should be rare that a circumstance warrants adding a
positive tabindex (`tabindex= "1"`) to a non-focusable element.
{% endAside %}

### Skip links

Most websites today have a long list of menu links in the page's main header
consistent from page to page. This is great for general navigation but can make
it difficult for keyboard-only users to easily get to the website's main
content without having to tab multiple times.

One way to jump over redundant or unuseful groups of links is to add a
[skip link](https://webaim.org/techniques/skipnav/). Skip links are anchor
links that jump to a different section of the same page, using that section's
ID, instead of sending the user to another page on the website or an external
resource. Skip links are typically added as the first focusable element a user
will encounter when arriving at a website and can be visible or visually hidden
until a user tabs to it, depending on what the design calls for.

When a user presses the tab key, and an active skip link is in place, it sends
the keyboard focus to the skip link. The user can click the skip link and jump
past the header section and main navigation. If they choose not to click the
skip link and continue to tab down the DOM, they'll be sent to the next
focusable element.

Like all links, it’s important that the skip link includes context about the
link's purpose. Adding the phrase "Skip to main content," lets the user know
where the link is taking them. There are many code options to choose from when
providing additional context to your links, such as
[aria-labelledby](https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA7),
[aria-label](https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA8), or adding it
to the text content of the `<a>` element, as demonstrated in the example.

<div class="switcher">
  <figure>
{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'LYrYEGo',
 height: 350,
 theme: 'dark',
 tab: 'html'
} %}
</figure>
<figure>
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/zQ9dGirSD5Tkg4NRdHDQ.gif", alt="Preview CodePen with keyboard focus.", width="800", height="450"
%}
<figcaption>Watch a keyboard user navigate with and without a skip link.</figcaption>
</figure>
</div>

## Focus indicator

As you just learned, focus order is an important aspect of keyboard
accessibility. It's also important to decide how that focus is styled. Because
even if the focus order is excellent, how could a user know where they are on
the page without the proper styling?

A [visible focus indicator](https://www.w3.org/WAI/WCAG21/Understanding/focus-visible)
is a vital tool in informing a user about where they are at all times on the
page. It's especially important for your sighted keyboard-only users.

{% Aside %}
WCAG 2.2's new success criterion,
[Focus Not Obscured (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html),
will ensure that the focus indicator is not hidden beneath other components.
{% endAside %}

### Browser default styling

Today, every modern web browser has a different default visual styling that
applies to focusable elements on your website or app—some more easily visible
than others. As a user tabs through the page, this styling is applied as the
element receives keyboard focus.

If you allow the browser to handle the focus styling, it's important to review
your code to confirm that your theme won't override the browser's default
styling. An override is often written as `"outline: 0"` or `"outline: none"` in
your stylesheet. This tiny piece of code can remove the browser's default focus
indicator styling, which makes it very difficult for users to navigate your
website or app.

<div class="switcher">
{% Compare 'worse' %}
```css
a:focus {
  outline: none; /* don't do this! */
}
```
{% endCompare %}

{% Compare 'better' %}
```css
a:focus {
  outline: auto 5px Highlight; /* for non-webkit browsers */
  outline: auto 5px -webkit-focus-ring-color; /* for webkit browsers */
}
```
{% endCompare %}
</div>

### Custom styles

Of course, you can go beyond the default browser style and create a custom
focus indicator that complements your theme. When creating a custom focus
indicator, you have a lot of freedom to be creative!

A focus indicator shape can take on many forms, be it an outline, a border, an
underline, a box, a background change, or some other obvious stylistic change
that does not rely on color alone to indicate the keyboard's focus is active on
that element.

You could change a focus indicator style to ensure it isn’t lost in the
background. For example, when a page has a white background, you could set the
button focus indicator to a blue background. When the page has a blue
background, you could set that same button focus style to a white background.

You could change the focus element style based on element type. For example,
you could use a dotted underline for body links but choose a rounded border for
a button element.

{% Aside %}
<p>Depending on how the focus indicator is styled, it may also need to meet the
[minimum color contrast](https://www.w3.org/WAI/WCAG21/Techniques/general/G195)
requirements against the background.</p>
<p>We recommend adhering to a 3:1 color contrast ratio for all focus
indicators. This will meet WCAG 2.2's
[Focus Appearance (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance-minimum).</p>
{% endAside %}

<div class="switcher">
<figure>

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'PoaowNz',
 height: 300,
 theme: 'dark',
 tab: 'css'
} %}

</figure>

<figure>
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/IXSs4AMZF8AePoCjkf0h.gif",
    alt="Focus style as demonstrated in CSS.", width="800", height="450"
    %}
    <figcaption>
      Watch what happens as a keyboard user tabs through each styled focus element.
    </figcaption>
</figure>
</div>

There is no rule about how many focus indicator styles you have on one
page&mdash;but be sure to keep it to a reasonable number to avoid unnecessary
confusion.

## Wrap-up

For a website or app to be considered accessible, everything that can be
accessed with a mouse must also be accessed with a keyboard. This module
focused on the visual aspect of keyboard accessibility, in particular, focus
order and focus indicators.

{% Assessment 'focus' %}

# Forms

A form is an element that allows a user to provide data into a field or a group
of fields. Forms can be as simple as a single field or as complicated as a
multi-step form element with multiple fields per page, input validation, and
sometimes a CAPTCHA.

Forms are considered one of the most difficult elements to get right from an
accessibility perspective, as they require knowledge of all the elements we
have already covered, as well as additional rules specific just to forms. With some
understanding and time, you can make an accessible form to suit you and your
users.

Forms is the last component-specific module in this course. This module will
focus on the form-specific guidelines, but all other guidelines you learned
about in the earlier modules, such as
[content structure](/learn/accessibility/structure),
[keyboard focus](/learn/accessibility/focus), and
[color contrast](/learn/accessibility/color-contrast), also apply to form
elements.

{% Aside %}
Review our [Learn Forms](/learn/forms) course to learn how to create better
forms. There is a [form accessibility](/learn/forms/accessibility) module in
that course with additional accessibility-specific form content.
{% endAside %}


## Fields

The backbone of forms is fields. Fields are small interactive patterns, such as
an input or radio button element, that allow users to enter content or make a
choice. There is a [wide variety of form fields](/learn/forms/fields) to
choose from. 

The default recommendation is to use established HTML patterns instead of
building something custom with ARIA, as certain features and
functionalities—such as field states, properties, and values—are inherently
built into the HTML elements, while you have to add custom ARIA manually.

{% Aside %}

If the situation requires you to build custom form fields, be sure to review
the [ARIA and HTML](/learn/accessibility/aria-html),
[Keyboard focus](/learn/accessibility/focus), and
[JavaScript](/learn/accessibility/javascript) modules to understand how to make
these custom form fields as accessible as possible.

{% endAside %}

<div class="switcher">
<figure>
<h4>ARIA</h4>

```html
<div role="form" id="sundae-order-form">
  <!-- form content -->
</div>
```
</figure>

<figure>
<h4>HTML</h4>

```html
<form id="sundae-order-form">
  <!-- form content -->
</form>
```
</figure>
</div>


In addition to choosing the most accessible form field patterns, where
applicable, you should also add
[HTML autocomplete attributes](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete)
to your fields. Adding autocomplete attributes allows a more fine-grained
[definition or identification of purpose](https://www.w3.org/TR/WCAG21/#input-purposes)
to user agents and assistive technologies (AT).

Autocomplete attributes allow users to personalize visual presentations,
such as showing a birthday cake icon in a field with the birthday autocomplete
attribute (`bday`) assigned to it. More generally, autocomplete attributes make
filling out forms easier and quicker. This is especially helpful for people
with cognitive and reading disorders and those using ATs, such as screen
readers.

```html
<form id="sundae-order-form">
  <p>Name: <input type="name" autocomplete="name"></p>
  <p>Telephone: <input type="tel" autocomplete="tel"></p>
  <p>Email address: <input type="email" autocomplete="email"></p>
</form>
```

Lastly, form fields should not produce contextual changes when they receive
focus or user input unless the user has been warned about the behavior before
using the component. For example, a form should not be automatically submitted
when a field receives focus or once a user adds content to the field.

## Labels

Labels inform a user about the purpose of a field, if the field is required,
and can also provide information about the field requirements, such as input
format. Labels must be visible at all times and accurately describe the form
field to users.

One of the foundational tenets of accessible forms is establishing a clear and
accurate connection between a field and its label. This is true both visually
and programmatically. Without this context, a user might not understand how to
fill out the fields in the form.

```html
<form id="sundae-order-form">
  <p><label>Name (required): <input type="name" autocomplete="name" required></label></p>
  <p><label>Telephone (required): <input type="tel" autocomplete="tel" required></label></p>
  <p><label>Email address: <input type="email" autocomplete="email"></label></p>
</form>
```

Additionally, related form fields, such as a mailing address, need to be
programmatically and visually grouped. One method is to use the fieldset/legend
pattern to group elements that are similar.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'zYLqwwQ',
 height: 400,
 theme: 'auto',
 tab: 'html, result'
} %}


## Descriptions

Field descriptions are similar to labels in purpose in that they are used to
give more context to the field and requirements. Field descriptions are not
required for accessibility if the labels or form instructions are descriptive
enough.

However, there are situations in which adding additional information is useful
to avoid form errors, such as relaying information about the minimum length of
input for a password field or telling a user which calendar format to use (such
as MM-DD-YYYY).

There are many different methods you can use to add field descriptions to your
forms. One of the best methods is to add an
[aria-describedby](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-describedby)
attribute to the form element, in addition to a `<label>` element. The screen
reader will read both the description and the label.

If you add the
[aria-labelledby](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)
attribute to your element, the attribute value overrides the text within your
`<label>`. As always, be sure to test the final code with all of the ATs you
plan to support.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'ExpKmXq',
 height: 400,
 theme: 'auto',
 tab: 'html, result'
} %}

## Errors

When creating accessible forms, there's a lot you can do to prevent users from
making form errors. Earlier in this module, we covered clearly marking-up
fields, creating identifying labels, and adding detailed descriptions whenever
possible. But no matter how clear you think your form is, eventually, a user
will make a mistake.

When a user encounters a form error, the first step is to
[make the error known](https://www.w3.org/WAI/tutorials/forms/notifications).
The field where the error occurred must be clearly identified, and the error
itself must be described to the user in text.

There are different methods for [displaying error
messages](https://webaim.org/techniques/formvalidation/#error), such as:

* A pop-up modal, inline near where the error occurred
* A collection of errors grouped in one larger message at the top of the page

Be sure to pay attention to the [keyboard focus](/learn/accessibility/focus)
and [ARIA live region options](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/ARIA_Live_Regions)
when announcing errors.

Whenever possible, offer the user a detailed suggestion on how to fix the
error. There are two attributes available to notify users of errors.

* You can use the HTML [required](https://developer.mozilla.org/docs/Web/HTML/Attributes/required) attribute. The browser will supply a generic error message based on the filed validation parameters.
* Or you can use the [aria-required](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-required) attribute to share a customized error message to ATs. Only ATs will receive the message unless you add additional code to make the message visible to all users. 

Once a user thinks all of the errors have been resolved, allow them to resubmit
the form and provide feedback about the results of their submission. An error
message tells a user they have more updates to make, while a success message
confirms that they have resolved all errors and successfully submitted the form.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'abjJYWR',
 height: 400,
 theme: 'auto',
 tab: 'html, result'
} %}

{% Aside %}

While WCAG 2.2 is still under development, there are several proposed success
criteria that will focus on more accessible form experiences, such as
[Target Size (Minimum)](https://www.w3.org/TR/WCAG22/#target-size-minimum),
[Consistent Help](https://www.w3.org/TR/WCAG22/#consistent-help),
[Accessible Authentication](https://www.w3.org/TR/WCAG22/#accessible-authentication),
and [Redundant Entry](https://www.w3.org/TR/WCAG22/#redundant-entry) to be
aware of for future projects.

{% endAside %}

{% Assessment 'forms' %}

# Glossary

In this document, you'll find common terms and concepts related to accessibility.

## A11y

[A11y](https://www.a11yproject.com/posts/a11y-and-other-numeronyms/) is 
numeronym for accessibility (a + 11 letters + y). Typically pronounced as 
"ally" as in "a person or group that provides assistance and support in an 
ongoing effort, activity, or struggle," giving the term "a11y" multiple 
meanings.

## Accessibility Conformance Report (ACR) {: #acr} 

The [ACR](https://tetralogical.com/blog/2021/10/15/introduction-to-accessibility-conformance-reports/)
is the final report presented to a client once a full ACT has been performed.
If you need a legally binding version of the ACR, you would utilize a version
of the [Voluntary Product Accessibility Template (VPAT)](#vpat).

## Accessibility Conformance Testing (ACT) {: #act}

[ACT](https://www.w3.org/WAI/standards-guidelines/act/) is commonly referred to
as an accessibility audit. The ACT utilizes various testing methodology and
tools: primarily automated, manual, and [assistive technology](#AT) (AT)
devices.

ACT is first performed as a baseline metric to gauge general
accessibility compliance of a digital product. It's often run multiple times
throughout the software product lifecycle to check for changes in the level of
conformance against a set of pre-determined accessibility checkpoints or 
guidelines. 

## ARIA

[ARIA](https://www.w3.org/WAI/standards-guidelines/aria/) is an acronym for
Accessible Rich Internet Applications (formally known as WAI-ARIA—Web
Accessibility Initiative Accessible Rich Internet Applications). ARIA is a
specification written by the W3C, defining a set of attributes that you can add
to HTML elements to support accessibility. These attributes communicate role,
state, and property to assistive technologies via accessibility APIs
implemented in the accessibility tree in modern browsers.

## Assitive technology (AT) {: #at}

[AT](https://en.wikipedia.org/wiki/Assistive_technology) is hardware and
software that can be no-tech (such as a mouthstick), low-tech (such as a 
keyboard), or high-tech (such as a screen reader). AT is used to help increase, 
maintain, or improve the capabilities of performing a task for a person with 
disabilities. AT includes braille keyboards, audio browsers, screen magnifiers, 
and alternative pointing devices.

## Digital accessibility

[Digital accessibility](https://www.w3.org/WAI/fundamentals/accessibility-intro/) is the 
practice of building digital products in a way that all users, regardless of 
their disability, will have equal access to the content or functionality of the 
product.

## POUR

[POUR](https://www.w3.org/WAI/fundamentals/accessibility-principles/) is 
shorthand for Perceivable, Operable, Understandable, and Robust, which are the 
foundational human-focused principles of WCAG.

## Screen reader

A [screen reader](https://www.afb.org/blindness-and-low-vision/using-technology/assistive-technology-products/screen-readers)
is a high-tech assistive technology that uses synthetic language to read and 
navigate digital documents for people with low or no vision, cognitive issues, 
and other disabilities.

* Desktop
    * [ChromeVox](https://support.google.com/chromebook/answer/7031755) (ChromeOS)
    * [JAWS](https://www.freedomscientific.com/Products/software/JAWS/) (Windows)
    * [Narrator](https://support.microsoft.com/en-us/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1) (Windows)
    * [NVDA](https://www.nvaccess.org/) (Windows)
    * [Orca](https://wiki.gnome.org/Projects/Orca) (Linux)
    * [VoiceOver](https://www.apple.com/accessibility/vision/) (macOS)
* Mobile
    * [TalkBack](https://support.google.com/accessibility/android/answer/6283677?hl=en) (Android)
    * [VoiceOver](https://www.apple.com/accessibility/vision/) (iOS)
* [Screen Reader Keyboard Shortcuts and Gestures](https://dequeuniversity.com/screenreaders/)

## VPAT

[VPAT](https://en.wikipedia.org/wiki/Voluntary_Product_Accessibility_Template) 
is shorthand for Voluntary Product Accessibility Template. A VPAT is a template 
to draft an [Accessibility Conformance Report](#acr) (ACR). An ACR clearly 
states which accessibility standards a product or service meets and warns users 
about any "accessibility blockers" they may encounter. A VPAT does not mean 
that a digital product is 100% accessible: it is just a report of the state 
of a product from an accessibility conformance perspective.

## Web Accessibility Initiative (WAI)

The [Web Accessibility Initiative (WAI)](https://www.w3.org/WAI/) is a 
sub-group of the W3C focuses only on digital accessibility. 

## Web Content Accessibility Guidelines (WCAG) {: #wcag}

Web Content Accessibility Guidelines (commonly referred to as ]=
[WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/)) is an international 
set of accessibility standards developed through the W3C in cooperation with 
individuals and organizations. The goal of WCAG is to provide a single shared 
standard for digital accessibility that meets the needs of individuals, 
organizations, and governments worldwide.

# Images

Accessible images may seem like a simple topic at first glance&mdash;you add
some "alt text" to an image, and you are done. But, the topic is more nuanced
than some people think. In this section, we'll review:

* How to update the code to make images accessible.
* What information should be shared with users and where to share it.
* Additional ways to improve your images to support people with disabilities.

## Image purpose and context

Before even one line of code is written, you must first think about the point
of the image and how it will be used. Asking yourself questions about the
purpose and context of the image can help you determine how best to convey the
information to a person using
[assistive technology (AT)](https://www.nichd.nih.gov/health/topics/rehabtech/conditioninfo/device)
such as screen readers.

You may ask yourself:

* _Is the image essential to understanding the context of the feature or page?_
* _What type of information is the image trying to convey?_
* _Is the image simple or complex?_
* _Does the image elicit emotion or prompt the user to act?_
* _Or is the image just visual "eye candy" with no real purpose?_

A visual flowchart, such as an
[image decision tree](https://www.w3.org/WAI/tutorials/images/decision-tree/),
can help you decide which category your image belongs to.

Try hiding the images on your site or web app using a browser extension or
other methods. Then ask yourself: "Do I understand the content that remains?"
If the answer is yes, it is most likely a decorative image. If not, the image
is instead informative in some way and contextually necessary. Once you
determine the image's purpose, you can determine the most accurate way to code
for it.

{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/cnUw9wOPYGvEpO69nqFe.png", alt="Example image decision tree.", width="632", height="598"
%}

### Decorative images

A [decorative image](https://www.w3.org/WAI/tutorials/images/decorative/) is a
visual element that doesn't add additional context or information that allows
the user to better understand the context. Decorative images are supplemental
and may provide style rather than substance.

If you decide an image is decorative, the image must be programmatically hidden
from ATs. When you program an image to be hidden, it signals to the AT that the
image is not needed to understand the page's content, context, or action. There
are many ways to hide images, including using an empty/null text alternative,
[applying ARIA](https://developer.mozilla.org/docs/Web/Accessibility/ARIA), or
adding the image as a CSS background. Below are a few examples of how to hide a
decorative image from users.

{% Aside 'caution' %}
<p>Be mindful when making this choice, as
"[decorative](https://www.smashingmagazine.com/2021/06/img-alt-attribute-alternate-description-decorative/)"
can mean different things to different users. Some AT users want to hear
descriptions for every visual on the screen.</p>
<p>Users can choose to skip over your image descriptions if and when they deem
  them redundant or verbose, but they cannot imagine descriptions that don't
  exist. When in doubt, add descriptions to your images.</p>
{% endAside %}

#### Empty or null `alt`

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'QWrMgxg',
 height: 300,
 theme: 'auto',
 tab: 'html,css,result'
} %}

An empty/null alternative text attribute differs from a missing alternative
text attribute. If the alternative text attribute is missing, the AT might read
out the file name or surrounding content to give the user more information
about the image.

#### Role set to `presentation` or `none`

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'mdLMwje',
 height: 350,
 theme: 'auto',
 tab: 'html,result'
} %}

A role set to [`presentation` or `none`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/presentation_role)
removes an element's semantics from exposure to the accessibility
tree. Meanwhile, [`aria-hidden= "true"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-hidden)
will remove the entire element&mdash;and all of its children&mdash;from the
accessibility API.

```html
<!-- All of these choices lead to the same result. -->
<img src=".../Ladybug.jpg" role="presentation">
<img src=".../Ladybug.jpg" role="none">
<img src=".../Ladybug.jpg" aria-hidden="true">
```

Use `aria-hidden` with caution as it may hide elements that
you do not wish to hide.

#### Images in CSS

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'GRdvEYo',
 height: 350,
 theme: 'auto',
 tab: 'css,result'
} %}

When you add a background image with CSS, a screen reader will not detect the
image file. Be sure you want the image to be hidden before applying this method.

### Informative images

An [informative image](https://www.w3.org/WAI/tutorials/images/informative/) is an image that conveys a simple concept, idea, or emotion. Types of informative images include photos of real-world objects, essential icons, simple drawings, and [images of text](https://www.w3.org/WAI/WCAG22/Understanding/images-of-text.html).

If your image is informative, you should include [programmatic alternative text](https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html) describing the purpose of the image. Alternative image descriptions&mdash;often abbreviated as "alt text"&mdash;give AT users more context about an image and help them better understand an image's message or intent.

Simple alternative descriptions using
[`<img>` elements](https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-alt)
are achieved by including the `alt` attribute, regardless of the file type it
points to, such as `.jpg`, `.png`, `.svg`, and others.

```html
<img src=".../Ladybug_Swarm.jpg" alt="A swarm of red ladybugs are eating the leaves of my prize rose bush.">
```
{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'yLjoXrj',
 height: 350,
 theme: 'auto',
 tab: 'html,result'
} %}

When you use `<svg>` elements inline, however, you need to pay attention to accessibility.

First, since SVGs are semantically coded, AT will skip over them by default.
If you have a decorative image, this is not an issue&mdash;the AT will ignore
it as intended. But if you have an informative image, an ARIA `role="img"`
needs to be added to the pattern for the AT to recognize it as an image.

Second, `<svg>` elements do not use the `alt` attribute, so
[different coding methods](https://codepen.io/web-dot-dev/pen/dyezRBP) must be
used instead to add alternative descriptions to your informative images.

```html
  <svg role="img"...>
     <title>Cartoon drawing of a red, black, and gray ladybug.</title>
  </svg>
```

### Functional images

A [functional image](https://www.w3.org/WAI/tutorials/images/functional/) is
connected to an action. An example of a functional image is a logo that links
to the home page, a magnifying glass used as a search button, or a social media
icon that directs you to a different website or app.

Like informative images, functional images must include an alternative
description to inform all users of their purpose. Unlike an informative image,
each functional image needs to describe the image's action&mdash;not the
visual aspects.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'YzLxxPw',
 height: 350,
 theme: 'auto',
 tab: 'html,result'
} %}

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'gOzxxbg',
 height: 350,
 theme: 'auto',
 tab: 'html,result'
} %}

In the logo example, the image is both informative and actionable as it is both
an image that conveys information and behaves as a link. In cases like these,
you can add alternative descriptions to each element&mdash;but it is not a
requirement.

One way to add alternative descriptions to images is through visually hidden
text. When you use this method, the text will be read by screen readers because
it is in the DOM, but it is visually hidden with the help of custom CSS.

You can see from the code snippet that "Navigate to the homepage" is the
wrapper title, and the image alternative text is "Lovely Ladybugs for your
Lawn." When you listen to the logo code with a screen reader, you hear both the
visual and the action conveyed in one image.

```html
<div title="Navigate to the homepage">
   <a href="/">
      <img src=".../Ladybug_Logo.png" alt="Lovely Ladybugs for your Lawn"></img>
   </a>
</div>
```

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'qBYXXdW',
 height: 350,
 theme: 'auto',
 tab: 'html,result'
} %}

### Complex images

A [complex image](https://www.w3.org/WAI/tutorials/images/complex/) often
requires more explanation than a decorative, informational, or
functional image. It requires both a short and a long alternative
description to convey the full message. Complex images include infographics,
maps, graphs/charts, and complex illustrations. As with the other
image types, there are different methods you can use to add alternative
descriptions to your complex images.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'NWMvvqw',
 height: 400,
 theme: 'auto',
 tab: 'html,result'
} %}

```html
<img src=".../Ladybug_Anatomy.svg" alt="Diagram of the anatomy of a ladybug."><a href="ladybug-science.html">Learn more about the anatomy of a ladybug</a>
```

One way to add additional explanation to an image is to link out to a resource
or provide a jump link to a longer explanation later on the page. This method
is a good choice, not only for AT users but also helps people with
disabilities&mdash;such as cognitive, learning, and reading
disabilities&mdash;who might benefit from having this additional image
information readily available on the screen instead of buried in the code.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'OJZjxGK',
 height: 400,
 theme: 'auto',
 tab: 'html,result'
} %}

Another method you can use is to append the `aria-describedby` attribute to the
`<img>` element. You can programmatically link the image to an ID containing a
longer description. This method creates a strong association between the image
and the full description. The extended description can be displayed on the
screen or visually hidden&mdash;but consider keeping it visible to support even
more people.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'MWGvEdJ',
 height: 450,
 theme: 'auto',
 tab: 'html,result'
} %}

One other way to group short alternative descriptions with a longer one is to use the HTML5 `<figure>` and `<figcaption>` elements. These elements act similarly to `aria-describedby` in that it semantically groups elements, forming a stronger association between the image and its description. Adding ARIA `role="group"` ensures backward compatibility with older web browsers that don't support the native semantics of the `<figure>` element.

### Alternative text best practices

Of course, including alternate text is not enough. The text should also be
meaningful. For example, if your image is about a swarm of ladybugs chewing the
leaves of your prize rose bush, but your alternative text reads "bugs," would
that convey the full message and intent of the image? Definitely not.

Alternative descriptions need to capture as much relevant visual information as
possible and be succinct. While there is no limit to the number of characters a
screen reader can read, it is usually advised to cap your alternative text to
150 characters or less to avoid reader fatigue. If you need to add additional
context to the image, you can use one of the complex image patterns, add
caption text, or further describe the image in the main copy.

Some additional [alternative text best
practices](https://www.w3.org/WAI/tutorials/images/tips/) include:

* Avoid using words like "image of" or "photo of" in the description, as the
  screen reader will identify these file types for you.
* When naming your images, be as consistent and accurate as possible. Image
  names are a fallback when the alternative text is missing or ignored.
* Avoid using non-alpha characters (for example, #, 9, &) and use dashes
  between words rather than underscores in your image names or alternative text.
* Use proper punctuation whenever possible. Without it, the image descriptions
  will sound like one long, never-ending, run-on sentence.
* Write alternative text like a human and not a robot. Keyword stuffing does
  not benefit anyone&mdash;people using screen readers will be annoyed, and search engine algorithms will penalize you.

{% Assessment 'images' %}

# JavaScript

JavaScript plays a major role in almost everything we create—from smaller
dynamic components to full products running on a JavaScript framework, such as
React or Angular.

This use (or overuse) of JavaScript has brought forward many alarming trends,
such as long load times due to large amounts of code, use of non-semantic HTML
elements, and injection of HTML and CSS through JavaScript. And you may be
unsure of how accessibility fits into each of these pieces.

JavaScript can have a huge impact on the accessibility of your site. In this
module, we'll share some general patterns for accessibility that are enhanced
by JavaScript, as well as solutions for accessibility issues that arise from
using JavaScript frameworks.

## Trigger events

JavaScript events allow users to interact with web content and perform a
specific action. Many people, such as screen reader users,
people with fine-motor skill disabilities, people without a mouse or trackpad,
and others, rely on keyboard support to interact with the web.
It's critical that you add keyboard support to your JavaScript actions, as it
affects all of these users.

Let's look at a [click event](https://developer.mozilla.org/docs/Web/API/Element/click_event).
If an `onClick()` event is used on a semantic HTML element such as a `<button>`
or `<a>`, it naturally includes both mouse and keyboard functionality. However,
keyboard functionality is not automatically applied when an `onClick()` event
is added to a non-semantic element, such as a generic `<div>`.

<div class="switcher">
{% Compare 'worse' %}
```html
<div role="button" tabindex="0" onclick="doAction()">Click me!</div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<button onclick="doAction()">Click me!</button>
```
{% endCompare %}
</div>

Preview this comparison [on CodePen](https://codepen.io/web-dot-dev/pen/bGKOrLj).

If a non-semantic element is used for a trigger event, a
[keydown/keyup event](https://www.w3.org/WAI/ARIA/apg/example-index/button/button.html)
must be added to detect the enter or space key press. Adding trigger events to
non-semantic elements is often forgotten. Unfortunately, when it's forgotten,
the result is a component that's only accessible via a mouse. Keyboard-only
users are left without access to the associated actions.

## Page titles

As we learned in the [Document module](/learn/accessibility/more-html),
the page title is essential for screen reader users. It tells users what page
they are on and whether they have navigated to a new page.

If you use a JavaScript framework, you need to consider how you handle page
titles. This is especially important for
[single-page apps](https://developer.mozilla.org/docs/Glossary/SPA) (SPAs)
that load from a singular `index.html` file, as transitions or routes (page
changes) will not involve a page reload. Each time a user loads a new page in
an SPA, the title won't change by default.

For SPAs, the [document.title](https://developer.mozilla.org/docs/Web/API/Document/title)
value can be added manually or with a helper package (depending on the
JavaScript framework). Announcing the
[updated page titles](https://hidde.blog/accessible-page-titles-in-a-single-page-app/)
to a screen reader user may take some additional work, but the good news is
you've got options, such as dynamic content.

## Dynamic content

One of the most powerful JavaScript functionalities is the ability to add HTML
and CSS to any element on the page. Developers can create dynamic applications
based on the actions or behaviors of the users.

Let's say you need to send a message to users when they log in to your website
or app. You want the message to stand out from the white background and relay
the message: "You are now logged in."

You can use the element [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML)
to set the content:

```javascript
document.querySelector("#banner").innerHTML = '<p>You are now logged in</p>';
```

You can apply CSS in a similar way, with
[`setAttribute`](https://developer.mozilla.org/docs/Web/API/Element/setAttribute):

```javascript
document.querySelector("#banner").setAttribute("style", "border-color:#0000ff;");
```

With great power comes great responsibility. Unfortunately, JavaScript
injection of HTML and CSS has historically been misused to create inaccessible
content. Some common misuses are listed here:

<div class="table-wrapper with-heading-tint">
<table>
<thead>
  <tr>
    <th>Possible misuse</th>
    <th>Correct use</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>Render large chunks of non-semantic HTML</td>
    <td>Render smaller pieces of semantic HTML</td>
  </tr>
  <tr>
    <td>Not allowing time for dynamic content to be recognized by assistive technology</td>
    <td>Using a <code>setTimeout()</code> time delay to allow users to hear the full message</td>
  </tr>
  <tr>
    <td>Applying style attributes for <code>onFocus()</code> dynamically</td>
    <td>Use <code>:focus</code> for the related elements in your CSS stylesheet</td>
  </tr>
  <tr>
    <td>Applying inline styles may cause user stylesheets to not be read properly</td>
    <td>Keep your styles in CSS files to keep the consistency of the theme</td>
  </tr>
  <tr>
    <td>Creating very large JavaScript files that slow down overall site performance</td>
    <td>Use less JavaScript. You may be able to perform similar functions in CSS (such as animations or sticky navigation), which parse faster and are more performant</td>
  </tr>
</tbody>
</table>
</div>

For CSS, toggle CSS classes instead adding inline styles, as this
allows for reusability and simplicity. Use hidden content on the page and
toggle classes to hide and show content for dynamic HTML. If you need to use
JavaScript to dynamically add content to your page, ensure it's simple and
concise, and of course, accessible.

## Focus management

In the [Keyboard focus module](/learn/accessibility/focus), we covered focus
order and indicator styles. Focus management is knowing when and where to trap
the focus and when it shouldn't be trapped.

Focus management is critical for keyboard-only users.

### Component level

You can create keyboard traps when a component's focus is not properly managed.
A keyboard trap occurs when a keyboard-only user gets stuck in a component, or
the focus is not maintained when it should be.

One of the most common patterns where users experience focus management issues
is in a modal component. When a keyboard-only user encounters a modal, the user
should be able to tab between the actionable elements of the modal, but they
should never be allowed outside of the modal without explicitly dismissing it.
JavaScript is essential to properly trapping this focus.

{% Compare 'worse' %}

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'ZERVJMz',
 height: 350,
 theme: 'auto',
 tab: 'js,result'
} %}

{% endCompare %}

{% Compare 'better' %}

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'zYaydmv',
 height: 350,
 theme: 'auto',
 tab: 'js,result'
} %}

{% endCompare %}

### Page level

Focus must also be maintained when a user navigates from page-to-page. This is
especially true in SPAs, where there is
[no browser refresh](https://marcysutton.com/prototype-testing-accessible-clientside-routing/),
and all content dynamically changes. Anytime a user clicks on a link to go
to another page within your application, the focus is either kept in the same
place or potentially placed somewhere else entirely.

When transitioning between pages (or routing), the development team must decide
where the focus goes when the page loads.

There are multiple techniques to achieve this:

* Place focus on the main container with an `aria-live` announcement.
* Put the focus back to a link to skip to the main content.
* Move the focus to the top-level heading of the new page.

Where you decide to put the focus will depend on the framework you are using
and the content you want to serve up to your users. It may be context- or
action-dependent.

## State management

Another area where JavaScript is critical to accessibility is state management,
or when a component or page's current visual state is relayed to a low-vision, blind, or deafblind assistive technology user.

Often, the state of a component or page is managed through ARIA attributes, as
introduced in the [ARIA and HTML module](/learn/accessibility/aria-html/).
Let's review a few of the most common types of ARIA attributes used to help
manage the state of an element.

### Component level

Depending on your page content and what information your users need, there are
many [ARIA states](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes)
to consider when relaying information about a component to the user.

For example, you may use an
[`aria-expanded`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)
attribute to tell the user whether a drop-down menu or list is expanded or
collapsed.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'oNyJeQZ',
 height: 300,
 theme: 'auto',
 tab: 'html,result'
} %}

Or you might use [`aria-pressed`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-pressed)
to indicate that a button has been pressed.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'jOKXLyv',
 height: 300,
 theme: 'auto',
 tab: 'html,result'
} %}

It's important to be selective when applying ARIA attributes. Think through the
user flow to understand what critical information should be conveyed to the user.

### Page level

Developers often use a visually hidden area called the
[ARIA live region](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/ARIA_Live_Regions)
to announce changes on the screen and alert messages to assistive technology
(AT) users. This area can be paired with JavaScript to notify users of dynamic
changes to the page without requiring the entire page to reload.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'Yzvdxdr',
 height: 450,
 theme: 'auto',
 tab: 'result'
} %}

Historically, JavaScript has struggled to announce content in
[`aria-live`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-live)
and alert regions due to its dynamic nature. Asynchronously adding content into
the DOM makes it hard for AT to pick up the region and announce it.
For the content to be properly read, the live or alert region must be in the
DOM on load, then the text can dynamically be swapped out.

If you use a JavaScript framework, the good news is almost all of them have a
"live announcer" package that does all the work for you and is fully
accessible. There is no need to worry about creating a live region and dealing
with the issues described in the previous section.

Here are some live packages for common JavaScript frameworks:

* React: [react-aria-live](https://www.npmjs.com/package/react-aria-live) and
  [react-a11y-announcer](https://github.com/thinkcompany/react-a11y-announcer)
* Angular: [`LiveAnnouncer`](https://material.angular.io/cdk/a11y/overview#liveannouncer)
* Vue: [vue-a11y-utils](https://jinjiang.dev/vue-a11y-utils/#vuelive-component)

Modern JavaScript is a powerful language that allows web developers to create
robust web applications. This sometimes leads to over-engineering and, by
extension, inaccessible patterns. By following the JavaScript patterns and tips
in this module, you can make your apps more accessible to all users.

{% Aside %}
Special thanks to [Mark Steadman](https://twitter.com/Steady5063) for providing
additional support on this module. Read more of his
[accessibility articles](https://dev.to/steady5063).
{% endAside %}

{% Assessment 'javascript' %}

# How is digital accessibility measured?

[Digital accessibility](https://www.w3.org/WAI/fundamentals/accessibility-intro/)
means designing and building your digital offerings so that, regardless of a
person's mental or physical ability, they can still interact with your website,
app, or other digital product in a meaningful and equal way. 

But how do you measure the accessibility of a digital product? How do you know
when something is accessible?

## Introduction to accessibility testing

There are many ways to test a digital product for accessibility. One
fundamental approach is to evaluate it against a set of accessibility
standards. 

There are many types of accessibility standards. Typically, your industry,
product type, local/country
[laws](https://www.3playmedia.com/blog/major-accessibility-laws/) and
[policies](https://www.w3.org/WAI/policies/), or overall accessibility goals
will dictate which set of guidelines to follow and levels to meet. If no
specific standard is required for your project, the standard recommendation is
to follow the latest version of the
[Web Content Accessibility Guidelines (WCAG)](#wcag).

Testing your digital product against an accessibility standard and conformance
level is commonly referred to as an
_[accessibility audit](https://www.w3.org/WAI/test-evaluate/)_.
An accessibility audit uses various methodologies, techniques, and tools,
including design, automated, manual, and assistive technology (AT) testing.

Perform an accessibility audit to capture the baseline accessibility compliance
of a digital product. But, running it once at the start of a project is not
enough to determine if a product is accessible. You should run this audit
multiple times throughout the software product lifecycle to check for changes
in the level of conformance, against a set of pre-determined accessibility
checkpoints or guidelines.

## Web Content Accessibility Guidelines (WCAG) {:#wcag}

The [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/WAI/standards-guidelines/wcag/)
are an international set of accessibility standards developed through the W3C,
in cooperation with individuals and organizations. The goal of WCAG is to
provide a single shared standard for digital accessibility that meets the needs
of individuals, organizations, and governments worldwide.

WCAG is primarily intended for web-based and native mobile app designers and
developers. However, many others, including software developers, content
creators/editors, and all levels of management, benefit from understanding and
applying WCAG-based techniques to their process. Additional W3C standards may
apply to your role, including the
[Authoring Tool Accessibility Guidelines (ATAG)](https://www.w3.org/WAI/standards-guidelines/atag/) and
[User Agent Accessibility Guidelines (UAAG)](https://www.w3.org/WAI/standards-guidelines/uaag/),
so make sure you review the
[W3C list of standards](https://www.w3.org/standards/) and use the one(s) most
applicable to your role and project.

In terms of accessibility, WCAG is considered the "gold standard" for
conformance testing. The
[first draft of WCAG](https://www.w3.org/TR/WAI-WEBCONTENT/) was released in
1999. The current version is [WCAG 2.1](https://www.w3.org/TR/WCAG21/),
released in June 2018, while [WCAG 2.2](https://www.w3.org/TR/WCAG22/) is
scheduled for 2023. A completely revamped version of the guidelines,
[WCAG 3.0](https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/), is
being drafted for a future release, but is not expected to be a completed W3C
standard for a few more years.

The WCAG guidelines have three levels of success criteria: A, AA, and AAA. The
success criteria determine conformance to WCAG. To meet WCAG conformance, the
digital product you are testing needs to meet the success criteria for your
target level.

<ul class="stats">
  <div class="stats__item">
    <p class="stats__figure">
      30
    </p>
    <p>A success criteria</p>
  </div>
  <div class="stats__item">
    <p class="stats__figure">
      20
    </p>
    <p>AA success criteria</p>
  </div>
  <div class="stats__item">
    <p class="stats__figure">
      28
    </p>
    <p>AAA success criteria</p>
  </div>
</ul>

For the current standard (WCAG 2.1), there are 78 success criteria in total,
split across each level. It is important to note that each level is
progressive, meaning if your accessibility goal is AA, you must pass the
success criteria for both A and AA to achieve this level of conformance.

<ul class="stats">
  <div class="stats__item">
    <p class="stats__figure">
      30
    </p>
    <p>Pass A level</p>
  </div>
  <div class="stats__item">
    <p class="stats__figure">
      50
    </p>
    <p>Pass A + AA level</p>
  </div>
  <div class="stats__item">
    <p class="stats__figure">
      78
    </p>
    <p>Pass A + AA + AAA level</p>
  </div>
</ul>

## Accessibility principles

The WCAG success criteria are a very important set of detailed guidelines that
inform designers and developers how to create accessible websites and apps.
Understanding these guidelines is critical to address issues that arise in
accessibility compliance testing, but the guidelines quickly become very technical.

If you are new to this field, start with the principles of
WCAG&mdash;[Perceivable, Operable, Understandable, and Robust (POUR)](https://www.w3.org/WAI/fundamentals/accessibility-principles/).
By applying POUR principles to your digital products, you can focus on how your
products are used by real humans, including people with disabilities. 

<figure class="screenshot">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/j2qQcEjknNhD46OxDtaE.png", alt="Perceivable, Operable, Understandable, and Robust all connect to one another.", width="800", height="679" %}
</figure>

{% Details 'open' %}

{% DetailsSummary 'h3' %}
Perceivable
{% endDetailsSummary %}

<figure data-float="right">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/haquBrDGcS5NehEPGYoK.png", alt="Perceivable is represented by glasses, but multiple sesnes are used to understand content on a screen.", width="234", height="98" %}
</figure>

The first category in POUR is Perceivable. This principle states that users
must be able to perceive all essential information on the screen, and it must
be conveyed to multiple senses.

**Ask yourself**: Is there any content or functionality in your digital product
that a person with a specific disability would not be able to perceive? Be sure
to consider all the different types of disabilities—visual, mobility, hearing,
cognitive, and speech impairments, vestibular and seizure disorders, and more.

**Examples of Perceivable**:

* Adding text alternatives to all non-decorative images and essential icons.
* Adding captions, transcripts, and audio descriptions to videos.
* Ensuring color is not the only method of conveying meaning.
{% endDetails %}

{% Details 'open' %}

{% DetailsSummary 'h3' %}
Operable
{% endDetailsSummary %}

<figure data-float="right">
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/XPLRoBlh2fFMgY9rUDeV.png", alt="Operable is represented by a keyboard, but there are a number of interfaces and softwares one may use to interact.", width="353", height="177" %}
</figure>

The second category is Operable. For this principle, users must be able to
operate the digital product's interface. The interface cannot require
interaction that a user cannot perform.

**Ask yourself**: Can users control the interactive elements of your digital
product? Are there any focus order issues or keyboard traps? How are touch
interfaces handled?

**Examples of Operable**:

* Adding keyboard and touchscreen support to all active elements.
* Ensuring slideshows and videos have all of the necessary controls available.
* Giving users enough time to fill out a form or a method to extend the time.
{% endDetails %}

{% Details 'open' %}

{% DetailsSummary 'h3' %}
Understandable
{% endDetailsSummary %}

<figure data-float="right">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/Wu11xfdtJVoYTNiY9BxO.png", alt="Understandable is represented by a head with colorful connected dots.", width="168", height="215" %}
</figure>

The third category of POUR is Understandable. For this principle, users must understand the information and the operation of the user interface.

**Ask yourself**: Is all of the content clearly written? Are all of the
interactions easy to understand? Does the order of the page make sense—to
sighted users, keyboard-only users, screen reader users?

**Examples of Understandable**:

* Writing simply—don't use a complex word when a simple one will do.
* Ensuring your digital product has predictable navigation.
* Ensuring error messages are clear and easy to resolve.
{% endDetails %}

{% Details 'open' %}

{% DetailsSummary 'h3' %}
Robust
{% endDetailsSummary %}

<figure data-float="right">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/6n5u7FVgb5dCCup50UKY.png", alt="Robust", width="362", height="218" %}
</figure>

The last category is Robust. This principle focuses on supporting assistive
technologies and ensuring that, as devices and user agents evolve, the digital
product remains accessible.

**Ask yourself**: What types of assistive technology are you supporting? Does
your digital product only work on the newest browsers or operating systems?
Does it work at all breakpoints and in different device orientations? 

**Examples of Robust**:

* Testing keyboard-only navigation.
* Testing with different screen reader technologies.
* Ensuring all of the content and functionality can be accessed, regardless of device size or orientation.
{% endDetails %}

Remember—the whole point of POUR is not about rigidly adhering to hard and fast
rules. Instead, it is a way to help you
[understand and meet](https://alistapart.com/article/getting-to-the-heart-of-digital-accessibility/)
the diverse needs of your users.

{% Assessment 'measure' %}

# The Document

Along with structure, there are many supporting HTML elements to consider when
building and designing for digital accessibility. Throughout the Learn
Accessibility course, we cover a lot of elements.

This module focuses on very specific elements that don't quite fit into any of
the other modules but are useful to understand.

{% Aside %}
Our [Learn HTML course](/learn/html/) covers the basics of HTML and semantic
structure in great detail. As such, this module builds off of that course
material and is focused specifically on digital accessibility. Likewise, be
sure to review the [ARIA and HTML module](/learn/accessibility/aria-html/) in
this course before diving into this module.
{% endAside %}

## Page title

The HTML [`<title>`](https://developer.mozilla.org/docs/Web/HTML/Element/title)
element defines the content of the page or screen a user is about to
experience. It's found in the
[`<head>`](https://developer.mozilla.org/docs/Web/HTML/Element/head) section of
an HTML document and is equivalent to the `<h1>` or main topic of the page. The
title content is displayed in the browser tab and helps users understand which
page they are visiting, but it is not displayed on the website or app itself.

In a [single-page app](https://developer.mozilla.org/docs/Glossary/SPA) (SPA),
the `<title>` is handled in a slightly different way, as users don't navigate
between pages as they do on multi-page websites. For SPAs, the value of the
[`document.title`](https://developer.mozilla.org/docs/Web/API/Document/title)
property can be added manually or by a helper package, depending on the
JavaScript framework. Announcing the
[updated page titles](https://hidde.blog/accessible-page-titles-in-a-single-page-app/)
to a screen reader user may take some additional work.


Descriptive page titles are good for both users and
[search engine optimization (SEO)](https://developer.mozilla.org/docs/Web/HTML/Element/title#page_titles_and_seo)—but
don't go overboard and add lots of keywords. Since the title is the first
thing announced when an AT user visits a page, it must be accurate, unique, and
descriptive, but also concise.

When writing page titles, it is also best practice to "front load" the interior
page or important content first, then add any preceding pages or information
after. This way, AT users don't have to sit through the information they have
already heard.

<div class="switcher">
{% Compare 'worse' %}
```html
<title>The Food Channel | Outrageous Pumpkins | Season 3 </title>
```
{% endCompare %}

{% Compare 'better' %}
```html
<title>Season 3 | Outrageous Pumpkins | The Food Channel</title>
```
{% endCompare %}
</div>

{% Aside 'important' %}
Search engines typically display only the first 55–60 characters of a page
title, so be sure to limit your total page title characters.
{% endAside %}

## Language

### Page language

The page language attribute ([`lang`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang)) sets the default language for the entire page. This attribute is added to the [`<html>`](https://developer.mozilla.org/docs/Web/HTML/Element/html) tag. A valid language attribute should be added to every page as it signals the AT to which language it should use.

It's recommended that you use two-character
[ISO language codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
for greater AT coverage, as many of them do not support
[extended language codes](https://webaim.org/techniques/language/).

When a language attribute is completely missing, the AT will default to the
user's programmed language. For example, if an AT was set to Spanish, but a
user visited an English website or app, the AT would try to read the English
text with Spanish accents and cadence. This combination results in an unusable
digital product and a frustrated user.

<div class="switcher">
{% Compare 'worse' %}
```html
<html>...</html>
```
{% endCompare %}

{% Compare 'better' %}
```html
<html lang="en">...</html>
```
{% endCompare %}
</div>

The lang attribute can only have one language associated with it. This means
the `<html>` attribute can only have one language, even if there are multiple
languages on the page. Set `lang` to the primary language of the page.

<div class="switcher">
{% Compare 'worse' %}
```html
<html lang="ar,en,fr,pt">...</html>
```

{% CompareCaption %}
Multiple languages are not supported.
{% endCompareCaption %}
{% endCompare %}

{% Compare 'better' %}
```html
<html lang="ar">...</html>
```

{% CompareCaption %}
Set only the page's primary language. In this case, the language is Arabic.
{% endCompareCaption %}
{% endCompare %}
</div>

### Section language

You can also use the language attribute ([lang](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang)) for language switches in the content itself. The same basic rules apply as the full-page language attribute, except you add it to the appropriate in-page element instead of on the `<html>` tag.

Remember that the language you add to the `<html>` element cascades down to all
the contained elements, so always set the primary language of the page
top-level `lang` attribute first.

For any in-page elements written in a different language, add that `lang`
attribute to the appropriate wrapper element. This will override the
top-level language setting until that element is closed.

<div class="switcher">
{% Compare 'worse' %}
```html
<html lang="en">
  <body>...
    <div>
      <p>While traveling in Estonia this summer, I often asked,
        "Kas sa räägid inglise keelt?" when I met someone new.</p>
    </div>
  </body>
</html>
```
{% endCompare %}

{% Compare 'better' %}
```html
<html lang="en">
  <body>...
    <div>
      <p>While traveling in Estonia this summer, I often asked,
        <span lang="et">"Kas sa räägid inglise keelt?"</span>
        when I met someone new.</p>
    </div>
  </body>
</html>
```
{% endCompare %}
</div>

## iFrames

The iFrame element
([`<iframe>`](https://developer.mozilla.org/docs/Web/HTML/Element/iframe)) is
used to host another HTML page or a third party's content within the page. It
essentially puts another webpage within the parent page. iFrames are commonly
used for advertisements, embedded videos, web analytics, and interactive
content.

To make your `<iframe>` accessible, there are a couple of aspects to consider. First, each `<iframe>` with distinct content should include a title element inside the parent tag. This title supplies AT users with more information about the content inside the `<iframe>`.

Second, as a best practice, it is good to set the scrolling to "auto" or "yes" in the `<iframe>` tag settings. This allows people with low vision to be able to scroll into content within the `<iframe>` that they might not otherwise be able to see. Ideally, the `<iframe>` container would also be flexible in its height and width.

<div class="switcher">
{% Compare 'worse' %}
```html
<iframe src="https://www.youtube.com/embed/3obixhGZ5ds"></iframe>
```
{% endCompare %}

{% Compare 'better' %}
```html
<iframe title="Google Pixel - Lizzo in Real Tone"
  src="https://www.youtube.com/embed/3obixhGZ5ds"
  scrolling="auto">
</iframe>
```
{% endCompare %}
</div>

{% Assessment 'document' %}

# Animation and motion

Have you ever been riding in a car, boat, or plane and suddenly felt the world
spin? Or had a migraine so bad that animations on your phone or tablet, 
created to "delight" you, suddenly make you sick? Or perhaps you've always been
sensitive to all types of motion? These are examples of different types of
vestibular disorders. 

By age 40, over 35% of adults will have experienced some form of
[vestibular dysfunction](https://vestibular.org/article/what-is-vestibular/about-vestibular-disorders/).
This may lead to a temporary dizzy spell, migraine-induced vertigo, or a more
permanent vestibular disability.

Beyond triggering vertigo, many people find moving, blinking, or scrolling
content distracting. People with
[ADHD](https://www.nimh.nih.gov/health/publications/attention-deficit-hyperactivity-disorder-in-children-and-teens-what-you-need-to-know)
and other attention deficit disorders might be so distracted by your animated
elements that they forget why they even went to your website or app in the
first place.

In this module, we'll look at some of the ways to help better support people
with all types of movement-triggered disorders. 

## Flashing and moving content

When building animation and motion, you should ask yourself whether the element's movement is excessive. For example, colors flickering from dark to light or quick movements on the screen, can cause seizures in people with photosensitive epilepsy. It is estimated that [3% of people with epilepsy](https://www.epilepsy.com/what-is-epilepsy/seizure-triggers/photosensitivity) suffer from photosensitivity, and it's more common in women and younger people.

The WCAG's [guidelines on flashing](https://www.w3.org/TR/WCAG21/#three-flashes-or-below-threshold) recommend against the following: 

* Flashes for more than three times in any one second
* Flashes below the
  [general flash and red flash threshold](https://www.w3.org/TR/WCAG21/#dfn-general-flash-and-red-flash-thresholds).

These flashes may, at best, cause an inability to use a webpage or, at worst,
lead to illness.

For any extreme movement, it is imperative that you test it using the
[Photosensitive Epilepsy Analysis Tool (PEAT)](https://trace.umd.edu/peat/).
PEAT is a free tool to identify if the screen's content, video, or animations
are likely to cause seizures. Not all content needs to be evaluated by PEAT,
but content that contains flashing or rapid transitions between light and dark
background colors should be evaluated, just to be safe.

Another question you should ask yourself about animation and motion is whether the element's movement is essential to understanding the content or actions on the screen. If it is not essential, consider removing all movement—even micro-movements—from the element you are building or designing.

Suppose you believe the element's movement is not essential but could enhance
the user's overall experience, or you cannot remove the movement for another
reason. In that case, you should follow WCAG's
[guidelines on motion](https://www.w3.org/WAI/WCAG21/Understanding/pause-stop-hide.html).
The guidelines state that you must build an option for users to pause, stop or
hide movement for: non-essential moving, blinking, or scrolling elements that
start automatically, last more than five seconds, and are part of other page
elements.

## Pause, stop, or hide movement {: #pause-stop-hide}

Add a [pause, stop, or hide](https://css-tricks.com/accessible-web-animation-the-wcag-on-animation-explained/#aa-pause-stop-hide)
mechanism to your page to allows users to turn off potentially problematic
motion animation. You can do this on the screen level or element level.

For example, suppose your digital product includes a lot of animations.
Consider adding an [accessible JavaScript toggle](https://css-irl.info/accessible-toggles/)
to allow users to control their experience. When the button is toggled to
"motion off," all animations are frozen on that screen and all others.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'xxjpBGE',
 height: 450,
 theme: 'auto',
 tab: 'js,result'
} %}

## Use media queries

In addition to being selective about your animations, giving your users options
to pause, stop, hide movement, and avoiding infinite animation loops, you can
also consider adding a movement-focused media query. This gives your users even
more choice when it comes to what is displayed on the screen.

### `@prefers-reduced-motion` {: #prefers-reduced-motion}

Similar to the color-focused media queries in the [color module](/learn/accessibility/color-contrast), the @prefers-reduced-motion media query checks the [user's OS settings](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion#user_preferences) related to animation.

<figure>
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/THGrOrf3wJxPZWDJAcZx.png", alt="MacOS Display settings UI, where Reduce motion is turned on.", width="800", height="580" %}
</figure>

A user may set display preferences to reduce motion. These settings are
different across operating systems, and may be framed positively or negatively.
With [@prefers-reduced-motion](/prefers-reduced-motion/), you can design a site
which respects these preferences.

{% BrowserCompat 'css.at-rules.media.prefers-reduced-motion' %}

On MacOS and Android, the user turns the setting on to reduce motion. On MacOS,
a user can set **Reduce motion** in Settings > Accessibility > Display.
Android's setting is **Remove animations**. On Windows, the setting is framed
positively as **Show animations**, which is on by default. A user must turn
this setting off to reduce motion.

{% Aside %}
As each UI uses different language, consider still [allowing users to choose for themselves](#allow-user-choice),
rather than guessing how much animation is too much. This may differ on a
situation-by-situation basis.
{% endAside %}

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'VwxyReM',
 height: 350,
 theme: 'auto',
 tab: 'css,result'
} %}

Alternatively, as shown in the next set of examples, you can code all your animations to stop moving within five seconds or less instead of playing on an infinite loop.

### Progressive enhancement for movement

As designers and developers, we have a lot of choices to make, including default movement states and how much movement to display. Let's take another look at the last example on motion.

Suppose we decide the animation is unnecessary for understanding the content on the screen. In that case, we can choose to set the default state to the reduced motion animation instead of the full motion version. Unless users specifically ask for animations, the animations are turned off. 

{% Aside %}
The motion preferences available are dependent on the operating system. Some allow you to opt-in to animations, while others require you to opt out of the animations.
{% endAside %}

We cannot predict what level of movement will cause issues for people with
seizure, vestibular, and other visual disorders. Even a small amount of motion
on the screen can trigger dizziness, blurred vision, or worse. So, in the
following example, we default to no animation.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'qBYpvam',
 height: 350,
 theme: 'auto',
 tab: 'css,result'
} %}

### Layered media queries

You can use multiple media queries to give your users even more choices. Let's
use `@prefers-color-scheme`, `@prefers-contrast`, and `@prefers-reduced-motion`
all together.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'wvjpOzR',
 height: 400,
 theme: 'auto',
 tab: 'css,result'
} %}

## Allow your users to choose {: #allow-user-choice}

While it can be fun to build animation into our digital products to delight
users, it's critical we remember some people will be affected by these designs.
Motion sensitivity can affect anyone, from feeling slight discomfort to causing 
a debilitating illness or seizure.

You can use a number of different tools to allow the user to decide what's best
for them, rather than guessing how much motion is too much. For example, add a
toggle to turn on or off animation within your site or web app. Consider
defaulting such a toggle to **off**.

{% Assessment 'motion' %}

# Patterns, components, and design systems

Many people use component-driven development using pattern style guides, component libraries, or full design systems in their
development workflow process. Even if you have not used these tools formally, it's likely you use a similar process to break up a
large design for a website, app, or other digital product into manageable pieces.

Like building a physical structure, it's important to build one piece at a time. First, the foundation, the structure, walls,
windows, roof, and everything in between. Component-driven development tools allow us to do this for websites, apps, and other digital products.

Some perks to component-driven development include breaking things down into
manageable pieces, so there is less development time with these reusable
components. It allows designers, frontend and backend developers, and QA to
work simultaneously. And clients, designers, PMs, and more, like it because
they can preview the build process and use a living style guide as a reference
after the website has launched.

However, when we look at patterns, components, and design systems with accessibility in mind, some questions arise. How do you know
which patterns are best when it comes to accessibility? Should you use an established pattern/library or create new ones? How do
you know if these patterns will actually help your users?

With the myriad of choices available, it's easy to quickly become confused about this topic. This module aims to give you general
information on how to evaluate patterns, components, and design systems for accessibility and gives you a starting point to help you make
more accessible choices.

## Think critically

Choosing an accessible pattern, component, or design system is not rocket
science, but it does take time and critical thinking. In fact, there's no such thing as "one perfect pattern," but there may potentially be many options that could work. It's about learning to choose the best option for your unique situation.

In the subsequent testing modules, you will learn more about the techniques and methods on how to evaluate patterns, components, and
design systems for accessibility. But before that stage, you need to step back and ask yourself some fundamental questions, such as:

* Does an established accessible pattern, component, or design system already exist?
* What browsers and assistive technology (AT) am I supporting?
* Are there any code/framework limitations or other integrations/factors/user needs I need to consider?

Depending on your dev environment and user needs, you may have additional or different questions from these. Consider
these questions as your starting point in your accessibility evaluation.

## Established resources

Before building something brand new, do your due diligence and review what already exists in terms of accessible patterns,
components, and design systems. With just a little research, you might be surprised to find a solution—or multiple—that fits your needs.

Some great resources for accessible patterns, components, and design systems include:

* [Accessible Components](https://github.com/scottaohara/accessible_components)
* [Deque University ARIA library](https://dequeuniversity.com/library)
* [Gov.UK Design System](https://design-system.service.gov.uk/components/)
* [Inclusive Components](https://inclusive-components.design/)
* [MagentaA11y](https://www.magentaa11y.com/)
* [U.S. Web Design System (USWDS)](https://designsystem.digital.gov/components/overview/), created for the U.S. federal government
* [List of accessible patterns from Smashing Magazine](https://www.smashingmagazine.com/the-smashing-newsletter/smashing-newsletter-issue-289/)

For JavaScript frameworks, the following resources are fairly accessible out of
the box or are easy to customize for accessibility:

* [When CSS Isn't Enough: JavaScript Requirements For Accessible Components](https://www.smashingmagazine.com/2021/06/css-javascript-requirements-accessible-components/)
* React
  * [ReachUI](https://reach.tech/)
  * [Reakit](https://reakit.io/)
  * [Chakra](https://chakra-ui.com/)
* Angular: [Material library](https://material.angular.io/cdk/a11y/overview)
* Vue: [Vuetensils](https://vuetensils.com/)

However—and this cannot be stressed enough—you should never just copy/paste
code and assume it will fit within your environment and automatically meet your
user needs. This is true of all patterns, components, and design systems, even
if labeled as fully accessible.

All resources should be seen as a starting point. Be sure to test everything!

## Browsers and assistive technology (AT) support

After researching a few base patterns, components, or a full design system that
might work for your dev environment, you can move on to assistive technology
support. One major type of AT you will want to focus on when evaluating
patterns, components, and design systems is screen readers.

Screen readers were built with specific browsers in mind and will work best
when paired with these browsers. We'll go into this topic in much more detail
in the module on AT testing, but for pattern evaluation purposes, it is helpful
to understand these combinations exist, so you know what you need in terms of
support.

<div class="table-wrapper with-heading-tint">
<table>
<thead>
  <tr>
    <th>Screen reader</th>
    <th>OS</th>
    <th>Browser compatibility</th>
    <th>Cost</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td>Job Access with Speech (JAWS)</td>
    <td>Windows</td>
    <td>Chrome, Firefox, Edge</td>
    <td>License require (a free 40-min version exists)</td>
  </tr>
  <tr>
    <td>Non-Visual Desktop Access (NVDA)</td>
    <td>Windows</td>
    <td>Chrome and Firefox</td>
    <td>Free (requires download)</td>
  </tr>
  <tr>
    <td>Narrator</td>
    <td>Windows</td>
    <td>Edge</td>
    <td>Free (built into Windows machines)</td>
  </tr>
  <tr>
    <td>VoiceOver</td>
    <td>macOS</td>
    <td>Safari</td>
    <td>Free (built into macOS machines)</td>
  </tr>
  <tr>
    <td>Orca</td>
    <td>Linus</td>
    <td>Firefox</td>
    <td>Free (built into Gnome-based distributions)</td>
  </tr>
  <tr>
    <td>TalkBack</td>
    <td>Android</td>
    <td>Chrome and Firefox</td>
    <td>Free (built into certain versions of Android OS)</td>
  </tr>
  <tr>
    <td>VoiceOver</td>
    <td>iOS</td>
    <td>Safari</td>
    <td>Free (built into iOS devices)</td>
  </tr>
</tbody>
</table>
</div>

Browser support is generally complicated, and things get even trickier when you add AT devices and ARIA specifications to the mix.

But it's not all bad news. Thankfully, great resources such as [HTML5 Accessibility](https://stevefaulkner.github.io/HTML5accessibility),
[Accessibility Support](https://a11ysupport.io), and WCAG's [Custom Control Accessible Development Checklist](https://w3c.github.io/using-aria/#checklist)
help us to better understand current browser and AT device support, and even when to use ARIA in the first place.

These resources outline the different HTML and ARIA pattern sub-elements available, including open-source community tests.
You can also review some pattern examples—for both desktop and mobile browsers/AT devices. As such, these resources can help
you make a more accessible decision regarding patterns, components, and design systems that you may want to use.

### Other considerations

Once you have chosen a few accessible base patterns or components, and factored
in browser and AT device support, you can move on to more specific contextual
questions about the pattern, component, design system, and dev environment.

For example, if you are working in a management system (CMS) or have legacy
code, there may be some limitations to which patterns you can use. Upon review,
several pattern choices may quickly be cut to one or two options.

Many JavaScript frameworks allow developers to use almost any pattern they
choose. In cases like these, you may have fewer restrictions and can choose the
most accessible pattern option.

There are additional considerations to weigh when choosing a pattern,
component, or design system, such as:

* Performance
* Security
* Search engine optimization
* Language translation support
* Third-party integrations

These factors will undoubtedly play into your pattern choice, but you should
also consider the people creating the content and code itself. The pattern you
choose must be robust enough to handle any potential limitations around
editor-generated or user-generated content, plus be built in a way that
developers of all accessibility knowledge can use.

{% Assessment 'patterns' %}

# Content structure

One of the most important aspects of digital accessibility is the underlying
structure of the page. When you build your website or app using
[structural elements](https://www.w3.org/WAI/tutorials/page-structure/) instead
of relying on styles alone, you give critical context to people using assistive
technologies (AT), such as screen readers.

Structural elements serve as an outline of the content on the screen, but they
also act as anchor points to allow for easier navigation within the content.

When you use [semantic HTML elements](https://developer.mozilla.org/docs/Glossary/Semantics#semantics_in_html),
the inherent meaning of each element is passed on to the accessibility tree and
used by the AT, giving more meaning to the content than non-semantic elements.
There may be cases where you need to add additional ARIA attributes to build
relationships or to enhance the overall user experience, but in most
situations, one of the [100+ HTML elements](https://developer.mozilla.org/docs/Web/HTML/Element)
available should work fairly well on its own.

While this module focuses on the most widely used structural elements critical
to digital accessibility, there are certainly additional elements and
environmental factors to consider when building structure into your website or
app. These examples are an introduction to the topic, rather than all-inclusive.

{% Aside %}

Our [Learn HTML course](/learn/html/) covers the basics of HTML and
[semantic structure](/learn/html/semantic-html/) in great detail. As such, this
module builds off of that course material and is focused specifically on
digital accessibility. Likewise, be sure to review the
[ARIA and HTML module](/learn/accessibility/aria-html/) in this course before
diving into this module.

{% endAside %}

## Landmarks

Users of AT rely on structural elements to give them information about the
page's overall layout. When sectioning off large regions of content, you can
use either ARIA landmark roles or the newer HTML landmark elements to add
structural context to your page.

Landmarks ensure content is in navigable regions. It's recommended that you supply at least one landmark per page.

Some resources suggest combining [ARIA and HTML landmarks](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/landmark_role#best_practices)
together to provide better AT coverage. While this type of redundancy shouldn't
cause issues for your users, test the patterns using a screen reader
to be certain. When in doubt, it's best to default to using only the newer HTML
landmark elements, as the
[browser support](https://stevefaulkner.github.io/HTML5accessibility/) is very
robust.

Let's compare the HTML landmark elements as
[mapped](https://www.a11yproject.com/posts/aria-landmark-roles/) to their
counterpart ARIA landmark roles.

<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>HTML landmark element</th>
        <th>ARIA landmark role</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><a href="https://developer.mozilla.org/docs/Web/HTML/Element/header"><code>&lt;header&gt;</code></a></td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/banner_role">banner</a></td>
      </tr>
      <tr>
        <td><a href="https://developer.mozilla.org/docs/Web/HTML/Element/aside"><code>&lt;aside&gt;</code></a></td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/complementary_role">complementary</a></td>
      </tr>
      <tr>
        <td><a href="https://developer.mozilla.org/docs/Web/HTML/Element/footer">
          <code>&lt;footer&gt;</code></a></td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/contentinfo_role">contentinfo</a></td>
      </tr>
      <tr>
        <td>
          <a href="https://developer.mozilla.org/docs/Web/HTML/Element/nav"><code>&lt;nav&gt;</code></a>
          </td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/navigation_role">navigation</a></td>
      </tr>
      <tr>
        <td><a href="https://developer.mozilla.org/docs/Web/HTML/Element/main"><code>&lt;main&gt;</code></a></td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/main_role">main</a></td>
      </tr>
      <tr>
        <td><a href="https://developer.mozilla.org/docs/Web/HTML/Element/form"><code>&lt;form&gt;</code></a> <sup>1</sup></td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/form_role">form</a></td>
      </tr>
      <tr>
        <td>
          <a href="https://developer.mozilla.org/docs/Web/HTML/Element/section"><code>&lt;section&gt;</code></a> <sup>1</sup></td>
        <td><a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/region_role">region</a></td>
      </tr>
  </tbody>
  <caption>
    <sup>1</sup> Requires inclusion of the <code>name</code> attribute to be accessible. A <code>section</code> must be <a href="https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#whatareaccessiblenamesanddescriptions?">accessibly-named</a> for its implicit ARIA role of <a href="https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/region_role"><code>region</code></a> to be visible to assistive technology.
  </caption>
</table>
</div>

Now, let's compare examples of accessible content structure.

<div class="switcher">
{% Compare 'worse' %}
```html
<div>
	<div>...</div>
</div>
<div>
	<p>Stamp collecting, also known as philately, is
    the study of postage stamps, stamped envelopes,
    postmarks, postcards, and other materials relating
    to postal delivery.</p>
</div>
<div>
<p>© 2022 - Stamps R Awesome</p>
</div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<header>
	<nav>...</nav>
</header>
<main>
	<section aria-label="Introduction to stamp collecting">
    <p>Stamp collecting, also known as philately, is
    the study of postage stamps, stamped envelopes,
    postmarks, postcards, and other materials relating
    to postal delivery.</p>
	</section>
</main>
<footer>
<p>© 2022 - Stamps R Awesome</p>
</footer>
```
{% endCompare %}
</div>

{% Aside %}

Check out the
[ARIA Landmarks Example](https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/main.html)
for more information and best practices.

{% endAside %}

## Headings

When implemented correctly, [HTML heading levels](https://developer.mozilla.org/docs/Web/HTML/Element/Heading_Elements)
form a succinct outline of the overall page content.

There are six heading levels we can use. Heading level one `<h1>` is used for the page's highest and most important information, moving incrementally to
heading level six `<h6>` for the lowest and least important information.

The sequence of the heading levels is important. Ideally, you won't skip
heading levels, for example, starting a section with an `<h1>` and immediately
following it with an `<h5>`. Instead, you should progress to the `<h5>` in
order. [Heading level order is especially important to AT users](https://youtu.be/vAAzdi1xuUY)
as this is one of their primary ways to navigate through content.

{% Aside %}

While you can use [ARIA heading roles](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/heading_role)
for heading levels, it's recommended you use semantic HTML heading levels
whenever possible.

{% endAside %}

To help you adhere to the proper semantic structure and order for headings,
consider decoupling your CSS styles from the heading levels. This allows you
more flexibility in heading styles while maintaining the heading level order.
It's critical you don't use styles alone to create headings, as these
aren't seen by AT as a heading.

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'Vwdajpe',
 height: 400,
 theme: 'auto',
 tab: 'html,css,result'
} %}

When we fake headings, the appropriate structure isn't conveyed to AT users.

Headings are also helpful for people with cognitive and attention deficit
disorders. It's important to make the heading content meaningful to help them
understand what is most important on the page.

<div class="switcher">
{% Compare 'worse' %}
```html
<div>
	<h3>Stamps</h3>
	<p>Stamp collecting, also known as philately, is the study of postage stamps, stamped envelopes, postmarks, postcards, and other materials relating to postal delivery.</p>
</div>
<div>
	<h3>How do I start a stamp collection?</h3>
  <h2>Equipment you will need</h2>
	<h4>...</h4>
  <h2>How to acquire stamps</h2>
	<h4>...</h4>
  <h2>Organizations you can join</h2>
	<h4>...</h4>
</div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<header>
  <h1>Stamp collecting</h1>
</header>
<main>
	<section aria-label="Introduction to stamp collecting">
		<h2>What is stamp collecting?</h2>
		<p>Stamp collecting, also known as philately, is the study of postage stamps, stamped envelopes, postmarks, postcards, and other materials relating to postal delivery.</p>
	</section>

	<section aria-label="Start a stamp collection">
		<h2>How do I start a stamp collection?</h2>
    <h3>Required equiment</h3>
    <p>...</p>

    <h3>How to acquire stamps</h3>
    <p>...</p>

    <h3>Organizations you can join</h3>
		<p>...</p>
	</section>
</main>
```
{% endCompare %}
</div>


## Lists

[HTML lists](https://www.w3.org/WAI/tutorials/page-structure/content/#lists)
are a way to semantically group items similar to one other giving them inherent
meaning, much like your grocery store list or that never-ending to-do list you
keep ignoring.

There are three types of HTML lists:

* ordered [`<ol>`](https://developer.mozilla.org/docs/Web/HTML/Element/ol)
* unordered [`<ul>`](https://developer.mozilla.org/docs/Web/HTML/Element/ul)
* description [`<dl>`](https://developer.mozilla.org/docs/Web/HTML/Element/dl)

The list item [`<li>`](https://developer.mozilla.org/docs/Web/HTML/Element/li)
element is used to represent an item in an ordered or unordered list, while the
description term
[`<dt>`](https://developer.mozilla.org/docs/Web/HTML/Element/dt) and definition
[`<dd>`](https://developer.mozilla.org/docs/Web/HTML/Element/dd) elements can
  be found in the description list.

When programmed correctly, these elements can inform non-sighted AT users about
the visible structure of the list. When an AT encounters a semantic list, it
can tell the user the list name and how many items are in it. As the user
navigates within the list, the AT will read each list item out loud and tell
which number it's in the list—item one of five, item two of five, and so on.

Grouping items into lists also helps sighted people who have cognitive and
attention disorders and those with reading disabilities, as list content is
typically styled to have more visual whitespace and the content is to the point.

<div class="switcher">
{% Compare 'worse' %}
```html
<div>
  <p>How do I start a stamp collection?</p>
  <p>Equipment you will need</p>
    <div>
      <p>Small tongs with rounded tips</p>
      <p>Stamp hinges</p>
      <p>Stockbook or albumn</p>
      <p>Magnifying glass</p>
      <p>Stamps</p>
    </div>
</div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<div>
  <h1>How do I start a stamp collection?</h1>
  <h2>Equipment you will need</h2>
  <ol>
    <li>Small tongs with rounded tips</li>
    <li>Stamp hinges</li>
    <li>Stockbook or albumn</li>
    <li>Magnifying glass</li>
    <li>Stamps</li>
  </ol>
</div>
```
{% endCompare %}
</div>

## Tables

In HTML, tables are generally used for organizing data or page layout.

Depending on the table's purpose, you'll use different semantic structural
elements. Tables can be very complex in structure, but when you stick to the
basic semantic rules, they are fairly accessible without much intervention.

### Layout

In the early days of the internet, layout tables were the primary HTML element
used to build visual structures. Today, we use a mix of semantic and
non-semantic elements such as `<div>`s and landmarks to create layouts.

While the days of creating layout tables are mostly over, there are times when
layout tables are still used, such as in visually rich emails, newsletters, and
advertisements. In these cases, tables used only for layout must not
use structural elements that convey relationships and add context, such as
`<th>` or `<caption>`.

Layout tables must also be hidden from AT users with the ARIA
[presentation role](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/presentation_role)
or [aria-hidden state](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-hidden).

<div class="switcher">
{% Compare 'worse' %}
```html
<table>
  <caption>My stamp collection</caption>
  <tr>
    <th>[Stamp Image 1]</th>
    <th>[Stamp Image 2]</th>
    <th>[Stamp Image 3]</th>
  </tr>
</table>
```
{% endCompare %}

{% Compare 'better' %}
```html
<table role="presentation">
  <tr>
    <td>[Stamp Image 1]</td>
    <td>[Stamp Image 2]</td>
    <td>[Stamp Image 3]</td>
  </tr>
</table>
```
{% endCompare %}
</div>

### Data

Unlike a layout table, which should be hidden from AT users, a
[data table](https://www.w3.org/WAI/tutorials/tables/) and all its elements
must be exposed. The structure of data tables is critical for conveying simple
and complex information to users.

When a table is structured correctly, relationships form between the column
headers and rows and the data within the table. When structured incorrectly,
the user is left to decipher the meaning and context of the information in the
table.

Depending on the complexity of the table, forming relationships through code is
accomplished in different ways. The first step to making a table accessible is
to mark up header cells with
[`<th>`](https://developer.mozilla.org/docs/Web/HTML/Element/th) and data cells
with [`<td>`](https://developer.mozilla.org/docs/Web/HTML/Element/td) elements.

For more complex tables, you may need to use additional HTML table elements
such as
[`<rowgroup>`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/rowgroup_role),
[`<colgroup>`](https://developer.mozilla.org/docs/Web/HTML/Element/colgroup),
[`<caption>`](https://developer.mozilla.org/docs/Web/HTML/Element/caption),
and
[`scope`](https://developer.mozilla.org/docs/Web/HTML/Element/th#attr-scope) to
convey meaning and relationships.

<div class="switcher">
{% Compare 'worse' %}
```html
<table>
  <tr>
    <td>Animal</td>
    <td>Year</td>
    <td>Condition</td>
  </tr>
  <tr>
    <td>Bird</td>
    <td>1947</td>
    <td>Fair</td>
  </tr>
  <tr>
    <td>Lion</td>
    <td>1982</td>
    <td>Good</td>
  </tr>
  <tr>
    <td>Horse</td>
    <td>1978</td>
    <td>Mint</td>
  </tr>
</table>
```
{% endCompare %}

{% Compare 'better' %}
```html
<table>
  <caption>My stamp collection</caption>
  <tr>
    <th>Animal</th>
    <th>Year</th>
    <th>Condition</th>
  </tr>
  <tr>
    <td>Bird</td>
    <td>1947</td>
    <td>Fair</td>
  </tr>
  <tr>
    <td>Lion</td>
    <td>1982</td>
    <td>Good</td>
  </tr>
  <tr>
    <td>Horse</td>
    <td>1978</td>
    <td>Mint</td>
  </tr>
</table>
```
{% endCompare %}
</div>

# Assistive Technology testing

{% Aside %}
This module is a continuation of the previous two testing modules, [automated accessibility testing](/learn/accessibility/automated-test/) and [manual accessibility testing](/learn/accessibility/manual-test/). If you have not gone through the exercises in those modules yet, we encourage you to do so, as this module starts where they left off.
{% endAside %}

This module focuses on using assistive technology (AT) for accessibility testing. A person with disabilities can use AT to help increase, maintain, or improve the capabilities of performing a task.

In the digital space, ATs can be:

* No/Low-tech: head/mouth sticks, hand-held magnifiers, devices with large buttons
* High-tech: voice-activated devices, eye-tracking devices, adaptive keyboards/mice
* Hardware: switch buttons, ergonomic keyboards, auto-refreshing Braille device
* Software: text-to-speech programs, live captions, screen readers

We encourage you to use multiple types of ATs in your overall testing workflow.

## Screen reader testing basics

In this module, we focus on one of the most popular digital ATs, screen readers. A screen reader is a piece of software that reads the underlying code of a website or app. It then converts that information into speech or Braille output for the user.

Screen readers are essential for people who are blind and deafblind, but they also could benefit people with low vision, reading disorders, or cognitive disabilities.

### Browser compatibility

There are multiple screen reader options available. The [most popular screen readers](https://webaim.org/projects/screenreadersurvey9) today are JAWS, NVDA, and VoiceOver for desktop computers and VoiceOver and Talkback for mobile devices.

Depending on your operating system (OS), favorite browser, and the device that you use, one screen reader may stand out as the best option. Most screen readers are  built with specific hardware and web browsers in mind. When you use a screen reader with a browser it was not calibrated for, you may encounter more "bugs" or unexpected behavior. Screen readers work best when used in the following combinations.

<div class="table-wrapper scrollbar">
  <table>
    <thead>
          <tr>
        <th>Screen reader</th>
        <th>OS</th>
        <th>Browser compatibility</th>
          </tr>
    </thead>
    <tbody>
          <tr>
             <td><a href="https://www.freedomscientific.com/products/software/jaws">Job Access With Speech (JAWS)</a></td>
             <td>Windows</td>
             <td>Chrome, Firefox, Edge</td>
          </tr>
          <tr>
             <td><a href="https://www.nvaccess.org">Non-Visual Desktop Access (NVDA)</a></td>
             <td>Windows</td>
             <td>Chrome and Firefox</td>
          </tr>
          <tr>
             <td><a href="https://support.microsoft.com/en-us/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1">Narrator</a></td>
             <td>Windows</td>
             <td>Edge</td>
          </tr>
          <tr>
             <td><a href="https://support.apple.com/guide/voiceover-guide/welcome/web">VoiceOver</a></td>
             <td>macOS</td>
             <td>Safari</td>
          </tr>
          <tr>
             <td><a href="https://help.gnome.org/users/orca/stable/index.html.en">Orca</a></td>
             <td>Linux</td>
             <td>Firefox</td>
          </tr>
          <tr>
             <td><a href="https://support.google.com/accessibility/android/answer/6283677">TalkBack</a></td>
             <td>Android</td>
             <td>Chrome and Firefox</td>
          </tr>
          <tr>
             <td><a href="https://support.apple.com/guide/iphone/turn-on-and-practice-voiceover-iph3e2e415f/ios">VoiceOver (for mobile)</a></td>
             <td>iOS</td>
             <td>Safari</td>
          </tr>
          <tr>
             <td><a href="https://support.google.com/chromebook/answer/7031755">ChromeVox</a></td>
             <td>ChromeOS</td>
             <td>Chrome</td>
          </tr>
    </tbody>
  </table>
</div>

### Screen reader commands

Once you have the proper set-up for your screen reader software for your desktop or mobile device, you should look at the screen reader documentation (linked in the preceding table) and run through some [essential screen reader commands](https://dequeuniversity.com/screenreaders) to familiarize yourself with the technology. If you have used a screen reader before, consider trying out a new one!

When using a screen reader for accessibility testing, your goal is to detect problems in your code that interfere with the usage of your website or app, not to emulate the experience of a screen reader user. As such, there is a lot you can do with some foundational knowledge, a few screen reader commands, and a bit—or a lot—of practice.

If you need to further understand the user experience of people using screen readers and other ATs, you can engage with many organizations and individuals to gain this valuable insight. Remember that using an AT to test code against a set of rules and asking users about their experience often yields different results. Both are important aspects to create fully inclusive products.

#### Key commands for desktop screen readers

<div class="table-wrapper scrollbar">
  <table>
    <thead>
      <tr>
        <th>Element</th>
        <th>NVDA (Windows)</th>
        <th>VoiceOver (macOS)</th>
      </tr>
    </thead>
    <tbody>
      <tr>
         <td>Command</td>
        <td>Insert (NVDA key)</td>
        <td>Control + Option (VO key)</td>
      </tr>
      <tr>
        <td>Stop audio</td>
        <td>Control</td>
        <td>Control</td>
      </tr>
      <tr>
        <td>Read next/prev
</td>
        <td>↓ or ↑
</td>
        <td>VO + → or ←
</td>
      </tr>
      <tr>
        <td>Start reading
</td>
        <td>NDVA + ↓
</td>
        <td>VO + A
</td>
      </tr>
      <tr>
        <td>Element List/Rotor
</td>
        <td>NVDA + F7
</td>
        <td>VO + U
</td>
      </tr>
      <tr>
        <td>Landmarks
</td>
        <td>D
</td>
        <td>VO + U
</td>
      </tr>
      <tr>
        <td>Headings
</td>
        <td>H
</td>
        <td>VO + Command + H
</td>
      </tr>
      <tr>
        <td>Links
</td>
        <td>K
</td>
        <td>VO + Command + L
</td>
      </tr>
      <tr>
        <td>Form controls
</td>
        <td>F
</td>
        <td>VO + Command + J
</td>
      </tr>
      <tr>
        <td>Tables
</td>
        <td>T
</td>
        <td>VO + Command + T
</td>
      </tr>
      <tr>
        <td>Within Tables
</td>
        <td>NDVA + Alt + ↓ ↑ ← →
</td>
        <td>VO + ↓ ↑ ← →
</td>
      </tr>
    </tbody>
  </table>
</div>

#### Key commands for mobile screen readers

<div class="table-wrapper scrollbar">
  <table>
    <thead>
          <tr>
        <th>Element</th>
        <th>TalkBack (Android)</th>
        <th>VoiceOver (iOS)</th>
          </tr>
    </thead>
    <tbody>
      <tr>
        <td>Explore</td>
        <td>Drag one finger around the screen</td>
        <td>Drag one finger around the screen</td>
      </tr>
      <tr>
        <td>Select or activate</td>
        <td>Double tap</td>
        <td>Double tap</td>
      </tr>
      <tr>
        <td>Move up/down</td>
        <td>Swipe up or down with two fingers</td>
        <td>Swipe up or down with three fingers</td>
      </tr>
      <tr>
        <td>Change pages</td>
        <td>Swipe left or right with two fingers</td>
        <td>Swipe left/right with three fingers</td>
      </tr>
      <tr>
        <td>Next/previous</td>
        <td>Swipe left/right with one finger</td>
        <td>Swipe left/right with one finger</td>
      </tr>
    </tbody>
  </table>
</div>

## Screen reader testing demo

To test our demo, we used a Safari on a laptop running MacOS and capture sound. You can walk through these steps using any screen reader, but the way you encounter some errors may be different from how its described in this module.

### Step 1

Visit the updated [CodePen](https://codepen.io/web-dot-dev/pen/eYjZdve), which
has all the automated and manual accessibility updates applied.

View it in [debug mode](https://cdpn.io/pen/debug/eYjZdve) to proceed with the
next tests. This is important, as it removes the `<iframe>` which surrounds the
demo webpage, which may interfere with some testing tools. Learn more about
[CodePen's debug mode](https://blog.codepen.io/documentation/debug-view/#getting-to-debug-view-3).

### Step 2

Activate the screen reader of your choice and go to the demo page. You may consider navigating through the entire page from top to bottom before focusing on specific issues.

We've recorded the our screen reader for each issue, before and after the fixes are applied to the demo. We encourage you to run through the demo with your own screen reader.

#### Issue 1: Content structure {: #content-structure}

Headings and landmarks are one of the primary ways people navigate using screen readers. If these are not present, a screen reader user has to read the entire page to understand the context. This can take a lot of time and cause frustration. If you try to navigate by either element in the demo, you will quickly discover that they do not exist.

* Landmark example: `<div class="main">...</div>`
* Heading example: `<p class="h1">Join the Club</p>`

If you have updated everything correctly, there should not be any visual changes, but your screen reader experience will have dramatically improved.

<figure>
  {% YouTube "o8gWVi97cMg" %}
  <figcaption>Listen to the screen reader navigate through this issue.</figcaption>
</figure>

<span class="solution" id="issue-1-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

Some inaccessible elements can't be observed by just looking at the site. You may remember the importance of heading levels and semantic HTML from the [Content structure](/learn/accessibility/structure) module. A piece of content may look like a heading, but the content is actually wrapped in a stylized `<div>`.

To fix the issue with headings and landmarks, you must first identify each element that should be marked up as such and update the related HTML. Be sure to update the related CSS as well.

Landmark example: `<main>...</main>`

Heading example: `<h1>Join the Club</h1>`

If you have updated everything correctly, there should not be any visual changes, but your screen reader experience will have dramatically improved.

<figure>
  {% YouTube "FfM3qvEWHjk" %}
  <figcaption>Now that we've fixed the content structure, listen to the screen reader navigate through the demo again.</figcaption>
</figure>

## Issue 2: Link context {: #link-context}

It's important to give content to screen reader users about the purpose of a link and if the link is redirecting them to a new location outside of the website or app.

In our demo, we fixed most of the links when we updated the active image alternative text, but there are a few additional links about the various rare diseases that could benefit from additional context—especially since they redirect to a new location.

```html
<a href="https://rarediseases.org/rare-diseases/maple-syrup-urine-disease">
  Maple syrup urine disease (MSUD)
</a>
```

<figure>
  {% YouTube "kk7LNdtfYMM" %}
  <figcaption>Listen to the screen reader navigate through this issue.</figcaption>
</figure>

<span class="solution" id="issue-2-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

To fix this issue for screen reader users, we update the code to add more information, without affecting the visuals element. Or, to help even more people such as those with reading and cognitive disorders, we may choose to add additional visual text instead.

There are many different patterns we may consider to add additional link information. Based on our simple environment that supports just one language, an ARIA label is a straightforward option in this situation. You may notice that the ARIA label overrides the original link text, so make sure to include that information in your update.

```html
<a href="https://rarediseases.org/rare-diseases/maple-syrup-urine-disease"
  aria-label="Learn more about Maple syrup urine disease on the Rare Diseases website.">
  Maple syrup urine disease (MSUD)
</a>
```

<figure>
  {% YouTube "Ezr7cMdCQlE" %}
  <figcaption>Now that we've fixed the link context, listen to the screen reader navigate through the demo again.</figcaption>
</figure>

## Issue 3: Decorative image

In our automated testing module, Lighthouse was unable to pick up on the inline SVG that acts as the main splash image on our demo page—but the screen reader finds it and announces it as "image" without additional information. This is true, even without explicitly adding the `role="img"` attribute to the SVG.

```html
<div class="section-right">
  <svg>...</svg>
</div>
```

<figure>
  {% YouTube "TKHHTGghrHs" %}
  <figcaption>Listen to the screen reader navigate through this issue.</figcaption>
</figure>

<span class="solution" id="issue-3-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

To fix this issue, we first need to decide if the image is [informative](/learn/accessibility/images/#informative-images) or [decorative](/learn/accessibility/images/#decorative-images). Based on that decision, we need to add the appropriate image alternative text (informative image) or hide the image from screen reader users (decorative).

We weighed the pros and cons of how best to categorize the image and decided it was decorative, which means we want to add or modify the code to hide the image. A quick method is to add a `role="presentation"` to the SVG image directly. This sends a signal to the screen reader to skip over this image and not list it in the images group.

```html
<div class="section-right">
  <svg role="presentation">...</svg>
</div>
```

<figure>
  {% YouTube "KqTf8Pl2lMU" %}
  <figcaption>Now that we've fixed the decorative image, listen to the screen reader navigate through the demo.</figcaption>
</figure>

### Issue 4: Bullet decoration {: #bullet-decoration}

You may have noticed that the screen reader reads the CSS bullet image under
the rare diseases sections. While not the traditional type of image we
discussed in the Images module, the image still must be modified as it disrupts
the flow of the content and could distract or confuse a screen reader user.

```html
<p class="bullet">...</p>
```

<figure>
  {% YouTube "sDR2w-HGHOo" %}
  <figcaption>Listen to the screen reader navigate through this issue.</figcaption>
</figure>

<span class="solution" id="issue-4-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

Much like the decorative image example discussed earlier, you can add a `role="presentation"` to the HTML with the bullet class to hide it from the screen reader. Similarly, a `role="none"` would work. Just be sure not to use `aria-hidden: true` or you will hide all of the paragraph information from screen reader users.

```html
<p class="bullet" role="none">...</p>
```

### Issue 5: Form field

In the [Forms](/learn/accessibility/forms/) module, we learned that all form
fields must also have a visual and programmatic label. This label must remain
visible at all times.

In our demo, we're missing both a visual and programmatic label on our newsletter sign-up email field. There is a text placeholder element, but this does not replace the label as it's not visually persistent and is not fully compatible with all screen readers.

```html
<form>
  <div class="form-group">
    <input type="email" placeholder="Enter your e-mail address" required>
    <button type="submit">Subscribe</button>
  </div>
</form>
```

<figure>
  {% YouTube "7hncAhi4UUk" %}
  <figcaption>Listen to the screen reader navigate through this issue.</figcaption>
</figure>

<span class="solution" id="issue-5-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

To fix this issue, replace the text placeholder with a look-alike label element. That label element is programmatically connected to the form field and movement was added with JavaScript to keep the label visible even when content is added to the field.

```html
<form>
  <div class="form-group">
    <input type="email" required id="youremail" name="youremail" type="text">
    <label for="youremail">Enter your e-mail address</label>
    <button type="submit" aria-label="Subscribe to our newsletter">Subscribe</button>
  </div>
</form>
```

<figure>
  {% YouTube "hNbDfcmdi_A" %}
  <figcaption>Now that we've fixed the form, listen to the screen reader navigate through the demo.</figcaption>
</figure>

## Wrap up

Congratulations! You have completed all of the testing for this demo. You can look at all of these changes in the [updated Codepen for this demo](https://codepen.io/web-dot-dev/pen/PoBZgrW).

Now, you can use what you've learned to review the accessibility of your own
websites and apps.

The goal of all of this accessibility testing is to address as many possible
issues that a user may potentially encounter. However, this does not mean that your website or app
will be perfectly accessible when you're finished. You'll find the most success by
designing your website or app with accessibility throughout the process, and
incorporating these tests with your other pre-launch testing.

{% Assessment 'at' %}

# Automated accessibility testing

So far in this course, you have learned about the individual, business, and
legal aspects of digital accessibility, and the basics of digital accessibility
conformance. You have explored specific topics related to inclusive design and
coding, including when to use ARIA versus HTML, how to measure color contrast,
when JavaScript is essential, amongst other topics.

In the remaining modules, we shift gears from designing and building to testing
for accessibility. We'll utilize a three-step testing process that includes
automated, manual, and assistive technology testing tools and techniques. We'll
use the same demo throughout these testing modules to progress the web page from
inaccessible to accessible.

Each test—automated, manual, and assistive tech—is critical to achieving the
most accessible product possible.

Our tests rely on the Web Content Accessibility Guidelines (WCAG) 2.1
[conformance level A and AA](https://www.w3.org/TR/WCAG21/#cc1) as our
standards. Remember that your industry, product type, local/country laws and
policies, or overall accessibility goals will dictate which guidelines to
follow and levels to meet. If you don't require a specific standard for your
project, the recommendation is to follow the latest version of WCAG.
Refer back to "[How is digital accessibility measured?](/learn/accessibility/measure/)"
for general information on accessibility audits, conformance types/levels,
[WCAG](/learn/accessibility/glossary/#wcag), and
[POUR](/learn/accessibility/glossary/#pour).

As you now know, accessibility conformance is _not_ the full story when it
comes to supporting people with disabilities. But, it's a good starting point
as it provides a metric you can test against. We encourage you to take
additional actions outside of accessibility conformance testing, such as
running usability tests with people with disabilities, hiring people with
disabilities to work on your team, or consulting an individual or company with
digital accessibility expertise to help you build more inclusive products.

## Automated testing basics

Automated accessibility testing uses software to scan your digital product for
accessibility issues against pre-defined accessibility conformance standards.

Pros of automated accessibility tests:

* Easy to repeat tests at different stages of the product lifecycle
* Just a few steps to run and very quick results
* Little accessibility knowledge is required to run the tests or understand the results

Cons of automated accessibility tests:

* Automated tools don't catch all of the accessibility errors in your product
* Reported false positives (an issue is reported that isn't a true WCAG violation)
* Multiple tools may be needed for different product types and roles

Automated testing is a great first step to check your website or app for
accessibility, but not all checks can be automated. We'll go into more detail
on how to check the accessibility of elements that cannot be automated in the
[manual accessibility testing](/learn/accessibility/test-manual/) module.

## Types of automated tools

One of the first online automated accessibility testing tools was developed in
1996 by the Center for Applied Special Technology (CAST), called
"[The Bobby Report](https://jimthatcher.com/bobbyeval.htm)." Today, there are
[over 100 automated testing tools](https://www.w3.org/WAI/ER/tools/) to choose
from!

Automated tool implementation varies from accessibility browser extensions to
code linters, desktop and mobile applications, online dashboards, and even
open-source APIs you can use to build your own automated tooling.

Which automated tool you decide to use can depend on many factors, including:

* Which conformance standards and levels are you testing against? This may
  include WCAG 2.1, WCAG 2.0, [U.S. Section 508](https://www.section508.gov/), or a modified list of accessibility rules.
* What type of digital product are you testing? This could be a website, web
  app, native mobile app, PDF, kiosk, or other product.
* What part of the software development life cycle are you testing your product?
* How much time does it take to set up and use the tool? For an individual,
  team, or company?
* Who is conducting the test: designers, developers, QA, etc.?
* How often do you want the accessibility to be checked? What details should be
  included in the report? Should issues be directly linked to a ticketing
  system?
* Which tools work best in your environment? For your team?

There are many additional factors to consider as well. Check out WAI's article
on "[Selecting Web Accessibility Evaluation Tools](https://www.w3.org/WAI/test-evaluate/tools/selecting/)"
for more information on how to select the best tool for you and your team.

## Demo: Automated test

For the automated accessibility testing demo, we'll be using Chrome's
[Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/).
Lighthouse is an open-source, automated tool created to improve the quality of
web pages through different types of audits, such as performance, SEO, and
accessibility.

Our demo is a website built for a made-up organization, the Medical Mysteries
Club. This site is intentionally made inaccessible for the demo. Some of this
inaccessibility may be visible to you, and some (but not all) will be caught in
our automated test.

### Step 1

Using your Chrome browser, install the
[Lighthouse extension](https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk).

There are [many ways to integrate Lighthouse](https://github.com/GoogleChrome/lighthouse)
into your testing workflow. We'll use the Chrome extension for this demo.

### Step 2

<figure class="screenshot" data-float="right">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/amnpKDgfwnlIa02HYMU1.png", alt="Medical Mystery Club website, outside of the iframe.", width="400", height="283" %}
</figure>

We have built a [demo in CodePen](https://codepen.io/web-dot-dev/pen/yLqOaEP).
View it in [debug mode](https://cdpn.io/pen/debug/yLqOaEP) to proceed with the
next tests. This is important, as it removes the `<iframe>` which surrounds the
demo web page, which may interfere with some testing tools. Learn more about
[CodePen's debug mode](https://blog.codepen.io/documentation/debug-view/#getting-to-debug-view-3).

### Step 3

[Open Chrome DevTools](https://developer.chrome.com/docs/devtools/open/) and
navigate to the Lighthouse tab. Uncheck all of the category options except for
"Accessibility." Keep the mode as the default and choose the device type you're
running the tests on.

<figure class="screenshot">
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/yv8fIyUnFaW0yPGJgohj.png",
    alt="Medical Mystery Club website, with the Lighthouse report DevTools panel open.", width="800", height="421"
  %}
</figure>

### Step 4

Click the "Analyze page load" button and give Lighthouse time to run its tests.

Once the tests are complete, Lighthouse displays a score that measures how
accessible the product you're testing is. The
[Lighthouse score](https://developer.chrome.com/docs/lighthouse/accessibility/scoring)
is calculated by the number of issues, issue types, and the impact on users of
the issues detected.

Beyond a score, the Lighthouse report includes detailed information about what
issues it has detected and links to resources to learn more about remedying
them. The report also includes tests that are passed or not applicable and a
list of additional items to check manually.

{% Aside %}

The automated Lighthouse tests were run in December 2022. Due to changes in the
codebase, browsers, assistive technology, accessibility standards, and/or
rulesets, your test results may vary.

{% endAside %}

<figure class="screenshot">
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/5SUhDMXiDYw43kt5ss3J.png",
    alt="The Medical Mysteries Club website received a 62 for the Lighthouse score in our December 2022 test.", width="800", height="421"
  %}
</figure>

### Step 5

Now, let's go through an example of each automated accessibility issue
discovered and fix the relevant styles and markup.

#### Issue 1: ARIA roles {: #aria-roles}

The first issue states: "Elements with an ARIA [role] that require children to
contain a specific [role] are missing some or all of those required children.
Some ARIA parent roles must contain specific child roles to perform their
intended accessibility functions."
[Learn more about ARIA role rules](https://dequeuniversity.com/rules/axe/4.4/aria-required-children).

In our demo, the newsletter subscribe button fails:

```html
<button role="list" type="submit" tabindex="1">Subscribe</button>
```

<span class="solution" id="issue-1-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

The "subscribe" button next to the input field has an incorrect ARIA role
applied to it. In this case, the role can be removed completely.

```html
<button type="submit" tabindex="1">Subscribe</button>
```

#### Issue 2: ARIA hidden {: #aria-hidden}

`"[aria-hidden="true"]` elements contain focusable descendants. Focusable
descendants within an `[aria-hidden="true"]` element prevent those interactive
elements from being available to users of assistive technologies like screen
readers. [Learn more about `aria-hidden` rules](https://dequeuniversity.com/rules/axe/4.4/aria-hidden-focus).

```html
<input type="email" placeholder="Enter your e-mail address" aria-hidden="true" tabindex="-1" required>
```

<span class="solution" id="issue-2-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

The input field had an `aria-hidden="true"` attribute applied to it. Adding
this attribute hides the element (and everything nested under it) from
assistive tech.

```html
<input type="email" placeholder="Enter your e-mail address" tabindex="-1" required>
```

In this case, you should remove this attribute from the input to allow people
using assistive technology to access and enter information into the form field.

#### Issue 3: Button name {: #button-name}

Buttons do not have an accessible name. When a button doesn't have an
accessible name, screen readers announce it as "button," making it unusable for
users who rely on screen readers.
[Learn more about button name rules](https://dequeuniversity.com/rules/axe/4.4/button-name).

```html
<button role="list" type="submit" tabindex="1">Subscribe</button>
```

<span class="solution" id="issue-3-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

When you remove the inaccurate ARIA role from the button element in
[issue 1](#aria-roles), the word "Subscribe" becomes the accessible button
name. This functionality is built into the semantic HTML button element. There
are additional pattern options to consider for more complex situations.

```html
<button type="submit" tabindex="1">Subscribe</button>
```

#### Issue 4: Image alt attributes {: #image-alt-attributes}

Image elements are missing `[alt]` attributes. Informative elements should aim
for short, descriptive alternate text. Decorative elements can be ignored with
an empty alt attribute. [Learn more about image alternative text
rules](https://dequeuniversity.com/rules/axe/4.4/image-alt).

```html
<a href="index.html">
  <img src="https://upload.wikimedia.org/wikipedia/commons/….png">
</a>
```

<span class="solution" id="issue-4-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

Since the logo image is also a link, you know from the
[image module](/learn/accessibility/images/) that it is called an actionable
image and requires alternative text information about the purpose of the image.
Normally, the first image on the page is a logo, so you can reasonably assume
your AT users will know this, and you may decide not to add this additional
contextual information to your image description.

```html
<a href="index.html">
  <img src="https://upload.wikimedia.org/wikipedia/commons/….png"
    alt="Go to the home page.">
</a>
```

#### Issue 5: Link text {: #link-text}

Links do not have a discernible name. Link text (and alternate text for images,
when used as links) that is discernible, unique, and focusable improves the
navigation experience for screen reader users.
[Learn more about link text rules](https://dequeuniversity.com/rules/axe/4.4/link-name).

```html
<a href="#!"><svg><path>...</path></svg></a>
```

<span class="solution" id="issue-5-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

All of the actionable images on the page must include information about where
the link will send users. One method to remedy this issue is to add alternative
text to the image about the purpose, as you did on the logo image in the
example above. This works great for an image using a `<img>` tag, but `<svg>`
tags cannot use this method.

For the social media icons, which use `<svg>` tags, you can use a
[different alternative description pattern](https://codepen.io/web-dot-dev/pen/poZyEZd)
targeting SVGs, add the information between the `<a>` and `<svg>` tags and then
hide it visually from users, add a supported ARIA, or other options. Depending
on your environment and code restrictions, one method might be preferable over
another. Let's use the simplest pattern option with the most assistive
technology coverage, which is adding a `role="img"` to the `<svg>` tag and
including a `<title>` element.

```html
<a href="#!">
  <svg role="img">
    <title>Connect on our Twitter page.</title>
    <path>...</path>
  </svg>
</a>
```

#### Issue 6: Color contrast {: #color-contrast }

Background and foreground colors don't have a sufficient contrast ratio.
Low-contrast text is difficult or impossible for many users to read.
[Learn more about color contrast rules](https://dequeuniversity.com/rules/axe/4.4/color-contrast).

Two examples were reported.

<div class="switcher">
  <figure class="screenshot">
    <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3Aeg1osulNGB1EVtGu8r.png" alt="View full size screenshot.">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/3Aeg1osulNGB1EVtGu8r.png", alt="Lighthouse score for reported club name. The teal value contrast ratio is too low.", width="320", height="228" %}
  </a>

  <figcaption>
   The club name, <code><div class="club-name">Medical Mysteries Club</div></code> , has a color hex value of <code>#01aa9d</code> and the background hex value is <code>#ffffff</code>. The color contrast ratio is 2.9:1.

   <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3Aeg1osulNGB1EVtGu8r.png">View full size screenshot</a>.
  </figcaption>
  </figure>
  
  <figure class="screenshot">
    <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/86Iongt2UcohbzEar4Pm.png" alt="View full size screenshot.">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/86Iongt2UcohbzEar4Pm.png", alt="Lighthouse score for mermaid syndrome copy. The grey value contrast ratio is too low.", width="320", height="228" %}
    </a>
    <figcaption>
      <code><b>Mermaid syndrome</b></code> has a text hex value of <code>#7c7c7c</code>, while the background's hex color is <code>#ffffff</code>. The color contrast ratio is 4.2:1.
      
      <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/86Iongt2UcohbzEar4Pm.png">View full size screenshot</a>.
    </figcaption>
  </figure>
</div>

<span class="solution" id="issue-6-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

There are many color contrast issues detected on the web page. As you learned in
the [color and contrast](/learn/accessibility/color-contrast/) module,
regular-sized text (less than 18pt / 24px) has a color contrast requirement of
4.5:1, while large-sized text (at least 18pt / 24px or 14pt / 18.5px bold) and
essential icons must meet the 3:1 requirement.

For the page title, the teal-colored text needs to meet the 3:1 color contrast
requirement since it is large-sized text at 24px. However, the teal buttons are
considered regular-sized text at 16px bold, so they must meet the 4.5:1 color
contrast requirement.

In this case, we could find a teal color that was dark enough to meet 4.5:1, or
we could increase the size of the button text to 18.5px bold and change the
teal color value slightly. Either method will stay in line with the design
aesthetics.

All the gray text on the white background also fails for color contrast, except
for the two largest headings on the page. This text must be darkened to meet
the 4.5:1 color contrast requirements.

<div class="switcher">
  <figure class="screenshot">
    <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/2JyEvvfRBNFr7YdPipLf.png" alt="View full size screenshot.">
      {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/2JyEvvfRBNFr7YdPipLf.png", alt="The teal has been fixed and no longer fails.", width="320", height="228" %}
  </a>
  <figcaption>
    The club name, <code><div class="club-name">Medical Mysteries Club</div></code> , has been given a color value of <code>#008576</code> and the background remains <code>#ffffff</code>. The updated color contrast ratio is 4.5:1.
    
    <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/2JyEvvfRBNFr7YdPipLf.png">View full size screenshot</a>.
  </figcaption>
  </figure>
  <figure class="screenshot">
    <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3DgVWG6oIRRVTGYmZP3c.png" alt="View full size screenshot.">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/3DgVWG6oIRRVTGYmZP3c.png", alt="The grey has been fixed and no longer fails.", width="320", height="228" %}
    </a>
    
    <figcaption>
      <code><b>Mermaid syndrome</b></code> now has a color value of <code>#767676</code> and the background remains <code>#ffffff</code>. The color contrast ratio is 4.5:1.
      
      <a href="https://web-dev.imgix.net/image/VbsHyyQopiec0718rMq2kTE1hke2/3DgVWG6oIRRVTGYmZP3c.png">View full size screenshot</a>.
    </figcaption>
  </figure>
</div>

#### Issue #7 - list structure  {: #list-structure }

List items (`<li>`) are not contained within `<ul>` or `<ol>` parent elements.
Screen readers require list items (`<li>`) to be contained within a parent
`<ul>` or `<ol>` to be announced properly.

[Learn more about list rules](https://dequeuniversity.com/rules/axe/4.4/listitem).

```html
<div class="ul">
  <li><a href="#">About</a></li>
  <li><a href="#">Community</a></li>
  <li><a href="#">Donate</a></li>
  <li><a href="#">Q&A</a></li>
  <li><a href="#">Subscribe</a></li>
</div>
```

<span class="solution" id="issue-7-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

We used a CSS class in this demo to simulate the unordered list instead of
using a `<ul>` tag. When we wrote this code improperly, we removed the inherent
semantic HTML features built into this tag. By replacing the class with a real
`<ul>` tag and modifying the related CSS, we resolve this accessibility issue.

```html
<ul>
  <li><a href="#">About</a></li>
  <li><a href="#">Community</a></li>
  <li><a href="#">Donate</a></li>
  <li><a href="#">Q&A</a></li>
  <li><a href="#">Subscribe</a></li>
</ul>
```

#### Issue #8 - tabindex  {: #tabindex }

Some elements have a [tabindex] value greater than 0. A value greater than 0
implies an explicit navigation ordering. Although technically valid, this often
creates frustrating experiences for users who rely on assistive technologies.
[Learn more about tabindex rules](https://dequeuniversity.com/rules/axe/4.4/tabindex).

```html
<button type="submit" tabindex="1">Subscribe</button>
```

<span class="solution" id="issue-8-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

Unless there is a specific reason to disrupt the natural tabbing order on a web
page, there is no need to have a positive integer on a tabindex attribute. To
keep the natural tabbing order, we can either change the tabindex to `0` or
remove the attribute altogether.

```html
<button type="submit">Subscribe</button>
```

### Step 6

Now that you've fixed all the automated accessibility issues, open up a new
debug mode page. Run the Lighthouse accessibility audit again. Your score
should be much better than on the first run.

<figure class="screenshot">
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/gcjuv10swXP62s1oT37d.png", alt="The lighthouse score is now 100, which means you addressed all Lighthouse issues.", width="800", height="421"
%}
</figure>

We've applied all of these automated accessibility updates to a new
[CodePen](https://codepen.io/web-dot-dev/pen/PoBZgrW).

## Next step

Great job. You have accomplished a lot already, but we haven't finished yet! Next,
we'll move on to manual checks, as detailed in the
[manual accessibility testing](/learn/accessibility/test-manual/) module.

{% Assessment 'automated' %}

# Manual accessibility testing

{% Aside %}
This module on manual accessibility testing is a continuation of the previous
module, [automated accessibility testing](/learn/accessibility/test-automated/).
If you have not yet completed the exercises in that module, we encourage you
to do so. This module starts where the previous one left off, focusing on
manual accessibility testing tools and techniques.
{% endAside %}

## Manual testing basics

Manual accessibility testing uses keyboard, visual, and cognitive tests, tools,
and techniques to find issues that automated tooling cannot. As automated
tooling does not cover all of the success criteria identified in WCAG, it's
_vital_ that you do not run automated accessibility tests and then stop testing!

As technology advances, [more tests could be covered by automated tooling alone](https://a11y-automation.dev/violations), but today, both manual and assistive technology checks need to be added to your testing protocols to cover all of the applicable WCAG checkpoints.

{% Aside %}
Each automated testing tool can have distinct accessibility rulesets and use them in different ways. The actual percentage of WCAG checkpoints covered will vary by tool and the content being tested.
{% endAside %}

Pros of manual accessibility tests:

* Reasonably straightforward and quick to run
* Catch a higher percentage of issues than automated tests alone
* Little tooling and expertise needed for success

Cons of manual accessibility tests:

* More complex and time-consuming than automated tests
* May be difficult to repeat at scale
* Require more accessibility expertise to run tests and interpret the results

Let's compare what accessibility elements and details can currently be detected
by an automated tool, versus those that won't be detected.

<div class="table-wrapper scrollbar">
  <table data-alignment="top" >
    <thead>
      <tr>
        <th>Can be automated</th>
        <th>Can't be automated</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Color contrast of text on solid backgrounds</td>
        <td><a href="/learn/accessibility/color-contrast">Color contrast</a> of text on gradients/images</td>
      </tr>
      <tr>
        <td>Image alternative text exists</td>
        <td><a href="/learn/accessibility/images">Image alternative text is accurate and is properly assigned</td>
      </tr>
      <tr>
        <td>Headings, lists, and landmarks exist</td>
        <td><a href="/learn/accessibility/structure">Headings, lists, and landmarks</a> are correctly marked-up and all elements are accounted for</td>
      </tr>
      <tr>
        <td>ARIA is present</td>
        <td><a href="/learn/accessibility/aria-html/">ARIA</a> is being used appropriately and applied to the correct element(s)</td>
      </tr>
      <tr>
        <td>Identifying keyboard-focusable elements</td>
        <td>Which elements are missing <a href="/learn/accessibility/focus/">keyboard focus</a>, the focus order makes logical sense, and the focus indicator is visible</td>
      </tr>
      <tr>
        <td>iFrame title detection</td>
        <td><a href="learn/accessibility/more-html/">iFrame</a>, the focus order makes logical sense, and the focus indicator is visible </td>
      </tr>
      <tr>
        <td>Video element is present</td>
        <td>Video element has appropriate <a href="/learn/accessibility/motion/">alternative media</a> present (such as captions and transcripts)</td>
      </tr>
    </tbody>
  </table>
</div>
<br>

## Types of manual tests

There are many manual tools and techniques to consider when looking at your
web page or app for digital accessibility. The three biggest focus areas in
manual testing are keyboard functionality, visually-focused reviews, and
general content checks.

We will cover each of these topics at a high level in this module, but the
following tests are not meant to be an exhaustive list of all the manual tests
you can or should run. We encourage you to start with a
[manual accessibility checklist](https://www.ibm.com/able/toolkit/verify/manual)
from a reputable source and develop your own focused manual testing checklist
for your specific digital product and team needs.

{% Aside %}
Some organizations consider assistive technology (AT) checks to be part of the
manual testing process as there are a lot of overlaps. In this course, we break
AT testing into a separate module, as it's more advanced than other manual tests
and deserves a deeper and separate focus.
{% endAside %}

### Keyboard checks

It's estimated that about 25% of all digital accessibility issues are related
to a lack of keyboard support. As we learned in the [keyboard focus](/learn/accessibility/focus) module, this affects all types of users, including sighted keyboard-only users, low-vision/blind screen reader users, and people using voice recognition software that uses technology that relies on content being keyboard accessible as well.

Keyboard tests answer questions such as:

* Does the web page or feature require a mouse to function?
* Is the tabbing order logical and intuitive?
* Is the keyboard focus indicator always visible?
* Can you get stuck in an element that shouldn't trap focus?
* Can you navigate behind or around an element that should be trapping focus?
* When closing an element that received focus, did the focus indicator return to a logical place?

While the impact of keyboard functionality is huge, the testing procedure is quite simple. All you need to do is set aside your mouse or install a [small JavaScript package](https://github.com/marcysutton/no-mouse-days) and test your website using only your keyboard. The following commands are essential for keyboard testing.

<div class="table-wrapper scrollbar">
  <table data-alignment="top" >
    <thead>
      <tr>
        <th>Key</th>
        <th>Result</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Tab</td>
        <td>Moves forward one active element to another</td>
      </tr>
      <tr>
        <td>Shift + Tab</td>
        <td>Moves backward one active element to another</td>
      </tr>
      <tr>
        <td>Arrows</td>
        <td>Cycle through related controls</td>
      </tr>
      <tr>
        <td>Spacebar</td>
        <td>Toggles states and moves down the page</td>
      </tr>
      <tr>
        <td>Shift + Spacebar</td>
        <td>Moves up the page</td>
      </tr>
      <tr>
        <td>Enter</td>
        <td>Triggers specific controls</td>
      </tr>
      <tr>
        <td>Escape</td>
        <td>Dismisses dynamically displayed objects</td>
      </tr>
    </tbody>
  </table>
</div>

### Visual checks

Visual checks focus on visual elements of the page and utilize tools such as screen magnification or browser zoom to review the website or app for accessibility.

Visual checks can tell you:

* Are there color contrast issues that an automated tool could not pick up, such as text on top of a gradient or image?
* Are there any elements that look like headings, lists, and other structural elements but are not coded as such?
* Are navigation links and form inputs consistent throughout the website or app?
* Is there any flashing, strobing, or animation that exceeds the recommendations?
* Does the content have proper spacing? For letters, words, lines, and paragraphs?
* Can you see all the content using a screen magnifier or browser zoom?

{% Aside %}
Sometimes, you can't observe the accessibility of a visual element without additional help. You'll read more about that in our next module on [assistive technology testing](/learn/accessibility/test-assistive-technology).
{% endAside %}

### Content checks

Unlike visual tests that focus on layouts, movement, and colors, content checks focus on the words on the page. Not only should you be looking at the copy itself, but you should review the context to be sure it makes sense to others.

Content checks answer questions such as:

* Are page titles, headings, and form labels clear and descriptive?
* Are image alternatives concise, accurate, and useful?
* Is color alone used as the only way of conveying meaning or information?
* Are links descriptive or do you use generic text such as “read more” or “click here?”
* Are there any changes to the language within a page?
* Is [plain language](https://www.w3.org/WAI/GL/WCAG3/2021/how-tos/clear-words/) being used and are all acronyms spelled out when first referenced?

Some content checks can be automated, in part. For example, you could write a JavaScript linter that checks for "Click here" and suggests you make a change. However, these custom solutions often still need a human to change the copy to something contextual.

## Demo: Manual test

So far, we have run automated tests on our demo web page and found and remediated eight different issue types. We are now ready to run manual checks to see if we can discover even more accessibility issues.

### Step 1

Our updated [CodePen demo](https://codepen.io/web-dot-dev/pen/NWBaMzb) has all
of the automated accessibility updates applied.

View it in [debug mode](https://cdpn.io/pen/debug/NWBaMzb) to proceed with the
next tests. This is important, as it removes the `<iframe>` which surrounds the
demo web page, which may interfere with some testing tools. Learn more about
[CodePen's debug mode](https://blog.codepen.io/documentation/debug-view/#getting-to-debug-view-3).

### Step 2

Start your manual testing process by setting your mouse or trackpad aside and navigate up and down the DOM using only your keyboard.

#### Issue 1: Visible focus indicator {: #visible-focus-indicator}

You should see the first keyboard issue right away—or rather, you shouldn't see it—as the visible focus indicator has been removed. When you scan the CSS in the demo, you should find the dreaded “outline: none” added to the codebase.

```css
  :focus {
    outline: none;
  }
```

<span class="solution" id="issue-1-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

As you learned in the [Keyboard focus module](/learn/accessibility/focus/#focus-indicator), you need to remove this line of code to allow web browsers to add a visible focus for users. You can go one step further and create a focus indicator styled to meet the aesthetics of your digital product.

```css
:focus {
  outline: 3px dotted #008576;
}
```

#### Issue 2: Focus order {: #focus-order}

Once you have modified the focus indicator and it's visible, be sure to tab
through the page. As you do so, you should notice that the form input field
used to subscribe to the newsletter does not receive focus. It has been removed
from the natural focus order by a negative tabindex.

```html
<input type="email" placeholder="Enter your e-mail address" aria-hidden="true" tabindex="-1" required>
```

<span class="solution" id="issue-2-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

Since we would like people to use this field to sign-up for our newsletter, all we need to do is remove the negative tabindex or set it to zero to allow the input to become keyboard focusable again.

```html
<input type="email" placeholder="Enter your e-mail address" aria-hidden="true" required>
```

### Step 3

Once keyboard focus has been checked, we move on to visual and content checks.

#### Issue 3: Link color contrast {: #link-color-contrast}

As you went through the keyboard tests by tabbing up and down the demo page,
you probably noticed the keyboard focused on three visually hidden links in the
paragraphs about the different medical conditions.

For our page to be accessible, links must stand out from the surrounding text
and include a non-color style change on mouse hover and keyboard focus.

<span class="solution" id="issue-3-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

A quick solution is to add an underline to the links inside the paragraphs to make them stand out. This would solve the accessibility issue, but it might not suit the overall design aesthetics you hope to achieve.

If you choose not to add an underline, you will need to modify the colors in such a way as to meet the requirements for both the background and copy.

When looking at the demo using a [link contrast checker tool](https://webaim.org/resources/linkcontrastchecker), you will see that the link color meets the 4.5:1 color contrast requirement between regular-sized text and the background. However, non-underlined links must also meet a 3:1 color contrast requirement against the surrounding text.

One option is to change the link color to match the other elements on the page. But if you change the link color to green, the body copy must also be modified to meet the overall color contrast requirements between all three elements: links, background, and surrounding text.

<div class="switcher">
<figure class="screenshot">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/DaRljFteyjHtmNuui4u1.png", alt="Screenshot of WebAIM for link text shows that the link to body text fails WCAG A level.", width="724", height="503" %}
<figcaption>
  When the link and body text is the same, the test fails.
</figcaption>
</figure>
<figure class="screenshot">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/YWk49YgsMcwT8ynusu7b.png", alt="Screenshot of WebAIM shows that all tests pass when the link color is green.", width="724", height="503" %}
<figcaption>
  When the link and body text is different, the test passes.
</figcaption>
</figure>
</div>

#### Issue 4: Icon color contrast {: #icon-color-contrast}

Another missed color contrast issue is the social media icons. In the [color and contrast](/learn/accessibility/color-contrast/#calculate-color-contrast) module, you learned that essential icons need to meet a 3:1 color contrast against the background. However, in the demo, the social media icons have a contrast ratio of 1.3:1.

<span class="solution" id="issue-4-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

To meet the 3:1 color contrast requirements, the social media icons are changed to a darker gray.

<figure class="screenshot">
  {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/E02bbVtKS9QCkQi8PvCc.png", alt="A screenshot of the demo with the color analyzer showing failing icon color contrast.", width="800", height="570"
  %}
</figure>

{% Aside %}

You may notice that the border around the text input doesn't meet the 3:1 color contrast requirement against the background. However, this input has placeholder text which meets the required color contrast requirements for its size, according to the [non-text contrast](https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html) overview page.

{% endAside %}

#### Issue 5: Content layout {: #content-layout}

If you look at the layout of the paragraph content, the text is fully
justified. As you learned in the
[Typography module](/learn/accessibility/typography/#structure-and-layout),
this creates "rivers of space," which may make the text difficult for some
users to read.

```css
p.bullet {
   text-align: justify;
}
```

<span class="solution" id="issue-5-solution" style="display:block;font-weight:strong; margin-top: var(--flow-space, 1em);">
  <figure data-float="left">
    {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/dNzbda0Lx1XUeCadVLMH.svg", alt="", width="28", height="28"%}
  </figure> <strong>Let's fix it.</strong>
</span>

To reset the text alignment in the demo, you can update the code to
`text-align: left;` or remove that line entirely from the CSS, as left is the
default alignment for browsers. Be sure to test the code, in case other
inherited styles remove the default text alignment.

```css
p.bullet {
   text-align: left;
}
```

### Step 4

<figure class="screenshot">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/9O3rKmEIy3u1gqn3HfYT.png", alt="Screenshot of the Medical Mysteries Club demo site.", width="800", height="570" %}
<figcaption>
  All manual issues have now been addressed in the demo, as shown in this image.
</figcaption>
</figure>

Once you've identified and fixed all the manual accessibility issues outlined in the previous steps, your page should look similar to our screenshot.

It's possible that you'll find more accessibility issues in your manual checks than we covered in this module. We'll discover many of these issues in the next module.

## Next step

Way to go! You have completed the automated and manual testing modules.
You can view our [updated CodePen](https://codepen.io/web-dot-dev/pen/eYjZdve),
which has all the automated and manual accessibility fixes applied.

Now, head over to the last testing module focused on
[assistive technology testing](/learn/accessibility/test-assistive-technology/).

{% Assessment 'manual' %}

# Typography

Creating and designing accessible content is more than just choosing an
easy-to-read font. Even with accessible font families, people with low vision,
cognitive, language, and learning disabilities may struggle to process the text
due to other elements such as font variations, size, spacing, and kerning—to
name a few. This module will look into basic design considerations to make
your content more inclusive and reach even more people.

{% Aside %}
To learn specific implementation of typography, check out the
[Learn CSS Typography module](/learn/design/typography/).
{% endAside %}

## Typeface

A major factor that can strongly impact copy accessibility is the typeface. Your choice of typeface and styling can make or break any page design.

People with reading, learning, and attention disorders like dyslexia and attention-deficit hyperactivity disorder (ADHD), as well as people with low vision, can all benefit when you use accessible typefaces. 

Choose common typefaces
The quickest way to create an accessible design is to choose a common typeface (for example, Arial, Times New Roman, Calibri, Verdana, and many others).

Many [typeface studies](http://dyslexiahelp.umich.edu/sites/default/files/good_fonts_for_dyslexia_study.pdf) testing people with disabilities show that common typefaces lead to faster reading speeds and a deeper comprehension level when compared to uncommon typefaces. While these common typefaces are not inherently more accessible than other typefaces, some people with disabilities have an easier time reading them because they have had a lot of experience working with (or around) these typefaces. 

In addition to choosing a common typeface, be sure to avoid ornate or handwritten typefaces, as well as ones with only one character case available (for example, only uppercase characters). These specialty typefaces with cursive designs, quirky shapes, or artistic features like thin lines may look nice, but they are much harder for some people with disabilities to read than common typefaces. 

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'ExLvWOV',
 height: 350,
 theme: 'auto',
 tab: 'css,result'
} %}

### Letter characteristics and kerning

The research on whether [serif or sans serif typefaces are easier to
read](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4612630/) is inconclusive,
but certain numbers, letters, or combinations can confuse
[people with language-based learning and cognitive disabilities](https://www.ncld.org/news/newsroom/the-state-of-ld-understanding-the-1-in-5/).
For people with these types of disabilities, every letter and number must be
clearly defined and have unique characteristics, so letters are not confused
with a numbers. 

Common readability offenders are the uppercase "I" (India), lowercase "l"
(lettuce), and the number "1". Likewise, letter pairs like b/d, p/q, f/t, i/j,
m/w, and n/u can sometimes flip either left-right or up-down for some readers.

The copy's readability also decreases when the letter spacing or kerning is too
tight. Pay special attention to kerning, especially between the problematic
letter pair r/n. Otherwise, words like "yarn" could change to "yam" or "stern"
to "stem," entirely changing the meaning of the copy. 

Open source typeface collections like [Google Fonts](https://fonts.google.com) can
aid you in selecting the most inclusive typeface for your next design.
If you use Adobe products, you can embed accessible font families from foundry
partners directly into your designs&mdash;this includes select
[Google Fonts](https://fonts.adobe.com/foundries/google).

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'BaxdWvV',
 height: 350,
 theme: 'auto',
 tab: 'css,result'
} %}

When you are looking for your next typeface, pay particular attention to the following:

* Use common fonts whenever possible.
* Avoid using elaborate or handwritten fonts and those with only one character case.
* Pick a typeface with unique characteristics—paying special attention to the uppercase I, lowercase l, and 1.
* Review certain letter combinations to be sure they are not an exact mirror image of one another.
* Check the kerning, especially between the r/n letter pair.

### Font size and typographic styling

People often assume that picking out an accessible font family is all there is to creating inclusive content, but it is also important to consider the [font size](https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html) and how the text is styled on a page. 

For example, people with low vision or color blindness may be unable to read some of the copy if it is too small, using an AT—like browser zoom—to read the copy. While other users, such as those with dyslexia or reading disorders, may have trouble reading italic text. Screen readers often ignore styling methods, such as bold and italics, so the intent of these styles is not conveyed to blind or low-vision users.

<div class="switcher">
{% Compare 'worse' %}
```text
h2 {font-size: 16px;}
```
{% endCompare %}

{% Compare 'better' %}
```text
h2 {font-size: 1rem;}
```
{% endCompare %}
</div>

Since you cannot predict what every user's needs are, when adding fonts to your digital products, be sure to consider the following guidelines:

* Base font sizes should be defined with a relative value (%, rem, or em) to
  allow easy resizing.
* Limit the number of typeface variations like color, **bold**, ALL CAPS, and
  _italics_ to increase readability. Instead, use methods to emphasize words in
  your copy, such as asterisks, dashes, or highlighting an individual word. 
* Use markup instead of text on images whenever possible. Screen readers cannot
  read embedded text on images (without extra code added), and embedded text
  can also become pixelated when magnified by low-vision users.

## Structure and layout 

While typeface, font size, and typographic styling are important to accessible
typography, the
[structure](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html)
and [layout](https://www.w3.org/WAI/WCAG21/Understanding/reflow) of copy on a
page can be equally important to a user's understanding.

Complex layouts can be a real barrier for people with low vision, reading
disabilities, and the [6.1 million people in the US with ADHD](https://www.cdc.gov/ncbddd/adhd/data.html).
These types of disabilities make it more difficult for people to keep their 
place and follow the flow of the copy due to the lack of clear linear pathways,
missing headings, and ungrouped elements. 

An important aspect of accessible layout designs is making critical elements
distinct from one another and grouping similar elements together. If the
elements are too close, it can be difficult to tell where one element begins
and ends, especially if they have similar styling.

Think about your copy as a collection of individual bullet points on an
outline. This will help you plan out the overall page structure and enable you
to use headings, subheadings, and lists whenever appropriate. 

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'poVreqB',
 height: 450,
 theme: 'auto',
 tab: 'result'
} %}

### Spacing

[Paragraph, sentence, and word spacing](https://www.w3.org/WAI/WCAG22/Understanding/text-spacing.html) is also important as it helps readers retain their focus on the copy and adds to the page's overall visual understanding. Long lines of copy can be a barrier for readers with disabilities, as they have trouble keeping their place and following the flow of the copy. A narrow block of copy makes it easier for readers to continue to the next line. 

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'ExLvWrP',
 height: 350,
 theme: 'auto',
 tab: 'result'
} %}

### Content alignment

Another frustration for many people with disabilities is reading justified
copy. The uneven spacing between words in justified copy can cause "rivers of
space" to form down the page, making the copy difficult to read.

Text justification can also cause words to be either bunched together or
stretched in unnatural ways, so readers can find it difficult to locate word
boundaries. 

{% Codepen {
 user: 'web-dev-codepen-external',
 id: 'OJZjpdE',
 height: 350,
 theme: 'auto',
 tab: 'result'
} %}

Thankfully, there are clear guidelines on spacing and tools such as [Good Line-Height](http://thegoodlineheight.com) and the [Golden Ratio Calculator](https://grtcalculator.com/) to help make our copy more accessible. Incorporating these guidelines helps people with attention-deficit disorders, reading, and vision-based disabilities focus more on the copy and less on the layout.

### Best practices for structure and layout

When considering structure and layout, be sure to:

* Use elements like headings, subheadings, lists, numbers, quote blocks, and
  other visual groupings to break the page into sections.
* Use clearly defined paragraphs, sentences, and word spacing.
* Build columns of copy that do not exceed 80 characters in width (40
  characters for logograms).
* Avoid justified paragraph alignment, which creates "rivers of space" within
  the copy. 

## Accessible typography takeaways 

Accessible typography can be boiled down to common-sense design choices based
on your knowledge of your users' needs. Keeping this module in mind as you
design and build out your content will go a long way toward helping you
communicate clearly with the greatest number of people.

{% Aside %}
Refer to the [Typography module for Learn CSS](/learn/design/typography/) to
learn how to implement certain rules and styles.
{% endAside %}

{% Assessment 'typography' %}

# Video and audio

Have you ever wanted to watch a live event but couldn't find your headphones,
so you turned on the captions? Or maybe you didn't quite catch the last few
talking points from your favorite podcast, so you decided to read the
transcript instead? If so, you probably understand the importance and
convenience of having alternative ways to access audio and video content. 

While your role at your company or organization may not require you to create
audio and video content directly, it's important to know the basics of
[accessibility requirements for media](https://www.w3.org/WAI/WCAG21/Understanding/time-based-media).
This knowledge will help you design and build the appropriate layouts and
features to accommodate users with different environmental and sensory needs,
such as the millions of people with hearing loss or visual impairment
worldwide.

## Alternative media types

Alternative media types were developed to support the media needs of people
with disabilities. This gives people additional formats to choose from when
accessing audio and video content.

The [alternative media types you must include](https://www.w3.org/WAI/media/av/planning/#wcag-standard)
with your media files depend on:

* The type of media you are supporting&mdash;audio-only, video-only, or video
  with audio (multimedia) formats
* Whether the media is live or pre-recorded
* The version and level of WCAG compliance you are targeting
* Any additional media-related user needs

To create [accessible audio and video content](https://www.w3.org/WAI/media/av/)
for websites and apps, there are four main types of alternative media types:
[captions](#captions), [transcripts](#transcripts),
[audio descriptions](#audio-descriptions), and
[sign language interpretation](#sign-language-interpretation).

## Captions

One of the most widely used alternative media types are
[captions](https://www.w3.org/WAI/media/av/captions/). Captions are written
text synchronized with multimedia content for people who can't hear or
understand spoken words. They are presented in the same language as the main
audio track and include important non-speech information, such as sound
effects, background noises, and essential music. 

Captions benefit people who are deaf, hard of hearing, or have cognitive
disabilities, but are useful to many other people as well.

Captions come in two forms&mdash;open or closed. 

* Closed captions (CC) are text on top of a video that can be turned on or off
  by the viewer and, depending on the media player, styled in a way that fits
  the user's needs.
* Open captions (OC) are text burned into the video and cannot be turned off or
  styled differently. 

One method might be preferable, depending on the situation or how the
multimedia will be consumed.

People often confuse captions with subtitles, but they aren't synonymous. Both
are text synchronized with multimedia content, often appearing at the bottom of
the media. Captions can be thought of as a transcription of dialogue and other
essential sounds for people with disabilities. Subtitles are visual text for
people who can hear the audio track but may not understand what was said, such
as when watching a foreign language film.

{% Aside %}
There are some geographical differences in what are considered captions and
subtitles, so be sure to check the terminology in your location.
{% endAside %}

<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>Features</th>
        <th>Subtitles</th>
        <th>Closed captions</th>
        <th>Open captions</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Visual text matches audio track</td>
        <td>No</td>
        <td>Yes</td>
        <td>Yes</td>
      </tr>
      <tr>
        <td>Includes essential background sounds</td>
        <td>No</td>
        <td>Yes</td>
        <td>Yes</td>
      </tr>
      <tr>
        <td>Ability to toggle on/off</td>
        <td>Yes</td>
        <td>Yes</td>
        <td>No</td>
      </tr>
    </tbody>
  </table>
</div>

<figure>
{% YouTube "pXc_w49fsmI" %}
<figcaption>
  Check out an example of captions in this video, <em>Google &mdash; A CODA Story</em>. Toggle the CC button to <strong>On</strong> to see the closed captions on this video.
</figcaption>
</figure>

{% Details %}
{% DetailsSummary %}
Compare screenshots from this video, with and without captions.
{% endDetailsSummary %}
<div class="switcher">
<figure class="screenshot">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/5gUlKnnfGwqP3SrG2oJa.png", alt="Video with captions.", width="800", height="450" %}
</figure>
<figure class="screenshot">
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/bfDTwxctgjbPpxqtLwsV.png", alt="Video without captions.", width="800", height="450" %}
</figure>
</div>
{% endDetails %}

## Transcripts

Close cousins to captions,
[transcripts](https://www.w3.org/WAI/media/av/transcripts/) are detailed,
text-based documents that capture all essential words, sounds, and important
visual information in your media. Transcripts primarily help people who are
hard of hearing or deaf, and descriptive transcripts help people who are
deafblind. 

Transcripts are also useful for people with cognitive disabilities or for people
who want to review the content at their own speed.

While transcripts are typically more detailed than captions, they are very
similar in format and purpose. They are so similar that many people first add
captions to their media, export them, and then use them as the foundation of
their transcripts. Repurposing your captions to build your transcripts saves
time versus creating everything from scratch.

Search bots can't access your captions but can crawl your text transcripts.
When you include transcripts with your media files, your search engine
optimization gets a boost. It's one of those rare exceptions when
duplicate content isn't confusing to users or penalized by search engine
algorithms.

Every media player handles transcripts in a different way. Some providers may
not have that functionality built into their media player, and even when they
do, some users may not be able to access the transcript interface. You can
ensure you've made your transcript available to all users by:

* Including the transcript text directly in-context, on the page with the
  embedded video.
* Adding a link to an accessible PDF containing the transcript.
* Linking out to the copy on another page.
* Including a link to the transcript, wherever it lives, within the video
  description on whatever media player platform you've used (such as YouTube or
  Vimeo).

For example, visit YouTube to watch [_Password Problems? | There's no place like Chrome_](https://www.youtube.com/watch?v=SlGuvC5nnTA) and review an example of a transcript.

<figure>
{% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/s1EjKIhORUdo3094N3Sq.png", alt="Video on YouTube with Transcript in the right panel. The steps to access the transcript are highlighted in blue.", width="800", height="459" %}
<figcaption>
  Under the video title, click <span aria-label="More actions"><strong>...</strong></span> and select <strong>Show transcript</strong> from the dropdown menu. The transcripts will show up to the right or bottom of the video, depending on your screen size.
</figcaption>
</figure>

## Audio descriptions

Another alternative media used to support people with disabilities is
[audio description](https://www.w3.org/WAI/media/av/description/). This type
of alternative media utilizes a narrator to explain important visual
information to people who can't see the visual content. These descriptions
include nonverbal information such as facial expressions, unspoken actions, and
the background environment in video-only and multimedia content.

Sometimes audio descriptions need to be very detailed due to the large amount
of information that needs to be shared with the viewer. If there aren't enough
natural pauses in the video for audio descriptions, extended audio descriptions
are used. In extended audio descriptions, a video will pause to give a narrator
enough time to convey all the information in the media before playing the rest
of the video.

Audio descriptions and extended audio descriptions help people who are blind or
have low vision, but could help people with some cognitive disorders as well.

<figure>
{% YouTube "fNq5jWyEeWo" %}
<figcaption>
  Here's an example of an illustrated video with an audio description, titled <em><code>[Audio Described]</code> Get started with Lookout from Google | Android</em>.
</figcaption>
</figure>

## Sign language interpretation

Another major alternative media type you may encounter is [sign language
interpretation](https://www.w3.org/WAI/media/av/sign-languages/), where
an interpreter narrates the auditory portion of the audio-only or multimedia
content using sign language. This is very important for many people who are
deaf, as sign language is their first and most fluent language. 

Sign language interpretation is often more expressive and detailed than written
documents, providing a much richer experience than captions or transcripts
alone.

That said, sign language interpretation can be time-consuming and
cost-prohibitive to many organizations. And even if you have the time and
budget to add sign language interpretation to your media, there are
[over 300 different sign languages](https://en.wikipedia.org/wiki/List_of_sign_languages)
worldwide. Adding one sign language interpretation to your media wouldn't be
enough to support a global audience.

<figure>
{% YouTube "MbHuSHGZf5U", startTime="34" %}
<figcaption>
  See how sign language interpreters narrated the story of Google sustainability in the video <em>Google Presents: Search On '22</em>.
</figcaption>
</figure>

# What is digital accessibility, and why does it matter?

Imagine a world where you couldn't buy a present for a friend because the
online shopping cart was incompatible with your device. Or a world where you
had to ask a coworker to help you understand the recent sales chart because it
only used soft monotone colors. Maybe you couldn't enjoy that new show
everyone's been talking about because the captions are missing or badly
automated.

For some people, this world is an everyday reality. But it doesn't have to be
this way—this is a reality you can help change when you make digital
accessibility a priority. Digital accessibility, commonly abbreviated to
[a11y](https://www.a11yproject.com/posts/a11y-and-other-numeronyms/), is about
designing and building digital products so that, regardless of a person's
disability, they can still interact with the product in a meaningful and
equivalent way.

Beyond the typical leadership buy-in, time, effort, and budget that are
required of any project, building digital products with full inclusivity in
mind also requires:

* Expert knowledge of various accessibility standards
* Understanding the fundamentals of accessible designs and code
* Understanding the importance of using multiple testing techniques and tools

Most importantly, true inclusivity can only come when you include people with
disabilities and accessibility best practices into the full product
lifecycle—from planning, to designing, to coding, and more.

## What is the individual impact?

The [World Health Organization](https://www.who.int/teams/noncommunicable-diseases/sensory-functions-disability-and-rehabilitation/world-report-on-disability)
(WHO) estimates that over 15% of the world's population—or 1.3 billion
people—self-identify as having a disability, making this group the largest
minority group globally.

More recent reports from the
[Centers for Disease Control and Prevention (CDC)](https://www.cdc.gov/ncbddd/disabilityandhealth/infographic-disability-impacts-all.html),
the [US Census](https://www.census.gov/content/dam/Census/library/publications/2018/demo/p70-152.pdf),
the [Academic Network of European Disability experts (ANED)](https://includ-ed.eu/sites/default/files/documents/aned_2013_task_6_-_comparative_data_synthesis_report_-_europe2020_final.pdf),
and others estimate the total number of people with disabilities to be even
greater. This number continues to grow as the world population ages and faces
chronic health conditions.

{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/wmi25b63ncEEhKTGYBUS.png",
  alt="Six people representing various disabilities. Each character will be represented.",
  width="800", height="200"
%}

Inaccessible digital products impact people with disabilities. Some types of
disabilities are impacted more in the digital world than others.

{% Aside %}
To learn more about identity and language choices, we recommend reading
[Demystifying Disability: What to Know, What to Say, and How to be an Ally](https://emilyladau.com/book/)
by Emily Ladau.
{% endAside %}

{% Details  'open' %}

{% DetailsSummary 'h3' %}
Visual impairments
{% endDetailsSummary %}

[Visual impairment](https://www.disabled-world.com/disability/types/vision/)
(vision impairment, vision disability) is a decreased ability to see to the
degree that causes problems not fixable by usual means, such as glasses or
medication. Visual impairment can be due to disease, trauma, or congenital or
degenerative conditions.

<figure data-float="right">
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/9rl95PJGmH4j9z6PYCVD.png",
  alt="A woman using a white cane.", width="240", height="300"
  %}
</figure>

* _Examples_: B/blindness, low vision, color blindness
* _Prevalence_: 253 million people with visual impairment worldwide—36 million
  are blind, 217 million have moderate to severe visual impairment (MSVI)
  ([Source](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5820628/)), and 1 in
  12 men and 1 in 200 women are colorblind.
  ([Source](https://www.colourblindawareness.org/colour-blindness/))
* _Tools include_: Screen reader software, screen magnification tools, Braille output devices.
* _Pain points_: Digital products that do not work with screen reader software,
  mobile websites/apps without pinch to zoom, complex graphs and charts differentiated
  by colors alone, color contrasts that make it difficult to read text on the screen

{% Aside 'important' %}
Use lowercase when referring to a vision-loss condition or to a blind person who prefers
lowercase. Capitalize for those who capitalize Blind when describing themselves.
{% endAside %}

<blockquote>
  <p>"My vision has deteriorated rapidly over the last three years, and my phone's default font size ranges from large to mega-large. There are a decent amount of mobile apps that I can barely use because of their absurd font sizes."</p>
  <cite>Frank</cite>
</blockquote>

Read a short [article in the New York Times](https://www.nytimes.com/2022/08/16/opinion/blindness-retinitis-pigmentosa.html)
or watch a [video](https://youtu.be/X04HKyW-3hc) on what it means to be
legally blind.

{% endDetails %}

{% Details %}
{% DetailsSummary 'h3' %}
Mobility impairments
{% endDetailsSummary %}

[Mobility impairment](https://www.disabled-world.com/disability/types/mobility/)
is a category of disability that includes people with various physical
disabilities. This type of disability includes upper or lower limb loss or
disability, manual dexterity, and disability in coordination with different
organs of the body.

<figure data-float="right">
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/QJhp1Phv2QSOAVsj9Ce9.png",
  alt="A man in a wheelchair, holding an open laptop.",
  width="240", height="300"
%}
</figure>

* _Examples_: Arthritis, paralysis, amputees, seizure disorders.
* _Prevalence_: 1 in 7 people have mobility issues.
  ([Source](https://www.cdc.gov/media/releases/2018/p0816-disability.html#:~:text=One%20in%204%20U.S.%20adults,affects%201%20in%207%20adults.))
* _Tools include_: Adaptive switches, eye tracking devices, mouth/head sticks, speech input.
* _Pain points_: Elements that are only designed to work with the use of a mouse.

<blockquote>
  <p>"Accessibility isn't just for people with disabilities. I had elbow surgery, and it temporarily changed how I managed my daily digital activities."</p>
  <cite>Melissa</cite>
</blockquote>

{% endDetails %}

{% Details %}

{% DetailsSummary 'h3' %}
Hearing impairments
{% endDetailsSummary %}

A [hearing impairment or hearing loss](https://www.disabled-world.com/disability/types/hearing/)
is a full or partial decrease in the ability to detect or understand sounds.
Hearing impairments are caused by a wide range of biological and environmental
factors.

<figure data-float="right">
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/1nUPylVp4y3mMe6ksPKq.png", alt="A man with a hearing aid.", width="183", height="320"
    %}
</figure>

* _Examples_: D/deafness, hard of hearing (HoH), hearing impaired (HI)
* _Prevalence_: Globally, over 1.5 billion people have a low to medium level of hearing loss, while it is estimated that 66 million people have a [significant level of hearing loss](https://www.who.int/health-topics/hearing-loss#tab=tab_1).
* _Tools include_: hearing aids, captions, transcripts, sign language.
* _Pain points_: Audio content without text transcripts, video with no synchronized captions

{% Aside 'important' %}
Use lowercase when referring to a hearing-loss condition or to a deaf person
who prefers lowercase. Capitalize for those who identify as members of the Deaf
community or when they capitalize Deaf when describing themselves.
{% endAside %}

<blockquote>
  <p>"Some deaf people say auto-captions are NOT better than nothing. Some deaf people say automatic captions ARE better than nothing. Unlike people with hearing, deaf people have nothing to fall back on. All they have is the captions. Personally, I'd rather see no captions than watch automatic captions. Sure, I'm disappointed there aren't captions. With no auto-captions, I avoid the painful experience of its notoriously bad captions."</p>
  <cite>Meryl</cite>
</blockquote>

{% endDetails %}

{% Details %}
{% DetailsSummary 'h3' %}
Cognitive impairments
{% endDetailsSummary %}

A [cognitive disability](https://www.disabled-world.com/disability/types/cognitive/) covers
a variety of medical conditions affecting cognitive ability. People with
cognitive disabilities include various intellectual or cognitive deficits,
deficits too mild to properly qualify as intellectual disability, specific
conditions, and problems acquired later in life through acquired brain injuries
or neurodegenerative diseases like dementia.

<figure data-float="right">
  {% Img
    src="image/VbsHyyQopiec0718rMq2kTE1hke2/FFQbr519qx67nnEU9YKU.png",
    alt="An older woman in glasses, holding an animal.", width="183", height="320"
    %}
</figure>

* _Examples_: Down's syndrome, A/autism, ADHD, dyslexia, aphasia.
* _Frequency_: Varies by condition.
* _Tools include_: Screen readers, text highlighting, text prediction,
  abstractive summarization tools.
* _Pain points_: Busy interfaces that make it overly complicated to focus on
  the task at hand, big walls of words with little whitespace, justified text,
  and small or hard-to-read fonts.

{% Aside 'important' %}
Use lowercase when referring to autism as a disorder or to an autistic person
who prefers lowercase. Capitalize for those who capitalize Autism or Autistic
when describing themselves.
{% endAside %}

<blockquote>
  <p>"Right now, I am recovering from an ocular migraine, and I would say dark mode is not helping enough. I still need contrast, but less harshly bright."</p>
  <cite>Ruth</cite>
</blockquote>

Read a short
[article in the New York Times](https://www.nytimes.com/2022/08/30/opinion/face-blindness-prosopagnosia.html)
or watch a [video](https://youtu.be/3-MzNPcEh6M) on face blindness
(prosopagnosia).

{% endDetails %}

{% Details %}
{% DetailsSummary 'h3' %}
Seizure and vestibular disorders
{% endDetailsSummary %}

A seizure is an excessive surge of electrical activity in the brain that can
cause various symptoms, depending on which parts of the brain are involved.
Seizures may result from genetics or a brain injury, but their
[cause is often unknown](https://nyulangone.org/conditions/epilepsy-seizure-disorders-in-adults/types).

The vestibular system includes the parts of the inner ear and brain that
process the sensory information that controls balance and eye movements. If
disease or injury damages these processing areas, vestibular disorders can
result. [Vestibular disorders](https://vestibular.org/article/diagnosis-treatment/types-of-vestibular-disorders/)
can also result from or be worsened by genetic or environmental conditions or
occur for unknown reasons.

<figure data-float="right">
 {% Img src="image/VbsHyyQopiec0718rMq2kTE1hke2/6jKwFBXkliZ0wtJgr8tj.png",
  alt="A person in a green jacket with glasses.", width="183", height="320"
 %}
</figure>

* _Examples_: Epilepsy, vertigo, dizziness, labyrinthitis, balance, and eye movement disorders.
* _Frequency_: [50 million people worldwide have epilepsy](https://www.who.int/health-topics/epilepsy),
  and 1.8 million adults worldwide have
  [bilateral vestibular hypofunction](https://www.hopkinsmedicine.org/news/newsroom/news-releases/implant-improves-balance-movement-and-quality-of-life-for-people-with-inner-ear-disorder) (BVH).
* _Tools include_: Operating system settings to reduce motion. In Windows, this
  setting is framed positively as **Show animation**, and is turned off. On
  Android, the setting **Remove animations** is turned on.
* _Pain points_: Videos that autoplay, extreme flashing or strobing of visual
  content, parallax effects, or scroll-triggered animations.

<blockquote>
  <p>"I <em>really</em> dislike the superfluous animation that plagues iOS transitions between apps, so I turn it off. Downside: I'm denied most of the thoughtfully executed motion design on the web because there's no “some motion is fine” middle ground."</p>
  <cite>Oliver</cite>
</blockquote>

{% endDetails %}

{% Details %}
{% DetailsSummary 'h3' %}
Speech impairments
{% endDetailsSummary %}

A [speech disorder](https://www.pennmedicine.org/for-patients-and-visitors/patient-information/conditions-treated-a-to-z/speech-and-language-disorders#:~:text=A%20speech%20disorder%20is%20a,Articulation%20disorders)
is a condition in which a person has problems creating or forming the speech
sounds needed to communicate with others.

<figure data-float="right">
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/uR06sT1scRQ8Qnt4hW6l.png", alt="A person wearing glasses and waving.", width="183", height="320"
%}
</figure>

* _Examples_: Muscular or cognitive issues that impede speech, such as apraxia, dysarthria, or stuttering.
* _Frequency_: 18.5 million individuals have a [speech, voice, or language disorder](https://www.nidcd.nih.gov/health/statistics/quick-statistics-voice-speech-language).
* _Tools include_: Augmentative and alternative communication (AAC) and speech-generating devices.
* _Pain points_: Voice-activated technology such as smart home devices and apps.

<blockquote>
  <p>"My son has a lisp due to dyspraxia.
He will say "seep" rather than "sheep" or
"fower" rather than "flower". It is sweet,
but he gets so frustrated by voice-activated
software.</p>
<p>Our new car uses voice activation to
interact with a phone. Often if we are
together, my husband will send us a
WhatsApp message. The car will read it
out loud, but when it asks us if we want
to reply, my son's reply is not understood.
He gets so upset... he now whispers the
message to me so I can say it for the
reply."</p>
  <cite>Helen</cite>
</blockquote>

Read a short [article in the New York
Times](https://www.nytimes.com/2022/08/23/opinion/stutter-speech-listening.html)
or watch a [video](https://youtu.be/m0E_wMIwfSI) on stuttering and technology.

{% endDetails %}

### Additional beneficiaries of accessibility

While the number of people with disabilities worldwide is large, it's important
to remember that these numbers aren't inclusive of everyone that benefits from
accessible digital spaces. This includes:

* _Temporarily disabled_. It may mean someone has a broken wrist or is
  cognitively impaired due to medication.
* _Situationally disabled_. For example, someone experiencing glare on a device
  screen or being unable to play the audio on a video in a public setting.
* _Mildly disabled_. A person needing eyeglasses to see a screen or captions to
  understand audio.
* _Non-native speakers_. If a person is not fluent in the language on the
  screen, they may need more time to read content on a slide on a
  carousel/slideshow.
* _Older people with age-related diminishing senses_. It could be a person
  needing reading glasses or bifocals to read small print or requiring a larger
  target size for buttons on their touch device due to an age-related hand
  tremor.
* _Search engine optimization (SEO) bots_. SEO bots do not have senses like
  sight and hearing and navigate by keyboard only. Your websites will be crawled more effectively when your site is accessible.

## Business impact

People with disabilities make up almost a fourth of the world's population, but
did you know that they also have a lot of spending power?

<figure data-float="right">
{% Img
  src="image/VbsHyyQopiec0718rMq2kTE1hke2/mPFzo0YRdCd8slPOjDgE.png",
  alt="A collection of coins, representing the lost revenue when disabled communities are ignored.",
  width="218", height="130"
%}
</figure>

According to the
[American Institutes for Research (AIR)](https://www.researchgate.net/profile/Dahlia-Shaewitz/publication/324603094_A_Hidden_Market_The_Purchasing_Power_of_Working-Age_Adults_With_Disabilities_A_Hidden_Market_The_Purchasing_Power_of_Working-Age_Adults_With_Disabilities/links/5ad89016458515c60f5918f3/A-Hidden-Market-The-Purchasing-Power-of-Working-Age-Adults-With-Disabilities-A-Hidden-Market-The-Purchasing-Power-of-Working-Age-Adults-With-Disabilities.pdf),
the total after-tax disposable income for working-age Americans with
disabilities is about $490 billion annually. This number is similar to other
significant market segments in the US, such as the Black ($501 billion) and
Latinx ($582 billion) communities. Companies that do not plan for, design, and
build accessible products can lose out on this potential revenue.

While these numbers are impressive, people with disabilities are also part of a
larger network of family members, friends, communities, and institutions. This
larger network often looks for and supports businesses that create accessible
digital products. When you factor in the friends and family of the over 1.3
billion people worldwide who identify as disabled, the disability market
touches 53% of all consumers. It's the world's largest emerging market.

In addition to money and market shares, businesses focused on disability
inclusion as part of an overall diversity strategy are [higher performing and
more innovative](https://www.w3.org/WAI/business-case/). There are many
examples of [everyday products](https://incl.ca/the-evolution-of-assistive-technology-into-everyday-products/)
that evolved from technology developed by, or for, people with disabilities,
including: 

* Telephones
* Typewriters / keyboards
* Email
* Kitchen utensils
* Easy-open pull-out drawers
* Automatic door openers
* Voice controls
* Eye gaze technology

When we look at accessibility as a design or coding challenge, not a begrudging
requirement, innovation is the byproduct. For people without disabilities, such
improvements can increase the overall user experience. For people with
disabilities, these improvements are essential for equal access.

## Legal impact

Beyond the individual and business impact, you should also be aware of the
looming [legal impact](https://f.hubspotusercontent30.net/hubfs/3280432/Remediated-2021-Year-End-Report-FINAL.pdf)
of not building accessible digital products. Public sector entities in the
United States, such as government-funded programs/schools, airlines, and
nonprofits, must follow certain digital accessibility rules, while many private
sector companies do not. In countries such as Canada, the United Kingdom,
Japan, Australia, and the European Union, stricter
[digital accessibility laws](https://www.w3.org/WAI/policies/) exist for both
public and private companies.

For many disabled people in the US, filing a lawsuit is their only option to
bring awareness and change to digital products. It is estimated that in the US,
over ten lawsuits are filed daily focused on digital accessibility. Many
businesses have received multiple digital accessibility-based lawsuits. And
every year, the number of total lawsuits has increased.

E-commerce websites and apps are typically the biggest targets, comprising over
74% of the lawsuits filed in 2021. If your company has both a physical location
and an online presence, you are more likely to have been part of a lawsuit. In
fact, of the top 500 e-commerce sites, 412 have been served with a lawsuit
within the past four years. Often, the first lawsuit is for the company's
website and the second for their mobile app.

While avoiding lawsuits shouldn't be the only reason you focus on making sure
your digital products are accessible, it is an important piece of the
conversation.

{% Assessment 'why' %}

# Learn CSS

This course breaks down the fundamentals of CSS into digestible,
easy to understand pieces.
Over the next few modules,
you'll learn how the core aspects of CSS work and how to use them effectively in your projects. Use the menu pane by the "Learn CSS" logo to navigate the modules.

You'll learn CSS fundamentals like the box model, cascade and specificity, flexbox, grid and z-index.
And, along with these fundamentals,
you'll learn about functions, color types, gradients, logical properties and inheritance
to make you a well-rounded front-end developer,
ready to take on any user interface.

Each module is full of interactive demos and self-assessments for you to test your knowledge.
In addition to learning through reading and demos,
there is an accompanying podcast episode for each topic as another way to learn and continue expanding your knowledge.

This course is created for beginner and advanced CSS developers alike.
You can go through the series from start to finish
to get a general understanding of CSS from top to bottom,
or you can use it as a reference for specific styling subjects.
For those new to web development overall, check out [Learn HTML](/learn/html/) to learn all about how to write markup and link your stylesheets.

Here's what you'll learn:

{% include 'partials/course-index.njk' %}

So, are you ready to learn CSS? [Let's get started](/learn/css/box-model/).

{% Aside %}
This course is written and edited by CSS community experts: [Andy Bell](https://twitter.com/piccalilli_), [Rachel Andrew](https://twitter.com/rachelandrew), [Una Kravets](https://twitter.com/Una), [Adam Argyle](https://twitter.com/argyleink), [Emma Twersky](https://twitter.com/twerske), [Camden Bickel](https://twitter.com/camdenbickel), and [Kevin Lozandier](https://twitter.com/KevinLozandier). [Rob Dodson](https://twitter.com/rob_dodson) and [Jiwoong Lee](https://twitter.com/jiwoong) shepherded the UX and production build, along with help from [Ewa Gasperowicz](https://twitter.com/devnook) and [Kayce Basques](https://twitter.com/kaycebasques).
{% endAside %}

# Animations

Sometimes you see little helpers on interfaces that when clicked,
provide some helpful information about that particular section.
These often have a pulsing animation to subtly let you know that the information is there
and should be interacted with.
How do you do this with CSS though?

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRXGeJ',
  height: 300
} %}
</figure>

In CSS, you can make this type of animation using CSS animations,
 which allow you to set an animation sequence, using keyframes.
Animations can be simple, one state animations,
or even complex, time-based sequences.

## What is a keyframe?

In animation software, CSS, and most other tools that enable you to animate something,
keyframes are the mechanism that you use to assign animation states to timestamps,
along a timeline.

Let's use the "pulser" as a context for this.
The entire animation runs for 1 second and runs over 2 states.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/pWCGpgzJqJNTBluK5u8S.svg",
alt="The states of the pulser animation over the 1 second timeframe",
width="800",
height="340" %}

There's a specific point where each of these animation states start and end.
You map these out on the timeline with keyframes.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/wmKVq5GFj7cf6jfuLiT8.svg",
alt="The same diagram as before, but this time, with keyframes",
width="800",
height="440" %}

### `@keyframes`
{% BrowserCompat 'css.at-rules.keyframes' %}

Now you know what a keyframe is,
that knowledge should help you understand how the CSS
[`@keyframes`](https://developer.mozilla.org/docs/Web/CSS/@keyframes) rule works.
Here is a basic rule with two states.

```css
@keyframes my-animation {
	from {
		transform: translateY(20px);
	}
	to {
		transform: translateY(0px);
	}
}
```

The first part to note is the
[custom ident](https://developer.mozilla.org/docs/Web/CSS/custom-ident)
(custom identifier)—or in more human terms, the name of the keyframes rule.
This rule's identifier is `my-animation`.
The custom identifier works like a function name. Which, as you learned in the [functions module](/learn/css/functions),
lets you reference the keyframes rule elsewhere in your CSS code.

{% Aside %}
A `<custom-ident>` is used in various places in CSS,
and allows you to provide your own name for things.
These identifiers are case-sensitive,
and in some cases there are words that you can't use.
For example, when naming lines in CSS Grid, you can't use the word `span`.
{% endAside %}

Inside the keyframes rule, `from` and `to` are keywords that represent `0%` and `100%`,
which are the start of the animation and end.
You could re-create the same rule like this:

```css
@keyframes my-animation {
	0% {
		transform: translateY(20px);
	}
	100% {
		transform: translateY(0px);
	}
}
```

You can add as many positions as you like along the timeframe.
Using the context of the "pulser" example, there are 2 states,
which translate to 2 keyframes.
This means you have 2 positions inside your keyframes rule to represent the changes for each of these keyframes.

```css
@keyframes pulse {
  0% {
    opacity: 0;
  }
  50% {
    transform: scale(1.4);
    opacity: 0.4;
  }
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRXGeJ',
  tab: 'css,result',
  height: 300
} %}
</figure>

## The `animation` properties
{% BrowserCompat 'css.properties.animation' %}

To use your `@keyframes` in a CSS rule, define various animation properties _or_, use the
[`animation`](https://developer.mozilla.org/docs/Web/CSS/animation) shorthand property.

### `animation-duration`
{% BrowserCompat 'css.properties.animation-duration' %}

```css
.my-element {
	animation-duration: 10s;
}
```

The [animation-duration](https://developer.mozilla.org/docs/Web/CSS/animation-duration)
property defines how long the `@keyframes` timeline should be. It should be a time value.
It defaults to 0 seconds, which means the animation still runs,
but it'll be too quick for you to see.
You can't add negative time values.

### `animation-timing-function`
{% BrowserCompat 'css.properties.animation-timing-function' %}

To help recreate natural motion in animation,
you can use timing functions that calculate the speed of an animation at each point.
Calculated values are often *curved*,
making the animation run at variable speeds over the course of `animation-duration`,
and if a value is calculated beyond that of the value defined in `@keyframes`, make the element appear to bounce.


There are several keywords available as presets in CSS, which are used as the value for
[animation-timing-function](https://developer.mozilla.org/docs/Web/CSS/animation-timing-function):
`linear`, `ease`, `ease-in`, `ease-out`, `ease-in-out`.

```css
.my-element {
	animation-timing-function: ease-in-out;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNeJbL'
} %}
</figure>

Values appear to curve with easing functions because easing is calculated using a **bézier curve**,
which is used to model velocity.
Each of the timing function keywords,
such as `ease`, reference a pre-defined bézier curve.
In CSS, you can define a bézier curve directly,
using the `cubic-bezier()` function,
which accepts four number values: `x1`, `y1`, `x2`, `y2`.

```css
.my-element {
	animation-timing-function: cubic-bezier(.42, 0, .58, 1);
}
```

These values plot each part of the curve along the X and Y axis.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/AZr17k5ejTYsikAPiwTm.svg",
alt="A bézier on a progression vs time chart",
width="800",
height="499" %}

Understanding bézier curves is complicated and visual tools,
such as
[this generator by Lea Verou](https://cubic-bezier.com/)
are very helpful.

#### The `steps` easing function

Sometimes you might want more granular control of your animation,
and instead of moving along a curve, you want to move in intervals instead.
The `steps()` easing function lets you break the timeline into defined, **equal intervals**.

```css
.my-element {
	animation-timing-function: steps(10, end);
}
```

The first argument is how many steps.
If steps are defined as 10 and there are 10 keyframes,
each keyframe will play in sequence for the exact amount of time,
with no transition between states.
If there are not enough keyframes for the steps,
steps between keyframes are added depending on the second argument.

The second argument is the direction.
If it's set to `end`, which is the default,
the steps finish at the end of your timeline.
If it is set to `start`, the first step of your animation completes as soon as it starts,
which means it ends one step earlier than `end`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEpege'
} %}
</figure>

### `animation-iteration-count`
{% BrowserCompat 'css.properties.animation-iteration-count' %}

```css
.my-element {
	animation-iteration-count: 10;
}
```

The [animation-iteration-count](https://developer.mozilla.org/docs/Web/CSS/animation-iteration-count)
property defines how many times the `@keyframes` timeline should run.
By default, this is 1,
which means that when the animation reaches the end of your timeline,
it will stop at the end.
The number can't be a negative number.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'oNBEaYB',
  tab: 'css,result'
} %}
</figure>

You can use the `infinite` keyword which will loop your animation,
which is how the "pulser" demo from the start of this lesson works.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRXGeJ',
  tab: 'css,result'
} %}
</figure>

### `animation-direction`
{% BrowserCompat 'css.properties.animation-direction' %}

```css
.my-element {
	animation-direction: reverse;
}
```

You can set which direction the timeline runs over your keyframes with
[animation-direction](https://developer.mozilla.org/docs/Web/CSS/animation-direction):

- `normal`: the default value, which is forwards.
- `reverse`: runs backwards over your timeline.
- `alternate`: for each animation iteration, the timeline will run forwards or backwards in sequence.
- `alternate-reverse`: the reverse of `alternate`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjWPqMv'
} %}
</figure>

### `animation-delay`
{% BrowserCompat 'css.properties.animation-delay' %}

```css
.my-element {
	animation-delay: 5s;
}
```

The [animation-delay](https://developer.mozilla.org/docs/Web/CSS/animation-delay)
property defines how long to wait before starting the animation.
Like the `animation-duration` property, this accepts a time value.

Unlike the `animation-duration` property, you *can* define this as a negative value.
If you set a negative value, the timeline in your `@keyframes` will start at that point.
For example, if your animation is 10 seconds long and you set `animation-delay` to `-5s`, it will start from half-way along your timeline.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGqbyPw'
} %}
</figure>

### `animation-play-state`
{% BrowserCompat 'css.properties.animation-play-state' %}

```css
.my-element:hover {
	animation-play-state: paused;
}
```

The [animation-play-state](https://developer.mozilla.org/docs/Web/CSS/animation-play-state)
property allows you to play and pause the animation.
The default value is `running` and if you set it to `paused`, it will pause the animation.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJQZyV',
  height: 400
} %}
</figure>

### `animation-fill-mode`
{% BrowserCompat 'css.properties.animation-fill-mode' %}

The [animation-fill-mode](https://developer.mozilla.org/docs/Web/CSS/animation-fill-mode)
property defines which values in your `@keyframes` timeline persist before the animation starts or after it ends.
The default value is `none` which means when the animation is complete, the values in your timeline are discarded.
Other options are:

- `forwards`: The last keyframe will persist, based on the animation direction.
- `backwards`: The first keyframe will persist, based on the animation direction.
- `both`: follows the rules for both `forwards` and `backwards`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNyBEVK'
} %}
</figure>

### The `animation` shorthand

Instead of defining all the properties separately,
you can define them in an `animation` shorthand,
which lets you define the animation properties in the following order:

1. `animation-name`
2. `animation-duration`
3. `animation-timing-function`
4. `animation-delay`
5. `animation-iteration-count`
6. `animation-direction`
7. `animation-fill-mode`
8. `animation-play-state`

```css
.my-element {
	animation: my-animation 10s ease-in-out 1s infinite forwards forwards running;
}
```

## Considerations when working with animation

Users can define in their operating system that they prefer to reduce motion
experienced when they interact with applications and websites.
This preference can be detected using the
[prefers-reduced-motion](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion)
media query.

```css
@media (prefers-reduced-motion) {
  .my-autoplaying-animation {
    animation-play-state: paused;
  }
}
```

This isn't necessarily a preference of no animation,
but rather, a preference to reduce animations—
[especially unexpected ones](/prefers-reduced-motion/).
You can learn more about this preference and overall performance with
[this animation guide](/animations/).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGqbPwq'
} %}
</figure>

{% Assessment 'animations' %}

# Backgrounds

Behind every CSS box is a specialized layer called the background layer. CSS provides a variety of ways to make meaningful changes to it–including allowing multiple backgrounds.

Background layers are furthest from the user, rendered behind the contents of a box starting from its `padding-box` region. This enables the background layer to not overlap with borders at all.

<figure>
{% Codepen {
  user: 'argyleink',
  id: 'BaLedvd',
  theme: 'dark',
  height: 700,
  tab: 'result'
} %}
</figure>

## Background color

{% BrowserCompat 'css.properties.background-color' %}

One of the simplest effects you can apply to a background layer is setting the [color](/learn/css/color/). The initial value of `background-color` is `transparent`, which allows the contents of a parent to be visible. A valid color set on a background layer sits behind other things painted on that element.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRvqQZZ',
  theme: 'dark',
  height: 850,
  tab: 'result'
} %}
</figure>

## Background images

{% BrowserCompat 'css.properties.background-image' %}

On top of the `background-color` layer, you can add a background image, using the `background-image` property. A `background-image` accepts the following:

* An image URL or [data URI](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) using the `url` CSS function.
* An image dynamically created by a gradient CSS function.

### Setting a background-image with the `url` CSS function

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjJNNro',
  theme: 'dark',
  height: 525,
  tab: 'result'
} %}
</figure>

### CSS gradient backgrounds

Several [gradient](/learn/css/gradients) CSS functions exist to allow you to generate a background-image, when passed two or more colors.

Regardless of which gradient function is used, the resulting image is [intrinsically sized](/learn/css/box-model/#content-and-sizing) to match the amount of space available.

Demo showing example of applying a background-image using gradient functions:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'oNeLZWa',
  theme: 'dark',
  height: 600,
  tab: 'result'
} %}
</figure>

## Repeating background images

{% BrowserCompat 'css.properties.background-repeat' %}

By default, background images repeat horizontally and vertically to fill the entire space of the background layer.

Change this by using the `background-repeat` property with one of the following values:

* `repeat`: The image repeats within the space available, cropping as necessary.
* `round`: The image repeats horizontally and vertically to fit as many instances into the space available, without cropping, compressing, or stretching it.
* `space`: The image repeats horizontally and vertically to fit as many instances within the space available without cropping—spacing out instances of the image as needed. Repeating images touch the edges of the space a background layer occupies, with white space evenly distributed between them.

The `background-repeat` property allows you to set the behavior for the x and y axis independently. The first parameter sets the horizontal repeat behavior, and the second parameter sets the vertical repeat behavior.

If you use a single value, it will be applied to both the horizontal and vertical repeats.

The shorthand also has convenient one-word options to make your intent clearer.

The value `repeat-x` repeats an image only horizontally; this is equivalent to `repeat no-repeat`.

The following demo demonstrates these capabilities of the `background-repeat` property:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKvMmjb',
  theme: 'dark',
  height: 1100,
  tab: 'result'
} %}
</figure>

## Background position

{% BrowserCompat 'css.properties.background-position' %}

You may have noticed when some images on the Web are styled with a `background-repeat: no-repeat` declaration, such images are displayed top left of their container.

The initial position of background images is top left. The `background-position`  property allows you to change this behavior by offsetting the image position.

As with `background-repeat`,  the `background-position` property allows you to position images along the x and y axis independently with two values by default.

When CSS lengths and percentages are used, the first parameter corresponds to the horizontal axis while the second parameter corresponds to the vertical axis.

When keywords are only used the order of the keywords does not matter:

{% Compare 'better' %}

```css
background-position: left 50%;
```

{% endCompare %}

{% Compare 'better' %}

```css
background-position: top left;
```

{% endCompare %}


{% Compare 'better' %}

```css
background-position: left top;
```

{% CompareCaption %}

Order does not matter for keywords associated with different axes of position.

{% endCompareCaption %}

{% endCompare %}


{% Compare 'worse' %}

```css
  background-position: 50% left;
```

{% CompareCaption %}

When CSS values are used alongside keywords, the order matters. The first value represents the horizontal axis and the second the vertical axis.
{% endCompareCaption %}

{% endCompare%}

{% Compare 'worse' %}

```css
  background-position: left right;
```

{% CompareCaption %}

You cannot use keywords associated with the same axis simultaneously.

{% endCompareCaption %}

{% endCompare %}


The `background-position` property also has a convenient one value shorthand; the omitted value resolves to `50%`.  Here's an example that demonstrates this using the keywords the `background-position` property accepts:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzxWQqx',
  theme: 'dark',
  height: 950,
  tab: 'result'
} %}
</figure>

In addition to its default two parameter form and one parameter form; the `background-position` property also accepts up to four parameters;

When three or four parameters are used, a CSS length or percentage must be preceded by the `top`, `left`, `right`, or `bottom` keywords in order for the browser to calculate which edge of the CSS box the offset should originate from.

When three parameters are used, a CSS length or value can be the second or third parameter with the other two being keywords; the keyword it succeeds will be used to determine the edge the CSS length or value corresponds to being the offset of. The offset of the other keyword specified is set to 0.



{% Compare 'better' %}

```css
background-position: bottom 88% right;
```

{% endCompare %}

{% Compare 'better' %}

```css
background-position: right bottom 88%;
```

{% endCompare %}

{% Compare 'worse' %}

```css
background-position: 88% bottom right;
```

{% CompareCaption %}
CSS length value must be preceded by the `top`, `right`, `bottom`, or `left` keywords when using three or more parameters.
{% endCompareCaption %}
{% endCompare %}

{% Compare 'better' %}

```css
background-position: bottom 88% right 33%;
```

{% endCompare %}


{% Compare 'better' %}

```css
background-position: right 33% bottom 88%;
```

{% endCompare %}


{% Compare 'worse' %}

```css
background-position: 88% 33% bottom left;
```

{% CompareCaption%}
CSS length value must be preceded by the `top`, `right`, `bottom`, or `left` keywords when using three or more parameters.
{% endCompareCaption %}
{% endCompare %}


If `background-position: top left 20%`is applied to a CSS background image, the image is placed at the top of the box, the `20%` value represents a 20% offset from the left of the box (on the x axis).

If `background-position: top 20% left` is applied to a CSS background image, the 20% value represents a 20% offset from the top of the CSS box (on the y axis), and the image is placed at the left of the box.

When four parameters are used, the two keywords are paired with two values corresponding to an offset against the origins of each keyword specified. If `background-position: bottom 20% right 30%` is applied to a background-image, the background-image is positioned 20% from the bottom, and 30% from the right of the CSS box.

The following demo demonstrates this behavior:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'porbwrM',
  theme: 'dark',
  tab: 'result'
} %}
</figure>

Here are more examples of using the `background-position` property using a mix of CSS and keyword values:

{% Aside %}
To learn more about the nuances related to positioning backgrounds,
check out [`background-position` on MDN](https://developer.mozilla.org/docs/Web/CSS/background-position).
{% endAside %}

## Background Size

{% BrowserCompat 'css.properties.background-size' %}

The `background-size` property sets the size of background images; By default background images are sized based on their intrinsic (actual) width, height, and aspect ratio.

The `background-size` property uses CSS length and percentage values or specific keywords.  The property accepts up to two parameters corresponding to allowing you to change width and height of a background independently.

The `background-size` property accepts the following keywords:

* `auto`: When used independently, the background image is sized based on its intrinsic width and height; when `auto` is used alongside another CSS value for the width (first parameter) or height (second parameter), the dimension set to `auto` is sized as needed to maintain the natural aspect ratio of the image. This is the default behavior of the `background-size` property.
* `cover`: Covers the entire area of the background layer. This may mean the image is stretched or cropped.
* `contain`:  Sizes the image to fill the space  without stretching or cropping. As a result, empty space can remain that will cause the image to repeat, unless `background-repeat` is set to `no-repeat`.

The latter 2 are intended to be used in a standalone fashion without another parameter.

The following demo demonstrates these keywords in action:

Demo demonstrating applying these keywords to `background-size`:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzxWQYY',
  theme: 'dark',
  height: 700,
  tab: 'result'
} %}
</figure>

## Background attachment

{% BrowserCompat 'css.properties.background-attachment' %}

The `background-attachment` property enables you to modify the fixed position behavior of background images (images part of a background layer) once the layer is visible on a screen.

It accepts 3 keywords: `scroll`, `fixed`, and `local`.

The default behavior of the `background-attachment` property is the initial value of `scroll`. When more space is needed, the images move with that space within the background layer determined by the bounds of the CSS box.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdwwzOe',
  theme: 'dark',
  height: 1000,
  tab: 'result'
} %}
</figure>

Using the value `fixed` fixes the position of background images to the viewport.

Once the space of the background layer images originally takes up needs to be scrolled (or rendered) offscreen, images within the background layer stay fixed in the original position the background layer enabled them to be until the entire layer is scrolled off screen by the viewport.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWoozvN',
  theme: 'dark',
  height: 1000,
  tab: 'result'
} %}
</figure>

The `local` keyword enables the position of background images to be fixed relative to the element's contents. Background images now move along the space they occupy as that space renders inside and outside the bounds of the CSS box (usually due to scrolling, 2D, or 3D transformations).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNExZmK',
  theme: 'dark',
  height: 1000,
  tab: 'result'
} %}
</figure>

## Background origin

{% BrowserCompat 'css.properties.background-origin' %}

The `background-origin` property enables you to modify the area of backgrounds associated with a particular box. The values the property accepts correspond to the `border-box` , `padding-box`, and `content-box` regions of a box .

Try these options out using the following demo:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExvyXeZ',
  theme: 'dark',
  height: 650,
  tab: 'result'
} %}
</figure>

## Background clip

{% BrowserCompat 'css.properties.background-clip' %}

The `background-clip` property controls what is visually seen from a background layer regardless of the bounds created by the `background-origin` property.

Like `background-origin` the regions that can be specified are `border-box`, `padding-box`, and `content-box` corresponding to where a CSS background layer can be rendered. When these keywords are used, any rendering of the background further than the region specified will be cropped or clipped.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYJKZba',
  theme: 'dark',
  height: 650,
  tab: 'result'
} %}
</figure>

The `background-clip` property also accepts a `text` keyword that clips the background to be no further than the text within the content box.  For this effect to be evident in the actual text within a CSS box, the text must be partially or completely transparent.

A relatively new property, at the time of this writing, Chrome and most browsers require the `-webkit-` prefix to use this property.

{% BrowserCompat 'css.properties.background-clip' %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBjjweL',
  theme: 'dark',
  height: 650,
  tab: 'result,css'
} %}
</figure>

{% Aside 'gotchas' %}
It should be also noted this property is not compatible with `background-clip: text` being simultaneously set on a CSS box.
{% endAside %}


## Multiple backgrounds

As mentioned at the beginning of the module, the background layer allows multiple sublayers to be defined. For brevity, I'll refer to these sublayers as backgrounds.

Multiple backgrounds are defined top to bottom; The first background is the closest to the user, while the last background is the furthest from the user.

The only background defined or the last layer is designated the *final background layer* by the browser. Only this layer is allowed to assign a `background-color`.

{% Aside %}
With the unpredictability of the web in mind, a background-image may fail to load. Setting a background-color on the final layer ensures good contrast for text and so on if important background layers fail to load.
{% endAside %}


Multiple layers can be individually configured using most background-related CSS properties that are comma separated, as demonstrated in the code snippet and live demo below.

```css
background-image: url("https://assets.codepen.io/7518/pngaaa.com-1272986.png"),
    url("https://assets.codepen.io/7518/blob.svg"),
    linear-gradient(hsl(191deg, 40%, 86%), hsla(191deg, 96%, 96%, 0.5));
  background-size: contain, cover, auto;
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-position: 50% 50%, 10% 50%, 0% 0%;
  background-origin: padding-box, border-box, content-box;
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyRzQBz',
  theme: 'dark',
  height: 650,
  tab: 'css'
} %}
</figure>

## The background shorthand

To make it easier to style the background layer of a box-especially when multiple background layers are desired–there is a shorthand that follows the following specific pattern:

```css
background:
  <background-image>
  <background-position> / <background-size>?
  <background-repeat>
  <background-attachment>
  <background-origin>
  <background-clip>
  <background-color>?
```

{% Aside 'gotchas' %}
It's important to note that any background properties omitted in the shorthand are set to their initial values.
{% endAside %}

Order is important in the shorthand form of declaring multiple backgrounds. The position and size values must both be provided, separated by a slash (`/`). Declaring the origin and clip behavior in the correct order allows you take advantage of setting keywords that are valid for both simultaneously

The following declaration clips the background, and originates it from the content box:

```css
background: url("https://assets.codepen.io/7518/blob.svg") 50%
      50% / contain no-repeat content-box;
```

With these shorthand semantics in mind, the previous background-related declarations of the code snippet could be rewritten to be following:

```css
background: url("https://assets.codepen.io/7518/pngaaa.com-1272986.png") 50% 50%/contain no-repeat padding-box, url("https://assets.codepen.io/7518/blob.svg") 10% 50% / cover border-box, linear-gradient(hsl(191deg, 40%, 86%), hsla(191deg, 96%, 96%, 0.5) ) 0% 0% / cover no-repeat content-box ;
```

{% Assessment 'backgrounds' %}

# Blend Modes

[Duotone](https://en.wikipedia.org/wiki/Duotone) is a popular color treatment for photography
which makes an image look like it is only made up of two contrasting colors:
one for highlights and the other for lowlights.
How do you do this with CSS though?

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgvYMG'
} %}
</figure>

Using blend modes—and other techniques you have learned about,
such as [filters](/learn/css/filters) and
[pseudo-elements](/learn/css/pseudo-elements)—you can apply this effect to any image.

## What is a blend mode?

Blend modes are commonly used in design tools such as Photoshop
to create a compositional effect by mixing colors from two or more layers.
By changing how colors mix, you can achieve really interesting visual effects.
You can also use blend modes as a utility,
such as isolating an image that has a white background,
so it appears to have a transparent background.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyNmJor'
} %}
</figure>

You can use most of the blend modes available in a design tool with CSS,
using the
[`mix-blend-mode`](https://developer.mozilla.org/docs/Web/CSS/mix-blend-mode) or the
[`background-blend-mode`](https://developer.mozilla.org/docs/Web/CSS/background-blend-mode) properties.
The `mix-blend-mode` applies blending to a whole element
and the `background-blend-mode` applies blending to the background of an element.

You use `background-blend-mode` when you have multiple backgrounds on an element
and want them all to blend into each other.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWpEVGO'
} %}
</figure>

The `mix-blend-mode` affects the entire element,
including its pseudo-elements.
One use-case is in the initial example of a duotone image,
which has color layers applied to the element through its pseudo-elements.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgvYMG'
} %}
</figure>

Blend modes fall into two categories: separable and non-separable.
A separable blend mode considers each color component,
such as RGB, individually.
A non-separable blend mode considers all color components equally.

## Browser compatibility

### `mix-blend-mode`

{% BrowserCompat 'css.properties.mix-blend-mode' %}

### `background-blend-mode`

{% BrowserCompat 'css.properties.background-blend-mode' %}

## Separable blend modes

### Normal

This is the default blend mode and changes nothing about how an element blends with others.

### Multiply

The `multiply` blend mode is like stacking multiple transparencies on top of each other.
White pixels will appear transparent,
and black pixels will appear black.
Anything in between will multiply its luminosity (light) values.
This means lights get much lighter and darks,
darker—most often producing a darker result.

```css
.my-element {
  mix-blend-mode: multiply;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgRdOy',
  height: 450
} %}
</figure>

### Screen

Using `screen` multiplies the *light* values—an inverse effect to `multiply`,
and will most often produce a brighter result.

```css
.my-element {
  mix-blend-mode: screen;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjELpYo',
  height: 450
} %}
</figure>

### Overlay

This blend mode—`overlay`—combines `multiply` and `screen`.
Base dark colors become darker and base light colors become lighter.
Mid-range colors, such as a 50% gray, are unaffected.

```css
.my-element {
  mix-blend-mode: overlay;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BaprYom',
  height: 450
} %}
</figure>

### Darken

The `darken` blend mode compares the source image and backdrop image's dark color luminosity
and selects the darkest of the two.
It does this by comparing rgb values instead of luminosity (like `multiply` and `screen` would do),
for each color channel.
With `darken` and `lighten`, new color values are often created from this comparison process.

```css
.my-element {
  mix-blend-mode: darken;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyNmdGM',
  height: 450
} %}
</figure>

### Lighten

Using `lighten` does the exact opposite of `darken`.

```css
.my-element {
  mix-blend-mode: lighten;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWvQNO',
  height: 450
} %}
</figure>

### Color dodge

If you use `color-dodge`, it lightens the background color to reflect the source color.
Pure black colors see no effect from this mode.

```css
.my-element {
  mix-blend-mode: color-dodge;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpYqpz',
  height: 450
} %}
</figure>

### Color burn

The `color-burn` blend mode is very similar to the `multiply` blend mode,
but increases contrast, resulting in more saturated mid-tones and reduced highlights.

```css
.my-element {
  mix-blend-mode: color-burn;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'gOgevmG',
  height: 450
} %}
</figure>

### Hard light

Using `hard-light` creates a vivid contrast.
This blend mode either screens or multiplies luminosity values.
If the pixel value is lighter than 50% gray, the image is lightened,
as if it were screened. If it is darker, it's multiplied.

```css
.my-element {
  mix-blend-mode: hard-light;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ZELxreN',
  height: 450
} %}
</figure>

### Soft light

The `soft-light` blend mode is a less-harsh version of `overlay`.
It works in very much the same way with less contrast.

```css
.my-element {
  mix-blend-mode: soft-light;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWvQmQ',
  height: 450
} %}
</figure>

### Difference

A good way to picture how `difference` works is a bit like how a photo negative works.
The `difference` blend mode takes the difference value of each pixel,
inverting light colors.
If the color values are identical, they become black.
Differences in the values will invert.

```css
.my-element {
  mix-blend-mode: difference;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRxXwM',
  height: 450
} %}
</figure>

### Exclusion

Using `exclusion` is very similar to `difference`,
but instead of returning black for identical pixels,
it will return 50% gray, resulting in a softer output with less contrast.

```css
.my-element {
  mix-blend-mode: exclusion;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjELpmb',
  height: 450
} %}
</figure>

## Non-separable blend modes

You can think of these blend modes like HSL [color](/learn/css/color) components.
Each takes a specific component value from the active layer and mixes it with other component values.

### Hue

The `hue` blend mode takes the hue of the source color
and applies it to the saturation and luminosity of the backdrop color.

```css
.my-element {
  mix-blend-mode: hue;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BaprYGO'
} %}
</figure>

### Saturation

This works like `hue`,
but using `saturation` as the blend mode applies the saturation of the source color
to the hue and luminosity of the backdrop color.

```css
.my-element {
  mix-blend-mode: saturation;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdmQoP'
} %}
</figure>

### Color

The `color` blend mode will create a color from the hue and saturation of the source color
and the luminosity of the backdrop color.

```css
.my-element {
  mix-blend-mode: color;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOyzZRo'
} %}
</figure>

### Luminosity

Lastly, `luminosity` is the inverse of `color`.
It creates a color with the luminosity of the source color and the hue and saturation of the backdrop color.

```css
.my-element {
  mix-blend-mode: luminosity;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNWWOK'
} %}
</figure>

## The `isolation` property

{% BrowserCompat 'css.properties.isolation' %}

If you set the [`isolation`](https://developer.mozilla.org/docs/Web/CSS/isolation)
property to have a value of `isolate`,
it will create a new stacking context,
which will prevent it from blending with a backdrop layer.
As you learned in the [z-index module](/learn/css/z-index), when you create a new stacking context,
that layer becomes the base layer.
This means that parent-level blend modes will no longer apply,
but elements inside of an element with `isolation: isolate` set can _still_ blend.

Note that this doesn't work with `background-blend-mode`
because the background property is already isolated.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjELLXy'
} %}
</figure>

{% Assessment 'blend-modes' %}

# Borders

In the [box model](/learn/css/box-model) module,
we considered a frame analogy to describe each section of the box model.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/FBaaJXdnuSkvOx1nB0CB.jpg",
alt="Three picture frames next to each other.
The middle frame has the sections of the box model over the top of it",
width="800",
height="562" %}

The border box is the frame of your boxes,
and the `border` properties give you a huge array of options to create that frame in
nearly any style that you can think of.

## Border properties

The individual `border` properties provide a way to style the various parts of a border.

{% BrowserCompat 'css.properties.border' %}

### Style

For a border to appear,
you have to define the
[`border-style`](https://developer.mozilla.org/docs/Web/CSS/border-style).
There's a few options to choose from:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrvyxY'
} %}
</figure>

When using the `ridge`, `inset`, `outset` and `groove` styles,
the browser will darken the border color for the second shown color to provide contrast and depth.
This behaviour can vary between browsers,
especially for dark colors such as `black`.
In Chrome, these border styles will appear to be solid and in Firefox,
they will be lightened to then provide a darker second color.

Browser behaviour can vary for other border styles too,
so it's important to test your site in different browsers.
A common example of this difference is how each browser renders the `dotted` and `dashed`  styles.

<figure>
  {% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/ybLca9jmTgUtltTwfIpt.jpg",
  alt="The border demo in Chrome,
  Firefox and Safari which demonstrates the subtle differences
  in how the borders display",
  width="800",
  height="489" %}
  <figcaption>Borders displayed in Chrome, Firefox, and Safari.</figcaption>
</figure>

To set border style on each side of your box,
you can use
[`border-top-style`](https://developer.mozilla.org/docs/Web/CSS/border-top-style),
[`border-right-style`](https://developer.mozilla.org/docs/Web/CSS/border-right-style),
[`border-left-style`](https://developer.mozilla.org/docs/Web/CSS/border-left-style),
and [`border-bottom-style`](https://developer.mozilla.org/docs/Web/CSS/border-bottom-style).


### Shorthand

As with `margin` and `padding`,
you can use the
[`border`](https://developer.mozilla.org/docs/Web/CSS/border)
shorthand property to define all the parts of your border in one declaration.

```css
.my-element {
	border: 1px solid red;
}
```

The order of values in the `border` shorthand are `border-width`,
`border-style` and then, `border-color`.

### Color

You can set color on all sides of your box or on each individual side with
[`border-color`](https://developer.mozilla.org/docs/Web/CSS/border-color).
By default, it uses the box's current text color: `currentColor`.
This means that if you only declare border properties,
like width,
the color will be that computed value unless you explicitly set it.

```css
.my-element {
	color: blue;
	border: solid; /* Will be a blue border */
}

.my-element {
	color: blue;
	border: solid yellow;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgovoX'
} %}
</figure>


To set a border color on each side of your box,
use
[`border-top-color`](https://developer.mozilla.org/docs/Web/CSS/border-top-color),
[`border-right-color`](https://developer.mozilla.org/docs/Web/CSS/border-right-color),
[`border-left-color`](https://developer.mozilla.org/docs/Web/CSS/border-left-color) and
[`border-bottom-color`](https://developer.mozilla.org/docs/Web/CSS/border-bottom-color).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJvQVO'
} %}
</figure>

### Width

The width of a border is how thick the line is, and is controlled by
[`border-width`](https://developer.mozilla.org/docs/Web/CSS/border-width).
The default border width is `medium`.
This won't be visible unless you define a style, though.
You can use other named widths such as `thin` and `thick`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PoWKQxN'
} %}
</figure>

The `border-width` properties also accept a length unit such as
`px`, `em`, `rem` or `%`.
To set border width on each side of your box, use
[`border-top-width`](https://developer.mozilla.org/docs/Web/CSS/border-top-width),
[`border-right-width`](https://developer.mozilla.org/docs/Web/CSS/border-right-width),
[`border-left-width`](https://developer.mozilla.org/docs/Web/CSS/border-left-width) and
[`border-bottom-width`](https://developer.mozilla.org/docs/Web/CSS/border-bottom-width).

## Logical properties

In the
[Logical Properties](/learn/css/logical-properties) module you discovered how to refer to block flow and inline flow,
rather than explicit top, right, bottom or left sides.

You have this capability with borders, too:

```css
.my-element {
	border: 2px dotted;
	border-inline-end: 2px solid red;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRraBp'
} %}
</figure>

In this example, `.my-element` has all sides defined as having a `2px`,
dotted border that is the current text color.
The `inline-end` border is then defined as `2px`, solid and red.
This means that in left-to-right languages—like English—
the red border will be on the right side of the box.
In right-to-left languages—like Arabic—
the red border will be on the left side of the box.

Browser support is varied for logical properties in borders,
so make sure you check support before using.

## Border radius

To give a box rounded corners use the
[`border-radius`](https://developer.mozilla.org/docs/Web/CSS/border-radius) property.

```css
.my-element {
	border-radius: 1em;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'LYxjQoK'
} %}
</figure>

This shorthand adds a consistent border to each corner of your box.
As with the other border properties,
you can define the border radius for each side with
[`border-top-left-radius`](https://developer.mozilla.org/docs/Web/CSS/border-top-left-radius),
[`border-top-right-radius`](https://developer.mozilla.org/docs/Web/CSS/border-top-right-radius),
[`border-bottom-right-radius`](https://developer.mozilla.org/docs/Web/CSS/border-bottom-right-radius) and
[`border-bottom-left-radius`](https://developer.mozilla.org/docs/Web/CSS/border-bottom-left-radius).

You can also specify each corner's radius in the shorthand,
which follows the order: top left, top right, bottom right then bottom left.

```css
.my-element {
	border-radius: 1em 2em 3em 4em;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgovdK'
} %}
</figure>

By defining a single value for a corner,
you are using another shorthand because a border radius is split into two parts:
the vertical and horizontal sides.
This means that when you set `border-top-left-radius: 1em`,
you are setting the top-left-**top** radius and the top-left-**left** radius.

You can define both properties, per corner like this:

```css
.my-element {
	border-top-left-radius: 1em 2em;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNRqoPM'
} %}
</figure>

This adds a `border-top-left-top` value of `1em`,
and a `border-top-left-left` value of `2em`.
This converts the top left border radius into an elliptical radius,
rather than the default circular radius.

You can define these values in the `border-radius` shorthand,
using a `/` to define the elliptical values, after the standard values.
This enables you to get creative and make some complex shapes.

```css
.my-element {
	border: 2px solid;
  border-radius: 95px 155px 148px 103px / 48px 95px 130px 203px;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpyqeM'
} %}
</figure>

## Border images

You don't just have to use a stroke-based border in CSS.
You can also use any type of image, using
[`border-image`](https://developer.mozilla.org/docs/Web/CSS/border-image).
This shorthand property allows you to set the source image,
how that image is sliced, the image width,
how far the border is outset from the edge and how it should repeat.

```css
.my-element {
  border-image-source: url(https://assets.codepen.io/174183/border-image-frame.jpg);
  border-image-slice: 61 58 51 48;
  border-image-width: 20px 20px 20px 20px;
  border-image-outset: 0px 0px 0px 0px;
  border-image-repeat: stretch stretch;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNdWNX'
} %}
</figure>

The [`border-image-width`](https://developer.mozilla.org/docs/Web/CSS/border-image-width)
property is like `border-width`:
it is how you set the width of your border image.
The [`border-image-outset`](https://developer.mozilla.org/docs/Web/CSS/border-image-outset)
property lets you set the distance between your border image and the box that it wraps around.

### `border-image-source`

 The [`border-image-source`](https://developer.mozilla.org/docs/Web/CSS/border-image-source)
 (source of the border image) can be a `url` for any valid image, which includes CSS gradients.

```css
.my-element {
	border-image-source: url('path/to/image.png');
}

.my-element {
	border-image-source: linear-gradient(to bottom, #000, #fff);
}
```

### `border-image-slice`

The [`border-image-slice`](https://developer.mozilla.org/docs/Web/CSS/border-image-slice)
property is a useful property that allows you to slice an image into 9 parts, made up of 4 split lines.
It works like the `margin` shorthand where you define the top, right, bottom and left **offset value**.

```css
.my-element {
	border-image: url('image.jpg');
	border-image-slice: 61 58 51 48;
}
```

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/WETsTwhFSfl30VfyfMTA.png",
alt="The image used in the demo with the four slices shown with blue lines",
width="800",
height="380" %}

With the offset values defined,
you now have 9 sections of the image: 4 corners, 4 edges and a middle section.
The corners are applied to the corners of the element with the border image.
The edges are applied to the edges of that element.
The [`border-image-repeat`](https://developer.mozilla.org/docs/Web/CSS/border-image-repeat)
property defines how those edges fill their space and the
[`border-image-width`](https://developer.mozilla.org/docs/Web/CSS/border-image-width)
property controls the size of the slices.

Lastly, the `fill` keyword determines whether the middle section, left by the slicing, is used as the element's background image or not.

### `border-image-repeat`

[`border-image-repeat`](https://developer.mozilla.org/docs/Web/CSS/border-image-repeat)
is how you instruct CSS how you would like your border image to repeat.
It works the same as `background-repeat`.

- The initial value is `stretch`,
which stretches the source image to fill available space where possible.
- The `repeat` value tiles the source image's edges as many times as possible,
and may clip the edge regions to achieve this.
- The `round` value is the same as repeat,
but instead of clipping the image edge regions to fit as many as possible,
it stretches the image as well as repeating it to achieve a seamless repeat
- The `space` value is again, the same as repeat,
but this value adds space between each edge region to create a seamless pattern.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrvBYv'
} %}
</figure>

{% Assessment 'borders' %}

# Box Model

Say you have this bit of HTML:

```html
<p>I am a paragraph of text that has a few words in it.</p>
```

Then you write this CSS for it:

```css
p {
  width: 100px;
  height: 50px;
  padding: 20px;
  border: 1px solid;
}
```

The content would break out of your element and it would be 142px wide,
rather than 100px.
Why is that?
The box model is a core foundation of CSS and understanding how it works,
how it is affected by other aspects of CSS and importantly,
how you can control it will help you to write more predictable CSS.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNRemxN',
  height: 300
} %}
</figure>

A really important thing to remember when writing CSS,
or working on the web as a whole,
is that everything displayed by CSS is a box.
Whether that's a box that uses `border-radius` to look like a circle, or even just some text:
the key thing to remember is that it's all boxes.

## Content and sizing

Boxes have different behavior based on their `display` value,
their set dimensions, and the content that lives within them.
This content could be even more boxes—generated by child elements—or plain text content.
Either way, this content will affect the size of the box by default.

You can control this by using **extrinsic sizing**, or,
you can continue to let the browser make decisions for you based on the content size,
using **intrinsic sizing**.

Let's quickly look at the difference, using a demo to help us.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpoMBL'
} %}
  <figcaption>Notice that when the box is using extrinsic sizing,
  there's a limit of how much content you can add before it overflows out of the box's bounds.
  This makes the word, "awesome", overflow.</figcaption>
</figure>

The demo has the words, "CSS is awesome" in a box with fixed dimensions and a thick border.
The box has a width, so is extrinsically sized.
It controls the sizing of its child content.
The problem with this though, is that the word "awesome" is too large for the box,
so it overflows outside of the parent box's **border box** (more on this later in the lesson).
One way to prevent this overflow is to allow the box to be intrinsically sized by either
unsetting the width,
or in this case,
setting the `width` to be `min-content`.
The `min-content` keyword tells the box to only be as wide as the intrinsic minimum width of
its content (the word "awesome").
This allows the box to fit around "CSS is awesome", perfectly.

Let's look at something more complex to see the impact of different sizing on real content:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'wvgwOJV',
  height: 650
} %}
</figure>

Toggle intrinsic sizing on and off
to see how you can gain more control with extrinsic sizing and let the content have more control
with intrinsic sizing.
To see the effect that intrinsic and extrinsic sizing has,
add a few sentences of content to the card.
When this element is using extrinsic sizing,
there's a limit of how much content you can add before it overflows out of the element's bounds,
but this isn't the case when intrinsic sizing is toggled on.

By default, this element has a set `width` and `height`—both `400px`.
These dimensions give strict bounds to everything inside the element,
which will be honored unless the content is too large for the box in which case visible overflow
will happen.
You can see this in action by changing the content of the caption,
under the flower picture to something that exceeds the height of the box, which is a few lines of
content.

{% Aside "key-term" %}
When content is too big for the box it is in, we call this overflow.
You can manage how an element handles overflow content, using the `overflow` property.
{% endAside %}

When you switch to intrinsic sizing,
you are letting the browser make decisions for you,
based on the box's content size.
It's much more difficult for there to be overflow with intrinsic sizing because our box will resize
with its content,
rather than try to size the content.
It's important to remember that this is the default, flexible behavior of a browser.
Though extrinsic sizing gives more control on the surface,
intrinsic sizing provides the most flexibility, most of the time.

## The areas of the box model

Boxes are made up of distinct box model areas that all do a specific job.

<figure>
{% Img
  src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/ECuEOJEGnudhXW5JEFih.svg",
  alt="A diagram showing the four main areas of the box model - content box, padding box, border box and margin box",
  width="800",
  height="547"
%}
  <figcaption>The four main areas of the box model: content box, padding box, border box and
  margin box.</figcaption>
</figure>

You start with **content box**, which is the area that the content lives in.
As you learned before: this content can control the size of its parent,
so is usually the most variably sized area.

The **padding box** surrounds the content box
and is the space created by
the [`padding`](https://developer.mozilla.org/docs/Web/CSS/padding) property.
Because padding is inside the box, the background of the box will be visible in the space that
it creates.
If our box has overflow rules set, such as `overflow: auto` or `overflow: scroll`,
the scrollbars will occupy this space too.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BaReoEV'
} %}
</figure>

The **border box** surrounds the padding box and its space is occupied by the `border` value.
The border box is the bounds of your box and the **border edge** is the limit of what you can
visually see. The [`border`](https://developer.mozilla.org/docs/Web/CSS/border)
property is used to visually frame an element.

The final area, the **margin box**, is the space around your box,
defined by the `margin` rule on your box.
Properties such as
[`outline`](https://developer.mozilla.org/docs/Web/CSS/outline) and
[`box-shadow`](https://developer.mozilla.org/docs/Web/CSS/box-shadow)
occupy this space too because they are painted on top,
so they don't affect the size of our box.
You could have an `outline-width` of `200px` on our box and everything inside and including the
border box would be exactly the same size.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWprGea'
} %}
</figure>

## A useful analogy

The box model is complex to understand,
so let's recap what you've learned with an analogy.

<figure>
{% Img
  src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/FBaaJXdnuSkvOx1nB0CB.jpg",
  alt="Three photo frames",
  width="800",
  height="562"
%}
</figure>

In this diagram, you have three photo frames,
mounted to a wall, next to each other.
The diagram has labels that associate elements of the frame with the box model.

To break this analogy down:

- The content box is the artwork.
- The padding box is the white matte, between the frame and the artwork.
- The border box is the frame, providing a literal border for the artwork.
- The margin box is the space between each frame.
- The shadow occupies the same space as the margin box.

## Debugging the box model

Browser DevTools provide a visualisation of a selected box's box model calculations,
which can help you understand how the box model works and importantly,
how it is affecting the website you're working on.

Go ahead and try this in your own browser:

1. [Open DevTools](https://developer.chrome.com/docs/devtools/open/)
1. [Select an element](https://developer.chrome.com/docs/devtools/css/reference/#select)
1. Show the box model debugger

<figure>
{% Video src="video/VbAJIREinuYvovrBzzvEyZOpw5w1/sKdHrAfqahgWfDVQEBBT.mp4", controls=true %}
</figure>

## Controlling the box model

To understand how to control the box model,
you first need to understand what happens in your browser.

Every browser applies a user agent stylesheet to HTML documents.
The CSS used varies between each browser,
but they provide sensible defaults to make content easier to read.
They define how elements should look and behave if there's no CSS defined.
It is in the user agent styles where a box's default `display` is set, too.
For example, if we are in a normal flow, a `<div>` element's default `display` value is `block`,
a `<li>` has a default `display` value of `list-item`,
and a `<span>` has a default `display` value of `inline`.

An `inline` element has block margin,
but other elements won't respect it.
Use `inline-block`, and those elements will respect the block margin,
while the element maintains most of the same behaviors it had as an `inline` element.
A `block` item will, by default,
fill the available **inline space**,
whereas a `inline` and `inline-block` elements will only be as large as their content.

Alongside an understanding of how user agent styles affect each box,
you also need to understand `box-sizing`,
which tells our box how to calculate its box size.
By default, all elements have the following user agent style: `box-sizing: content-box;`.

Having `content-box` as the value of `box-sizing` means that when you set dimensions,
such as a `width` and `height`,
they will be applied to the **content box**.
If you then set `padding` and `border`,
these values will be added to the content box's size.

{% Assessment 'box-model' %}

The actual width of this box will be 260px.
As the CSS uses the default `box-sizing: content-box`,
the applied width is the width of the content,
`padding` and `border` on both sides are added to that.
So 200px for the content + 40px of padding + 20px of border makes a total visible width of 260px.

You _can_ control this, though,
by making the following modification to use the alternative box model, `border-box`:

```css/1
.my-box {
  box-sizing: border-box;
	width: 200px;
	border: 10px solid;
	padding: 20px;
}
```

This alternative box model tells CSS to apply the `width` to the border box instead of the
content box. This means that our `border` and `padding` get _pushed in_,
and as a result,
when you set `.my-box` to be `200px` wide: it actually renders at `200px` wide.

Check out how this works in the following interactive demo.
Notice that when you toggle the `box-sizing` value
it shows—via a blue background—which CSS is being applied _inside_ our box.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'oNBvVpM',
  height: 650
} %}
</figure>

```css
*,
*::before,
*::after {
  box-sizing: border-box;
}
```

This CSS rule selects every element in the document
and every `::before` and `::after` pseudo element and applies `box-sizing: border-box`.
This means that every element will now have this alternative box model.

Because the alternative box model can be more predictable,
developers often add this rule to resets and normalizers,
[like this one](https://piccalil.li/blog/a-modern-css-reset).

## Resources

- [Introduction to the box model](https://developer.mozilla.org/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model)
- [What are browser developer tools?](https://developer.mozilla.org/docs/Learn/Common_questions/What_are_browser_developer_tools)

### User agent stylesheets

- [Chromium](https://chromium.googlesource.com/chromium/blink/+/master/Source/core/css/html.css)
- [Firefox](https://searchfox.org/mozilla-central/source/layout/style/res/html.css)
- [Webkit](https://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css)

# Color

Color is an important part of any website and in CSS there are many options for color types,
functions and treatments.

How do you decide which color type to use?
How do you make your colors semi-transparent?
In this lesson,
you're going to learn which options you have to help you make the right decisions for your project and team.

CSS has [various different data types](https://developer.mozilla.org/docs/Web/CSS/CSS_Types),
such as strings and numbers.
Color is one of these types and uses other types,
such as numbers for its own definitions.

## Numeric colors

It is very likely that your first exposure to colors in CSS is via numeric colors.
We can work with numerical color values in a few different forms.

### Hex colors

```css
h1 {
  color: #b71540;
}
```

Hexadecimal notation (often shortened to hex) is a shorthand syntax for RGB,
which assigns a numeric value to red green and blue,
which are the three **primary colors**.

{% Aside %}
According to the Web Almanac,
[hex is the most popular color syntax type](https://almanac.httparchive.org/en/2019/css#color-types).
{% endAside %}

The hexadecimal ranges are **0-9** and **A-F**.
When used in a six digit sequence,
they are translated to the RGB numerical ranges which are 0-255
which correspond to the red, green, and blue color channels respectively.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BapNrPG',
  height: 430
} %}
</figure>

You can also define an alpha value with any numerical colors.
An alpha value is a percentage of transparency.
In hex code, you add another two digits to the six digit sequence,
making an eight digit sequence.
For example, to set black in hex code, write `#000000`.
To add a 50% transparency, change it to `#00000080`.

Because the hex scale is **0-9** and **A-F**, the transparency values are probably not quite what you'd expect them to be.
Here are some key, common values added to the black hex code, `#000000`:

- 0% alpha—which is fully transparent—is **00**: `#00000000`
- 50% alpha is **80**: `#00000080`
- 75% alpha is **BF**: `#000000BF`

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwPLXdr',
  height: 540
} %}
</figure>

To convert a two digit hex to a decimal,
take the first digit and multiply it by 16 (because hex is base 16),
then add the second digit. Using **BF** as an example for 75% alpha:

1. B is equal to 11, which when multiplied by 16 equals 176
1. F is equal to 15
1. 176 + 15 = 191
1. The alpha value is 191—75% of 255

{% Aside %}
You can also write hex codes in a three digit shorthand.
A three digit hex code is a shortcut to an equivalent six digit sequence.
For example, `#a4e` is identical to `#aa44ee`.
To add alpha, then `#a4e8` would expand to `#aa44ee88`.
{% endAside %}

### RGB (Red, Green, Blue)

```css
h1 {
  color: rgb(183, 21, 64);
}
```

RGB colors are defined with the
[`rgb()`](<https://developer.mozilla.org/docs/Web/CSS/color_value/rgb()>) color function,
using either numbers or percentages as parameters.
The numbers need to be within the **0-255** range and the percentages are between **0% and 100%‌**.
RGB works on the 0-255 scale,
so 255 would be equivalent to 100%, and 0 to 0%.

To set black in RGB, define it as `rgb(0 0 0)`,
which is zero red, zero green and zero blue.
Black can also be defined as `rgb(0%, 0%, 0%)`.
White is the exact opposite: `rgb(255, 255, 255)` or `rgb(100%, 100%, 100%)`.

An alpha is set in `rgb()` in one of two ways.
Either add a `/` **after** the red, green and blue parameters,
or use the [`rgba()`](<https://developer.mozilla.org/docs/Web/CSS/color_value/rgba()>) function.
The alpha can be defined with a percentage or a decimal between 0 and 1.
For example, to set a 50% alpha black in modern browsers, write: `rgb(0 0 0 / 50%)` or `rgb(0 0 0 / 0.5)`.
For wider support, using the `rgba()` function,
write: `rgba(0, 0, 0, 50%)` or `rgba(0, 0, 0, 0.5)`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyNomWW',
  height: 430
} %}
</figure>

{% Aside %}
Commas were removed from the `rgb()` and `hsl()` notation because newer color functions,
such as `lab()` and `lch()` use spaces instead of commas as a delimiter.
This change provides more consistency not just with newer color functions,
but with CSS in general.
For better backwards compatibility,
you can still use commas to define `rgb()` and `hsl()`.
{% endAside %}

### HSL (Hue, Saturation, Lightness)

```css
h1 {
  color: hsl(344, 79%, 40%);
}
```

HSL stands for hue, saturation and lightness.
Hue describes the value on the color wheel, from 0 to 360 degrees, starting with red (being both 0 and 360).
A hue of 180, or 50% would be in the blue range.
It's the origin of the color that we see.

{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/ob7MTste1Obu9AoLvbKq.svg", alt="A color wheel with labels for degree values in 60 degree increments to help visuals what each angle value represents", width="800", height="507" %}

Saturation is how vibrant the selected hue is.
A fully desaturated color (with a saturation of `0%`) will appear grayscale.
And finally, lightness is the parameter which describes the scale from white to black of added light.
A lightness of `100%` will always give you white.

Using the [`hsl()`](<https://developer.mozilla.org/docs/Web/CSS/color_value/hsl()>) color function,
you define a true black by writing `hsl(0 0% 0%)`, or even `hsl(0deg 0% 0%)`.
This is because the hue parameter defines the degree on the color wheel,
which if you use the number type, is **0-360**.
You can also use the angle type, which is (`0deg`) or `(0turn)`.
Both saturation and lightness are defined with percentages.

{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/RhVxWSZ6bH35eBdN6Prj.svg", alt="The HSL color function broken down visually. The hue uses the color wheel. The saturation shows grey blending into teal. The lightness shows black into white.", width="800", height="478" %}

{% Aside %}
[The angle type](https://developer.mozilla.org/docs/Web/CSS/angle)
in CSS is great for defining hue because it represents the angle of the color wheel really well.
This type accepts degrees, turns, radians and gradians.
{% BrowserCompat 'css.types.angle' %}
{% endAside %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRJLQo',
  height: 430
} %}
</figure>

Alpha is defined in `hsl()`,
in the same way as `rgb()` by adding a `/` after the hue, saturation and lightness parameters _or_ by using the
[`hsla()`](<https://developer.mozilla.org/docs/Web/CSS/color_value/hsla()>) function.
The alpha can be defined with a percentage or a decimal between 0 and 1.
For example, to set a 50% alpha black, use: `hsl(0 0% 0% / 50%)` or `hsl(0 0% 0% / 0.5)`.
Using the `hsla()` function, write: `hsla(0, 0%, 0%, 50%)` or `hsla(0, 0%, 0%, 0.5)`.

{% Aside %}
There are some newer color types coming to CSS.
These include [lab()](<https://developer.mozilla.org/docs/Web/CSS/color_value/lab()>)
and [lch()](<https://developer.mozilla.org/docs/Web/CSS/color_value/lch()>),
which allow a far wider range of color to be specified than is possible in RGB.
{% endAside %}

## Color Keywords

There are [148 named colors in CSS](https://developer.mozilla.org/docs/Web/CSS/color_value#color_keywords).
These are plain English names such as purple, tomato and goldenrod.
Some of the most popular names,
according to the [Web Almanac](https://almanac.httparchive.org/en/2019/css),
are black, white, red, blue and gray.
Our favorites include goldenrod, aliceblue, and hotpink.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ZELGraM'
} %}
</figure>

Aside from standard colors, there are also special keywords available:

- `transparent` is a fully transparent color.
  It is also the initial value of `background-color`
- `currentColor` is the contextual computed dynamic value of the `color` property.
  If you have a text color of `red` and then set the `border-color` to be `currentColor`, it will also be red.
  If the element that you define `currentColor` on doesn't have a value for `color` defined,
  `currentColor` will be computed by the cascade instead

{% Aside %}
System keywords are colors that are defined by your operating system theme.
Some examples of these colors are `Background`,
which is the desktop background color or `Highlight`,
which is the highlight color of selected items. These are just two of
[many options](https://www.w3.org/wiki/CSS/Properties/color/keywords#System_Colors).

All color keywords are case-insensitive,
however you will often see system colors with capitalization to differentiate them from standard color keywords.
{% endAside %}

## Where to use color in CSS rules

If a CSS property accepts the
[`<color>`](https://developer.mozilla.org/docs/Web/CSS/color_value) data type as a value,
it will accept any of the above methods of expressing color.
For styling text, use the `color`, `text-shadow` and `text-decoration-color` properties
which all accept color as the value or color as part of the value.

For backgrounds, you can set a color as the value for `background` or `background-color`.
Colors can also be used in gradients, such as `linear-gradient`.
Gradients are a type of image that can be programmatically defined in CSS.
Gradients accept two or more colors in any combination of color format, such as hex, rgb or hsl.

{% Aside %}
There's lots to learn with gradients so we wrote [a whole lesson](/learn/css/gradients) on how to use them.
{% endAside %}

Finally, `border-color`, and `outline-color` set the color for borders and outlines on your boxes.
The `box-shadow` property also accepts color as one of the values.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgdJKd'
} %}
</figure>

{% Assessment 'color' %}

## Resources

- [A handy demo showing how you can use angles with HSL](https://codepen.io/argyleink/pen/ExjReJa)
- [A comprehensive guide on color](https://css-tricks.com/nerds-guide-color-web/)
- [A comprehensive guide on wide gamut color](https://developer.chrome.com/articles/high-definition-css-color-guide/)
- [[video] An explainer on how to read hex codes](https://www.youtube.com/watch?v=eqZqx6lRPe0)
- [How hexadecimal codes work](https://medium.com/basecs/hexs-and-other-magical-numbers-9785bc26b7ee)

# Conclusion and next steps

Congratulations! You've made it to the end!
By now, you have learned _a lot_ about CSS,
and hopefully you feel more comfortable working with it than you did before.

You might be wondering where you can go from here.
One of the  best ways to learn is to learn by doing: try out your new CSS skills by building a website of your own.
To continue to build your CSS skillset, here are some additional resources to explore:

## Additional resources

- [CSS Documentation on MDN](https://developer.mozilla.org/docs/Web/CSS)
- [Listen to the CSS Podcast](https://thecsspodcast.libsyn.com)
- [CSS articles on web.dev](/tags/css/)
- [How To Learn CSS - Smashing Magazine](https://www.smashingmagazine.com/2019/01/how-to-learn-css/)
- [CSS-Tricks](https://css-tricks.com/tag/css/)
- [Layout Land - Youtube](https://www.youtube.com/channel/UC7TizprGknbDalbHplROtag)

## Brought to you by

{% include 'partials/authors-stack.njk' %}

# Filters

Say you need to build an element that's got a slightly opaque,
frosted glass effect that sits over the top of an image.
The text needs to be live text and not an image.
How do you do that?

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKaQLoL'
} %}
</figure>

A combination of CSS filters and the `backdrop-filter`
allow us to apply effects and blur what's needed in real time.
Blur and opacity are two of many available filters,
so let's have a quick run through what they all do and how to use them.

{% Aside %}
Take care when placing text over images,
that the text is still readable should the filter effect not be supported in a user's browser.
For example, at the moment
[`backdrop-filter`](https://developer.mozilla.org/docs/Web/CSS/backdrop-filter)
is not supported in Firefox,
and so you should check that Firefox users aren't left with text they cannot easily read:
{% BrowserCompat 'css.properties.backdrop-filter' %}
{% endAside %}

## The `filter` property

{% BrowserCompat 'css.properties.filter' %}

You can apply one or many of the following filters as a value for
[`filter`](https://developer.mozilla.org/docs/Web/CSS/filter).
If you incorrectly apply a filter,
the rest of the filters defined for `filter` will not work.

### `blur`

This applies a gaussian blur and the only argument you can pass is a `radius`,
which is
[how much blur is applied](https://dbaron.org/log/20110225-blur-radius).
This needs to be a length unit, like `10px`. Percentages are not accepted.

```css
.my-element {
	filter: blur(0.2em);
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwPQJwX',
  height: 450
} %}
</figure>

### `brightness`

{% BrowserCompat 'css.types.filter-function.brightness' %}

To increase or decrease the brightness of an element,
use the brightness function.
The brightness value is expressed as a percentage with the unchanged image being expressed as a value of 100%.
A value of 0% turns the image completely black,
therefore values between 0% and 100% make the image less bright.
Use values over 100% to increase the brightness.

```css
.my-element {
	filter: brightness(80%);
}
```

{% Aside %}
You can also use decimal values,
instead of percentage values in filters like `brightness`.
To set 80% brightness with a decimal, write `0.8`.
{% endAside %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKaQjpp',
  height: 450
} %}
</figure>

### `contrast`

{% BrowserCompat 'css.types.filter-function.contrast' %}

Set a value between 0% and 100% to decrease or increase the contrast, respectively.

```css
.my-element {
	filter: contrast(160%);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjJEOW',
  height: 450
} %}
</figure>

### `grayscale`

{% BrowserCompat 'css.types.filter-function.grayscale' %}

You can apply a completely grayscale effect by using `1` as a value for `grayscale()`,
or `0` to have a completely saturated element.
You can also use percentage or decimal values to only apply a partial grayscale effect.
If you pass no arguments, the element will be completely grayscale.
If you pass a value greater than 100%, it will be capped at 100%.

```css
.my-element {
	filter: grayscale(80%);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJQMKe',
  height: 450
} %}
</figure>

### `invert`
{% BrowserCompat 'css.types.filter-function.invert' %}

Just like `grayscale`,
you can pass `1` or `0` to the `invert()` function to turn it on or off.
When it is on, the element's colors are completely inverted.
You can also use percentage or decimal values to only apply a partial inversion of colors.
If you don't pass any arguments into the `invert()` function,
the element will be completely inverted.

```css
.my-element {
	filter: invert(1);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgvdOO',
  height: 450
} %}
</figure>

### `opacity`

{% BrowserCompat 'css.types.filter-function.opacity' %}

The `opacity()` filter works just like the `opacity` property,
where you can pass a number or percentage to increase or reduce opacity.
If you pass no arguments, the element is fully visible.

```css
.my-element {
	filter: opacity(0.3);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'RwKQzae',
  height: 450
} %}
</figure>

### `saturate`

{% BrowserCompat 'css.types.filter-function.saturate' %}

The saturate filter is very similar to the `brightness` filter and accepts the same argument:
number or percentage.
Instead of increasing or decreasing the brightness effect,
`saturate` increases or decreases color saturation.

 ```css
.my-element {
	filter: saturate(155%);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BapYgQg',
  height: 450
} %}
</figure>

### `sepia`

{% BrowserCompat 'css.types.filter-function.sepia' %}

You can add a sepia tone effect with this filter that works like `grayscale()`.
The sepia tone is a photographic printing technique that converts black tones to brown tones to warm them up.
You can pass a number or percentage as the argument for `sepia()`
which increases or decreases the effect.
Passing no arguments adds a full sepia effect (equivalent to `sepia(100%)`).

```css
.my-element {
	filter: sepia(70%);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNRMqpb',
  height: 450
} %}
</figure>

### `hue-rotate`

{% BrowserCompat 'css.types.filter-function.hue-rotate' %}

You learned about how the hue in `hsl` references a rotation of the color wheel in the
[colors lesson](/learn/css/color) and this filter works in a similar way.
If you pass an angle, such as degrees or turns,
it shifts the hue of all the element's colors,
changing the part of the color wheel it references. If you pass no argument, it does nothing.

```css
.my-element {
	filter: hue-rotate(120deg);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExZQBWw',
  height: 450
} %}
</figure>

### `drop-shadow`

{% BrowserCompat 'css.types.filter-function.drop-shadow' %}

You can apply a curve-hugging drop shadow like you would in a design tool,
such as Photoshop with
[`drop-shadow`](https://developer.mozilla.org/docs/Web/CSS/filter-function/drop-shadow()).
This shadow is applied to an alpha mask which makes it very useful for adding a shadow to a cutout image.
The `drop-shadow` filter takes a shadow parameter which contains space separated offset-x, offset-y, blur and color values.
It is almost identical to `box-shadow`,
but the `inset` keyword and spread value are not supported.

```css
.my-element {
	filter: drop-shadow(5px 5px 10px orange);
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PoWQrJr',
  height: 450
} %}
</figure>

Learn more about the different types of shadows in the [shadows](/learn/css/shadows) module.

### `url`

{% BrowserCompat 'svg.elements.filter' %}

The `url` filter allows you to apply an SVG filter from a linked SVG element or file.
You can
[read more about SVG filters here](https://developer.mozilla.org/docs/Web/SVG/Element/filter)

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRNgyp',
  height: 450
} %}
</figure>

## Backdrop filter

{% BrowserCompat 'css.properties.backdrop-filter' %}

The [backdrop-filter](https://developer.mozilla.org/docs/Web/CSS/backdrop-filter)
property accepts all of the same filter function values as `filter`.
The difference between `backdrop-filter` and `filter`
is that the `backdrop-filter` property only applies the filters to the background,
where the `filter` property applies it to the whole element.

The example right at the start of this lesson is the perfect example,
because you don't want the text to be blurred and ideally you don't want to have to add extra HTML elements.
Being able to apply filters only to the backdrop enables that.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKaQLoL'
} %}
</figure>

{% Assessment 'filters' %}

# Flexbox

A design pattern that can be tricky in responsive design is a sidebar that sits inline with some
content. Where there is viewport space,
this pattern works great,
but where space is condensed,
that rigid layout can become problematic.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRENWv',
  height: 420
} %}
</figure>

The Flexible Box Layout Model (flexbox) is a layout model designed for one-dimensional content.
It excels at taking a bunch of items which have different sizes,
and returning the best layout for those items.

This is the ideal layout model for this sidebar pattern.
Flexbox not only helps lay the sidebar and content out inline,
but where there's not enough space remaining, the sidebar will break onto a new line.
Instead of setting rigid dimensions for the browser to follow,
with flexbox,
you can instead provide flexible boundaries to hint how the content could display.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxgERMp',
  height: 400
} %}
</figure>

## What can you do with a flex layout?

Flex layouts have the following features,
which you will be able to explore in this guide.

- They can display as a row, or a column.
- They respect the writing mode of the document.
- They are single line by default,
  but can be asked to wrap onto multiple lines.
- Items in the layout can be visually reordered,
  away from their order in the DOM.
- Space can be distributed inside the items,
  so they become bigger and smaller according to the space available in their parent.
- Space can be distributed around the items and flex lines in a wrapped layout,
  using the Box Alignment properties.
- The items themselves can be aligned on the cross axis.

## The main axis and the cross axis

The key to understanding flexbox is to understand the concept of a main axis and a cross axis.
The main axis is the one set by your `flex-direction` property.
If that is `row` your main axis is along the row,
if it is `column` your main axis is along the column.

<figure>
{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/xKtf0cHRw0xQyiyYuuyz.svg",
alt="Three boxes next to each other with an arrow, pointing left to right. The arrow is labelled Main axis",
width="800",
height="320"
%}
</figure>

Flex items move as a group on the main axis.
Remember: we've got a bunch of things and we are trying to get the best layout for them as a group.

The cross axis runs in the other direction to the main axis,
so if `flex-direction` is `row` the cross axis runs along the column.

<figure>
{% Img
  src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/5wCsZcBmK5L33LS7nOmP.svg", alt="Three boxes of different heights, next to each other with an arrow, pointing left to right. The arrow is labelled Main axis. There's another arrow pointing top to bottom. This one is labelled Cross axis", width="800", height="320" %}
</figure>

You can do two things on the cross axis.
You can move the items individually or as a group, so they align against each other and the flex
container. Also, if you have wrapped flex lines,
you can treat those lines as a group to control how space is assigned to those lines.
You will see how this all works in practice throughout this guide,
for now just keep in mind that the main axis follows your `flex-direction`.

## Creating a flex container

Let's see how flexbox behaves by taking a group of different sized items and using flexbox to lay
them out.

```html
<div class="container" id="container">
  <div>One</div>
  <div>Item two</div>
  <div>The item we will refer to as three</div>
</div>
```

To use flexbox you need to declare that you want to use a flex formatting context and not regular
block and inline layout.
Do this by changing the value of the `display` property to `flex`.

```css
.container {
  display: flex;
}
```

As you learned in the [layout guide](/learn/css/layout) this will give you a block-level box,
with flex item children.
The flex items immediately start exhibiting some flexbox behavior, using their **initial values**.

{% Aside %}
All CSS properties have initial values which control how they behave "out of the box"
when you haven't applied any CSS to change that initial behavior.
The children of our flex container become flex items as soon as their parent gets
`display: flex`, so these initial values mean that we start seeing some flexbox behavior.
{% endAside %}

The initial values mean that:

- Items display as a row.
- They do not wrap.
- They do not grow to fill the container.
- They line up at the start of the container.

## Controlling the direction of items

Even though you haven't added a `flex-direction` property yet,
the items display as a row because the initial value of `flex-direction` is `row`.
If you want a row then you don't need to add the property.
To change the direction, add the property and one of the four values:

- `row`: the items lay out as a row.
- `row-reverse:` the items lay out as a row from the end of the flex container.
- `column`: the items lay out as a column.
- `column-reverse` : the items lay out as a column from the end of the flex container.

You can try out all of the values using our group of items in the demo below.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgKNXq'
} %}
</figure>

### Reversing the flow of items and accessibility

You should be cautious when using any properties that reorder the visual display
away from how things are ordered in the HTML document,
as it can negatively impact accessibility.
The `row-reverse` and `column-reverse` values are a good example of this.
The reordering only happens for the visual order, not the logical order.
This is important to understand as the logical order is the order that a screen reader will read out
the content,
and anyone navigating using the keyboard will follow.

You can see in the following video how in a reversed column layout,
tabbing between links becomes disconnected as the keyboard navigation follows the DOM not the visual
display.

{% Video
  src="video/VbAJIREinuYvovrBzzvEyZOpw5w1/IgpaIRZd7kOq8sd46eaR.mp4",
  autoplay=true,
  controls=true
%}

Anything which can change the order of items in flexbox or grid can cause this problem.
Therefore any reordering should include thorough testing to check that it will not make your site
hard to use for some people.

For more information see:

- [Content reordering](/content-reordering/)
- [Flexbox and the keyboard navigation disconnect](https://tink.uk/flexbox-the-keyboard-navigation-disconnect/)

### Writing modes and direction

Flex items lay out as a row by default.
A row runs in the direction that sentences flow in your writing mode and script direction.
This means that if you are working in Arabic,
which has a right-to-left (rtl) script direction, the items will line up on the right.
Tab order would also begin on the right as this is the way sentences are read in Arabic.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExZgwWN'
} %}
</figure>

If you are working with a vertical writing mode,
like some Japanese typefaces, then a row will run vertically, from top to bottom.
Try changing the `flex-direction` in this demo which is using a vertical writing mode.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBRaPXX',
  height: 600
} %}
</figure>

Therefore the way flex items behave by default is linked to the writing mode of the document.
Most tutorials are written using English, or another horizontal,
left to right writing mode.
This would make it easy to assume that flex items line up **on the left**, and run **horizontally**.

With the main and cross axis plus the writing mode to consider,
the fact that we talk about **start** and **end** rather than top, bottom, left, and right in
flexbox might be easier to understand.
Each axis has a start and an end.
The start of the main axis is referred to as **main-start**.
So our flex items initially line up from main-start.
The end of that axis is **main-end**.
The start of the cross axis is **cross-start** and the end **cross-end**.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/uSH4TxRv8KNQDTK7Vn8h.svg",
alt="A labelled diagram of the above terms",
width="800",
height="382" %}

## Wrapping flex items

The initial value of the `flex-wrap` property is `nowrap`.
This means that if there is not enough space in the container the items will overflow.

<figure>
{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/VTUdLS9PeBziBvbOSc4q.jpg",
alt="A flex container with nine items inside it, the items have shrunk down so one word is on a line
but there is not enough room to show them side by side so the flex items have extended outside the
box of the container.",
width="800",
height="282" %}
  <figcaption>
  Once they hit min-content size flex items will start to overflow their container
  </figcaption>
</figure>

Items displaying using the initial values will shrink as small as they can,
down to the `min-content` size before overflow happens.

To cause the items to wrap add `flex-wrap: wrap` to the flex container.

```css
.container {
  display: flex;
  flex-wrap: wrap;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNRGdNZ',
  height: 601
} %}
</figure>

When a flex container wraps it creates multiple **flex lines**.
In terms of space distribution,
each line acts like a new flex container.
Therefore if you are wrapping rows,
it is not possible to get something in row 2 to line up with something above it in row 1.
This is what is meant by flexbox being one-dimensional.
You can control alignment in one axis, a row or a column,
not both together as we can do in grid.

### The flex-flow shorthand

You can set the `flex-direction` and `flex-wrap` properties using the shorthand `flex-flow`.
For example, to set `flex-direction` to `column` and allow items to wrap:

```css
.container {
  display: flex;
  flex-flow: column wrap;
}
```

## Controlling space inside flex items

Assuming our container has more space than is needed to display the items,
the items line up at the start and do not grow to fill the space.
They stop growing at their max-content size.
This is because the initial value of the `flex-` properties is:

- `flex-grow: 0`: items do not grow.
- `flex-shrink: 1`: items can shrink smaller than their [`flex-basis`](https://developer.mozilla.org/docs/Web/CSS/flex-basis).
- `flex-basis: auto`: items have a base size of `auto`.

This can be represented by a keyword value of `flex: initial`.
The `flex` shorthand property,
or the longhands of `flex-grow`, `flex-shrink` and `flex-basis` are applied to the children of the
flex container.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'LYxRebE'
} %}
</figure>

To cause the items to grow,
while allowing large items to have more space than small ones use `flex:auto`.
You can try this using the demo above.
This sets the properties to:

- `flex-grow: 1`: items can grow larger than their `flex-basis`.
- `flex-shrink: 1`: items can shrink smaller than their `flex-basis`.
- `flex-basis: auto`: items have a base size of `auto`.

Using `flex: auto` will mean that items end up different sizes,
as the space that is shared between the items is shared out _after_ each item is laid out as
max-content size.
So a large item will gain more space.
To force all of the items to be a consistent size and ignore the size of the content change
`flex:auto` to `flex: 1` in the demo.

This unpacks to:

- `flex-grow: 1`: items can grow larger than their `flex-basis`.
- `flex-shrink: 1`: items can shrink smaller than their `flex-basis`.
- `flex-basis: 0`: items have a base size of `0`.

Using `flex: 1` says that all items have zero size,
therefore all of the space in the flex container is available to be distributed.
As all items have a `flex-grow` factor of `1` they all grow equally and the space is shared equally.

{% Aside %}
There is also a value of `flex: none`,
which will give you inflexible flex items that do not grow or shrink.
This might be useful if you are purely using flexbox to access the alignment properties but don't
want any flexible behavior.
{% endAside %}

### Allowing items to grow at different rates

You don't have to give all items a `flex-grow` factor of `1`.
You could give your flex items different `flex-grow` factors.
In the demo below the first item has `flex: 1`, the second `flex: 2` and third `flex: 3`.
As these items grow from `0` the available space in the flex container is shared into six.
One part is given to the first item,
two parts to the second,
three parts to the third.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWRzEz'
} %}
</figure>

You can do the same thing from a `flex-basis` of `auto`, though you will need to specify the three
values.
The first value being `flex-grow`,
the second `flex-shrink`,
and the third `flex-basis`.

```css
.item1 {
  flex: 1 1 auto;
}

.item2 {
  flex: 2 1 auto;
}
```

This is a less common use case as the reason to use a `flex-basis` of `auto`
is to allow the browser to figure out space distribution.
If you wanted to cause an item to grow a little more than the algorithm decides however it might be
useful.

## Reordering flex items

Items in your flex container can be reordered using the `order` property.
This property allows the ordering of items in **ordinal groups**.
Items are laid out in the direction dictated by `flex-direction`,
lowest values first.
If more than one item has the same value it will be displayed with the other items with that value.

The example below demonstrates this ordering.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdRXoL'
} %}
</figure>

{% Aside 'warning' %}
Using `order` has the same problems as the `row-reverse` and `column-reverse`
values of `flex-direction`.
It would be very easy to create a disconnected experience for some users.
Do not use `order` because you are fixing things being out of order in the document.
If the items logically should be in a different order, change your HTML!
{% endAside %}

{% Assessment 'flex' %}

## Flexbox alignment overview

Flexbox brought with it a set of properties for aligning items and distributing space between items.
These properties were so useful they have since been moved into their own specification,
you'll encounter them in Grid Layout too.
Here you can find out how they work when you are using flexbox.

The set of properties can be placed into two groups.
Properties for space distribution, and properties for alignment.
The properties which distribute space are:

- `justify-content`: space distribution on the main axis.
- `align-content`: space distribution on the cross axis.
- `place-content`: a shorthand for setting both of the above properties.

The properties used for alignment in flexbox:

- `align-self`: aligns a single item on the cross axis.
- `align-items`: aligns all of the items as a group on the cross axis.

If you are working on the main axis then the properties begin with `justify-`.
On the cross axis they begin with `align-`.

## Distributing space on the main axis

With the HTML used earlier, the flex items laid out as a row, there is space on the main axis.
The items are not big enough to completely fill the flex container.
The items line up at the start of the flex container because the initial value of `justify-content`
is `flex-start`.
The items line up at the start and any extra space is at the end.

Add the `justify-content` property to the flex container,
give it a value of `flex-end`,
and the items line up at the end of the container and the spare space is placed at the start.

```css
.container {
  display: flex;
  justify-content: flex-end;
}
```

You can also distribute the space between the items with `justify-content: space-between`.

Try some of the values in the demo,
and [see MDN](https://developer.mozilla.org/docs/Web/CSS/justify-content) for the full set of
possible values.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjERpGb'
} %}
</figure>

{% Aside %}
For the `justify-content` property to do anything you have to have spare space in your container on
the main axis.
If your items fill the axis then there is no space to share out so the property won't do anything.
{% endAside %}

### With `flex-direction: column`

If you have changed your `flex-direction` to `column` then `justify-content` will work on
the column.
To have spare space in your container when working as a column you need to give your container a
`height` or `block-size`.
Otherwise you won't have spare space to distribute.

Try the different values, this time with a flexbox column layout.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgwLgz',
  height: 600
} %}
</figure>

## Distributing space between flex lines

With a wrapped flex container you might have space to distribute on the cross axis.
In this case you can use the `align-content` property with the same values as `justify-content`.
Unlike `justify-content` which aligns items to `flex-start` by default,
the initial value of `align-content` is `stretch`.
Add the property `align-content` to the flex container to change that default behavior.

```css
.container {
  align-content: center;
}
```

Try this out in the demo.
The example has wrapped lines of flex items,
and the container has a `block-size` in order that we have some spare space.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poREawo'
} %}
</figure>

### The `place-content` shorthand

To set both `justify-content` and `align-content` you can use `place-content` with one
or two values.
A single value will be used for both axes,
if you specify both the first is used for `align-content` and the second for `justify-content`.

```css
.container {
  place-content: space-between;
  /* sets both to space-between */
}

.container {
  place-content: center flex-end;
  /* wrapped lines on the cross axis are centered,
  on the main axis items are aligned to the end of the flex container */
}
```

## Aligning items on the cross-axis

On the cross axis you can also align your items within the flex line using `align-items`
and `align-self`.
The space available for this alignment will depend on the height of the flex container,
or flex line in the case of a wrapped set of items.

The initial value of `align-self` is `stretch`,
which is why flex items in a row stretch to the height of the tallest item by default.
To change this, add the `align-self` property to any of your flex items.

```css
.container {
  display: flex;
}

.item1 {
  align-self: flex-start;
}
```

Use any of the following values to align the item:

- `flex-start`
- `flex-end`
- `center`
- `stretch`
- `baseline`

See [the full list of values on MDN](https://developer.mozilla.org/docs/Web/CSS/align-self).

The next demo has a single line of flex items with `flex-direction: row`.
The last item defines the height of the flex container.
The first item has the `align-self` property with a value of `flex-start`.
Try changing the value on that property to see how it moves within its space on the cross axis.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'RwKGQee',
  height: 600
} %}
</figure>

The `align-self` property is applied to individual items.
The `align-items` property can be applied to the flex container
to set all of the individual `align-self` properties as a group.

```css
.container {
  display: flex;
  align-items: flex-start;
}
```

In this next demo try changing the value of `align-items` to align all of the items on the cross
axis as a group.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdKmby',
  height: 600
} %}
</figure>

## Why is there no justify-self in flexbox?

Flex items act as a group on the main axis.
So there is no concept of splitting an individual item out of that group.

In grid layout the `justify-self` and `justify-items` properties work on the inline axis
to do alignment of items on that axis within their grid area.
Due to the way that flex layouts treat items as a group,
these properties are not implemented in a flex context.

It is worth knowing that flexbox does work very nicely with auto margins.
If you come across a need to split off one item from a group,
or separate the group into two groups you can apply a margin to do this.
In the example below the last item has a left margin of `auto`.
The auto margin absorbs all space in the direction it is applied.
This means that it pushes the item over to the right, thus splitting the groups.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRELbR'
} %}
</figure>

## How to center an item vertically and horizontally

The alignment properties can be used to center an item inside another box.
The `justify-content` property aligns the item on the main axis,
which is row. The `align-items` property on the cross axis.

```css
.container {
  width: 400px;
  height: 300px;
  display: flex;
  justify-content: center;
  align-items: center;
}
```

{% Aside %}
In the future we may be able to do this alignment without needing to make the parent a
flex container.
The alignment properties are specified for block and inline layout.
At present no browser has implemented these.
However, switching into a flex formatting context gives you access to the properties.
If you need to align something it's a great way to do it.
{% endAside %}

{% Assessment 'conclusion' %}

## Resources

- [MDN CSS Flexible Box Layout](https://developer.mozilla.org/docs/Web/CSS/CSS_Flexible_Box_Layout) includes a series of detailed guides with examples.
- [CSS Tricks Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
- [What Happens When You Create a Flexbox Flex Container](https://www.smashingmagazine.com/2018/08/flexbox-display-flex-container/)
- [Everything You Need To Know About Alignment In Flexbox](https://www.smashingmagazine.com/2018/08/flexbox-alignment/)
- [How Big Is That Flexible Box?](https://www.smashingmagazine.com/2018/09/flexbox-sizing-flexible-box/)
- [Use Cases For Flexbox](https://www.smashingmagazine.com/2018/10/flexbox-use-cases/)
- [Inspect and debug CSS Flexbox layouts in Chrome DevTools](https://developer.chrome.com/docs/devtools/css/flexbox/)

# Focus

On your webpage,
you click a link that skips the user to the main content of the website.
These are often referred to as skip links, or anchor links.
When that link is activated by a keyboard, using the *tab* and *enter* keys,
the main content container has a focus ring around it. Why is that?

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRWRjp'
} %}
</figure>

This is because the `<main>` has a `tabindex="-1"` attribute value,
which means it can be programmatically focused.
When the `<main>` is targeted—because the `#main-content`
in the browser URL bar matches the `id`—it receives programmatic focus.
It's tempting to remove the focus styles in these situations,
but handling focus appropriately and with care helps to create a good,
accessible, user experience.
It can also be a great place to add some interest to interactions.

## Why is focus important?

As a web developer,
it's your job to make a website accessible and inclusive to all.
Creating accessible focus states with CSS is a part of this responsibility.

Focus styles assist people who use a device such as a keyboard or a
[switch control](https://www.24a11y.com/2018/i-used-a-switch-control-for-a-day/)
to navigate and interact with a website.
If an element receives focus and there is no visual indication,
a user may lose track of what is in focus.
This can create navigation issues and result in unwanted behaviour if,
say, the wrong link is followed.

{% Aside %}
Learn more about the importance of focus for accessibility in [Learn Accessibility: Focus](/learn/accessibility/focus/), 
and more information on how to manage focus in HTML in [Learn HTML: Focus](/learn/html/focus/).
{% endAside%}

## How elements get focus

Certain elements are automatically focusable;
these are elements that accept interaction and input, such as `<a>`,
`<button>`, `<input>` and `<select>`.
In short, all form elements, buttons and links.
You can typically navigate a website's focusable elements using the *tab* key to move forward on the page, and *shift* + *tab* to move backward.

There is also a HTML attribute called `tabindex` which allows you to change the tabbing index—which is
order in which elements are focused—every time someone presses their <kbd>tab</kbd> key,
or focus is shifted with a hash change in the URL or by a JavaScript event.
If `tabindex` on a HTML element is set to `0`,
it can receive focus via the <kbd>tab</kbd> key and it will honour the global tab index,
which is defined by the document source order.

If you set `tabindex` to `-1`, it can only receive focus programmatically,
which means only when a JavaScript event happens
or a hash change (matching the element's `id` in the URL) occurs.
If you set `tabindex` to be anything higher than `0`,
it will be removed from the global tab index,
defined by document source order.
Tabbing order will now be defined by the value of `tabindex`,
so an element with `tabindex="1"` will receive focus before an element with `tabindex="2"`, for example.

{% Aside 'warning' %}
Honoring document source order is really important,
and focus order should only be changed if you **absolutely have to change it**.
This applies both when setting `tabindex` **and** changing visual order with CSS layout,
such as flexbox and grid.
Anything that creates unpredictable focus on the web
can create an inaccessible experience for the user.
{% endAside %}

## Styling focus

The default browser behavior when an element receives focus is to present a focus ring.
This focus ring varies between both browser and operating systems.

{% Video
  src="video/VbAJIREinuYvovrBzzvEyZOpw5w1/zVu8FoqteYCP1sTj3uCm.mp4",
  controls="true",
  autoplay="true"
%}

This behavior can be changed with CSS,
using the `:focus`, `:focus-within` and `:focus-visible`
pseudo-classes that you learned about in the
[pseudo-classes lesson](/learn/css/pseudo-classes).
It is important to set a focus style which has **contrast** with the default style of an element.
For example, a common approach is to utilize the `outline` property.

```css
a:focus {
  outline: 2px solid slateblue;
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ZELXLMw'
} %}
</figure>

The `outline` property could appear too close to the text of a link,
but the `outline-offset` property can help with that,
as it adds extra visual `padding` without affecting the geometric size that the element fills.
A positive number value for `outline-offset` will push the outline outwards,
a negative value will pull the outline inwards.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxgXgQx'
} %}
</figure>

Currently in some browsers,
if you have a `border-radius` set on your element and use `outline`,
it won't match—the outline will have sharp corners.
Due to this,
it is tempting to use a `box-shadow` with a small blur radius because `box-shadow` clips to the shape,
honouring `border-radius`,
but **this style will not show in Windows High Contrast Mode**.
This is because Windows High Contrast Mode doesn't apply shadows,
and mostly ignores background images to favor the user's preferred settings.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgogyM'
} %}
</figure>


{% Video src="video/VbAJIREinuYvovrBzzvEyZOpw5w1/MqMoKpLJ2rF5RRkn5jEO.mp4" %}

## In summary

Creating a focus state that has contrast with an element's default state is incredibly important. The default browser styles do this already for you, but if you want to change this behaviour, remember the following:

- Avoid using `outline: none` on an element that can receive keyboard focus.
- Avoid replacing `outline` styles with `box-shadow`.
as they don't show up in Windows High Contrast Mode.
- Only set a positive value for `tabindex` on an HTML element if you absolutely have to.
- Make sure the focus state is very clear vs the default state.

{% Assessment 'focus' %}

# Functions

So far in this course, you've been exposed to several CSS functions.
In the [grid](/learn/css/grid) module,
you were introduced to `minmax()` and `fit-content()`,
which help you size elements.
In the [color](/learn/css/color) module,
you were introduced to `rgb()`, and `hsl()`, which help you define colors.

Like many other programming languages,
[CSS has **a lot** of built-in functions](https://developer.mozilla.org/docs/Web/CSS/CSS_Functions)
that you can access whenever you need them.

Every CSS function has a specific purpose,
in this lesson, you'll get  a high-level overview,
giving you a much better understanding of where and how to use them.

## What is a function?

A function is a named, self-contained piece of code that completes a specific task.
A function is named so you can call it within your code and you can pass data into the function.
This is known as passing arguments.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/OCUXCuKLxHwZYFIIErUd.svg",
alt="A diagram of a function as described above",
width="800",
height="311" %}

A lot CSS functions are *pure functions*,
which means that if you pass the same arguments into them,
they will always give you the same result back,
regardless of what is happening in the rest of your code.
These functions will often re-compute as values change in your CSS,
similar to other elements in the language,
such as computed cascaded values like `currentColor`.

In CSS, you can only use the provided functions,
rather than write your own,
but functions can be nested within each other in some contexts,
giving them more flexibility.
We'll cover that in more detail, later in this module.

## Functional selectors

```css
.post :is(h1, h2, h3) {
	line-height: 1.2;
}
```

You learned about functional selectors in the
[pseudo-classes module](/learn/css/pseudo-classes)
which detailed functions like
[`:is()`](https://developer.mozilla.org/docs/Web/CSS/:is) and
[`:not()`](https://developer.mozilla.org/docs/Web/CSS/:not).
The arguments passed into these functions are CSS selectors,
which are then evaluated.
If there is a match with elements,
the rest of the **CSS rule** will be applied to them.

## Custom properties and `var()`

```css
:root {
	--base-color: #ff00ff;
}

.my-element {
	background: var(--base-color);
}
```

A custom property is a variable which allows you to tokenize values in your CSS code.
[Custom properties are also affected by the cascade](https://piccalil.li/tutorial/getting-started-with-css-custom-properties/)
which means they can be contextually manipulated or redefined.
A custom property must be prefixed with two dashes (`--`) and are case sensitive.

The [`var()`](https://developer.mozilla.org/docs/Web/CSS/var())
function takes one required argument:
the custom property that you are trying to return as a value.
In the above snippet, the `var()` function has `--base-color` passed as an argument.
If `--base-color` is defined, then `var()` will return the value.

```css
.my-element {
	background: var(--base-color, hotpink);
}
```

You can also pass a fallback declaration value into the `var()` function.
This means that if `--base-color` can't be found,
the passed **declaration** will be used instead, which in this sample's case is the `hotpink` color.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNPOjP',
  tab: 'css,result',
  height: 250
} %}
</figure>

## Functions that return a value

The `var()` function is just one of the CSS functions that return a value.
Functions like
[`attr()`](https://developer.mozilla.org/docs/Web/CSS/attr()) and
[`url()`](https://developer.mozilla.org/docs/Web/CSS/url()) follow a similar structure to `var()`—
you pass one or more arguments and use them on the **right side** of your CSS declaration.

```css
a::after {
  content: attr(href);
}
```

The `attr()` function here
is taking the content of the `<a>` element's `href` attribute
and setting it as the `content` of the `::after` pseudo-element.
If the value of the `<a>` element's `href` attribute was to change,
this would automatically be reflected in this `content` attribute.

```css
.my-element {
	background-image: url('/path/to/image.jpg');
}
```

The `url()` function takes a **string** URL and is used to load images, fonts and content.
If a valid URL isn't passed in or the resource that the URL points to can't be found,
nothing will be returned by the `url()` function.

## Color functions

You learned all about color functions in the [color](/learn/css/color) module.
If you haven't read that one yet, it is strongly recommended that you do.

Some available color functions in CSS are
`rgb()`, `rgba()`, `hsl()`, `hsla()`, `hwb()`, `lab()` and `lch()`.
All of these have a similar form where configuration arguments are passed in and a color is returned back.

## Mathematical expressions

Like many other programming languages,
CSS provides useful mathematical functions to assist with various types of calculation.

### calc()
{% BrowserCompat 'css.types.calc' %}

The [`calc()`](https://developer.mozilla.org/docs/Web/CSS/calc())
function takes a single mathematical expression as its parameter.
This mathematical expression can be a mix of types,
such as length, number, angle and frequency. Units can be mixed too.

```css
.my-element {
	width: calc(100% - 2rem);
}
```

In this example, the `calc()` function is being used to size an element's width
as 100% of its containing parent element,
then removing `2rem` off that computed value.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PopYema'
} %}
</figure>

```css
:root {
  --root-height: 5rem;
}

.my-element {
  width: calc(calc(10% + 2rem) * 2);
  height: calc(var(--root-height) * 3);
}
```

The `calc()` function can be nested inside another `calc()` function.
You can also pass custom properties in a `var()` function as part of an expression.

### `min()` and `max()`

{% BrowserCompat 'css.types.min' %}

The [`min()`](https://developer.mozilla.org/docs/Web/CSS/min())
function returns the smallest computed value of the one or more passed arguments.
The [`max()`](https://developer.mozilla.org/docs/Web/CSS/max())
function does the opposite: get the largest value of the one or more passed arguments.

```css
.my-element {
  width: min(20vw, 30rem);
  height: max(20vh, 20rem);
}
```

In this example,
the width should be the smallest value between `20vw`
—which is 20% of the **viewport width**—and `30rem`.
The height should be the largest value between `20vh`
—which is 20% of the **viewport height**—and `20rem`.

{% Aside %}
We cover units like `vw` and `vh` in the [sizing](/learn/css/sizing) units module.
{% endAside %}

### clamp()
{% BrowserCompat 'css.types.clamp' %}

The [`clamp()`](https://developer.mozilla.org/docs/Web/CSS/clamp())
function takes three arguments: the minimum size,
the ideal size and the maximum.

```css
h1 {
  font-size: clamp(2rem, 1rem + 3vw, 3rem);
}
```

In this example, the `font-size` will be fluid based on the width of the viewport.
The `vw` unit is added to a `rem` unit to assist with screen zooming,
because regardless of zoom level a `vw` unit will be the same size.
Multiplying by a `rem` unit—based on the root font size—
provides the `clamp()` function with a relative calculation point.

You can learn more about the `min()`, `max()`, and `clamp`() functions in
[this article](/min-max-clamp/).

## Shapes

The
[`clip-path`](https://developer.mozilla.org/docs/Web/CSS/clip-path),
[`offset-path`](https://developer.mozilla.org/docs/Web/CSS/offset-path) and
[`shape-outside`](https://developer.mozilla.org/docs/Web/CSS/shape-outside)
CSS properties use shapes to visually clip your box or provide a shape for content to flow around.

There are shape functions that can be used with both of these properties.
Simple shapes such as
[`circle()`](https://developer.mozilla.org/docs/Web/CSS/basic-shape/circle()),
[`ellipse()`](https://developer.mozilla.org/docs/Web/CSS/basic-shape/ellipse()) and
[`inset()`](https://developer.mozilla.org/docs/Web/CSS/basic-shape/inset())
take configuration arguments to size them.
More complex shapes, such as
[`polygon()`](https://developer.mozilla.org/docs/Web/CSS/basic-shape/polygon())
take comma separated pairs of X and Y axis values to create custom shapes.

```css
.circle {
  clip-path: circle(50%);
}

.polygon {
  clip-path: polygon(0% 0%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjYNNd'
} %}
</figure>

Like `polygon()`, there is also a `path()` function which takes an SVG fill rule as an argument.
This allows for highly complex shapes that can be drawn in a graphics tool
such as Illustrator or Inkscape and then copied into your CSS.

## Transforms

Lastly in this overview of CSS functions are the transform functions,
which skew, resize and even change the depth of an element.
All of the following functions are used with the `transform` property.

### Rotation
{% BrowserCompat 'css.types.transform-function.rotate' %}

You can rotate an element using the
[`rotate()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/rotate())
function, which will rotate an element on its center axis.
You can also use the
[`rotateX()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/rotateX()),
[`rotateY()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/rotateY()) and
[`rotateZ()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/rotateZ())
functions to rotate an element on a specific axis instead.
You can pass degree, turn and radian units to determine the level of rotation.

```css
.my-element {
  transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJOWzP'
} %}
</figure>

The [`rotate3d()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/rotate3d())
function takes four arguments.

{% BrowserCompat 'css.types.transform-function.rotate3d' %}

The first 3 arguments are numbers, which define the X, Y and Z coordinates.
The fourth argument is the rotation which,
like the other rotation functions, accepts degrees, angle and turns.

```css
.my-element {
  transform: rotate3d(1, 1, 1, 10deg);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrOJxa'
} %}
</figure>

### Scale
{% BrowserCompat 'css.types.transform-function.scale' %}

You can change the scaling of an element with `transform` and the
[`scale()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/scale()) function.
The function accepts one or two numbers as a value which determine a positive or negative scaling.
If you only define one number argument,
both the X and Y axis will be scaled the same and defining both is a shorthand for X and Y.
Just like `rotate()`,
there are
[`scaleX()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/scaleX()),
[`scaleY()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/scaleY()) and
[`scaleZ()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/scaleZ())
functions to scale an element on a specific axis instead.

```css
.my-element {
  transform: scaleX(1.2) scaleY(1.2);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgWOoq'
} %}
</figure>

Also like the `rotate` function, there is a
[`scale3d()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/scale3d()) function.
This is similar to `scale()`, but it takes three arguments: the X, Y and Z scale factor.

### Translate
{% BrowserCompat 'css.types.transform-function.translate' %}

The [`translate()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/translate())
functions move an element while it maintains its position in the document flow.
They accept length and percentage values as arguments.
The `translate()` function translates an element along the X axis if one argument is defined,
and translates an element along the X and Y axis if both arguments are defined.

```css
.my-element {
  transform: translatex(40px) translatey(25px);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'RwKjWgP'
} %}
</figure>

You can—just like with other transform functions—use specific functions for a specific axis,
using
[`translateX`](https://developer.mozilla.org/docs/Web/CSS/transform-function/translateX()),
[`translateY`](https://developer.mozilla.org/docs/Web/CSS/transform-function/translateY()) and
[`translateZ`](https://developer.mozilla.org/docs/Web/CSS/transform-function/translateZ()).
You can also use
[`translate3d`](https://developer.mozilla.org/docs/Web/CSS/transform-function/translate3d())
which allows you to define the X, Y and Z translation in one function.

### Skewing
{% BrowserCompat 'css.types.transform-function.skew' %}

You can skew an element, using the
[`skew()`](https://developer.mozilla.org/docs/Web/CSS/transform-function/skew())
functions which accept angles as arguments.
The `skew()` function works in a very similar way to `translate()`.
If you only define one argument, it will only affect the X axis and if you define both,
it will affect the X and Y axis.
You can also use
[`skewX`](https://developer.mozilla.org/docs/Web/CSS/transform-function/skewX()) and
[`skewY`](https://developer.mozilla.org/docs/Web/CSS/transform-function/skewY()) to affect each axis independently.

```css
.my-element {
  transform: skew(10deg);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEOYMq'
} %}
</figure>

### Perspective
{% BrowserCompat 'css.properties.perspective' %}

Lastly, you can use the
[`perspective`](https://developer.mozilla.org/docs/Web/CSS/perspective) property
—which is part of the transform family of properties—to alter the distance between the user and the Z plane.
This gives the feeling of distance and can be used to create a depth of field in your designs.

This example by David Desandro, from their very useful article, shows how it can be used,
along with `perspective-origin-x` and `perspective-origin-y` properties to create truly 3D experiences.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bMqZmr'
} %}
</figure>

## Animation functions, gradients and filters

CSS also provides functions that help you [animate](/learn/css/animations) elements,
apply [gradients](/learn/css/gradients) to them and use graphical [filters](/learn/css/filters) to manipulate how they look.
To keep this module as concise as possible,
they are covered in the linked modules.
They all follow a similar structure to the functions demonstrated in this module.

{% Assessment 'functions' %}

# Gradients

Imagine you've got a site to build and at the top,
there's an intro with a heading, summary and a button.
The designer has handed over a design which has a purple background for this intro.
The only problem is the background features two shades of purple as a gradient.
How do you do this?

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/0T5kGhQWJTLUclxSWipH.svg",
alt="A dark to light purple gradient background with heading, paragraph and link",
width="800",
height="411" %}

You might initially think that you're going to need to export an image from your design tool for this,
but you can use a
[`linear-gradient`](https://developer.mozilla.org/docs/Web/CSS/linear-gradient())
instead.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWpzdoV'
} %}
</figure>

A gradient is an image and can be used anywhere images can be used,
but it's created with CSS and is made up with colors, numbers and angles.
CSS gradients allow you to create anything from a smooth gradient between two colors,
right up to impressive artwork by mixing and repeating multiple gradients.

## Linear gradient
{% BrowserCompat 'css.types.image.gradient.linear-gradient' %}

The [`linear-gradient()`](https://developer.mozilla.org/docs/Web/CSS/linear-gradient())
function generates an image of two or more colors, progressively.
It takes multiple arguments, but in its simplest configuration,
you can pass some colors like this and it will automatically split them evenly, while blending them.

```css
.my-element {
	background: linear-gradient(black, white);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRqPoZ',
  tab: 'css,result',
  height: 400
} %}
</figure>

You can also pass an angle or keywords that represent an angle.
If you choose to use keywords, specify a direction after the `to` keyword.
This means if you want a gradient that is black and white,
that runs from left (black) to right (white),
you would specify the angle as `to right` as the first argument.

```css
.my-element {
	background: linear-gradient(to right, black, white);
}
```
<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNPqXW',
  tab: 'css,result',
  height: 400
} %}
</figure>

A color stop value defined where a color stops and mixes with its neighbors.
For a gradient starting with a dark shade of red running at a 45deg angle,
at 30% of the size of the gradient changing to a lighter red: it looks like this.

```css
.my-element {
	background: linear-gradient(45deg, darkred 30%, crimson);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdwNZr',
  tab: 'css,result',
  height: 400
} %}
</figure>

You can add as many colors and color stops as you like in a `linear-gradient()`,
and you can layer gradients on top of each other by separating each gradient with a comma.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpVZbj',
  tab: 'css,result',
  height: 400
} %}
</figure>

## Radial gradient
{% BrowserCompat 'css.types.image.gradient.radial-gradient' %}

To create a gradient that radiates in a circular fashion, the
[`radial-gradient()`](https://developer.mozilla.org/docs/Web/CSS/radial-gradient())
function steps in to help.
It's similar to `linear-gradient()`,
but instead of specifying an angle, you optionally specify a position and ending shape.
If you just specify colors, the `radial-gradient()` will auto-select the position as `center`
and select either a circle or ellipse, depending on the size of the box.

```css
.my-element {
	background: radial-gradient(white, black);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'LYxOZEq',
  tab: 'css,result',
  height: 400
} %}
</figure>

The gradient's position is similar to `background-position` using keywords and/or number values.
The size of the radial gradient determines the size of the gradient's ending shape
(circle or ellipse) and by default will be `farthest-corner`,
which means it exactly meets the farthest corner of the box from the center.
You can also use the following keywords:

- `closest-corner` will meet the closest corner to the center of the gradient.
- `closest-side` will meet the side of the box closest to the center of the gradient.
- `farthest-side` will do the opposite to `closest-side`.

You can add as many color stops as you like, just like with the `linear-gradient`.
Likewise, you can add as many `radial-gradients` as you like too.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJOepV',
  tab: 'css,result',
  height: 400
} %}
</figure>

## Conic gradient
{% BrowserCompat 'css.types.image.gradient.conic-gradient' %}

A conic gradient has a center point in your box and starts from the top (by default),
and goes around in a 360 degree circle.

```css
.my-element {
	background: conic-gradient(white, black);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBRVNXG',
  tab: 'css,result',
  height: 400
} %}
</figure>

The [`conic-gradient()`](https://developer.mozilla.org/docs/Web/CSS/conic-gradient())
function accepts position and angle arguments.

By default, the angle is 0 degrees which starts at the top, in the center.
If you were to set the angle to be `45deg`, it would be the top right corner.
The angle argument accepts any type of angle value, like the linear and radial gradients.

The position is center by default.
As with radial and linear gradients,
positioning can be keyword-based,
or it can be defined with numeric values.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgWKpO',
  tab: 'css,result',
  height: 400
} %}
</figure>

You can add as many color stops as you want, like with other gradient types.
A good use case for this capability, with conic gradients is rendering pie charts with CSS.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRqExP',
  tab: 'css,result',
  height: 400
} %}
</figure>

## Repeating and mixing

Each type of gradient has a repeating type, too.
These are
[`repeating-linear-gradient()`](https://developer.mozilla.org/docs/Web/CSS/repeating-linear-gradient()),
[`repeating-radial-gradient()`](https://developer.mozilla.org/docs/Web/CSS/repeating-radial-gradient()) and
[`repeating-conic-gradient()`](https://developer.mozilla.org/docs/Web/CSS/repeating-conic-gradient()).
They are similar to the non-repeating functions and take the same arguments.
The difference is that if the defined gradient can be repeated to fill the box,
based on both of their sizes, it will.

If your gradient doesn't appear to be repeating,
you probably haven't set a length for one of the color stops.
For example,
you can create a striped background with a `repeating-linear-gradient` by setting color stop lengths.

```css
.my-element {
  background: repeating-linear-gradient(
    45deg,
    red,
    red 30px,
    white 30px,
    white 60px
  );
}

```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExZbgdy',
  tab: 'css,result',
  height: 400
} %}
</figure>

You can also mix gradient functions on `background` properties,
as well as defining as many gradients as you like,
just like you would with a background image.
For example, you can mix multiple linear-gradients together, or two linear-gradients with a radial gradient.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExZqGxP',
  tab: 'css,result',
  height: 400
} %}
</figure>

## Resources

- [Conic.css](https://www.conic.style/) - a useful collection of conic gradients
- [MDN guide to gradients](https://developer.mozilla.org/docs/Web/CSS/CSS_Images/Using_CSS_gradients)
- [Gradient generator](https://www.colorzilla.com/gradient-editor/)

{% Assessment 'gradients' %}

# Grid

A really common layout in web design is a header, sidebar, body and footer layout.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/tj7KmP72RKkffGQRswpA.svg",
alt="A header with logo and navigation with a sidebar and content area that features an article",
width="800",
height="531" %}

Over the years,
there have been many methods to solve this layout,
but with CSS grid,
not only is it relatively straightforward,
but you have lots of options.
Grid is exceptionally useful at combining the control
that extrinsic sizing provides with the flexibility of intrinsic sizing,
which makes it ideal for this sort of layout.
This is because grid is a layout method designed for two-dimensional content.
That is, laying things out in rows and columns at the same time.

When creating a grid layout you define a grid with rows and columns.
Then you place items onto that grid,
or allow the browser to auto-place them into the cells you have created.
There's a lot to grid,
but with an overview of what is available
you'll be making grid layouts in no time.

## Overview

So what can you do with grid?
Grid layouts have the following features.
 You'll learn about all of them in this guide.

1. A grid can be defined with rows and columns.
You can choose how to size these row and column tracks or they can react to the size of the content.
1. Direct children of the grid container will be automatically placed onto this grid.
1. Or, you can place the items in the precise location that you want.
1. Lines and areas on the grid can be named to make placement easier.
1. Spare space in the grid container can be distributed between the tracks.
1. Grid items can be aligned within their area.

## Grid terminology

Grid comes with a bunch of new terminology as it's the first time CSS has had a real layout system.

### Grid lines

A grid is made up of lines,
which run horizontally and vertically.
If your grid has four columns,
it will have five column lines including the one after the last column.

Lines are numbered starting from 1,
with the numbering following the writing mode and script direction of the component.
This means that column line 1 will be on the left in a left-to-right language such as English,
and on the right in a right-to-left language such as Arabic.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/Sf8WXYmbhZkbhhPeqTrY.svg",
alt="A diagram representation of grid lines",
width="800",
height="434" %}

### Grid tracks

A track is the space between two grid lines.
A row track is between two row lines and a column track between two column lines.
When we create our grid we create these tracks by assigning a size to them.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/7YkhnpgOQLrcaxjlKmlU.svg",
alt="A diagram representation of a grid track",
width="800",
height="434" %}

### Grid cell

A grid cell is the smallest space on a grid defined by the intersection of row and column tracks.
It's just like a table cell or a cell in a spreadsheet.
If you define a grid and don't place any of the items
they will automatically be laid out one item into each defined grid cell.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/lpiPCpW6fy4BjFOL6j77.svg",
alt="A diagram representation of a grid cell",
width="800",
height="434" %}

### Grid area

Several grid cells together.
Grid areas are created by causing an item to span over multiple tracks.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/pGmMokRfoVbLNxf1VXrF.svg",
alt="A diagram representation of a grid area",
width="800",
height="434" %}

### Gaps

A gutter or alley between tracks.
For sizing purposes these act like a regular track.
You can't place content into a gap but you can span grid items across it.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/JNXSRH4j77loSB099E04.svg",
alt="A diagram representation of a grid with gaps",
width="800",
height="434" %}

### Grid container

The HTML element which has `display: grid` applied,
and therefore creates a new grid formatting context for the direct children.

```css
.container {
  display: grid;
}
```

### Grid item

A grid item is an item which is a direct child of the grid container.

```html/1-3
<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
```

## Rows and columns

To create a basic grid you can define a grid with three column tracks,
two row tracks and a 10 pixel gap between the tracks as follows.

```css
.container {
    display: grid;
    grid-template-columns: 5em 100px 30%;
    grid-template-rows: 200px auto;
    gap: 10px;
}
```

This grid demonstrates many of the things described in the terminology section.
It has three column tracks.
Each track uses a different length unit.
It has two row tracks,
one using a length unit and the other auto.
When used as a track sizing auto can be thought of as being as big as the content.
Tracks are auto sized by default.

If the element with a class of `.container` has child items,
they will immediately lay out on this grid. You can see this in action in the demo below.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdbrzr'
} %}
</figure>

The [grid overlay in Chrome DevTools](https://developer.chrome.com/docs/devtools/css/grid/) can help you understand the various parts of the grid.

Open the [demo](https://codepen.io/web-dot-dev/full/NWdbrzr) in Chrome.
Inspect the element with the grey background, which has an ID of `container`.
Highlight the grid by selecting the grid badge in the DOM, next to the `.container` element.
Inside the Layout tab,
select **Display Line Numbers** in the dropdown to see the line numbers on your grid.

<figure>
{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/YxpjWBUDsqQB2fr6rzU3.jpg",
alt="As described in the caption and instructions",
width="800",
height="449" %}
<figcaption>
A grid highlighted in Chrome DevTools showing line numbers, cells and tracks.
</figcaption>
</figure>

### Intrinsic sizing keywords

In addition to the length and percentage dimensions as described in the section on
[sizing units](/learn/css/sizing),
grid tracks can use intrinsic sizing keywords.
These keywords are defined in the Box Sizing specification
and add additional methods of sizing boxes in CSS,
not just grid tracks.

- `min-content`
- `max-content`
- `fit-content()`

The [`min-content`](https://developer.mozilla.org/docs/Web/CSS/min-content)
keyword will make a track as small as it can be without the track content overflowing.
Changing the example grid layout to have three column tracks all at `min-content` size
will mean they become as narrow as the longest word in the track.

The [`max-content`](https://developer.mozilla.org/docs/Web/CSS/max-content)
keyword has the opposite effect.
The track will become as wide enough for all of the content to display in one long unbroken string.
This might cause overflows as the string will not wrap.

The [`fit-content()`](https://developer.mozilla.org/docs/Web/CSS/fit-content())
function acts like `max-content` at first.
However, once the track reaches the size that you pass into the function,
the content starts to wrap.
So `fit-content(10em)` will create a track that is less than 10em,
if the `max-content` size is less than 10em,
but never larger than 10em.

In the next demo try out the different intrinsic sizing keywords by changing the sizing of the grid tracks.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBRqNgL',
  height: 600
} %}
</figure>

{% Aside %}
You might spot in this demo that when auto is used the grid columns stretch to fill the container.
Auto sized tracks will stretch by default if there is additional space in the grid container.
{% endAside %}

### The `fr` unit

We have existing length dimensions, percentages, and also these new keywords.
There is also a special sizing method which only works in grid layout.
This is the `fr` unit,
a flexible length which describes a share of the available space in the grid container.

The `fr` unit works in a similar way to using `flex: auto` in flexbox.
It distributes space after the items have been laid out.
Therefore to have three columns which all get the same share of available space:

```css
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
```

As the fr unit shares out available space,
it can be combined with a fixed size gap or fixed size tracks.
To have a component with a fixed size element and the second track taking up whatever space is left,
you can use as a tracklisting of `grid-template-columns: 200px 1fr`.

Using different values for the fr unit will share the space in proportion.
Larger values getting more of the spare space.
In the demo below change the value of the third track.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgyXNE',
  height: 600
} %}
</figure>

### The `minmax()` function
{% BrowserCompat 'css.properties.grid-template-columns.minmax' %}

This function means that you can set a minimum and a maximum size for a track.
This can be quite useful.
If we take the example of the `fr` unit above which distributes remaining space,
it could be written out using
[`minmax()`](https://developer.mozilla.org/docs/Web/CSS/minmax()) as `minmax(auto, 1fr)`.
Grid looks at the intrinsic size of the content,
then distributes available space after giving the content enough room.
This means that you might not get tracks that each have an equal share
of all space available in the grid container.

To force a track to take an equal share of the space in the grid container minus gaps use minmax.
Replace `1fr` as a track size with `minmax(0, 1fr)`.
This makes the minimum size of the track 0 and not the min-content size.
Grid will then take all of the available size in the container,
deduct the size needed for any gaps,
and share the rest out according to your fr units.

### `repeat()` notation
{% BrowserCompat 'css.properties.grid-template-columns.repeat' %}

If you want to create a 12 column track grid with equal columns,
you could use the following CSS.

```css
.container {
    display: grid;
    grid-template-columns:
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr),
      minmax(0,1fr);
}
```

Or, you could write it out using
[`repeat()`](https://developer.mozilla.org/docs/Web/CSS/repeat()):

```css
.container {
    display: grid;
    grid-template-columns: repeat(12, minmax(0,1fr));
}
```

The `repeat()` function can be used to repeat any section of your track listing.
For example you can repeat a pattern of tracks.
 You can also have some regular tracks and a repeating section.

```css
.container {
    display: grid;
    grid-template-columns: 200px repeat(2, 1fr 2fr) 200px; /*creates 6 tracks*/
}
```

### `auto-fill` and `auto-fit`

You can combine everything you have learned about track sizing,
`minmax()`, and repeat,
to create a useful pattern with grid layout.
Perhaps you don't want to specify the number of column tracks,
but instead want to create as many as will fit in your container.

You can achieve this with `repeat()` and the `auto-fill` or `auto-fit` keywords.
In the demo below grid will create as many 200 pixel tracks as will fit in the container.
Open the demo in a new window and see how the grid changes as you change the size of the viewport.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWpNjgO'
} %}
</figure>

In the demo we get as many tracks as will fit.
The tracks are not flexible however.
You will get a gap on the end until there is enough space for another 200 pixel track.
If you add the `minmax()` function,
you can request as many tracks as will fit with a minimum size of 200 pixels and a maximum of 1fr.
Grid then lays out the 200 pixel tracks and whatever space is leftover is distributed equally to them.

This creates a two-dimensional responsive layout with no need for any media queries.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWbRax'
} %}
</figure>

There is a subtle difference between `auto-fill` and `auto-fit`.
In the next demo play with a grid layout using the syntax explained above,
but with only two grid items in the grid container.
Using the `auto-fill` keyword you can see that empty tracks have been created.
Change the keyword to `auto-fit` and the tracks collapse down to 0 size.
This means that the flexible tracks now grow to consume the space.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJbbNe'
} %}
</figure>

The `auto-fill` and `auto-fit` keywords otherwise act in exactly the same way.
There is no difference between them once the first track is filled.

## Auto-placement

You have already seen grid auto-placement at work in the demos so far.
Items are placed on the grid one per cell in the order that they appear in the source.
For many layouts this might be all you need.
If you need more control then there are a couple of things you might like to do.
The first is to tweak the auto-placement layout.

### Placing items in columns

The default behavior of grid layout is to place items along the rows.
You can instead cause the items to place into columns using `grid-auto-flow: column`.
You need to define row tracks otherwise the items will create intrinsic column tracks,
and layout out all in one long row.

These values relate to the writing mode of the document.
A row always runs in the direction a sentence runs in the writing mode of the document or component.
In the next demo you can change mode the value of `grid-auto-flow` and the `writing-mode` property.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PoWbWbr',
  height: 600
} %}
</figure>

### Spanning tracks

You can cause some or all of the items in an auto-placed layout to span more than one track.
Use the `span` keyword plus the number of lines to span as a value for  `grid-column-end` or `grid-row-end`.

```css
.item {
    grid-column-end: span 2; /* will span two lines, therefore covering two tracks */
}
```

As you have not specified a `grid-column-start`,
this uses the initial value of `auto` and is placed according to the auto-placement rules.
You can also specify the same thing using the shorthand `grid-column`:

```css
.item {
    grid-column: auto / span 2;
}
```

### Filling gaps

An auto-placed layout with some items spanning multiple tracks
may result in a grid with some unfilled cells.
The default behavior of grid layout with a fully auto-placed layout
is to always progress forward.
The items will be placed according to the order they are in the source,
or any modification with the `order` property.
If there is not enough space to fit an item,
grid will leave a gap and move to the next track.

The next demo shows this behavior.
The checkbox will apply the dense packing mode.
This is enabled by giving `grid-auto-flow` a value of `dense`.
With this value in place,
grid will take items later in the layout and use them to fill gaps.
This may mean that the display becomes disconnected from the logical order.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ZELBLrJ',
  height: 600
} %}
</figure>

## Placing items

You have a lot of functionality from CSS Grid already.
Let's now take a look at how we position items on the grid we have created.

The first thing to remember is that CSS Grid Layout is based on a grid of numbered lines.
The simplest way to place things onto the grid is to place them from one line to another.
You'll discover other ways of placing items in this guide,
but you always have access to those numbered lines.

The properties that you can use to place items by line number are:

- [`grid-column-start`](https://developer.mozilla.org/docs/Web/CSS/grid-column-start)
- [`grid-column-end`](https://developer.mozilla.org/docs/Web/CSS/grid-column-end)
- [`grid-row-start`](https://developer.mozilla.org/docs/Web/CSS/grid-row-start)
- [`grid-row-end`](https://developer.mozilla.org/docs/Web/CSS/grid-row-end)

They have shorthands which allow you to set both start and end lines at once:

- [`grid-column`](https://developer.mozilla.org/docs/Web/CSS/grid-column)
- [`grid-row`](https://developer.mozilla.org/docs/Web/CSS/grid-row)

To place your item set the start and end lines of the grid area that it should be placed into.

```css
.container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: repeat(2, 200px 100px);
}

.item {
    grid-column-start: 1; /* start at column line 1 */
    grid-column-end: 4; /* end at column line 4 */
    grid-row-start: 2; /*start at row line 2 */
    grid-row-end: 4; /* end at row line 4 */
}
```

[Chrome DevTools](https://developer.chrome.com/docs/devtools/css/grid/) can give you a visual guide to the lines in order to check where your item is placed.

The line numbering follows the writing mode and direction of the component.
In the next demo change the writing mode or direction
to see how the placement of the items stays consistent to the way that text flows.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdGdzd',
  height: 600
} %}
</figure>

### Stacking items

Using line-based positioning you can place items into the same cell of the grid.
This means that you can stack items,
or cause one item to partly overlap another.
Items which come later in the source will be displayed on top of items that come earlier.
You can change this stacking order using `z-index` just as with positioned items.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BapQWQW',
  height: 600
} %}
</figure>

### Negative line numbers

When you create a grid using `grid-template-rows` and `grid-template-columns`
you create what is known as the **explicit grid**.
This is a grid that you have defined and given size to the tracks.

Sometimes you will have items which display outside this explicit grid.
For example,
you might define column tracks and then add several rows of grid items without ever defining row tracks.
The tracks would be auto sized by default.
You also might place an item using `grid-column-end` that is outside of the explicit grid defined.
In both of these cases grid will create tracks to make the layout work,
and these tracks are referred to as the **implicit grid**.

Most of the time it will make no difference if you are working with an implicit or explicit grid.
However, with line-based placement you may run into the main difference between the two.

Using negative line numbers you can place items from the end line of the explicit grid.
This can be useful if you want an item to span from the first to the last column line.
In that case you can use `grid-column: 1 / -1`.
The item will stretch right across the explicit grid.

This only works for the explicit grid however.
Take a layout of three rows of auto-placed items
where you would like the very first item to span to the end line of the grid.

{%
Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/Dt8yG376MqSyWJJ8KqPr.svg",
alt="A sidebar with 8 sibling grid items",
width="800",
height="359" %}

You might think that you can give that item `grid-row: 1 / -1`.
In the demo below you can see that this doesn't work.
The tracks are created in the implicit grid,
there is no way to reach the end of the grid using `-1`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNpZeq'
} %}
</figure>

#### Sizing implicit tracks

The tracks created in the implicit grid will be auto-sized by default.
However if you want to control the sizing of the rows,
use the
[`grid-auto-rows`](https://developer.mozilla.org/docs/Web/CSS/grid-auto-rows) property,
and for columns
[`grid-auto-columns`](https://developer.mozilla.org/docs/Web/CSS/grid-auto-columns).

To create all implicit rows at a minimum size of `10em` and a maximum size of `auto`:

```css
.container {
    display: grid;
    grid-auto-rows: minmax(10em, auto);
}
```

To create implicit columns with a pattern of 100px and 200px wide tracks.
In this case the first implicit column will be 100px,
the second 200px,
the third 100px, and so on.

```css
.container {
    display: grid;
    grid-auto-columns: 100px 200px;
}
```

## Named grid lines

It can make it easier to place items into a layout if the lines have a name rather than a number.
You can name any line on your grid by adding a name of your choosing between square brackets.
Multiple names can be added,
separated by a space inside the same brackets.
Once you have named lines they can be used instead of the numbers.

```css
.container {
    display: grid;
    grid-template-columns:
      [main-start aside-start] 1fr
      [aside-end content-start] 2fr
      [content-end main-end]; /* a two column layout */
}

.sidebar {
    grid-column: aside-start / aside-end;
    /* placed between line 1 and 2*/
}

footer {
    grid-column: main-start / main-end;
    /* right across the layout from line 1 to line 3*/
}
```

## Grid Template Areas

You can also name areas of the grid and place items onto those named areas.
This is a lovely technique as it allows you to see what your component looks like right there in the CSS.

To start, give the direct children of your grid container a name using the
[`grid-area`](https://developer.mozilla.org/docs/Web/CSS/grid-area) property:

```css
header {
    grid-area: header;
}

.sidebar {
    grid-area: sidebar;
}

.content {
    grid-area: content;
}

footer {
    grid-area: footer;
}
```

The name can be anything you like other than the keywords `auto` and `span`.
Once all of your items are named,
use the
[`grid-template-areas`](https://developer.mozilla.org/docs/Web/CSS/grid-template-areas)
property to define which grid cells each item will span.
Each row is defined within quotes.

```css
.container {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    grid-template-areas:
        "header header header header"
        "sidebar content content content"
        "sidebar footer footer footer";
}
```

There are a few rules when using `grid-template-areas`.

- The value must be a complete grid with no empty cells.
- To span tracks repeat the name.
- The areas created by repeating the name must be rectangular and cannot be disconnected.

If you break any of the above rules the value is treated as invalid and thrown away.

To leave white space on the grid use a `.` or multiples with no white space between them.
For example to leave the very first cell on the grid empty I could add a series of `.` characters:

```css
.container {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    grid-template-areas:
        "....... header header header"
        "sidebar content content content"
        "sidebar footer footer footer";
}
```

As your entire layout is defined in one place,
it makes it straightforward to redefine the layout using media queries.
In the next example I have created a two column layout which moves to three columns
by redefining the value of `grid-template-columns` and `grid-template-areas`.
Open the example in a new window to play with the viewport size and see the layout change.

You can also see how the `grid-template-areas` property relates to `writing-mode` and direction,
as with other grid methods.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'oNBYepg',
  height: 600
} %}
</figure>

## Shorthand properties

There are two shorthand properties which allow you to set many of the grid properties in one go.
These can look a little confusing until you break down exactly how they go together.
Whether you want to use them or prefer to use longhands is up to you.

### `grid-template`
{% BrowserCompat 'css.properties.grid-template' %}

The [`grid-template`](https://developer.mozilla.org/docs/Web/CSS/grid-template)
property is a shorthand for `grid-template-rows`, `grid-template-columns` and `grid-template-areas`.
The rows are defined first,
along with the value of `grid-template-areas`.
Column sizing is added after a `/`.

```css
.container {
    display: grid;
    grid-template:
      "head head head" minmax(150px, auto)
      "sidebar content content" auto
      "sidebar footer footer" auto / 1fr 1fr 1fr;
}
```

### `grid` property
{% BrowserCompat 'css.properties.grid' %}

The [`grid`](https://developer.mozilla.org/docs/Web/CSS/grid)
shorthand can be used in exactly the same way as the `grid-template` shorthand.
When used in this way it will reset the other grid properties that it accepts to their initial values.
The full set being:

- `grid-template-rows`
- `grid-template-columns`
- `grid-template-areas`
- `grid-auto-rows`
- `grid-auto-columns`
- `grid-auto-flow`

You can alternately use this shorthand to define how the implicit grid behaves,
for example:

```css
.container {
    display: grid;
    grid: repeat(2, 80px) / auto-flow  120px;
}
```

## Alignment

Grid layout uses the same alignment properties that you learned about in the guide to
[flexbox](/learn/css/flexbox).
In grid the properties which begin with `justify-` are always used on the inline axis,
the direction in which sentences run in your writing mode.

The properties which begin with `align-` are used on the block axis,
the direction in which blocks are laid out in your writing mode.

- [`justify-content`](https://developer.mozilla.org/docs/Web/CSS/justify-content)
and [`align-content`](https://developer.mozilla.org/docs/Web/CSS/align-content):
distribute additional space in the grid container around or between tracks.
- [`justify-self`](https://developer.mozilla.org/docs/Web/CSS/justify-self) and
[`align-self`](https://developer.mozilla.org/docs/Web/CSS/align-self):
are applied to a grid item to move it around inside the grid area it is placed in.
- [`justify-items`](https://developer.mozilla.org/docs/Web/CSS/justify-items) and
[`align-items`](https://developer.mozilla.org/docs/Web/CSS/align-items):
are applied to the grid container to set all of the `justify-self` properties on the items.

### Distributing extra space

In this demo the grid is larger than the space needed to lay out the fixed width tracks.
This means we have space in both the inline and block dimensions of the grid.
Try different values of `align-content` and `justify-content` to see how the tracks behave.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjjMVd',
  height: 650
} %}
</figure>

Note how the gaps become larger when using values such as `space-between`,
and any grid item spanning two tracks also grows to absorb the additional space added to the gap.

{% Aside %}
As with flexbox, these properties will only work if there is additional space to distribute.
If your grid tracks neatly fill the container then there will be no space to share out.
{% endAside %}

### Moving content around

Items with a background color appear to completely fill the grid area they are placed in,
because the initial value for `justify-self` and `align-self` is `stretch`.

{% Aside %}
If your item is an image,
or something else with an intrinsic aspect ratio,
the initial value will be `start` rather than `stretch` to avoid stretching things out of shape.
{% endAside %}

In the demo change the values of `justify-items` and `align-items` to see how this changes the layout.
The grid area is not changing size,
instead the items are being moved around inside the defined area.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzZOOXB',
  height: 650
} %}
</figure>

{% Assessment 'grid' %}

## Resources

This guide has given you an overview of the different parts of the grid layout specification.
To find out more, take a look at the following resources.

- [MDN CSS Grid Layout](https://developer.mozilla.org/docs/Web/CSS/CSS_Grid_Layout)
- [A Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid/)
- [Creating a Grid Container](https://www.smashingmagazine.com/2020/01/understanding-css-grid-container/)
- [Inspect CSS grid in Chrome DevTools](https://developer.chrome.com/docs/devtools/css/grid/)
- [A comprehensive collection of grid learning material](https://gridbyexample.com/)

# Inheritance

Say you just wrote some CSS to make elements look like a button.

```html
<a href="http://example.com" class="my-button">I am a button link</a>
```

```css
.my-button {
  display: inline-block;
  padding: 1rem 2rem;
  text-decoration: none;
  background: pink;
  font: inherit;
  text-align: center;
}
```

You then add a link element to an article of content,
with a `class` value of `.my-button`. However there's an issue,
the text is not the color that you expected it to be. How did this happen?

Some CSS properties inherit if you don't specify a value for them.
In the case of this button, it **inherited** the `color` from this CSS:

```css
article a {
  color: maroon;
}
```

In this lesson you'll learn why that happens and
how inheritance is a powerful feature to help you write less CSS.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNGEbg',
  height: 400
} %}
</figure>

## Inheritance flow

Let's take a look at how inheritance works,
using this snippet of HTML:

```html
<html>
  <body>
    <article>
      <p>Lorem ipsum dolor sit amet.</p>
    </article>
  </body>
</html>
```

The root element (`<html>`) won't inherit anything because it is the first element in the document.
Add some CSS on the HTML element,
and it starts to cascade down the document.

```css
html {
  color: lightslategray;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEKgBX',
  height: 200
} %}
</figure>

The `color` property is inheritable by other elements.
The `html` element has `color: lightslategray`,
therefore all elements that can inherit color will now have a color of `lightslategray`.

```css
body {
  font-size: 1.2em;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwPLrLP',
  height: 200
} %}
</figure>

{% Aside %}
Because this demo sets the font size on the `body` element,
the `html` element will still have the initial font size set by the browser (user agent stylesheet),
but the `article` and `p` will inherit the font size declared by the `body`.
This is because inheritance only cascades downwards.
{% endAside %}

```css
p {
  font-style: italic;
}
```

Only the `<p>` will have italic text because it's the deepest nested element.
Inheritance only flows downwards, not back up to parent elements.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEKgmK',
  tab: 'css,result',
  height: 400
} %}
</figure>

## Which properties are inheritable?

Not all CSS properties are inheritable,
but there are a lot that are.
For reference, here is the entire list of inheritable properties,
taken from the W3 reference of all CSS properties:

- [azimuth](https://developer.mozilla.org/docs/Web/SVG/Attribute/azimuth)
- [border-collapse](https://developer.mozilla.org/docs/Web/CSS/border-collapse)
- [border-spacing](https://developer.mozilla.org/docs/Web/CSS/border-spacing)
- [caption-side](https://developer.mozilla.org/docs/Web/CSS/caption-side)
- [color](https://developer.mozilla.org/docs/Web/CSS/color)
- [cursor](https://developer.mozilla.org/docs/Web/CSS/cursor)
- [direction](https://developer.mozilla.org/docs/Web/CSS/direction)
- [empty-cells](https://developer.mozilla.org/docs/Web/CSS/empty-cells)
- [font-family](https://developer.mozilla.org/docs/Web/CSS/font-family)
- [font-size](https://developer.mozilla.org/docs/Web/CSS/font-size)
- [font-style](https://developer.mozilla.org/docs/Web/CSS/font-style)
- [font-variant](https://developer.mozilla.org/docs/Web/CSS/font-variant)
- [font-weight](https://developer.mozilla.org/docs/Web/CSS/font-weight)
- [font](https://developer.mozilla.org/docs/Web/CSS/font)
- [letter-spacing](https://developer.mozilla.org/docs/Web/CSS/letter-spacing)
- [line-height](https://developer.mozilla.org/docs/Web/CSS/line-height)
- [list-style-image](https://developer.mozilla.org/docs/Web/CSS/list-style-image)
- [list-style-position](https://developer.mozilla.org/docs/Web/CSS/list-style-position)
- [list-style-type](https://developer.mozilla.org/docs/Web/CSS/list-style-type)
- [list-style](https://developer.mozilla.org/docs/Web/CSS/list-style)
- [orphans](https://developer.mozilla.org/docs/Web/CSS/orphans)
- [quotes](https://developer.mozilla.org/docs/Web/CSS/quotes)
- [text-align](https://developer.mozilla.org/docs/Web/CSS/text-align)
- [text-indent](https://developer.mozilla.org/docs/Web/CSS/text-indent)
- [text-transform](https://developer.mozilla.org/docs/Web/CSS/text-transform)
- [visibility](https://developer.mozilla.org/docs/Web/CSS/visibility)
- [white-space](https://developer.mozilla.org/docs/Web/CSS/white-space)
- [widows](https://developer.mozilla.org/docs/Web/CSS/widows)
- [word-spacing](https://developer.mozilla.org/docs/Web/CSS/word-spacing)

## How inheritance works

Every HTML element has every CSS property defined by default with an initial value.
An initial value is a property that's not inherited and shows up as a default
if the cascade fails to calculate a value for that element.

<figure>
{% Video src="video/VbAJIREinuYvovrBzzvEyZOpw5w1/OvoYqOMcdFZL7wJQIL2C.mp4" %}
</figure>

Properties that can be inherited cascade downwards,
and child elements will get a computed value which represents its parent's value.
This means that if a parent has `font-weight` set to `bold` all child elements will be bold,
unless their `font-weight` is set to a different value,
or the user agent stylesheet has a value for `font-weight` for that element.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxgGPOZ'
} %}
</figure>

## How to explicitly inherit and control inheritance

Inheritance can affect elements in unexpected ways so CSS has tools to help with that.

### The `inherit` keyword

You can make any property inherit its parent's computed value with the `inherit` keyword.
A useful way to use this keyword is to create exceptions.

```css
strong {
  font-weight: 900;
}
```

This CSS snippet sets all `<strong>` elements to have a `font-weight` of `900`,
instead of the default `bold` value, which would be the equivalent of `font-weight: 700`.

```css
.my-component {
  font-weight: 500;
}
```

The `.my-component` class sets `font-weight` to `500` instead.
To make the `<strong>` elements inside `.my-component` also `font-weight: 500` add:

```css
.my-component strong {
  font-weight: inherit;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYgNedO',
  height: 400
} %}
</figure>

Now, the `<strong>` elements inside `.my-component` will have a `font-weight` of `500`.

You could explicitly set this value,
but if you use `inherit` and the CSS of `.my-component` changes in the future,
you can guarantee that your `<strong>` will automatically stay up to date with it.

### The `initial` keyword

Inheritance can cause problems with your elements and `initial` provides you with a powerful reset option.

You learned earlier that every property has a default value in CSS.
The `initial` keyword sets a property back to that initial, default value.

```css
aside strong {
  font-weight: initial;
}
```

This snippet will remove the bold weight from all `<strong>` elements inside an `<aside>` element and instead,
make them normal weight, which is the initial value.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWVORZ',
  tab: 'css,result',
  height: 300
} %}
</figure>

### The `unset` keyword

The `unset` property behaves differently if a property is inheritable or not.
If a property is inheritable,
the `unset` keyword will be the same as `inherit`.
If the property is not inheritable, the `unset` keyword is equal to `initial`.

Remembering which CSS properties are inheritable can be hard,
`unset` can be helpful in that context.
For example, `color` is inheritable,
but `margin` isn't, so you can write this:

```css
/* Global color styles for paragraph in authored CSS */
p {
  margin-top: 2em;
  color: goldenrod;
}

/* The p needs to be reset in asides, so you can use unset */
aside p {
  margin: unset;
  color: unset;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEdpjw',
  tab: 'css,result',
  height: 400
} %}
</figure>

Now, the `margin` is removed and `color` reverts back to being the inherited computed value.

You can use the `unset` value with the `all` property, too.
Going back to the above example,
what happens if the global `p` styles get an additional few properties?
Only the rule that was set for `margin` and `color` will apply.

```css/4-5
/* Global color styles for paragraph in authored CSS */
p {
	margin-top: 2em;
	color: goldenrod;
	padding: 2em;
	border: 1px solid;
}

/* Not all properties are accounted for anymore */
aside p {
	margin: unset;
	color: unset;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgdLNB',
  tab: 'css,result'
} %}
</figure>

If you change the `aside p` rule to `all: unset` instead,
it doesn't matter what global styles are applied to `p` in the future,
they will always be unset.

```css/3
aside p {
	margin: unset;
	color: unset;
	all: unset;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWpbZbB',
  tab: 'css,result'
} %}
</figure>

{% Assessment 'conclusion' %}

## Resources

- [MDN reference on computed values](https://developer.mozilla.org/docs/Web/CSS/computed_value)
- [An article on how inheritance can be useful in modular front-ends](https://www.smashingmagazine.com/2016/11/css-inheritance-cascade-global-scope-new-old-worst-best-friends/)

# Layout

Imagine you're working as a developer,
and a designer colleague hands you a design for a brand new website.
The design has all sorts of interesting layouts and compositions:
two-dimensional layouts that are considerate of viewport width and height,
as well as layouts that need to be fluid and flexible.
How do you decide the best way to style these with CSS?

CSS provides us with various ways to solve layout problems,
on a horizontal axis, vertical axis, or even both.
Choosing the right layout method for a context can be hard,
and often you may need more than one layout method to solve your problem.
To help with this, in the following modules,
you'll learn about the unique features of each CSS layout mechanism to inform those decisions.

## Layout: a brief history

In the early days of the web,
designs more complex than a simple document were laid out with `<table>` elements.
Separating HTML from visual styles was made easier when CSS was widely adopted by browsers in the late '90s.
CSS opened the door to developers being able to completely change the look and feel of a website without ever touching HTML.
This new capability inspired projects such as [The CSS Zen Garden](http://www.csszengarden.com),
which was created to demonstrate the power of CSS to encourage more developers to learn it.

CSS has evolved as our needs for web design and browser technology have evolved.
You can read how CSS layout and our approach to layout has evolved over time in
[this article by Rachel Andrew](https://24ways.org/2019/a-history-of-css-through-15-years-of-24-ways/).

{% Img
  src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/vDDoFFoPVgJEuEaqcP4H.svg",
  alt="A timeline showing how CSS has evolved over the years, starting in 1996 up to 2021",
  width="760",
  height="270"
%}

## Layout: the present and future

Modern CSS has exceptionally powerful layout tooling.
We have dedicated systems for layout and we're going to have a high-level look at what we have at our disposal,
before digging into more detail of Flexbox and Grid in the next modules.

## Understanding the `display` property

The `display` property does two things.
The first thing it does is determine if the box it is applied to acts as inline or block.

```css
.my-element {
  display: inline;
}
```

Inline elements behave like words in a sentence.
They sit next to each other in the inline direction.
Elements such as `<span>` and `<strong>`,
which are typically used to style pieces of text within containing elements like a `<p>` (paragraph),
are inline by default.
They also preserve surrounding whitespace.

{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/GezxDZXkJgkMevkKg39M.png", alt="A diagram showing all the different sizes of a box and where each sizing section starts and ends", width="800", height="559" %}

You can't set an explicit width and height on inline elements.
Any block level margin and padding will be ignored by the surrounding elements.

```css
.my-element {
	display: block;
}
```

Block elements don't sit alongside each other.
They create a new line for themselves. Unless changed by other CSS code,
a block element will expand to the size of the inline dimension,
therefore spanning the full width in a horizontal writing mode.
The margin on all sides of a block element will be respected.

```css
.my-element {
	display: flex;
}
```

The `display` property also determines how an element's children should behave.
For example,
setting the `display` property to `display: flex` makes the box a block-level box,
and also converts its children to flex items.
This enables the flex properties that control alignment, ordering and flow.

## Flexbox and Grid

There are two main layout mechanisms that create layout rules for multiple elements, *[flexbox](/learn/css/flexbox)* and *[grid](/learn/css/grid)*.
They share similarities, but are designed to solve different layout problems.


{% Aside %}
We will be going into much more detail for both of these in future modules, but here is a high-level overview of what both are and what they are useful for.
{% endAside %}

### Flexbox

```css
.my-element {
	display: flex;
}
```

Flexbox is a layout mechanism for one-dimensional layouts.
Layout across a single axis, either horizontally or vertically.
By default, flexbox will align the element's children next to each other,
in the inline direction,
and stretch them in the block direction, so they're all the same height.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjxmor',
  tab: 'css,result',
  height: 300
} %}
</figure>


Items will stay on the same axis and not wrap when they run out of space.
Instead they will try to squash onto the same line as each other.
This behaviour can be changed using the `align-items`, `justify-content` and `flex-wrap` properties.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOyWLmg'
} %}
</figure>

Flexbox also converts the child elements to be **flex items**,
which means you can write rules on how they behave inside a flex container.
You can change alignment, order and justification on an individual item.
You can also change how it shrinks or grows using  the `flex` property.

```css
.my-element div {
 	flex: 1 0 auto;
}
```

The `flex` property is a shorthand for `flex-grow`, `flex-shrink` and `flex-basis`.
 You can expand the above example like this:

```css
.my-element div {
 flex-grow: 1;
 flex-shrink: 0;
 flex-basis: auto;
}
```

Developers provide these low-level rules to hint a browser how the layout should behave
when it is challenged by content and viewport dimensions.
This makes it a very useful mechanism for responsive web design.

### Grid

```css
.my-element {
	display: grid;
}
```

Grid is similar in a lot of ways to **flexbox**,
but it is designed to control multi-axis layouts instead of single-axis layouts (vertical or horizontal space).

Grid enables you to write layout rules on an element that has `display: grid`,
and introduces a few new primitives for layout styling,
such as the `repeat()` and `minmax()` functions.
One useful grid unit is the  `fr` unit—which is a fraction of remaining space—you can build traditional 12 column grids,
with a gap between each item, with 3 CSS properties:

```css
.my-element {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1rem;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjxGVz'
} %}
</figure>

This example above shows a single axis layout.
Where flexbox mostly treats items as a group,
grid gives you precise control over their placement in two dimensions.
We could define that the first item in this grid takes up 2 rows and 3 columns:

```css
.my-element :first-child {
  grid-row: 1/3;
  grid-column: 1/4;
}
```

The `grid-row` and `grid-column` properties instruct the first element in the grid to span to the start of the fourth column,
from the first column, then span to the third row, from the first row.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNwrwB',
  height: 650
} %}
</figure>

## Flow layout

If not using grid or flexbox,
your elements display in normal flow.
There are a number of layout methods that you can use to adjust the behavior and position of items when in normal flow.

### Inline block

Remember how surrounding elements don't respect block margin and padding on an inline element?
With `inline-block` you *can* cause that to happen.

```css
p span {
	display: inline-block;
}
```

Using `inline-block` gives you a box that has some of the characteristics of a block-level element,
but still flows inline with the text.

```css
p span {
	margin-top: 0.5rem;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PoWZJKw',
  height: 300,
  tab: 'css,result'
} %}
</figure>

### Floats

If you have an image that sits within a paragraph of text,
wouldn't it be handy for that text to wrap around that image like you might see in a newspaper?
You can do this with floats.

```css
img {
	float: left;
	margin-right: 1em;
}
```

The `float` property instructs an element to "float" to the direction specified.
The image in this example is instructed to float left,
which then allows sibling elements to "wrap" around it.
You can instruct an element to float `left`, `right` or `inherit`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwPaLMg',
  height: 300
} %}
</figure>

{% Aside 'warning' %}
When you use `float`, keep in mind that any elements following the floated element may have their layout adjusted.
To prevent this, you can clear the float,
either by using `clear: both` on an element that follows your floated element
*or* with `display: flow-root` on the parent of your floated elements.

Find out more in the article
[The end of the clearfix hack](https://rachelandrew.co.uk/archives/2017/01/24/the-end-of-the-clearfix-hack/).
{% endAside %}

### Multicolumn layout

If you have a really long list of elements,
such as a list of all of the countries of the world,
it can result in _a lot_ of scrolling and time wasted for a user.
It can also create excess whitespace on the page.
With CSS multicolumn,
you can split this into multiple columns to help with both of these issues.

```html
<h1>All countries</h1>
<ul class="countries">
  <li>Argentina</li>
  <li>Aland Islands</li>
  <li>Albania</li>
  <li>Algeria</li>
  <li>American Samoa</li>
  <li>Andorra</li>
  …
</ul>
```

```css
.countries {
	column-count: 2;
	column-gap: 1em;
}
```

This automatically splits that long list into two columns and adds a gap between the two columns.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'gOgrpzO'
} %}
</figure>

```css
.countries {
	width: 100%;
	column-width: 260px;
	column-gap: 1em;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOyqPvB'
} %}
</figure>

Instead of setting the number of columns that the content is split into,
you can also define a minimum desired width, using `column-width`.
As more space is made available in the viewport,
more columns will automatically be created and as space is reduced,
columns will also reduce.
This is very useful in responsive web design contexts.

### Positioning

Last on this overview of layout mechanisms is positioning.
The `position` property changes how an element behaves in the normal flow of the document,
and how it relates to other elements.
The available options are `relative`, `absolute`, `fixed` and `sticky` with the default value being `static`.

```css
.my-element {
  position: relative;
  top: 10px;
}
```

This element is nudged 10px down based on its current position in the document,
as it is positioned relative to itself.
Adding `position: relative` to an element also makes it the containing block of any child elements with `position: absolute`.
This means that its child will now be repositioned to this particular element,
instead of the topmost relative parent, when it has an absolute position applied to it.

```css
.my-element {
  position: relative;
  width: 100px;
  height: 100px;
}

.another-element {
	position: absolute;
	bottom: 0;
	right: 0;
	width: 50px;
	height: 50px;
}
```

When you set `position` to `absolute`,
it breaks the element out of the current document flow.
This means two things:

1. You can position this element wherever you like, using `top`, `right`, `bottom` and `left` in its nearest relative parent.
1. All of the content surrounding an absolute element reflows to fill the remaining space left by that element.

An element with a `position` value of `fixed` behaves in a similar way to `absolute`,
with its parent being the root `<html>` element.
Fixed position elements stay anchored from the top left based on the `top`, `right`, `bottom` and `left` values that you set.

You can achieve the anchored,
fixed aspects of `fixed` and the more predictable document flow-honoring aspects of `relative` by using `sticky`.
With this value, as the viewport scrolls past the element,
it stays anchored to the `top`, `right`, `bottom` and `left` values that you set.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdNGZB',
  height: 600
} %}
</figure>

## Wrap-up

There's a lot of choice and flexibility with CSS layout.
To dive further into the power of CSS [Flexbox](/learn/css/flexbox) and [Grid](/learn/css/grid), continue into the next few modules.


{% Assessment 'layout' %}

# Lists

Imagine you have a bunch of items you plan to buy during your next grocery trip. One common way to represent this visually is a list—but how can you add styling to your grocery list?

```html
<ul>
  <li>oat milk</li>
  <li>rhubarb</li>
  <li>cereal</li>
  <li>pie crust</li>
</ul>
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYzrEOW',
  tab: 'result'
} %}
</figure>

## Creating a List

The preceding list started with a semantic element, or `<ul>`, with grocery list items (`<li>` elements) as children. If you inspect each `<li>` element you can see that they all have `display: list-item`, which is why the browser renders a `::marker` by default.

```css
li {
  display: list-item;
}
```

There are two other types of lists.

Ordered lists can be created with `<ol>`, in which case the list-item will display a number as the `::marker`.

```html
<ol>
  <li>oat milk</li>
  <li>rhubarb</li>
  <li>cereal</li>
  <li>pie crust</li>
</ol>
```

And description lists are created with `<dl>`, however this list type does not use the `<li>` list item element.

```html
<dl>
  <dt>oat milk</dt>
  <dd>- non dairy trendy drink</dd>
  <dt>cereal</dt>
  <dd>- breakfast food</dd>
</dl>
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNOrZNG',
  tab: 'result'
} %}
</figure>

## List styles
{% BrowserCompat 'css.properties.list-style-position' %}

Now that you know how to make a list, you can style them. The first CSS properties to discover are those that are applied to the entire list.

There are three list-style properties you can use to style your example: `list-style-position`, `list-style-image`, and `list-style-type`.

### `list-style-position`

[`list-style-position`](https://developer.mozilla.org/docs/Web/CSS/list-style-position) allows you to move your bullet point to either `inside` or `outside` the list-item's contents. The default `outside` means the bullet point is not included in the list items contents while `inside` moves the first element among the list item's contents.

{% Img src="image/dQwiPAoChjTYzXYCNg6U6Tsnr3x1/qVlpVCrwKwbGjEJdmqh0.jpg", alt="A list with both outside and inside ::marker which shows that outside (default value) is not in the list-item and is inside the list-item content box.", width="800", height="270" %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExXPwxL',
  tab: 'result'
} %}
</figure>

### `list-style-image`

[`list-style-image`](https://developer.mozilla.org/docs/Web/CSS/list-style-image) allows you to replace your list's bullet points with images. This enables you to set an image such as an `url` or `none` to make your bullets an image, svg or gif even. You can also use any media type or even a data URI.

Let's look at how we can add an image of each of our grocery items as the `list-style-image`:

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GREoMgK',
  tab: 'css,result'
} %}
</figure>

{% Aside %}
This property is a bit limited in controlling the position, size, etc. of the bullets, so we recommend using the [`::marker`](#marker-pseudo) property for a more customizable approach.
{% endAside %}

### `list-style-type`

The final option is to style the [`list-style-type`](https://developer.mozilla.org/docs/Web/CSS/list-style-type) which changes the bullet points to known style keywords, custom strings, emojis and more. You can view all of the possible list style types [here](https://developer.mozilla.org/docs/Web/CSS/list-style-type ).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOwWGEy',
  tab: 'css,result'
} %}
</figure>

### `list-style` shorthand

Now that we have all of these individual properties, we can use the [`list-style`](https://developer.mozilla.org/docs/Web/CSS/list-style) shorthand to set all of our list styles in one line:

```css
list-style: <'list-style-type'> || <'list-style-position'> || <'list-style-image'>
```

`list-style` allows you to declare combinations of one, two, or three of the `list-style` properties in any order. If `list-style-type` and `list-style-image` are both set, then` list-style-type` is used as a fallback if the image is unavailable.

```css
/* type */
list-style: square;

/* image */
list-style: url('../img/shape.png');

/* position */
list-style: inside;

/* type | position */
list-style: georgian inside;

/* type | image | position */
list-style: lower-roman url('../img/shape.png') outside;

/* Keyword value */
list-style: none;

/* Global values */
list-style: inherit;
list-style: initial;
list-style: revert;
list-style: unset;
```

This is the most commonly used property of the list styles covered in this section. One common application is `list-style: none` to hide default styles. Default styles come from the browser, and you often see reset stylesheets removing list styles like padding and margins. You can also use this shorthand to set styles, like `list-style: square inside;`

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYRJGme',
  tab: 'result'
} %}
</figure>

So far, the examples have focused on styling an entire list and list items, but what about a more granular approach?

## `::marker` pseudo-element

The `list-item` marker element is the bullet, hyphen, or roman numeral that helps indicate each item in your list.

{% Img src="image/dQwiPAoChjTYzXYCNg6U6Tsnr3x1/pOWTl4BYyJI7qgbMVeYu.jpg", alt="A list with three items which shows that each of the bullets are ::marker pseudo-elements.", width="800", height="395" %}

If you inspect the list in DevTools, you can see a `::marker` element for each of the list items, despite not declaring any in HTML. If you inspect the `::marker` further, you'll see the browser default styling for it.

```css
::marker {
    unicode-bidi: isolate;
    font-variant-numeric: tabular-nums;
    text-transform: none;
    text-indent: 0px !important;
    text-align: start !important;
    text-align-last: start !important;
}
```

When you declare a list, each item is given a marker, despite there being no bullet point or roman numeral in your HTML. This is  a pseudo-element because the browser generates it for you, and provides a limited styling API to target it. [Learn more about the anatomy of the CSS bullet.](/css-marker-pseudo-element/) `::marker` currently has [limited support](https://developer.mozilla.org/docs/Web/CSS/::marker#browser_compatibility) in Safari.

### Marker box

In the CSS layout model, list item markers are represented by a marker box associated with each list item. The marker box is the container which typically contains the bullet or number.

To style the marker box, you can use the `::marker` selector. This allows you to select just the marker instead of styling based on the entire list.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOwWGPy',
  tab: 'css,result'
} %}
</figure>

{% Aside %}
Note: `::marker` elements precede any pseudo-elements that you may have inserted using CSS `::before`.
{% endAside %}

### Marker styles

Now that you have selected the marker, let's look at the styling properties available to this selector. You can learn more about [Custom bullets with CSS ::marker](/css-marker-pseudo-element/) on web.dev.

There are quite a few allowed CSS `::marker` Properties:

- `animation-*`
- `transition-*`
- `color`
- `direction`
- `font-*`
- `content`
- `unicode-bidi`
- `white-space`

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYRJGNy',
  tab: 'result'
} %}
</figure>

{% Aside %}
In ordered lists, the bullets default to numbers. The `::marker` content value is a use case for [counters](https://developer.mozilla.org/docs/Web/CSS/CSS_Lists_and_Counters/Using_CSS_counters) to create custom numbering.
{% endAside %}

## Display type

All of our `list-style` and `::marker` properties know to style `<li>` elements because they have a default display value of list-item. You can also make things that aren't an `<li>` into a list item.

You do this by adding the property `display: list-item`. One example of using `display: list-item` is if you want a hanging bullet on a heading, so that you can change it to something else with `::marker`. The following example shows a heading using `display: list-item` for styling purposes, with a list using correct list markup below.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExXPwjR',
  tab: 'css,result'
} %}
</figure>

While you can turn anything into a list-item view with `display`, you should not use this instead of using correct list markup, if the content you are styling really is a list. Changing the visual appearance of an item to a list item does not change how accessibility services read and recognize the item, so it will not be read as a list item to screen readers or switch devices. You should always use semantic markup and create lists with `<li>` whenever possible.

{% Assessment 'lists' %}

## Resources

- [MDN Guide on Styling Lists](https://developer.mozilla.org/docs/Learn/CSS/Styling_text/Styling_lists)
- [Custom bullets with CSS ::marker](/css-marker-pseudo-element/)
- [Smashing Magazine: CSS Lists, Markers and Counters](https://www.smashingmagazine.com/2019/07/css-lists-markers-counters/)
- [MDN Using CSS Counters](https://developer.mozilla.org/docs/Web/CSS/CSS_Lists_and_Counters/Using_CSS_counters)
- [CSS Lists and Counters Module Level 3](https://www.w3.org/TR/css-lists-3/)
- [CSS-Tricks: Counting With CSS Counters and CSS Grid](https://css-tricks.com/counting-css-counters-css-grid/)

# Logical Properties

A really common user interface pattern is a text label with a supporting inline icon.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYgvZBx'
} %}
</figure>

The icon sits to the left of the text with a small gap between the two,
provided by `margin-right` on the icon.
There's a problem though,
because this will only work when the text direction is left to right.
If the text direction changed to right-to-left—which is how languages like Arabic read—the icon will sit up against the text.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BapWKWm'
} %}
</figure>

How do you account for this in CSS?
Logical properties allow you to resolve these situations. Among many other benefits, they provide free, automatic support for internationalization.
They help you build a more resilient, inclusive front-end.

## Terminology

The physical properties of top, right, bottom, and left refer to the physical dimensions of the viewport.
You can think of these like a compass rose on a map.
Logical properties, on the other hand,
refer to the edges of a box as they relate to the _flow of content_.
Therefore, they can change if the text direction or writing mode changes.
This is a big shift from directional styles,
and it gives us a lot more flexibility when styling our interfaces.

## Block flow

Block flow is the direction in which content blocks are placed.
For example, if there are two paragraphs, the block flow is where the second paragraph will go.
In an English document, the block flow is top-to-bottom.
Think of this in the context of paragraphs of text following each other, top-to-bottom.

<figure>
{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/JKfvuIFBBtmvylmFSV8K.svg",
alt="Three blocks, div elements, with a down arrow, labelled 'block flow'",
width="800",
height="507" %}
</figure>

## Inline flow

The inline flow is how text flows in a sentence.
In an English document the inline flow is left to right.
If you were to change the document language of your webpage to Arabic (`<html lang="ar">`),
then the inline flow would be right-to-left.

<figure>
{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/DfyMS0jh0SjSxaeNioJt.svg",
alt="Three words, 'she sells seashells', with a left-to-right arrow, labelled 'inline flow'",
width="800",
height="507" %}
</figure>

Text flows in the direction determined by the document's writing mode.
You can change the direction that text is laid out with the `writing-mode` property.
This can be applied to the entire document, or to individual elements.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNZGam'
} %}
</figure>

## Flow relative

Historically in CSS,
we have only been able to apply properties like margin relative to the direction of their sides.
For example, `margin-top` is applied to the physical top of the element.
With logical properties, `margin-top` becomes `margin-block-start`.
This means that regardless of language and text direction,
the **block flow** has appropriate margin rules.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ZELeBzM'
} %}
</figure>

<figure>
{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/GezxDZXkJgkMevkKg39M.png",
alt="A diagram showing all the different sizes of a box and where each sizing section starts and ends",
width="800",
height="559" %}
</figure>

## Sizing

To prevent an element exceeding a certain width or height,
write a rule like this:

```css
.my-element {
  max-width: 150px;
  max-height: 100px;
}
```

The flow-relative equivalents are `max-inline-size` and `max-block-size`.
You can also use `min-block-size` and `min-inline-size` instead of `min-height` and `min-width`.

With logical properties,
that max width and height rule would look like this:

```css
.my-element {
  max-inline-size: 150px;
  max-block-size: 100px;
}
```

## Start and end

Instead of using directions such as top, right, bottom and left,
use start and end. This gives you block-start, inline-end, block-end, and inline-start.
These allow you to apply CSS properties that respond to writing mode changes.

For example, to align text to the right, you could use this CSS:

```css
p {
  text-align: right;
}
```

If your aim is not to align to the physical right,
but rather to the start of the reading direction,
this isn't helpful.
With logical values, there are more helpful `start` and `end` values which map to the text direction.
The text alignment rule now looks like this:

```css
p {
  text-align: end;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdpdwo'
} %}
</figure>

## Spacing and positioning

Logical properties for `margin`, `padding` and `inset`
make positioning elements, and determining how these elements interact with each other across writing modes easier and more efficient.
The margin and padding related properties are still direct mappings to directions,
but the key difference is that when a writing mode changes, they change with it.

```css
.my-element {
  padding-top: 2em;
  padding-bottom: 2em;
  margin-left: 2em;
  position: relative;
  top: 0.2em;
}
```

This adds some vertical inside space with `padding` and pushes it out from the left with `margin`.
The `top` property also shifts it downwards.
With logical property equivalents, it would instead look like this:

```css
.my-element {
  padding-block-start: 2em;
  padding-block-end: 2em;
  margin-inline-start: 2em;
  position: relative;
  inset-block-start: 0.2em;
}
```

This adds some inline inside space with `padding` and pushes it out from the inline-start with `margin`.
The `inset-block` property moves it inwards from the block-start.

The `inset-block` property isn't the only shorthand option with logical properties.
This rule can be further condensed,
using shorthand versions of the margin and padding properties.

```css
.my-element {
  padding-block: 2em;
  margin-inline: 2em 0;
  position: relative;
  inset-block: 0.2em 0;
}
```

## Borders

Adding `border` and `border-radius` can also be done with logical properties.
To add a border on the bottom and right, with a right-hand radius, you might write a rule like this:

```css
.my-element {
  border-bottom: 1px solid red;
  border-right: 1px solid red;
  border-bottom-right-radius: 1em;
}
```

Or, you could use logical properties like this:

```css
.my-element {
  border-block-end: 1px solid red;
  border-inline-end: 1px solid red;
  border-end-end-radius: 1em;
}
```

The `end-end` in `border-end-end-radius` is the block end _and_ inline end.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgMgby'
} %}
</figure>

## Units

Logical properties bring two new units: `vi` and `vb`.
A `vi` unit is 1% of the viewport size in the inline direction.
The non-logical property equivalent is `vw`.
The `vb` unit is 1% of the viewport in the block direction.
The non-logical property equivalent is `vh`.

These units will always map to the reading direction.
For example, if you want an element to take up 80% of the available inline space of a viewport,
using the `vi` unit will automatically switch that size to be top to bottom if the writing mode is vertical.

## Using logical properties pragmatically

Logical properties and writing modes are not just for internationalization.
You can use them to produce a more versatile user interface.

If you have a chart that has labels on the X axis and Y axis,
you might want the text on the Y label to read vertically.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNZNgE'
} %}
</figure>

Because the Y axis label in the demo has a `writing-mode` of `vertical-rl`,
you can use the same `margin` values on both labels.
The `margin-block-start` value applies to both labels
because the block start is on the right for the Y axis and on the top for the X axis.
The block-start sides have a red border so you can see them.

## Solving the icon issue

Now that we've covered logical properties,
this knowledge can be applied to the design problem we started with.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYgvZBx'
} %}
</figure>

```css
p {
  display: inline-flex;
  align-items: center;
}

p svg {
  width: 1.2em;
  height: 1.2em;
  margin-right: 0.5em;
  flex: none;
}
```

The margin has been applied to the right of the icon element.
In order for the spacing between the icon and the text to support all reading direction,
the `margin-inline-end` property needs to be used instead.

```css/8
p {
  display: inline-flex;
  align-items: center;
}

p svg {
  width: 1.2em;
  height: 1.2em;
  margin-inline-end: 0.5em;
  flex: none;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBRrrOy'
} %}
</figure>

Now, regardless of reading direction,
the icon will position itself and space itself appropriately.

{% Assessment 'logical-props' %}

# Overflow

When content extends beyond its parent, there are many options for how you can handle it. You can scroll to add additional space, clip the overflowing edges, indicate the cut-off with an ellipsis, and so much more. Overflow is especially important to consider when developing for phone applications and multiple screen sizes.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'LYjEjWZ',
  tab: 'result'
} %}
</figure>

There are two different clipping options in CSS; `text-overflow` will help with individual lines of text, and the `overflow` properties will help control overflow in the box model.

## Single line overflow with `text-overflow`

Use the [`text-overflow`](https://developer.mozilla.org/docs/Web/CSS/text-overflow) property on any element that contains text node(s), for example a paragraph, `<p>`. It specifies how the text appears when it doesn’t fit in the available space of the element. All viewable HTML text on a page is in [text nodes](https://developer.mozilla.org/docs/Web/API/Text). To use `text-overflow` you need a single unwrapped line of text, so you must also set `overflow` to `hidden` and have a `white-space` value that prevents wrapping.

```css
p {
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNwQXyN',
  tab: 'result'
} %}
</figure>

## Using overflow properties

Overflow properties are set on an element to control what happens when its children need more space than it has available. This can be intentional, like in an interactive map like Google Maps, where a user pans around a large image clipped to a specific size. It can also be unintentional like in a chat application where the user types a lengthy message that doesn’t fit in the text bubble.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKvwvXE',
  tab: 'result'
} %}
</figure>

You can think of the overflow in two parts. The parent element has a firmly constrained space that will not change. You can think of this as a window. The child elements are content that want more space from the parent. You can think of this as what you are looking through the window at. Managing overflow will help guide how the window frames this content.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxrmxOm',
  tab: 'result'
} %}
</figure>

### Scrolling on the vertical and horizontal axis

The `overflow-y` property controls physical overflow along the vertical axis of the device viewport, therefore scrolling up and down.

The `overflow-x` property controls overflow along the horizontal axis of the device viewport, therefore scrolling left and right.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzQdzoG',
  tab: 'css,result'
} %}
</figure>

### Logical properties for scroll direction
{% BrowserCompat 'css.properties.overflow-inline' %}

The [`overflow-inline`](https://developer.mozilla.org/docs/Web/CSS/overflow-inline) and [`overflow-block`](https://developer.mozilla.org/docs/Web/CSS/overflow-block) properties set the overflow based on the document direction and writing mode.

### The `overflow` shorthand

The [`overflow`](https://developer.mozilla.org/docs/Web/CSS/overflow) shorthand sets both `overflow-x` and `overflow-y` styles in one line:

```css
overflow: hidden scroll;
```

If two keywords are specified, the first applies to `overflow-x` and the second to `overflow-y`. Otherwise, both `overflow-x` and `overflow-y` use the same value.

#### Values

Let's take a closer look at the [values and keywords](https://developer.mozilla.org/docs/Web/CSS/overflow#values) available for the `overflow` properties.

`overflow: visible` (default)
: Without setting the property, `overflow: visible` is the default value for the web. This ensures that content is never unintentionally hidden and follows the core tenets of "never hide content" or "safe layouts of precise layouts".

`overflow: hidden`
: With `overflow: hidden` content is clipped in the specified direction, and no scrollbars are provided to show it.

`overflow: scroll`
: `overflow: scroll` enables scrollbars to allow users to scroll through content. Even if content isn't currently overflowing, scrollbars will be present. This is a great way to reduce future layout shift if a container may be scrollable in the future based, for example, on resize, and visually prepare the user for scrollable areas.

`overflow: clip`
: Like `overflow: hidden`, the content with `overflow: clip` is clipped to the element's padding box. The difference between `clip` and `hidden` is that the `clip` keyword also forbids all scrolling, including programmatic scrolling.

`overflow: auto`
: Finally, the value most commonly used, `overflow: auto`. This respects the user's preferences and shows scrollbars if needed, but hides them by default, and gives responsibility for scrolling to the user and browser.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'gORZaaa',
  tab: 'result'
} %}
</figure>

{% Aside %}
Using the `overflow` property with a value other than `visible` creates a [block formatting context](https://developer.mozilla.org/docs/Web/Guide/CSS/Block_formatting_context).
{% endAside %}

## Scrolling and overflow

Many of these `overflow` behaviors introduce a scrollbar, but there’s a few specific scroll behaviors and properties that can help you control scrolling on your overflow container.

### Scrolling and accessibility

It's important to make sure that the scrollable area can accept focus so that a keyboard user can tab to the box, then use the arrow keys to scroll.

To allow a scrolling box to accept focus add `tabindex="0"`, a name with the [`aria-labelledby`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby) attribute, and an appropriate `role` attribute. For example:

```html
<div tabindex="0" role="region" aria-labelledby="id-of-descriptive-text">
    content
</div>
```

CSS can then be used to indicate that the box has focus, using the `outline` property to give a visual clue that it will now be scrollable.

In [Using CSS to Enforce Accessibility](https://adrianroselli.com/2021/06/using-css-to-enforce-accessibility.html) Adrian Roselli demonstrates how CSS can help prevent accessibility regressions. For example, to only turn on scrolling and add the focus indicator if the correct attributes are used. The following rules will only make the box scrollable if it has a `tabindex`, `aria-labelledby`, and `role` attribute.

```css
[role][aria-labelledby][tabindex] {
  overflow: auto;
}

[role][aria-labelledby][tabindex]:focus {
  outline: .1em solid blue;
}
```

### Scrollbar positioning within the box model

Scroll bars take up space within the padding box and can compete for space if `inline` and not `overlayed`. The [box model module](/learn/css/box-model/#the-areas-of-the-box-model) expands more on this potential source of layout shift.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BaReoEV',
  tab: 'result'
} %}
</figure>

### root-scroller vs implicit-scroller

You may notice that some scrollers have a pull-to-refresh behavior and other special behaviors, especially when developing for mobile and hybrid applications. This scroll behavior happens on the root scroller. There is only ever one root scroller on a page. By default, the [documentElement](https://developer.mozilla.org/docs/Web/API/Document/documentElement) is the page's root scroller, however, by changing which element is the root scroller, the special behaviors can be applied to scrollers other than the documentElement, we call this new scroller the implicit root scroller.

To create a root scroller, you can use something called *scroller promotion* by positioning a container as fixed, ensuring it covers the entire viewport and is z-index on top with a scroller. Experience a root scroller vs a nested implicit scroller [here](https://cdpn.io/web-dot-dev/debug/dyzPzwz).

<figure>
  {% Video
    src="video/dQwiPAoChjTYzXYCNg6U6Tsnr3x1/sn1cOusFy18gRkZroAET.mp4",
    autoplay="true",
    loop="true",
    width="380",
    muted="true"
  %}
  <figcaption>
    The video shows a root scroller with bounce behavior and new styling features, <br>
    compared to scrolling an implicit scroller with no enhanced scroll behavior.
  </figcaption>
</figure>

### scroll-behavior
{% BrowserCompat 'css.properties.scroll-behavior' %}

`scroll-behavior` allows you to opt into browser-controlled scrolling to elements. This allows you to specify how in-page navigation like `.scrollTo()` or links are handled.

This is especially useful when used with [prefers-reduced-motion](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion) to specify scroll behavior based on user preference.

```css
@media (prefers-reduced-motion: no-preference) {
  .scroll-view {
    scroll-behavior: auto;
  }
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'oNwJgae',
  tab: 'result'
} %}
</figure>

### overscroll-behavior
{% BrowserCompat 'css.properties.overscroll-behavior' %}

If you’ve ever reached the end of a modal overlay, then continued scrolling and had the page behind the overlay move, this is the scroll chaining, or bubbling up to the parent scroll container. The [`overscroll-behavior`](https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior) property allows you to prevent overflow scrolling leaking into a parent container (called scroll chaining).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'powqJQe',
  tab: 'result'
} %}
</figure>

{% Assessment 'overflow' %}

## Resources

[Overflow And Data Loss In CSS from Smashing Magazine](https://www.smashingmagazine.com/2019/09/overflow-data-loss-css/)

# Pseudo-classes

Say you've got an email sign up form,
and you want the email form field to have a red border if it contains an invalid email address.
How do you do that?
You can use an `:invalid` CSS pseudo-class,
which is one of many browser-provided pseudo-classes.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdMGjE',
  height: 250
} %}
</figure>

A pseudo-class lets you apply styles based on state changes and external factors.
This means that your design can react to user input such as an invalid email address.
These are covered in the [selectors](/learn/css/selectors) module,
and this module will take you through them in more detail.

Unlike pseudo-elements,
which you can learn more about in the [previous module](/learn/css/pseudo-elements),
pseudo-*classes* hook onto specific *states* that an element might be in,
rather than generally style parts of that element.

## Interactive states

The following pseudo-classes apply due to an interaction a user has with your page.

### `:hover`
{% BrowserCompat 'css.selectors.hover' %}

If a user has a pointing device like a mouse or trackpad,
and they place it over an element,
you can hook on to that state with
[`:hover`](https://developer.mozilla.org/docs/Web/CSS/:hover) to apply styles.
This is a useful way to hint that an element can be interacted with.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgJyNP',
  height: 250
} %}
</figure>

### `:active`
{% BrowserCompat 'css.selectors.active' %}

This state is triggered when an element is actively being interacted with—
such as a click—before click is released.
If a pointing device like a mouse is used,
this state is when the click starts and hasn't yet been released.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNxpam',
  height: 250
} %}
</figure>

### `:focus`, `:focus-within`, and `:focus-visible`
{% BrowserCompat 'css.selectors.focus' %}

If an element can receive focus—like a `<button>`—
you can react to that state with the
[`:focus`](https://developer.mozilla.org/docs/Web/CSS/:focus) pseudo-class.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNREoyj'
} %}
</figure>

You can also react if a child element of your element receives focus with
[`:focus-within`](https://developer.mozilla.org/docs/Web/CSS/:focus-within).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'mdRMOoV',
  height: 250
} %}
</figure>

Focusable elements, like buttons,
will show a focus ring when they are in focus—even when clicked.
In this sort of situation, a developer will apply the following CSS:

```css
button:focus {
	outline: none;
}
```

This CSS removes the default browser focus ring when an element receives focus,
which presents an accessibility issue for users who navigate a web page with a keyboard.
If there is no focus style,
they won't be able to keep track of where focus currently is when using the <kbd>tab</kbd> key.
With [`:focus-visible`](https://developer.mozilla.org/docs/Web/CSS/:focus-visible)
you can present a focus style when an element receives focus via the keyboard,
while also using the `outline: none` rule to prevent it when a pointer device interacts with it.

```css
button:focus {
	outline: none;
}

button:focus-visible {
	outline: 1px solid black;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBRXRdW',
  height: 350
} %}
</figure>

### `:target`
{% BrowserCompat 'css.selectors.target' %}

The [`:target`](https://developer.mozilla.org/docs/Web/CSS/:target)
pseudo-class selects an element that has an `id` matching a URL fragment.
Say you have the following HTML:

```html
<article id="content">
	…
</article>
```

You can attach styles to that element when the url contains `#content`.

```css
#content:target {
	background: yellow;
}
```

This is useful for highlighting areas that might have been specifically linked to,
such as the main content on a website, via a skip link.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKavaqx'
} %}
</figure>

## Historic states

### `:link`
{% BrowserCompat 'css.selectors.link' %}

The [`:link`](https://developer.mozilla.org/docs/Web/CSS/:link)
pseudo-class can be applied to any `<a>` element that has a `href` value that **hasn't been** visited yet.

### `:visited`

You can style a link that's already been visited by the user using the
[`:visited`](https://developer.mozilla.org/docs/Web/CSS/:visited) pseudo-class.
This is the opposite state to `:link` but you have fewer CSS properties to use for
[security reasons](https://developer.mozilla.org/docs/Web/CSS/Privacy_and_the_:visited_selector).
You can only style `color`, `background-color`,
`border-color`, `outline-color` and the color of SVG `fill` and `stroke`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWjmzM'
} %}
</figure>

#### Order matters

If you define a `:visited` style,
it can be overridden by a link pseudo-class with at least equal specificity.
Because of this,
it's recommended that you use the LVHA rule for styling links with pseudo-classes in a particular order:
`:link`, `:visited`, `:hover`, `:active`.

```css
a:link {}
a:visited {}
a:hover {}
a:active {}
```

{% Aside %}
For security reasons,
you can only change styles defined by a `:link` or unvisited state with the `:visited` pseudo-class,
so making sure you define changeable styles first is important.
Sticking to the LVHA rule will help with that.
{% endAside %}

## Form states

The following pseudo-classes can select form elements,
in the various states that these elements might be in during interaction with them.

### `:disabled` and `:enabled`
{% BrowserCompat 'css.selectors.disabled' %}

If a form element,
such as a `<button>` is disabled by the browser,
you can hook on to that state with the
[`:disabled`](https://developer.mozilla.org/docs/Web/CSS/:disabled) pseudo-class.
The [`:enabled`](https://developer.mozilla.org/docs/Web/CSS/:enabled)
pseudo-class is available for the opposite state,
though form elements are also `:enabled` by default,
therefore you might not find yourself reaching for this pseudo-class.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgogPG',
  height: 250
} %}
</figure>

### `:checked` and `:indeterminate`
{% BrowserCompat 'css.selectors.checked' %}

The [`:checked`](https://developer.mozilla.org/docs/Web/CSS/:checked)
pseudo-class is available when a supporting form element,
such as a checkbox or radio button is in a checked state.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrvrxv',
  height: 250
} %}
</figure>

The `:checked` state is a binary(true or false) state,
but checkboxes do have an in-between state when they are neither checked or unchecked.
This is known as the
[`:indeterminate`](https://developer.mozilla.org/docs/Web/CSS/:indeterminate) state.

An example of this state is when you have a "select all" control that checks all checkboxes in a group.
If the user was to then uncheck one of these checkboxes,
the root checkbox would no longer represent "all" being checked,
so should be put into an indeterminate state.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdvdLB',
  height: 250
} %}
</figure>

The `<progress>` element also has an indeterminate state that can be styled.
A common use case is to give it a striped appearance to indicate it's unknown how much more is needed.

### `:placeholder-shown`
{% BrowserCompat 'css.selectors.placeholder-shown' %}

If a form field has a `placeholder` attribute and **no value**,
the [`:placeholder-shown`](https://developer.mozilla.org/docs/Web/CSS/:placeholder-shown)
pseudo-class can be used to attach styles to that state.
As soon as there is content in the field,
whether it has a `placeholder` or not,
this state will no longer apply.

### Validation states
{% BrowserCompat 'css.selectors.valid' %}

You can respond to HTML form validation with pseudo-classes such as
[`:valid`](https://developer.mozilla.org/docs/Web/CSS/:valid),
[`:invalid`](https://developer.mozilla.org/docs/Web/CSS/:invalid) and
[`:in-range`](https://developer.mozilla.org/docs/Web/CSS/:in-range).
The `:valid` and `:invalid` pseudo-classes are useful for contexts
such as an email field that has a `pattern` that needs to be matched,
for it to be a valid field.
This valid value state can be shown to the user,
helping them understand they can safely move to the next field.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdMpaL',
  height: 250
} %}
</figure>

The `:in-range` pseudo-class is available if an input has a `min` and `max`,
such as a numeric input *and* the value is within those bounds.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBRXrpP',
  height: 250
} %}
</figure>

With HTML forms,
you can determine that a field is required with the `required` attribute.
The [`:required`](https://developer.mozilla.org/docs/Web/CSS/:required)
pseudo-class will be available for required fields.
Fields that are not required can be selected with the
[`:optional`](https://developer.mozilla.org/docs/Web/CSS/:optional) pseudo-class.

{% Aside %}
It's not a good idea to rely solely on color to signify state changes—
especially red and green—because colorblind and low-vision users can struggle to see a state change,
or even miss it completely.
A good idea is to use color to support state changes,
along with text changes and icon changes to visually signify change
{% endAside %}

## Selecting elements by their index, order and occurrence

There is a group of pseudo-classes that select items based on where they are in the document.

### `:first-child` and `:last-child`
{% BrowserCompat 'css.selectors.first-child' %}

If you want to find the first or last item,
you can use
[`:first-child`](https://developer.mozilla.org/docs/Web/CSS/:first-child) and
[`:last-child`](https://developer.mozilla.org/docs/Web/CSS/:last-child).
These pseudo-classes will return either the first or last element in a group of sibling elements.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNxZRO'
} %}
</figure>

### `:only-child`
{% BrowserCompat 'css.selectors.only-child' %}

You can also select elements that have no siblings,
with the
[`:only-child`](https://developer.mozilla.org/docs/Web/CSS/:only-child) pseudo-class.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyNzvaj'
} %}
</figure>

### `:first-of-type` and `:last-of-type`
{% BrowserCompat 'css.selectors.first-of-type' %}

You can select the
[`:first-of-type`](https://developer.mozilla.org/docs/Web/CSS/:first-of-type) and
[`:last-of-type`](https://developer.mozilla.org/docs/Web/CSS/:last-of-type) which at first,
look like they do the same thing as `:first-child` and `:last-child`, but consider this HTML:

```html
<div class="my-parent">
	<p>A paragraph</p>
	<div>A div</div>
	<div>Another div</div>
</div>
```

And this CSS:

```css
.my-parent div:first-child {
	color: red;
}
```

No elements would be colored red because the first child is a paragraph and not a div.
The `:first-of-type` pseudo-class is useful in this context.

```css
.my-parent div:first-of-type {
	color: red;
}
```

Even though the first `<div>` is the second child,
it is still the first of type inside the `.my-parent` element,
so with this rule, it will be colored red.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRreXE',
  height: 250
} %}
</figure>

### `:nth-child` and `:nth-of-type`
{% BrowserCompat 'css.selectors.nth-child' %}

You're not limited to first and last children and types either.
The [`:nth-child`](https://developer.mozilla.org/docs/Web/CSS/:nth-child) and
[`:nth-of-type`](https://developer.mozilla.org/docs/Web/CSS/:nth-of-type)
pseudo-classes allow you to specify an element that is at a certain index.
The indexing in CSS selectors starts at 1.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrvWbL'
} %}
</figure>

You can pass more than an index into these pseudo-classes too.
If you wanted to select all even elements, you can use `:nth-child(even)`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'wvgqdwv'
} %}
</figure>

You can also create more complex selectors that find items at regularly spaced intervals,
using [the An+B microsyntax](https://www.w3.org/TR/css-syntax-3/#anb-microsyntax).

```css
li:nth-child(3n+3) {
	background: yellow;
}
```

This selector selects every third item,
starting at item 3.
The `n` in this expression is the index,
which starts at zero the 3 (`3n`) is how much you multiply that index by.

Let's say you have 7 `<li>` items.
The first item that is selected is 3 because `3n+3` translates to `(3 * 0) + 3`.
The next iteration would pick item 6 because `n` has now incremented to `1`,
so `(3 * 1) + 3)`.
This expression works for both `:nth-child` and `:nth-of-type`.

You can play around with this sort of selector on this
[nth-child tester](https://css-tricks.com/examples/nth-child-tester/) or this
[quantity selector tool](https://quantityqueries.com).

### `:only-of-type`
{% BrowserCompat 'css.selectors.only-of-type' %}

Lastly, you can find the only element of a certain type in a group of siblings with
[`:only-of-type`](https://developer.mozilla.org/docs/Web/CSS/:only-of-type).
This is useful if you want to select lists with only one item,
or if you want to find the only bold element in a paragraph.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgobJb',
  height: 250
} %}
</figure>

## Finding empty elements

It can sometimes be useful to identify completely empty elements,
and there is a pseudo-class for that too.

### `:empty`
{% BrowserCompat 'css.selectors.empty' %}

If an element has no children, the
[`:empty`](https://developer.mozilla.org/docs/Web/CSS/:empty) pseudo-class applies to them.
Children aren't just HTML elements or text nodes though: they can also be whitespace,
which can be confusing when you're debugging the following HTML and wondering why it isn't working with `:empty`:

```html
<div>
</div>
```

The reason is that there's some whitespace between the opening and closing `<div>`,
so empty won't work.

The `:empty` pseudo-class can be useful if you have little control over the HTML and want to hide empty elements,
such as a WYSIWYG content editor.
Here, an editor has added a stray, empty paragraph.

```html
<article class="post">
 <p>Donec ullamcorper nulla non metus auctor fringilla.</p>
 <p></p>
 <p>Curabitur blandit tempus porttitor.</p>
</article>
```

With `:empty`, you can find that and hide it.

```css
.post :empty {
	display: none;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwPzbKg',
  height: 250,
  tab: 'html,result'
} %}
</figure>

## Finding and excluding multiple elements

Some pseudo-classes help you to write more compact CSS.

### `:is()`
{% BrowserCompat 'css.selectors.is' %}

If you want to find all of the `h2`, `li` and `img` child elements in a `.post` element,
you might think to write a selector list like this:

```css
.post h2,
.post li,
.post img {
	…
}
```

With the [`:is()`](https://developer.mozilla.org/docs/Web/CSS/:is)
pseudo-class, you can write a more compact version:

```css
.post :is(h2, li, img) {
	…
}
```

The `:is` pseudo-class is not only more compact than a selector list but it is also more forgiving.
In most cases,
if there's an error or unsupported selector in a selector list,
the entire selector list will no longer work.
If there's an error in the passed selectors in an `:is` pseudo-class,
it will ignore the invalid selector, but use those which are valid.

### `:not()`
{% BrowserCompat 'css.selectors.not' %}

You can also exclude items with the
[`:not()`](https://developer.mozilla.org/docs/Web/CSS/:not) pseudo-class.
For example, you can use it to style all links that don't have a `class` attribute.

```css
a:not([class]) {
	color: blue;
}
```

A `:not` pseudo-class can also help you to improve accessibility.
For example, an `<img>` must have an `alt`, even if its an empty value,
so you could write a CSS rule that adds a thick red outline to invalid images:

```css
img:not([alt]) {
	outline: 10px red;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpyWJK'
} %}
</figure>

{% Assessment 'pseudo-classes' %}

# Pseudo-elements

If you've got an article of content
and you want the first letter to be a much bigger drop cap—
how do you achieve that?

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/Qpo2f3eRInt5iM6qW2p2.svg",
alt="A couple of paragraphs of text with a blue drop cap",
width="800",
height="318" %}

In CSS,
you can use the `::first-letter` pseudo-element to achieve this sort of design detail.

```css
p::first-letter {
  color: blue;
  float: left;
  font-size: 2.6em;
  font-weight: bold;
  line-height: 1;
  margin-inline-end: 0.2rem;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PoWjybP'
} %}
</figure>

A pseudo-element is like adding or targeting an extra element without having to add more HTML.
This example solution, using `::first-letter`,
is one of many pseudo-elements.
They have a range of roles,
and in this lesson you're going to learn which pseudo-elements are available and how you can use them.

## `::before` and `::after`

Both the
[`::before`](https://developer.mozilla.org/docs/Web/CSS/::before) and
[`::after`](https://developer.mozilla.org/docs/Web/CSS/::after)
pseudo-elements create a child element inside an element **only** if you define a `content` property.

```css
.my-element::before {
	content: "";
}

.my-element::after {
	content: "";
}
```

The `content` can be any string
—even an empty one—
but be mindful that anything other than an empty string will likely be announced by a screen reader.
You can add an image `url`,
which will insert an image at its original dimensions,
so you won't be able to resize it.
You can also insert a
[`counter`](https://developer.mozilla.org/docs/Web/CSS/counter()).

{% Aside 'key-term' %}
You can create a named counter and then increment it,
based on its position in the document flow.
There's all sorts of contexts where they can be really useful, such as automatically numbering an outline.
{% endAside %}

Once a `::before` or `::after` element has been created,
you can style it however you want with no limits.
You can only insert a `::before` or `::after` element to an element that will accept child elements
([elements with a document tree](https://www.w3.org/TR/CSS21/generate.html)),
so elements such as `<img />`, `<video>` and `<input>` won't work.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrEYrg'
} %}
</figure>

{% Aside 'gotchas' %}
`input[type="checkbox"]` is an exception.
It is allowed to have pseudo-element children.
{% endAside %}

## `::first-letter`

We met this pseudo-element at the start of the lesson.
It is worth being aware that not all CSS properties can be used when targeting
[`::first-letter`](https://developer.mozilla.org/docs/Web/CSS/::first-letter).
The available properties are:

- `color`
- `background` properties (such as `background-image`)
- `border` properties (such as `border-color`)
- `float`
- `font` properties (such as `font-size` and `font-weight`)
- text properties (such as `text-decoration` and `word-spacing`)

```css
p::first-letter {
  color: goldenrod;
  font-weight: bold;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEJmOx'
} %}
</figure>

{% Aside %}
You can only use `:first-letter` on block containers.
Therefore, it won't work if you try to add it to an element that has `display: inline`.
{% endAside %}

## `::first-line`

The [`::first-line`](https://developer.mozilla.org/docs/Web/CSS/::first-line)
pseudo-element will let you style the first line of text
only if the element with `::first-line` applied has a `display` value of `block`,
`inline-block`, `list-item`, `table-caption` or `table-cell`.

```css
p::first-line {
  color: goldenrod;
  font-weight: bold;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgZVaO'
} %}
</figure>

Like the `::first-letter` pseudo-element,
there's only a subset of CSS properties you can use:

- `color`
- `background` properties
- `font` properties
- `text` properties

## `::backdrop`

If you have an element that is presented in full screen mode,
such as a `<dialog>` or a `<video>`,
you can style the backdrop—the space between the element and the rest of the page—with the
[`::backdrop`](https://developer.mozilla.org/docs/Web/CSS/::backdrop) pseudo-element:


```css
video::backdrop {
  background-color: goldenrod;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjwqRQ'
} %}
</figure>

The `::backdrop` pseudo-element is supported in all major browsers apart from Safari.

## `::marker`

The [`::marker`](https://developer.mozilla.org/docs/Web/CSS/::marker)
pseudo-element lets you style the bullet or number for a list item or the arrow of a `<summary>` element.

```css
::marker {
  color: hotpink;
}

ul ::marker {
  font-size: 1.5em;
}

ol ::marker {
  font-size: 1.1em;
}

summary::marker {
  content: '\002B'' '; /* Plus symbol with space */
}

details[open] summary::marker {
  content: '\2212'' '; /* Minus symbol with space */
}
```

Only a small subset of CSS properties are supported for `::marker`:

- `color`
- `content`
- `white-space`
- `font` properties
- `animation` and `transition` properties

You can change the marker symbol, using the `content` property. You can use this to set a plus and minus symbol for the closed and empty states of a `<summary>` element, for example.


<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJozrR'
} %}
</figure>

## `::selection`

The [`::selection`](https://developer.mozilla.org/docs/Web/CSS/::selection)
pseudo-element allows you to style how selected text looks.

```css
::selection {
  background: green;
  color: white;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEJeZK'
} %}
</figure>

This pseudo-element can be used to style all selected text as in the above demo.
It can also be used in combination with other selectors for a more specific selection style.

```css
p:nth-of-type(2)::selection {
  background: darkblue;
  color: yellow;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWJozXM'
} %}
</figure>

As with other pseudo-elements, only a subset of CSS properties are allowed:

- `color`
- `background-color` but **not** `background-image`
- `text` properties

## `::placeholder`
{% BrowserCompat 'css.selectors.placeholder' %}

You can add a helper hint to form elements,
such as `<input>` with a `placeholder` attribute.
The [`::placeholder`](https://developer.mozilla.org/docs/Web/CSS/::placeholder)
pseudo-element allows you to style that text.

```css
input::placeholder {
  color: darkcyan;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKaqrrY'
} %}
</figure>

The `::placeholder` only supports a subset of CSS rules:

- `color`
- `background` properties
- `font` properties
- `text` properties

{% Aside %}
A `placeholder` is not `<label>`
and should not be used in place of a `<label>`.
Form elements must be labelled or they will be inaccessible.
{% endAside %}

## `::cue`
{% BrowserCompat 'css.selectors.cue' %}

Last in this tour of pseudo-elements is the
[`::cue`](https://developer.mozilla.org/docs/Web/CSS/::cue) pseudo-element.
This allows you to style the WebVTT cues,
which are the captions of a `<video>` element.

You can also pass a selector into a `::cue`,
which allows you to style specific elements _inside_ a caption.

```css
video::cue {
  color: yellow;
}

video::cue(b) {
  color: red;
}

video::cue(i) {
  color: lightpink;
}
```

{% Assessment 'pseudo-elements' %}

# Selectors

If you've got some text that you only want to be larger and red if it's the first paragraph of an article,
how do you do that?

```html
<article>
  <p>I want to be red and larger than the other text.</p>
  <p>I want to be normal sized and the default color.</p>
</article>
```

You use a CSS selector to find that specific element and apply a CSS rule, like this.

```css
article p:first-of-type {
  color: red;
  font-size: 1.5em;
}
```

CSS provides you with a lot of options to select elements and apply rules to them,
ranging from very simple to very complex,
to help solve situations like this.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWprGYz',
  height: 250
} %}
</figure>

## The parts of a CSS rule

To understand how selectors work and their role in CSS,
it's important to know the parts of a CSS rule.
A CSS rule is a block of code,
containing one or more selectors and one or more declarations.

<figure>
{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/hFR4OOwyH5zWc5XUIcyu.svg", alt="An image of a CSS rule with the selector .my-css-rule.", width="800", height="427" %}
</figure>

In this CSS rule, the **selector** is `.my-css-rule`
which finds all elements with a class of `my-css-rule` on the page.
There are three declarations within the curly brackets.
A declaration is a property and value pair which applies styles to the elements matched by the selectors.
A CSS rule can have as many declarations and selectors as you like.

## Simple selectors

The most straightforward group of selectors target HTML elements plus
classes, IDs, and other attributes which may be added to an HTML tag.

### Universal selector
{% BrowserCompat 'css.selectors.universal' %}

A [universal selector](https://developer.mozilla.org/docs/Web/CSS/Universal_selectors)—also known as a wildcard—matches any element.

```css
* {
  color: hotpink;
}
```

This rule causes every HTML element on the page to have hotpink text.

### Type selector
{% BrowserCompat 'css.selectors.type' %}

A [type selector](https://developer.mozilla.org/docs/Web/CSS/Type_selectors)
matches a HTML element directly.

```css
section {
  padding: 2em;
}
```

This rule causes every `<section>` element to have `2em` of `padding` on all sides.

### Class selector
{% BrowserCompat 'css.selectors.class' %}

A HTML element can have one or more items defined in their `class` attribute.
The
[class selector](https://developer.mozilla.org/docs/Web/CSS/Class_selectors)
matches any element that has that class applied to it.

```html
<div class="my-class"></div>
<button class="my-class"></button>
<p class="my-class"></p>
```

Any element that has the class applied to it will get colored red:

```css
.my-class {
  color: red;
}
```

Notice how the `.` is only present in CSS and **not** the HTML.
This is because the `.` character instructs the CSS language to match class attribute members.
This is a common pattern in CSS, where a special character,
or set of characters, is used to define selector types.

A HTML element that has a class of `.my-class` will still be matched to the above CSS rule,
even if they have several other classes, like this:

```html
<div class="my-class another-class some-other-class"></div>
```

This is because CSS looks for a `class` attribute that _contains_ the defined class,
rather than matching that class exactly.

{% Aside %}
The value of a class attribute can be almost anything you want it to be.
One thing that could trip you up, is that you can't start a class (or an ID) with a number,
such as `.1element`.
You can read more [in the specification](https://www.w3.org/TR/CSS21/syndata.html#characters).
{% endAside %}

### ID selector
{% BrowserCompat 'css.selectors.id' %}

An HTML element with an `id` attribute should be the only element on a page with that ID value.
You select elements with an
[ID selector](https://developer.mozilla.org/docs/Web/CSS/ID_selectors) like this:

```css
#rad {
  border: 1px solid blue;
}
```

This CSS would apply a blue border to the HTML element that has an `id` of `rad`, like this:

```html
<div id="rad"></div>
```

Similarly to the class selector `.`,
use a `#` character to instruct CSS to look for an element that matches the `id` that follows it.

{% Aside %}
If the browser encounters more than one instance of an `id`
it will still apply any CSS rules that match its selector.
However, any element that has an `id` attribute is supposed to have a unique value for it,
so unless you're writing very specific CSS for a single element,
avoid applying styles with the `id` selector as it means you can't re-use those styles elsewhere.
{% endAside %}

### Attribute selector
{% BrowserCompat 'css.selectors.attribute' %}

You can look for elements that have a certain HTML attribute,
or have a certain value for an HTML attribute,
using the [attribute selector](https://developer.mozilla.org/docs/Web/CSS/Attribute_selectors).
Instruct CSS to look for attributes by wrapping the selector with square brackets (`[ ]`).

```css
[data-type='primary'] {
  color: red;
}
```

This CSS looks for all elements that have an attribute of `data-type` with a value of `primary`, like this:

```html
<div data-type="primary"></div>
```

Instead of looking for a specific value of `data-type`,
you can also look for elements with the attribute present, regardless of its value.

```css
[data-type] {
  color: red;
}
```

```html
<div data-type="primary"></div>
<div data-type="secondary"></div>
```

Both of these `<div>` elements will have red text.

You can use case-sensitive attribute selectors
by adding an `s` operator to your attribute selector.

```css
[data-type='primary' s] {
  color: red;
}
```

This means that if a HTML element had a `data-type` of `Primary`,
instead of `primary`, it would not get red text.
You can do the opposite—case insensitivity—by using an `i` operator.

Along with case operators,
you have access to operators that match portions of strings inside attribute values.

```css
/* A href that contains "example.com" */
[href*='example.com'] {
  color: red;
}

/* A href that starts with https */
[href^='https'] {
  color: green;
}

/* A href that ends with .com */
[href$='.com'] {
  color: blue;
}
```

<figure>
{% Codepen {
    user: 'web-dot-dev',
    id: 'BapBbOy'
  } %}
  <figcaption>In this demo, the `$` operator in our attribute selector gets the filetype from the `href` attribute.
  This makes it possible to prefix the label—based on that filetype—using a pseudo-element.</figcaption>
</figure>

### Grouping selectors

A selector doesn't have to match only a single element.
You can group multiple selectors by separating them with commas:

```css
strong,
em,
.my-class,
[lang] {
  color: red;
}
```

This example extends the color change to both `<strong>` elements and `<em>` elements.
It's also extended to a class named `.my-class`, and an element that has a `lang` attribute.

{% Assessment 'simple-selectors' %}

## Pseudo-classes and pseudo-elements

CSS provides useful selector types that focus on specific platform state,
like when an element is hovered, structures _inside_ an element, or parts of an element.

### Pseudo-classes

HTML elements find themselves in various states,
either because they are interacted with,
or one of their child elements is in a certain state.

For example, an HTML element could be hovered with the mouse pointer by a user
_or_ a child element could also be hovered by the user.
For those situations, use the `:hover` pseudo-class.

```css
/* Our link is hovered */
a:hover {
  outline: 1px dotted green;
}

/* Sets all even paragraphs to have a different background */
p:nth-child(even) {
  background: floralwhite;
}
```

Find out more in the [pseudo-classes module](/learn/css/pseudo-classes).

### Pseudo-element

Pseudo-elements differ from pseudo-classes because instead of responding to the platform state,
they act as if they are inserting a new element with CSS.
Pseudo-elements are also syntactically different from pseudo-classes,
because instead of using a single colon (`:`), we use a double colon (`::`).

{% Aside %}
A double colon (`::`) is what distinguishes a pseudo-element from a pseudo-class,
but because this distinction wasn't present in older versions of CSS specs,
browsers support a single colon for the original pseudo-elements,
such as `:before` and `:after` to help with backwards compatibility with older browsers, like IE8.
{% endAside %}

```css
.my-element::before {
  content: 'Prefix - ';
}
```

As in the above demo where you prefixed a link's label with the type of file it was,
you can use the `::before` pseudo-element to insert content **at the start of an element**,
or the `::after` pseudo-element to insert content at the **end of an element**.

Pseudo-elements aren't limited to inserting content, though.
You can also use them to target specific parts of an element.
For example, suppose you have a list.
Use `::marker` to style each bullet point (or number) in the list

```css
/* Your list will now either have red dots, or red numbers */
li::marker {
  color: red;
}
```

You can also use `::selection` to style the content that has been highlighted by a user.

```css
::selection {
  background: black;
  color: white;
}
```

Learn more in the [module on pseudo-elements](/learn/css/pseudo-elements).

{% Assessment 'pseudo-selectors' %}

## Complex selectors

You have already seen a vast array of selectors,
but sometimes, you will need more _fine-grained control_ with your CSS.
This is where complex selectors step in to help.

It's worth remembering at this point that although the following selectors give us more power,
we can only **cascade downwards**, selecting child elements.
We are not able to target upwards and select a parent element.
We cover what the cascade is and how it works
[in a later lesson](/learn/css/the-cascade).

### Combinators

A combinator is what sits between two selectors.
For example, if the selector was `p > strong`, the combinator is the `>` character.
The selectors which use these combinators help you select items based on their position in the document.

#### Descendant combinator

To understand descendant combinators,
you need to first understand parent and child elements.

```html
<p>A paragraph of text with some <strong>bold text for emphasis</strong>.</p>
```

The parent element is the `<p>` which contains text.
Inside that `<p>` element is a `<strong>` element, making its content bold.
Because it is inside the `<p>`, it is a child element.

A descendant combinator allows us to target a child element.
This uses a space (` `) to instruct the browser to look for child elements:

```css
p strong {
  color: blue;
}
```

This snippet selects all `<strong>` elements
that are child elements of `<p>` elements only, making them blue recursively.

<figure>
  {% Codepen {
    user: 'web-dot-dev',
    id: 'BapBbGN'
  } %}
  <figcaption>Because the descendant combinator is recursive,
the padding added to each child element applies, resulting in a staggered effect.</figcaption>
</figure>

This effect is better visualised in the above example,
using the combinator selector, `.top div`.
That CSS rule adds left padding to those `<div>` elements.
Because the combinator is recursive,
all `<div>` elements that are in `.top` will have that same padding applied to them.

Take a look at the HTML panel in this demo
to see how the `.top` element has several `<div>` child elements which themselves,
have `<div>` child elements.

#### Next sibling combinator

You can look for an element that immediately follows another element
by using a `+` character in your selector.

<figure>
{% Codepen {
    user: 'web-dot-dev',
    id: 'JjEPzwB'
} %}
</figure>

To add space between stacked elements,
use the next sibling combinator to add space
_only_ if an element is a **next sibling** of a child element of `.top`.

You could add margin to all child elements of `.top`,
using the following selector:

```css
.top * {
  margin-top: 1em;
}
```

The problem with this is that because you're selecting every child element of `.top`,
this rule potentially creates extra, unnecessary space.
The **next sibling combinator**,
mixed with a **universal selector** enables you to not only control what elements get space,
but also apply space to **any element**.
This provides you with some long-term flexibility,
regardless of what HTML elements appear in `.top`.

#### Subsequent- sibling combinator

A subsequent combinator is very similar to a next sibling selector.
Instead of a `+` character however,
use a `~` character.
How this differs is that an element just has to follow another element with the same parent,
rather than being the next element with the same parent.

<figure>
  {% Codepen {
    user: 'web-dot-dev',
    id: 'ZELzPPX',
    height: 400
  } %}
  <figcaption>Use a subsequent selector along with a `:checked` pseudo class to create a pure CSS switch element.</figcaption>
</figure>

This subsequent combinator provides a little less rigidity,
which is useful in contexts like the above sample,
where we change the color of a custom switch when its associated checkbox has the `:checked` state.

#### Child combinator

A child combinator (also known as direct descendant)
allows you more control over the recursion that comes with combinator selectors.
By using the `>` character, you limit the combinator selector to apply **only** to direct children.

Consider the previous, next sibling selector example.
The space is added to each **next sibling**,
but if one of those elements also has **next sibling elements** as children,
it can result in undesirable, extra spacing.

<figure>
{% Codepen {
    user: 'web-dot-dev',
    id: 'ExZYMJL'
} %}
</figure>

To alleviate this problem,
change the **next sibling selector** to incorporate a child combinator: `> * + *`.
The rule will now **only** apply to direct children of `.top`.

<figure>
{% Codepen {
    user: 'web-dot-dev',
    id: 'dyNbrEr'
} %}
</figure>

### Compound selectors

You can combine selectors to increase specificity and readability.
For example, to target `<a>` elements,
that also have a class of `.my-class`, write the following:

```css
a.my-class {
  color: red;
}
```

This wouldn't apply a red color to all links
and it would also only apply the red color to `.my-class` **if** it was on an `<a>` element.
For more on this, see the [specificity module](/learn/css/specificity).

{% Assessment 'complex-selectors' %}

## Resources

- [CSS selectors reference](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors)
- [Interactive selectors game](https://flukeout.github.io/)
- [Pseudo-class and pseudo-elements reference](https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements)
- [A tool that translates CSS selectors into plain-english explainers](https://kittygiraudel.github.io/selectors-explained/)

# Shadows

Say you've been sent a design to build and in that design there's a picture of a t-shirt,
cut out, with a drop shadow.
The designer tells you that the product image is dynamic
and can be updated via the content management system,
so the drop shadow needs to be dynamic too. Instead of a t-shirt,
the image could be a visor or shorts, or any other item.
How do you do that with CSS?

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'wvgrMrR',
  height: 600
} %}
</figure>

CSS has the
[`box-shadow`](https://developer.mozilla.org/docs/Web/CSS/box-shadow) and
[`text-shadow`](https://developer.mozilla.org/docs/Web/CSS/text-shadow) properties,
but the picture isn't text, so you can't use `text-shadow`.
If you use `box-shadow`, the shadow is on the surrounding box,
_not_ around the t-shirt.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNrwae',
  height: 600
} %}
</figure>

Luckily, there is another option: the
[`drop-shadow()`](https://developer.mozilla.org/docs/Web/CSS/filter-function/drop-shadow()) filter.
This enables you to do exactly what the designer asked for.
There are plenty of options when it comes to shadows in CSS,
each designed for a different use case.

## Box shadow
{% BrowserCompat 'css.properties.box-shadow' %}

The `box-shadow` property is for adding shadows to the box of an HTML element.
It works on block elements and inline elements.

```css
.my-element {
	box-shadow: 5px 5px 20px 5px #000;
}
```

The order of values for `box-shadow` are as follows:

1. **Horizontal offset**:
a positive number pushes it out from the left and a negative number will push it out from the right.
1. **Vertical offset**:
a positive number pushes it down from the top,
and a negative number will push it up from the bottom.
1. **Blur radius**:
a larger number produces a more blurred shadow,
whereas a small number produces a sharper shadow.
1. **Spread radius** (optional):
a larger number increases the size of the shadow and a smaller number decreases it,
making it the same size as the **blur radius** if it's set to 0.
1. **Color**:
[Any valid color value](/learn/css/color).
If this isn't defined, the computed text color will be used.

To make a box shadow an inner shadow,
rather than the default outer shadow,
add an `inset` keyword **before** the other properties.

```css
/* Outer shadow */
.my-element {
	box-shadow: 5px 5px 20px 5px #000;
}

/* Inner shadow */
.my-element {
	box-shadow: inset 5px 5px 20px 5px #000;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'rNjGevp',
  height: 600
} %}
</figure>

### Multiple shadows

You can add as many shadows as you like with `box-shadow`.
Add a comma separated collection of value sets to achieve this:

```css
.my-element {
  box-shadow: 5px 5px 20px 5px darkslateblue, -5px -5px 20px 5px dodgerblue,
    inset 0px 0px 10px 2px darkslategray, inset 0px 0px 20px 10px steelblue;
}

```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpLNXR',
  tab: 'css,result'
} %}
</figure>

### Properties affecting box-shadow

Adding a `border-radius` to your box will also affect the shape of the box shadow.
This is because CSS is creating a shadow based on the shape of the box
as if light is pointing at it.

```css
.my-element {
  box-shadow: 0px 0px 20px 5px darkslateblue;
  border-radius: 25px;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'RwKLaXN',
  tab: 'css,result'
} %}
</figure>

If your box with `box-shadow` is in a container that has `overflow: hidden`,
the shadow **won't** break out of that overflow either.

```html
<div class="my-parent">
  <div class="my-shadow">My shadow is hidden by my parent.</div>
</div>
```

```css
.my-parent,
.my-shadow {
  width: 250px;
  height: 250px;
}

.my-shadow {
  box-shadow: 0px 0px 20px 5px darkslateblue;
}

.my-parent {
  overflow: hidden;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BapwzyQ',
  tab: 'css,result'
} %}
</figure>

## Text shadow
{% BrowserCompat 'css.properties.text-shadow' %}

The `text-shadow` property is very similar to the `box-shadow` property.
It only works on text nodes.

```css
.my-element {
  text-shadow: 3px 3px 3px hotpink;
}
```

The values for `text-shadow` are the same as `box-shadow` and in the same order.
The only difference is that `text-shadow` has no `spread` value and no `inset` keyword.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgeKqm'
} %}
</figure>

When you add a `box-shadow` it is clipped to the shape of your box,
but `text-shadow` has no clipping.
This means that if your text is fully or semi transparent,
the shadow is visible through it.

```css
.my-element {
  text-shadow: 3px 3px 3px gold;
  color: rgb(0 0 0 / 70%);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'LYxzRpb'
} %}
</figure>

### Multiple shadows

You can add as many shadows as you like with `text-shadow`,
just as with `box-shadow`.
Add a comma separated collection of value sets,
and you can create some really cool text effects, such as 3D text.

```css
.my-element {
  text-shadow: 1px 1px 0px white,
    2px 2px 0px firebrick;
  color: darkslategray;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'RwKLGaL',
  tab: 'css,result'
} %}
</figure>

## Drop shadow
{% BrowserCompat 'css.properties.drop-shadow' %}

To achieve a drop shadow that follows any potential curves of an image,
use the CSS `drop-shadow` filter.
This shadow is applied to an alpha mask which makes it very useful for adding a shadow to a cutout image,
as in the case in the intro of this module.

```css
.my-image {
  filter: drop-shadow(0px 0px 10px rgba(0 0 0 / 30%))
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYgGdvm'
} %}
</figure>

{% Aside 'key-term' %}
We cover CSS [filters](/learn/css/filters) in another module,
but in short, filters allow you to apply multiple graphical effects to the pixels of an element.
{% endAside %}

The `drop-shadow` filter has the same values as `box-shadow` **but** the `inset` keyword and `spread` value are not allowed. You can add as many shadows as you like,
by adding multiple instances of `drop-shadow` values to the `filter` property.
Each shadow will use the last shadow as a positioning reference point.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYgeXmW'
} %}
</figure>

{% Assessment 'shadows' %}

# Sizing Units

The web is a responsive medium,
but sometimes you want to control its dimensions to improve the overall interface quality.
A good example of this is limiting line lengths to improve readability.
How would you do that in a flexible medium like the web?

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgEGxj',
  tab: 'css,result'
} %}
</figure>

For this case,
you can use a `ch` unit, which is equal to the width of a "0" character in the rendered font at its computed size.
This unit allows you to limit the width of text with a unit that's designed to size text,
which in turn,
allows predictable control regardless of the size of that text.
The `ch` unit is one of a handful of units that are helpful for specific contexts like this example.

## Numbers

Numbers are used to define `opacity`, `line-height` and even for color channel values in `rgb`.
Numbers are unitless integers (1, 2, 3, 100) and decimals (.1, .2, .3).

Numbers have meaning depending on their context.
For example, when defining `line-height`,
a number is representative of a ratio if you define it without a supporting unit:

```css
p {
  font-size: 24px;
  line-height: 1.5;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLgYZRK',
  tab: 'css,result'
} %}
</figure>

In this example, `1.5` is equal to **150%** of the `p` element's **computed pixel font size**.
This means that if the `p` has a `font-size` of `24px`,
the line height will be computed as `36px`.

{% Aside %}
It's a good idea to use a unitless value for `line-height`,
rather than specifying a unit.
As you learned in the [inheritance module](/learn/css/inheritance),
`font-size` can be inherited.
Defining a unitless `line-height` keeps the line-height relative to the font size.
This provides a better experience than, say, `line-height: 15px`,
which will not change and might look strange with certain font sizes.
{% endAside %}

Numbers can also be used in the following places:

- When setting values for filters: `filter: sepia(0.5)` applies a `50%` sepia filter to the element.
- When setting opacity: `opacity: 0.5` applies a `50%` opacity.
- In color channels: `rgb(50, 50, 50)`,
  where the values 0-255 are acceptable to set a color value.
  [See color lesson](/learn/css/color).
- To transform an element: `transform: scale(1.2)` scales the element by 120% of its initial size.

## Percentages

When using a percentage in CSS you need to know how the percentage is calculated.
For example,`width` is calculated as a percentage of the available width in the parent element.

```css
div {
  width: 300px;
  height: 100px;
}

div p {
  width: 50%; 
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ZELbwwj',
  tab: 'css,result'
} %}
</figure>

In the above example, the width of `div p` is `150px`, assuming that the layout uses the default `box-sizing: content-box`.

If you set `margin` or `padding` as a percentage,
they will be a portion of the **parent element's width**,
regardless of direction.

```css
div {
  width: 300px;
  height: 100px;
}

div p {
  margin-top: 50%; /* calculated: 150px */
  padding-left: 50%; /* calculated: 150px */
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNRQPqX',
  tab: 'css,result'
} %}
</figure>

In the above snippet, both the `margin-top` and `padding-left` will compute to `150px`.

```css
div {
  width: 300px;
  height: 100px;
}

div p {
  width: 50%; /* calculated: 150px */
  transform: translateX(10%); /* calculated: 15px */
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxgwBxv',
  tab: 'css,result'
} %}
</figure>

If you set a `transform` value as a percentage,
it is based on the element with the transform set.
In this example, the `p` has a `translateX` value of `10%` and a `width` of `50%`.
First, calculate what the width will be: `150px` because it is **50% of its parent's width**.
Then, take `10%` of `150px`, which is `15px`.

{% Aside 'key-term' %}
The transform property allows you alter an element's appearance and position by rotating, skewing, scaling and translating it.
This can be done in a 2D and 3D space.
{% endAside %}

## Dimensions and lengths

If you attach a unit to a number, it becomes a dimension.
For example, `1rem` is a dimension.
In this context, the unit that is attached to a number is referred to in specifications as a dimension token.
Lengths are **dimensions that refer to distance** and they can either be absolute or relative.

### Absolute lengths

All absolute lengths resolve against the same base,
making them predictable wherever they're used in your CSS.
For example, if you use `cm` to size your element and then print,
it should be accurate if you compared it to a ruler.

```css
div {
  width: 10cm;
  height: 5cm;
  background: black;
}
```

If you printed this page, the `div` would print as a 10x5cm black rectangle.
Keep in mind, CSS is used not only for digital content, but also to style print content.
Absolute lengths can really come in handy when designing for print.

<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>Unit</th>
        <th>Name</th>
        <th>Equivalent to</th>
      </tr>
    </thead>
  <tbody>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#cm">cm</a></td>
      <td>Centimeters</td>
      <td>1cm = 96px/2.54</td>
    </tr>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#mm">mm</a></td>
      <td>Millimeters</td>
      <td>1mm = 1/10th of 1cm</td>
    </tr>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#q">Q</a></td>
      <td>Quarter-millimeters</td>
      <td>1Q = 1/40th of 1cm</td>
    </tr>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#in">in</a></td>
      <td>Inches</td>
      <td>1in = 2.54cm = 96px</td>
    </tr>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#pc">pc</a></td>
      <td>Picas</td>
      <td>1pc = 1/6th of 1in</td>
    </tr>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#pt">pt</a></td>
      <td>Points</td>
      <td>1pt = 1/72th of 1in</td>
    </tr>
    <tr>
      <td><a href="https://www.w3.org/TR/css-values-4/#px">px</a></td>
      <td>Pixels</td>
      <td>1px = 1/96th of 1in</td>
    </tr>
    </tbody>
  </table>
</div>

### Relative lengths

A relative length is calculated against a base value, much like a percentage.
The difference between these and percentages is that you can contextually size elements.
This means that CSS has units such as `ch` that use the text size as a basis,
and `vw` which is based on the width of the viewport (your browser window).
Relative lengths are particularly useful on the web due to its responsive nature.

#### Font-size-relative units

CSS provides helpful units that are relative to the size of elements of rendered typography,
such as the size of the text itself (`em` units) or width of the typefaces characters (`ch` units).

<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>unit</th>
        <th>relative to:</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#em">em</a></td>
        <td>Relative to the font size,
        i.e. 1.5em will be 50% larger than the base computed font size of its parent.
        (Historically, the height of the capital letter "M").</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#ex">ex</a></td>
        <td>Heuristic to determine whether to use the x-height,
        a letter "x", or `.5em` in the current computed font size of the element.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#cap">cap</a></td>
        <td>Height of the capital letters in the current computed font size of the element.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#ch">ch</a></td>
        <td>Average <a href="https://www.w3.org/TR/css-values-4/#length-advance-measure">character advance</a>
        of a narrow glyph in the element's font
        (represented by the "0" glyph).</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#ic">ic</a></td>
        <td>Average
        <a href="https://www.w3.org/TR/css-values-4/#length-advance-measure">character advance</a>
        of a full width glyph in the element's font,
        as represented by the "水" (CJK water ideograph, U+6C34) glyph.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#rem">rem</a></td>
        <td>Font size of the root element (default is 16px).</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#lh">lh</a></td>
        <td>Line height of the element.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#rlh">rlh</a></td>
        <td>Line height of the root element.</td>
      </tr>
    </tbody>
  </table>
</div>

<figure>
{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/ttaikDgwEC572lrGgWlG.svg", alt="The text, CSS is 10x great with labels for ascender height, descender height and x-height. The x-height represents 1ex and the 0 represents 1ch", width="800", height="203" %}
</figure>

#### Viewport-relative units

You can use the dimensions of the viewport (browser window) as a relative basis.
These units portion up the available viewport space.

<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>unit</th>
        <th>relative to</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#vw">vw</a></td>
        <td>1% of viewport's width. People use this unit to do cool font tricks,
        like resizing a header font based on the width of the page so as the user resizes,
        the font will also resize.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#vh">vh</a></td>
        <td>1% of viewport's height.
        You can use this to arrange items in a UI,
        if you have a footer toolbar for example.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#vi">vi</a></td>
        <td>1% of viewport's size in the root element's <a href="https://www.w3.org/TR/css-writing-modes-4/#inline-axis">inline axis</a>.
        Axis refers to writing modes.
        In horizontal writing modes like English,
        the inline axis is horizontal.
        In vertical writing modes like some Japanese typefaces, the inline axis runs top to bottom.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#vb">vb</a></td>
        <td>1% of viewport's size in the root element's <a href="https://www.w3.org/TR/css-writing-modes-4/#block-axis">block axis</a>.
        For the block axis, this would be the directionality of the language.
        LTR languages like English would have a vertical block axis,
        since English language readers parse the page from top to bottom.
        A vertical writing mode has a horizontal block axis.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#vmin">vmin</a></td>
        <td>1% of the viewport's smaller dimension.</td>
      </tr>
      <tr>
        <td><a href="https://www.w3.org/TR/css-values-4/#vmax">vmax</a></td>
        <td>1% of the viewport's larger dimension.</td>
      </tr>
    </tbody>
  </table>
</div>

```css
div {
  width: 10vw;
}

p {
  max-width: 60ch;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjEYqXa'
} %}
</figure>

In this example, the `div` will be 10% of the viewport's width because `1vw` is **1% of the viewport width**.
The `p` element has a `max-width` of `60ch`
which means it can't exceed the width of 60 "0" characters in the calculated font and size.

{% Aside 'objective' %}

By sizing text with relative units like `em` or `rem`,
rather than an absolute unit, like `px`, the size of your text can respond to user preferences.
This can include the system font size or parent element's font size, such as the `<body>`.
The base size of the `em` is the element's parent and the base size of the `rem` is the base font size of the document.

If you don't define a `font-size` on your `html` element,
this user-preferred system font size will be honoured if you use relative lengths,
such as `em` and `rem`.
If you use `px` units for sizing text,
this preference will be ignored.

{% Video
  src="video/VbAJIREinuYvovrBzzvEyZOpw5w1/cUEl77VN4ZtAdElV4fd6.mp4",
  autoplay=true,
  controls=true,
  muted=true
%}

{% endAside %}

## Miscellaneous units

There are some other units which have been specified to deal with particular types of values.

### Angle units

In the [color module](/learn/css/color/),
we looked at **angle units**,
which are helpful for defining degree values,
such as the hue in `hsl`.
They are also useful for rotating elements within transform functions.

```css
div {
  width: 150px;
  height: 150px;
  transform: rotate(60deg);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwPvRbK',
  tab: 'css,result'
} %}
</figure>

Using the `deg` angle unit, you can rotate a `div` 90° on its center axis.

```css
div {
  background-image: url('a-low-resolution-image.jpg');
}

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
  div {
    background-image: url('a-high-resolution-image.jpg');
  }
}
```

{% Aside %}
Other angle units include `rad` (radians), `grad` (gradians), and `turn` units,
which represent a part of an angle, where `1turn` = `360deg`, and `0.5turn` = `180deg`.
{% endAside %}

#### Resolution units

In the previous example the value of `min-resolution` is `192dpi`.
The `dpi` unit stands for **dots per inch**.
A useful context for this is detecting very high resolution screens,
such as Retina displays in a media query and serving up a higher resolution image.

{% Assessment 'sizing' %}

## Resources

- [CSS Spec Values and Units Level 4](https://www.w3.org/TR/css-values-4)
- [Sizing and Units on MDN](https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Values_and_units)
- [All About Ems](https://learn.scannerlicker.net/2014/07/31/so-how-much-is-an-em/)
- [A percentages explainer](https://wattenberger.com/blog/css-percents)

# Spacing

Say you've got a collection of three boxes,
stacked on top of each other and you want space between them.
How many ways can you think of to do that in CSS?

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/jGjBqBRk3uCvXT7Tdjre.svg",
alt="Three stacked boxes with a downward arrow",
width="800",
height="498" %}

The `margin` property *might* give you what you need,
but it also might add additional spacing that you don't want.
For example, how do you target just the space *in between* each of those elements?
Something like `gap` might be more appropriate in this case.
There are many ways to adjust spacing within a UI,
each with its own strengths and caveats.

## HTML spacing

HTML itself provides some methods to space elements.
The `<br>` and `<hr>` elements allow you to space elements in the block direction,
which if you are in a latin-based language,
is top-to-bottom.

If you use a `<br>` element,
it will create a line-break,
just like if you were to press your enter key in a word processor.

The `<hr>` creates a horizontal line with space either-side, known as `margin`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyNRJQg'
} %}
</figure>

Along with using HTML elements,
HTML *entities* can create space.
An HTML entity is a reserved string of characters that are replaced with character entities by the browser.
For example,
if you were to type `&copy;` in your HTML file,
it would be converted into a © character.
The `&nbsp;` entity is converted into a non-breaking space character,
which provides an inline space.
Be careful though,
because the non-breaking aspect of this character stitches the two elements together,
which can result in odd behaviour.

{% Aside %}
Use HTML elements to add space only when the element helps with the understanding of the document.
For example, an `<hr>` doesn't just add space,
it creates a logical separation of two chunks of content.
If you just want a line with space around it,
adding a border with CSS might be more appropriate.
{% endAside %}

## Margin

If you want to add space to the outside of an element,
you use the `margin` property.
Margin is like adding a cushion around your element.
The `margin` property is shorthand for `margin-top`,
`margin-right`, `margin-bottom` and `margin-left`.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/ECuEOJEGnudhXW5JEFih.svg",
alt="A diagram of the four main areas of the box model.",
width="800",
height="547" %}

The `margin` shorthand applies properties in a particular order:
top, right, bottom and left.
You can remember these with trouble: TRouBLe.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/F8jtvl15CsAcs8Oaid2l.svg",
alt="The word 'Trouble' running downwards with T, R, B and L
extending to Top, Right, Bottom and Left.
A box with arrows showing the directions too.",
width="800",
height="320" %}

The `margin` shorthand can also be used with one, two, or three values.
Adding a fourth value lets you set each individual side.
These are applied as follows:

- One value will be applied to all sides. (`margin: 20px`).
- Two values: the first value will be applied to the top and bottom sides,
and the second value will be applied to the left and right sides.
(`margin: 20px 40px`)
- Three values: the first value is `top`,
the second value is `left` **and** `right`,
and the third value is `bottom`. (`margin: 20px 40px 30px`).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpwqyQ'
} %}
</figure>

Margin can be defined with a length,
percentage or auto value, such as `1em` or `20%`.
If you use a percentage,
the value will be calculated based on the width of your element's containing block.

This means that if your element's containing block has a width of `250px`
and your element has a `margin` value of `20%`:
each side of your element will have a computed margin of `50px`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNQeyb'
} %}
</figure>

You can also use a value of `auto` for margin.
For block level elements with a restricted size,
an `auto` margin will take up available space in the direction that it is applied to.
A good example is this one,
from the [flexbox module](/learn/css/flexbox), where the items push away from each other.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'poRELbR'
} %}
</figure>

Another good example of `auto` margin is a horizontally centered wrapper which has a max width.
This sort of wrapper is often used to create a consistent center column on a website.

```css
.wrapper {
	max-width: 400px;
	margin: 0 auto;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWpgZKq'
} %}
</figure>

Here, margin is removed from the top and bottom (block) sides,
and `auto` shares the space between the left and right (inline) sides.

{% Aside %}
In the previous module on [logical properties](/learn/css/logical-properties),
you learned that instead of specifying `margin-top`, `margin-right`, `margin-bottom` and `margin-left`,
you can use `margin-block-start`, `margin-inline-end`, `margin-block-end` and `margin-inline-start`.
{% endAside %}

### Negative margin

Negative values can also be used for margin.
Instead of adding space between adjacent sibling elements,
it will **reduce space** between them.
This can result in overlapping elements,
if you declare a negative value that's more than the available space.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNQeLP'
} %}
</figure>

### Margin collapse

Margin collapse is a tricky concept,
but it's something you'll run into very commonly when building interfaces.
Say you have two elements: a heading and a paragraph that both have vertical margin on them:

```html
<article>
  <h1>My heading with teal margin</h1>
  <p>A paragraph of text that has blue margin on it, following the heading with margin.</p>
</article>
```

```css
h1 {
	margin-bottom: 2rem;
}

p {
	margin-top: 3rem;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJWgvMx'
} %}
</figure>

At first glance,
you would be forgiven for thinking that the paragraph will be spaced `5em` from the heading,
because `2rem` and `3rem` combined calculate to `5rem`.
Because **vertical margin collapses**, though, the space is actually `3rem`.

Margin collapse works by selecting the largest value of two adjoining elements
with vertical margin set on the adjoining sides.
The bottom of the `h1` meets the top of the `p`,
so the largest value of the `h1`'s bottom margin and the `p`'s top margin is selected.
If the `h1` were to have `3.5rem` of bottom margin,
the space between them both would then be `3.5rem` because that is larger than `3rem`.
Only block margins collapse, not inline (horizontal) margins.

{% Aside %}
This behavior is rooted back to when the web was mostly just documents.
Collapsing margins help to set consistent spacing between elements
without accidentally creating huge gaps between elements that also have margin defined.
{% endAside %}

Margin collapse also helps with empty elements.
If you have a paragraph that has a top and bottom margin of `20px`,
it will only create `20px` of space: not `40px`.
If *anything* is added to the inside of this element though,
including `padding`, its margin will no longer collapse in itself and will be treated as any box with content.

{% Assessment 'margin-collapsing' %}

#### Preventing margin collapse

If you make an element absolutely positioned,
using `position: absolute`, the margin will no longer collapse.
The margin also won't collapse if you use the `float` property, too.

If you have an element with no margin between two elements with block margin,
the margin won't collapse either,
because the two elements with block margin are no longer adjacent siblings: they are just siblings.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNQavQ'
} %}
</figure>

In the [layout lesson](/learn/css/layout),
you learned that flexbox and grid containers are very similar to block containers,
but handle their child elements very differently.
This is the case with margin collapse, too.

If we take the original example from the lesson and apply flexbox with column direction,
the margins are combined,
instead of collapsed.
This can provide predictability with layout work,
which is what flexbox and grid containers are designed for.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdgmNx'
} %}
</figure>

Margin and margin collapse can be tricky to understand,
but understanding how they work, in detail, is very useful,
so [this detailed explainer](https://www.smashingmagazine.com/2019/07/margins-in-css)
is strongly recommended.

## Padding

Instead of creating space on the outside of your box,
like `margin` does,
the `padding` property creates space on the **inside** of your box instead:
like insulation.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/kClqXks3zC6Dio1c6f6v.png",
alt="A box with arrows pointing inwards to show that padding lives inside a box",
width="800",
height="336" %}

Depending on which box model you are using—which was covered back in the
[box model lesson](/learn/css/box-model/)
—`padding` can also affect the overall dimensions of the element too.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYgRrzz'
} %}
</figure>

The `padding` property is shorthand for `padding-top`, `padding-right`, `padding-bottom` and `padding-left`.
Just like `margin`, `padding` has logical properties, too:
`padding-block-start`, `padding-inline-end`, `padding-block-end` and `padding-inline-start`.

## Positioning

Also covered  in the [layout](/learn/css/layout/) module,
if you set a value for `position` that is anything other than `static`,
you can space elements with the `top`, `right`, `bottom` and `left` properties.
There are some differences with how these directional values behave:

- An element with `position: relative` will maintain its place in the document flow,
even when you set these values.
They will be relative to your element's position too.
- An element with `position: absolute`
will base the directional values from the relative parent's position.
- An element with `position: fixed`
will base the directional values on the viewport.
- An element with `position: sticky`
will only apply the directional values when it is in its docked/stuck state.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdNGZB'
} %}
</figure>

In the [logical properties](/learn/css/logical-properties) module,
you learn about the `inset-block` and `inset-inline` properties,
which allow you to set directional values that honor writing mode.

Both properties are shorthands combining the `start` and `end` values
and as such accept either one value to be set for `start` and `end` or
two individual values.

## Grid and flexbox

Lastly, in both grid and flexbox you can use the `gap` property to create space *between* child elements.
The `gap` property is shorthand for `row-gap` and `column-gap`,
it accepts one or two values, which can be lengths or percentages.
You can also use keywords such as `unset`, `initial` and `inherit`.
If you define only one value,
the same `gap` will be applied to both the rows and columns,
but if you define both values,
the first value is `row-gap` and the second value is `column-gap`.

With both flexbox and grid, you can also create space using their distribution and alignment capabilities,
which we cover in the
[grid module](/learn/css/grid) and
[flexbox module](/learn/css/flexbox).

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/JNXSRH4j77loSB099E04.svg",
alt="A diagram representation of a grid with gaps",
width="800",
height="434" %}

## Creating consistent spacing

It is a really good idea to choose a strategy and stick with it
to help you create a consistent user interface that has good flow and rhythm.
A good way to achieve this is use consistent measures for your spacing.

For example, you could commit to using `20px`
as a consistent measure for all gaps between elements—known as gutters—so
all layouts look and feel consistent.
You could also decide to use `1em` as the vertical spacing between flow content,
which would achieve consistent spacing based on the element's `font-size`.
Whatever you choose,
you should save these values as variables (or CSS custom properties)
to tokenize those values and make the consistency a bit easier.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/8eun6aGNHPTr4kyOrYkc.svg",
alt="Consistent spacing between elements,
using either 20px for a layout or 1em for flow content.",
width="800",
height="602" %}

```css
:root {
  --gutter: 20px;
  --spacing: 1em;
}

h1 {
  margin-left: var(--gutter);
  margin-top: var(--spacing);
}

```

Using custom properties like this allows you to define them once,
then use them throughout your CSS.
When they are updated,
either locally within an element or globally,
the values will pass down through the cascade and the updated values will be reflected.

{% Assessment 'conclusion' %}

# Specificity

Suppose that you're working with the following HTML and CSS:

```html
<button class="branding">Hello, Specificity!</button>
```

```css
button {
  color: red;
}

.branding {
  color: blue;
}
```

There's two competing rules here.
One will color the button red and the other will color it blue.
Which rule gets applied to the element?
Understanding the CSS specification's algorithm about specificity
is the key to understanding how CSS decides between competing rules.

Specificity is one of the four distinct stages of the cascade,
which was covered in the last module, on [the cascade](/learn/css/the-cascade/).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzNKMXm',
  height: 200
} %}
</figure>

## Specificity scoring

Each selector rule gets a scoring.
You can think of specificity as a total score and each selector type earns points towards that score.
The selector with the highest score wins.

With specificity in a real project,
the balancing act is making sure the CSS rules you expect to apply, actually _do apply,_
while generally keeping scores low to prevent complexity.
The score should only be as high as we need it to be,
rather than aiming for the highest score possible.
In the future, some genuinely more important CSS might need to be applied.
If you go for the highest score, you'll make that job hard.

## Scoring each selector type

Each selector type earns points.
You add all of these points up to calculate a selector's overall specificity.

### Universal selector

A [universal selector](https://developer.mozilla.org/docs/Web/CSS/Universal_selectors) (`*`)
has **no specificity** and gets **0 points**.
This means that any rule with 1 or more points will override it

```css
* {
  color: red;
}
```

### Element or pseudo-element selector

An [element](https://developer.mozilla.org/docs/Web/CSS/Type_selectors) (type)
or [pseudo-element](https://developer.mozilla.org/docs/Web/CSS/Pseudo-elements)
selector gets **1 point of specificity** .

#### Type selector

```css
div {
  color: red;
}
```

#### Pseudo-element selector

```css
::selection {
  color: red;
}
```

### Class, pseudo-class, or attribute selector

A [class](https://developer.mozilla.org/docs/Web/CSS/Class_selectors),
[pseudo-class](https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes) or
[attribute](https://developer.mozilla.org/docs/Web/CSS/Attribute_selectors) selector gets **10 points of specificity**.

#### Class selector

```css
.my-class {
  color: red;
}
```

#### Pseudo-class selector

```css
:hover {
  color: red;
}
```

#### Attribute selector

```css
[href='#'] {
  color: red;
}
```

The [`:not()`](https://developer.mozilla.org/docs/Web/CSS/:not)
pseudo-class itself adds nothing to the specificity calculation.
However, the selectors passed in as arguments do get added to the specificity calculation.

```css
div:not(.my-class) {
  color: red;
}
```

This sample would have **11 points** of specificity
because it has one type selector (`div`) and one class _inside_ the `:not()`.

### ID selector

An [ID](https://developer.mozilla.org/docs/Web/CSS/ID_selectors)
selector gets **100 points of specificity**,
as long as you use an ID selector (`#myID`) and not an attribute selector (`[id="myID"]`).

```css
#myID {
  color: red;
}
```

### Inline style attribute

CSS applied directly to the `style` attribute of the HTML element,
gets a **specificity score of 1,000 points**.
This means that in order to override it in CSS,
you have to write an extremely specific selector.

```html
<div style="color: red"></div>
```

### `!important` rule

Lastly, an `!important` at the end of a CSS value gets a specificity score of **10,000 points**.
This is the highest specificity that one individual item can get.

An `!important` rule is applied to a CSS property,
so everything in the overall rule (selector and properties) does not get the same specificity score.

```css
.my-class {
  color: red !important; /* 10,000 points */
  background: white; /* 10 points */
}
```

{% Assessment 'scoring-beginner' %}

## Specificity in context

The specificity of each selector that matches an element is added together.
Consider this example HTML:

```html
<a class="my-class another-class" href="#">A link</a>
```

This link has two classes on it.
Add the following CSS, and it gets **1 point of specificity**:

```css
a {
  color: red;
}
```

Reference one of the classes in this rule,
it now has **11 points of specificity**:

```css
a.my-class {
  color: green;
}
```

Add the other class to the selector,
it now has **21 points of specificity**:

```css
a.my-class.another-class {
  color: rebeccapurple;
}
```

Add the `href` attribute to the selector,
it now has **31 points of specificity**:

```css
a.my-class.another-class[href] {
  color: goldenrod;
}
```

Finally,add a `:hover` pseudo-class to all of that,
the selector ends up with **41 points of specificity**:

```css
a.my-class.another-class[href]:hover {
  color: lightgrey;
}
```

{% Assessment 'scoring-advanced' %}

## Visualizing specificity

In diagrams and specificity calculators,
the specificity is often visualized like this:

{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/McrFhjqHXMznUzXbRuJ6.svg", alt="A diagram demonstrating most specific to least specific selectors", width="800", height="474" %}

The left group is `id` selectors.
The second group is class, attribute, and pseudo-class selectors.
The final group is element and pseudo-element selectors.

For reference, the following selector is `0-4-1`:

```css
a.my-class.another-class[href]:hover {
  color: lightgrey;
}
```

{% Assessment 'visualizing' %}

## Pragmatically increasing specificity

Let's say we have some CSS that looks like this:

```css
.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}
```

With HTML that looks like this:

```html
<button class="my-button" onclick="alert('hello')">Click me</button>
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abpoxdR',
  tab: 'css,result'
} %}
</figure>

The button has a grey background,
because the second selector earns **11 points of specificity** (`0-1-1`).
This is because it has one type selector (`button`),
which is **1 point** and an attribute selector (`[onclick]`), which is **10 points**.

The previous rule—`.my-button`—gets **10 points** (`0-1-0`),
because it has one class selector.

If you want to give this rule a boost,
repeat the class selector like this:

```css
.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNOXBJ',
  tab: 'css,result'
} %}
</figure>

Now, the button will have a blue background,
because the new selector gets a specificity score of **20 points** (`0-2-0`).

{% Aside 'caution' %}
If you find that you are needing to boost specificity like this frequently,
it may indicate that you are writing overly specific selectors.
Consider whether you can refactor your CSS to reduce the specificity of other selectors
to avoid this problem.
{% endAside %}

## A matching specificity score sees the newest instance win

Let's stay with the button example for now and switch the CSS around to this:

```css
.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}
```

The button has a grey background,
because **both selectors have an identical specificity score** (`0-1-0`).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYNOXKJ',
  tab: 'css,result'
} %}
</figure>

If you switch the rules in the source order,
the button would then be blue.

```css
[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNReWRO',
  tab: 'css,result'
} %}
</figure>

This is the only instance where newer CSS wins.
To do so it must match the specificity of another selector that targets the same element.

## Resources

- [CSS SpeciFISHity](http://specifishity.com)
- [Specificity Calculator](https://specificity.keegan.st)
- [MDN Specificity](https://developer.mozilla.org/docs/Web/CSS/Specificity)
- [Specifics on CSS Specificity](https://css-tricks.com/specifics-on-css-specificity/)
- [Another Specificity Calculator](https://polypane.app/css-specificity-calculator)

# The cascade

CSS stands for Cascading Stylesheets.
The cascade is the algorithm for solving conflicts where multiple CSS rules apply to an HTML element.
It's the reason that the text of the button styled with the following CSS will be blue.

```css
button {
  color: red;
}

button {
  color: blue;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrgMOm',
  height: 200
} %}
</figure>

Understanding the cascade algorithm helps you understand how the browser resolves conflicts like this.
The cascade algorithm is split into 4 distinct stages.

1. **Position and order of appearance**: the order of which your CSS rules appear
2. **Specificity**: an algorithm which determines which CSS selector has the strongest match
3. **Origin**: the order of when CSS appears and where it comes from, whether that is a browser style,
   CSS from a browser extension, or your authored CSS
4. **Importance**: some CSS rules are weighted more heavily than others,
   especially with the `!important` rule type

## Position and order of appearance

The order in which your CSS rules appear and how they appear is taken into consideration by the cascade
while it calculates conflict resolution.

The demo right at the start of this lesson is the most straightforward example of position.
There are two rules that have selectors of identical specificity,
so the last one to be declared won.

Styles can come from various sources on an HTML page,
such as a `<link>` tag,
an embedded `<style>` tag,
and inline CSS as defined in an element's `style` attribute.

If you have a `<link>` that includes CSS at the top of your HTML page,
then another `<link>` that includes CSS at the bottom of your page: the bottom `<link>` will have the most specificity.
The same thing happens with embedded `<style>` elements, too.
They get more specific, the further down the page they are.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'NWdPaWv'
} %}
  <figcaption>The button has a blue background,
  as defined by CSS which is included by a <code>&lt;link /&gt;</code> element.
  A CSS rule that sets it to be dark is in a second linked stylesheet
  and is applied because of its later position.</figcaption>
</figure>

This ordering also applies to embedded `<style>` elements.
If they are declared before a `<link>`,
the linked stylesheet's CSS will have the most specificity.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxgbLoB'
} %}
<figcaption>The <code>&lt;style&gt;</code> element is declared in the <code>&lt;head&gt;</code>,
while the <code>&lt;link /&gt;</code> element is declared in the <code>&lt;body&gt;</code>.
This means it gets more specificity than the <code>&lt;style&gt;</code> element</figcaption>
</figure>

An inline `style` attribute with CSS declared in it will override all other CSS,
regardless of its position, unless a declaration has `!important` defined.

Position also applies in the order of your CSS rule.
In this example, the element will have a purple background because `background: purple` was declared last.
Because the green background was declared before the purple background, it is now ignored by the browser.

```css
.my-element {
  background: green;
  background: purple;
}
```

Being able to specify two values for the same property
can be a simple way to create fallbacks for browsers that do not support a particular value.
In this next example, `font-size` is declared twice.
If `clamp()` is supported in the browser,
then the previous `font-size` declaration will be discarded.
If `clamp()` isn't supported by the browser,
the initial declaration will be honored, and the font-size will be 1.5rem

```css
.my-element {
  font-size: 1.5rem;
  font-size: clamp(1.5rem, 1rem + 3vw, 2rem);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxgbPMP'
} %}
</figure>

{% Aside %}
This approach of declaring the same property twice works because browsers ignore values they don't understand.
Unlike some other programming languages, CSS will not throw an error or break your program when it detects a line it
cannot parse—the value it cannot parse is invalid and therefore ignored.
The browser then continues to process the rest of the CSS without breaking stuff it already understands.
{% endAside %}

{% Assessment 'position' %}

## Specificity

Specificity is an algorithm which determines which CSS selector is the most specific,
using a weighting or scoring system to make those calculations.
By making a rule more specific,
you can cause it to be applied even if some other CSS that matches the selector appears later in the CSS.

In [the next lesson](/learn/css/specificity) you can learn the details of how specificity is calculated,
however keeping a few things in mind will help you avoid too many specificity issues.

CSS targeting a class on an element will make that rule more specific,
and therefore seen as more important to be applied,
than CSS targeting the element alone.
This means that with the following CSS,
the `h1` will be colored red even though both rules match and the rule for the `h1` selector comes later in the stylesheet.

```html
<h1 class="my-element">Heading</h1>
```

```css
.my-element {
  color: red;
}

h1 {
  color: blue;
}
```

An `id` makes the CSS even more specific,
so styles applied to an ID will override those applied many other ways.
This is one reason why it is generally not a good idea to attach styles to an `id`.
It can make it difficult to overwrite that style with something else.

### Specificity is cumulative

As you can find out in the next lesson,
each type of selector is awarded points which indicate how specific it is,
the points for all of the selectors you have used to target an element are added together.
This means that if you target an element with a selector list such as
`a.my-class.another-class[href]:hover` you get something quite hard to overwrite with other CSS.
For this reason, and to help make your CSS more reusable,
it's a good idea to keep your selectors as simple as possible.
Use specificity as a tool to get at elements when you need to,
but always consider refactoring long, specific selector lists, if you can.

## Origin

The CSS that you write isn't the only CSS applied to a page.
The cascade takes into account the origin of the CSS.
This origin includes the browser's internal stylesheet,
styles added by browser extensions or the operating system,
and your authored CSS.
The **order of specificity of these origins**, from least specific, to most specific is as follows:

1. **User agent base styles**. These are the styles that your browser applies to HTML elements by default.
2. **Local user styles**. These can come from the operating system level, such as a base font size,
   or a preference of reduced motion.
   They can also come from browser extensions,
   such as a browser extension that allows a user to write their own custom CSS for a webpage.
3. **Authored CSS**. The CSS that you author.
4. **Authored `!important`**. Any `!important` that you add to your authored declarations.
5. **Local user styles `!important`**. Any `!important` that come from the operating system level,
   or browser extension level CSS.
6. **User agent `!important`**. Any `!important` that are defined in the default CSS,
   provided by the browser.

<figure>
{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/zPdaZ6G11oYrgJ78EfF7.svg",
alt="A visual demonstration of the order of origins as also explained in the list.", width="800", height="347" %}
</figure>

If you have an `!important` rule type in the CSS you have authored
and the user has an `!important` rule type in their custom CSS, whose CSS wins?

{% Assessment 'origin' %}

## Importance

Not all CSS rules are calculated the same as each other,
or given the same specificity as each other.

The **order of importance**, from least important,
to most important is as follows:

1. normal rule type, such as `font-size`, `background` or `color`
2. `animation` rule type
3. `!important` rule type (following the same order as origin)
4. `transition` rule type

Active animation and transition rule types have higher importance than normal rules.
In the case of transitions higher importance than `!important` rule types.
This is because when an animation or transition becomes active,
its expected behaviour is to change visual state.

## Using DevTools to find out why some CSS is not applying

Browser DevTools will typically show all CSS that could match an element,
with those which are not being used crossed out.

<figure>
{% Img src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/Z6aLsqcqjGAUsWzq7DZs.png",
alt="An image of browser DevTools with overwritten CSS crossed out", width="800", height="446" %}
</figure>

If the CSS you expected to apply doesn't appear at all,
then it didn't match the element.
In that case you need to look elsewhere,
perhaps for a typo in a class or element name or some invalid CSS.

{% Assessment 'conclusion' %}

## Resources

- [A highly interactive explainer of the cascade](https://wattenberger.com/blog/css-cascade)
- [MDN cascade reference](https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance)

# Transitions

When interacting with a website, you might notice that many elements have _state_. For example, dropdowns can be in opened or closed states. Buttons might change color when focused or hovered. Modals appear and disappear.

By default, CSS switches the style of these states instantly.

Using CSS transitions, we can interpolate between the initial state and the target state of the element. The transition between the two enhances the user experience by providing visual direction, support, and hints about the cause and effect of the interaction.

{% Aside 'key-term' %}
_Interpolation_ is the process of creating "in-between" steps that smoothly transition from one state to another.
{% endAside %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'zYzNrJV',
  height: 320
} %}
</figure>

## Transition properties
{% BrowserCompat 'css.properties.transition-property' %}

To use transitions in CSS, you can use the various transition properties or the `transition` shorthand property.

### transition-property

The [`transition-property`](https://developer.mozilla.org/docs/Web/CSS/transition-property) property specifies which style(s) to transition.

```css
.my-element {
  transition-property: background-color;
}
```

The `transition-property` accepts one or more CSS property names in a comma-separated list.

Optionally, you may use `transition-property: all` to indicate that every property should transition.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwWPeEj',
  height: 400
} %}
</figure>

### transition-duration

The [`transition-duration`](https://developer.mozilla.org/docs/Web/CSS/transition-duration) property is used to define the length of time that a transition will take to complete.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'wvegMYp',
  height: 400
} %}
</figure>

`transition-duration` accepts time units, either in seconds (`s`) or milliseconds (`ms`) and defaults to `0s`.

### transition-timing-function

Use the [`transition-timing-function`](https://developer.mozilla.org/docs/Web/CSS/transition-timing-function) property to vary the speed of a CSS transition over the course of the `transition-duration`.

By default, CSS will transition your elements at a constant speed (`transition-timing-function: linear`). Linear transitions can end up looking somewhat artificial, though: in real life, objects have weight and can't stop and start instantly. Easing into or out of a transition can make your transitions more lively and natural.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWgdyZx'
} %}
</figure>

Our [module on CSS Animation](/learn/css/animations/#animation-timing-function) has a good overview of timing functions.

You can use [DevTools](https://developer.chrome.com/docs/devtools/css/animations/) to experiment with different timing functions in real-time.

{% Img src="image/eiKy1JcjHqPp3gaedjAQWjPJ8YK2/dRwKg0RIsy5wWVzkUFUA.png", alt="Chrome DevTools visual transition timing editor.", width="800", height="418" %}

### transition-delay

Use the [`transition-delay`](https://developer.mozilla.org/docs/Web/CSS/transition-delay) property to specify the time at which a transition will start. If `transition-duration` is not specified, transitions will start instantly because the default value is `0s`. This property accepts a time unit, for example seconds (`s`) or milliseconds (`ms`).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOwyWep'
} %}
</figure>

This property is useful for staggering transitions, achieved by setting a longer `transition-delay` for each subsequent element in a group.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLXgeRQ',
  height: 410
} %}
</figure>

`transition-delay` is also useful for debugging. Setting the delay to a negative value can start a transition further into the timeline.

### shorthand: transition

Like most CSS properties, there is a shorthand version. [`transition`](https://developer.mozilla.org/docs/Web/CSS/transition) combines `transition-property`, `transition-duration`, `transition-timing-function`, and `transition-delay`.

```css
.longhand {
  transition-property: transform;
  transition-duration: 300ms;
  transition-timing-function: ease-in-out;
  transition-delay: 0s;
}

.shorthand {
  transition: transform 300ms ease-in-out 0s;
}
```

## What can and can't transition?

When writing CSS, you can specify which properties should have animated transitions. See [this MDN list of animatable CSS properties](https://developer.mozilla.org/docs/Web/CSS/CSS_animated_properties).

In general, it's only possible to transition elements that can have a "middle state" between their start and final states. For example, it's impossible to add transitions for `font-family`, because it's unclear what the "middle state" between `serif` and `monospace` should look like. On the other hand, it is possible to add transitions for `font-size` because its unit is a length that can be interpolated between.

{% Img src="image/eiKy1JcjHqPp3gaedjAQWjPJ8YK2/1Lr1iC56nyUyYWWv6qF2.jpg", alt="Diagram of shapes transitioning smoothly from one state to another, and two lines of text in different fonts that cannot be transitioned smoothly.", width="800", height="600" %}

Here are some common properties you can transition.

### Transform
{% BrowserCompat 'css.properties.transform' %}

The [`transform`](https://developer.mozilla.org/docs/Web/CSS/transform) CSS property is commonly transitioned because it is a GPU-accelerated property that results in smoother animation that also consumes less battery. This property lets you arbitrarily scale, rotate, translate, or skew an element.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRErowE'
} %}
</figure>

Check out [the section on transforms](/learn/css/functions/#transforms) in [our Functions module](/learn/css/functions/).

### Color

Before, during, and after interaction, color can be a great indicator of state. For example, a button might change color if it's being hovered. This color change can provide feedback to the user that the button is clickable.

The `color`, `background-color`, and `border-color` properties are just a few places where color can
be transitioned upon interaction.

{% Aside %}
Color transitions do not usually need to be behind a [reduced motion](#accessibility-considerations) preference. Use your best judgment.
{% endAside %}

Check out [our module on color](/learn/css/color/).

### Shadows

Shadows are often transitioned to indicate elevation change, like from user focus.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'gORgPQx',
  height: 300
} %}
</figure>

Check out [our module on shadows](/learn/css/shadows/).

### Filters

[`filter`](https://developer.mozilla.org/docs/Web/CSS/filter) is a powerful CSS property that lets you add graphic effects on the fly. Transitioning between different `filter` states can create some pretty impressive results.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PojWZxJ',
  height: 350
} %}
</figure>

Check out [our module on filters](/learn/css/filters/).

## Transition triggers

Your CSS must include a change of state *and* an event that triggers that state change for CSS transitions to activate. A typical example of such a trigger is the `:hover` [pseudo-class](/learn/css/pseudo-classes/). This pseudo-class matches when the user hovers over an element with their cursor.

Below is a list of some pseudo-classes and events that can trigger state changes in your elements.

* [`:hover`](/learn/css/pseudo-classes/#hover): matches if the cursor is over the element.
* [`:focus`](/learn/css/pseudo-classes/#focus,-focus-within,-and-focus-visible): matches if the element is focused.
* [`:focus-within`](/learn/css/pseudo-classes/#focus,-focus-within,-and-focus-visible) : matches if the element or any of its descendants are
    focused.
* [`:target`](/learn/css/pseudo-classes/#target): matches when the current URL's [fragment](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web#fragment) matches the element's id.
* [`:active`](/learn/css/pseudo-classes/#active):  matches when the element is being activated (typically when the
    mouse is pressed over it).
* `class` change from JavaScript: when an element's CSS `class` changes via
    JavaScript, CSS will transition eligible properties that have changed.

## Different transitions for enter or exit

By setting different `transition` properties on hover/focus, it's possible to create some interesting effects.

```css
.my-element {
  background: red;

  /* This transition is applied on the "exit" transition */
  transition: background 2000ms ease-in;
}

.my-element:hover {
  background: blue;

  /* This transition is applied on the "enter" transition */
  transition: background 150ms ease;
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJgWMaO'
} %}
</figure>

## Accessibility considerations

CSS transitions are not for everyone. For some people, transitions and animations can cause motion sickness or discomfort. Thankfully, CSS has a media feature called [`prefers-reduced-motion`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion) that detects if a user has indicated a preference for less motion from their device.

```css
/*
  If the user has expressed their preference for
  reduced motion, then don't use transitions.
*/
@media (prefers-reduced-motion: reduce) {
  .my-element {
    transition: none;
  }
}

/*
  If the browser understands the media query and the user
  explicitly hasn't set a preference, then use transitions.
*/
@media (prefers-reduced-motion: no-preference) {
  .my-element {
    transition: transform 250ms ease;
  }
}
```

Check out our blog post [prefers-reduced-motion: Sometimes less movement is more](/prefers-reduced-motion/) for more information on this media feature.

{% Aside %}
In the Learn Accessibility module on [animation and motion](/learn/accessibility/motion/) discover how to add delight to your site without causing problems for some users.
{% endAside %}

## Performance considerations

When working with CSS transitions, you may encounter performance issues if you add transitions for certain CSS properties. For example, when properties such as `width` or `height` change, they push content around on the rest of the page. This forces CSS to calculate new positions for every affected element for each frame of the transition. When possible, we recommend using properties like `transform` and `opacity` instead.

Check out our [guide on high-performance CSS animations](/animations-guide/) for a deep-dive on this topic.

{% Assessment 'transitions' %}

# Text and typography

Text is one of the core building blocks of the web.

When making a website, you don’t necessarily need to style your text; HTML actually has some pretty reasonable default styling.

However, text will likely make up the majority of your website, so it’s worthwhile to add some styling to spruce it up. By changing a few basic properties, you can significantly improve the reading experience for your users!

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNEJWGy',
  height: 590
} %}
</figure>

In this module, we’ll first look at some fundamental CSS font properties like `font-family`, `font-style`, `font-weight`, and `font-size`. Then, we’ll dive into properties that affect paragraphs of text, such as `text-indent` and `word-spacing`. The module finishes with some more advanced topics such as variable fonts and pseudo-elements.

## Change the typeface
{% BrowserCompat 'css.properties.font-family' %}

Use [`font-family`](https://developer.mozilla.org/docs/Web/CSS/font-family) to change the typeface of your text.

The `font-family` property accepts a comma-separated list of strings, either referring to *specific* or *generic* font families. Specific font families are quoted strings, such as “Helvetica”, “EB Garamond”, or “Times New Roman”. Generic font families are keywords such as `serif`, `sans-serif`, and `monospace` (find the [full list of options on MDN](https://developer.mozilla.org/docs/Web/CSS/font-family#values)). The browser will display the first available typeface from the provided list.

{% Aside %}
When the browser chooses which font to display from your `font-family` declaration, it doesn’t stop at the first available font in the list. Instead, it selects fonts one character at a time. If a particular character isn’t available in the first font in the list, it moves on to the next, and so on.
{% endAside %}

When using `font-family`, you should specify at least one generic font family in case the user’s browser doesn’t have your preferred fonts. Generally, the fallback generic font family should be similar to your preferred fonts: if using `font-family: "Helvetica"` (a sans-serif font family), your fallback should be `sans-serif` to match.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'yLojraG',
  height: 470,
  tab: 'css,result'
} %}
</figure>

## Use italic and oblique fonts
{% BrowserCompat 'css.properties.font-style' %}

Use [`font-style`](https://developer.mozilla.org/docs/Web/CSS/font-style) to set whether text should be italic or not. `font-style` accepts one of the following keywords: `normal`, `italic`, and `oblique`.

{% Aside %}
Q: What’s the difference between `italic` and `oblique`?
A: In fonts that support it, `font-style: italic` is typically a cursive version of the regular typeface. `font-style: oblique` displays a slanted version of regular typeface.
{% endAside %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWvGRjx',
  height: 280
} %}
</figure>

## Make text bold
{% BrowserCompat 'css.properties.font-weight' %}

Use [`font-weight`](https://developer.mozilla.org/docs/Web/CSS/font-weight) to set the “boldness” of text. This property accepts keyword values (`normal`, `bold`), relative keyword values (`lighter`, `bolder`), and numeric values (`100` to `900`).

The keywords `normal` and `bold` are equivalent to the numeric values `400` and `700`, respectively.

The keywords `lighter` and `bolder` are calculated relative to the parent element. See MDN’s [Meaning of Relative Weights](https://developer.mozilla.org/docs/Web/CSS/font-weight#meaning_of_relative_weights) for a handy chart showing how this value is determined.

{% Aside %}
Most fonts, especially the ["web-safe" ones](#font-family), only support the weights `400` (`normal`) and `700` (`bold`). When importing fonts using `@font-face` or `@import`, you can choose specific weights you want to pull in. Still, non-variable fonts only support numeric values for `font-weight` in the 100s, e.g. `100`, `200`, `300`, etc. If you want to use `font-weight: 321` (for example), you’ll have to use a [Variable Font](#variable-fonts).
{% endAside %}

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'gOxKxNz',
  height: 580
} %}
</figure>

## Change the size of text
{% BrowserCompat 'css.properties.font-size' %}

Use [`font-size`](https://developer.mozilla.org/docs/Web/CSS/font-size) to control the size of your text elements. This property accepts length values, percentages, and a handful of keyword values.

In addition to length and percentage values, `font-size` accepts some *absolute* keyword values (`xx-small`, `x-small`, `small`, `medium`, `large`, `x-large`, `xx-large`) and a couple of *relative* keyword values (`smaller`, `larger`). The relative values are relative to the parent element’s `font-size`.

{% Aside %}
Q: What’s the difference between `em` and `rem`?
A: In CSS, `em` represents the `font-size` inherited from the element’s parent. For example, `font-size: 2em` is equivalent to the parent’s `font-size` multiplied by two. `rem` is similar, but instead represents the `font-size` inherited from the *root element*, i.e. `<html>`.
{% endAside %}


<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYEroda',
  height: 370
} %}
</figure>

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'vYJzYzw'
} %}
</figure>

## Change the space between lines
{% BrowserCompat 'css.properties.line-height' %}

Use [`line-height`](https://developer.mozilla.org/docs/Web/CSS/line-height) to specify the height of each line in an element. This property accepts either a number, length, percentage, or the keyword `normal`. Generally, it’s recommended to use a number instead of a length or percentage to avoid issues with inheritance.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWaqQjv',
  height: 600
} %}
</figure>

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'ExvLJNx',
  height: 820
} %}
</figure>

## Change the space between characters
{% BrowserCompat 'css.properties.letter-spacing' %}

Use [`letter-spacing`](https://developer.mozilla.org/docs/Web/CSS/letter-spacing) to control the amount of horizontal space between characters in your text. This property accepts length values such as `em`, `px`,  and `rem`.

Note that the specified value *increases* the amount of natural space between characters. In the demo below, try selecting an individual letter to see the size of its letterbox and how it changes with `letter-spacing`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'abyGxBz',
  height: 560
} %}
</figure>

## Change the space between words
{% BrowserCompat 'css.properties.word-spacing' %}

Use [`word-spacing`](https://developer.mozilla.org/docs/Web/CSS/word-spacing) to increase or decrease the length of space between each word in your text. This property accepts length values such as `em`, `px`, and `rem`. Note that the length you specify is for *extra* space in addition to the normal spacing. This means that `word-spacing: 0` is equivalent to `word-spacing: normal`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'xxLjeRG',
  height: 280
} %}
</figure>

## `font` shorthand

You can use the shorthand [`font`](https://developer.mozilla.org/docs/Web/CSS/font) property to set many font-related properties at once. The list of possible properties are [`font-family`](#font-family), [`font-size`](#font-size), [`font-stretch`](https://developer.mozilla.org/docs/Web/CSS/font-stretch), [`font-style`](#font-style), [`font-variant`](#font-variant), [`font-weight`](#font-weight), and [`line-height`](#line-height).

Check out [MDN’s `font` article](https://developer.mozilla.org/docs/Web/CSS/font#syntax) for the specifics of how to order these properties.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjyvVbY',
  height: 270
} %}
</figure>

## Change the case of text
{% BrowserCompat 'css.properties.text-transform' %}

Use [`text-transform`](https://developer.mozilla.org/docs/Web/CSS/text-transform) to modify the capitalization of your text without needing to change the underlying HTML. This property accepts the following keyword values: `uppercase`, `lowercase`, and `capitalize`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'qBXYwqb',
  height: 450
} %}
</figure>

## Add underlines, overlines, and through-lines to text
{% BrowserCompat 'css.properties.text-decoration' %}

Use [`text-decoration`](https://developer.mozilla.org/docs/Web/CSS/text-decoration) to add lines to your text. Underlines are most commonly used, but it’s possible to add lines above your text or right through it!

The `text-decoration` property is shorthand for the more specific properties detailed below.

The [`text-decoration-line`](https://developer.mozilla.org/docs/Web/CSS/text-decoration-line) property accepts the keywords `underline`, `overline`, and `line-through`. You can also specify multiple keywords for multiple lines.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'LYjmvbN',
  height: 460,
  tab: 'css,result'
} %}
</figure>

The [`text-decoration-color`](https://developer.mozilla.org/docs/Web/CSS/text-decoration-color) property sets the color of all decorations from `text-decoration-line`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'oNedOYL',
  height: 460,
  tab: 'css,result'
} %}
</figure>

The [`text-decoration-style`](https://developer.mozilla.org/docs/Web/CSS/text-decoration-style) property accepts the keywords `solid`, `double`, `dotted`, `dashed`, and `wavy`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'dyzeLOp',
  height: 460,
  tab: 'css,result'
} %}
</figure>

The [`text-decoration-thickness`](https://developer.mozilla.org/docs/Web/CSS/text-decoration-thickness) property accepts any length values and sets the stroke width of all decorations from `text-decoration-line`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'VwzxNmm',
  height: 460,
  tab: 'css,result'
} %}
</figure>

The `text-decoration` property is a shorthand for all the above properties.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'YzxLMpN',
  height: 460,
  tab: 'css,result'
} %}
</figure>

{% Aside %}
Use [`text-underline-position`](https://developer.mozilla.org/docs/Web/CSS/text-underline-position) to offset the underline of a `text-decoration: underline` by the specified amount. This property doesn’t work for `overline` or `line-through`.
{% endAside %}

## Add an indent to your text
{% BrowserCompat 'css.properties.text-indent' %}

Use [`text-indent`](https://developer.mozilla.org/docs/Web/CSS/text-indent) to add an indent to your blocks of text. This property takes either a length (for example, `10px`, `2em`) or a percentage of the containing block’s width.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'RwZyOoV',
  height: 300
} %}
</figure>

## Deal with overflowing or hidden content
{% BrowserCompat 'css.properties.text-overflow' %}

Use [`text-overflow`](https://developer.mozilla.org/docs/Web/CSS/text-overflow) to specify how hidden content is represented. There are two options: `clip` (the default), which truncates the text at the point of overflow; and `ellipsis`, which displays an ellipsis (…) at the point of overflow.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRvdLNv',
  height: 250,
  tab: 'css,result'
} %}
</figure>

## Control white-space
{% BrowserCompat 'css.properties.white-space' %}

The [`white-space`](https://developer.mozilla.org/docs/Web/CSS/white-space) property is used to specify how whitespace in an element should be handled. For more details, check out the [`white-space` article on MDN](https://developer.mozilla.org/docs/Web/CSS/white-space).

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'PoKegbO',
  height: 970
} %}
</figure>

`white-space: pre` can be useful for rendering [ASCII art](https://en.wikipedia.org/wiki/ASCII_art) or carefully indented code blocks.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'OJjZGbz',
  height: 440
} %}
</figure>

## Control how words break
{% BrowserCompat 'css.properties.word-break' %}

Use [`word-break`](https://developer.mozilla.org/docs/Web/CSS/word-break) to change how words should be “broken” when they would overflow the line. By default, the browser will not split words. Using the keyword value `break-all` for `word-break` will instruct the browser to break words at individual characters if necessary.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'BadxEQY'
} %}
</figure>

## Change text alignment
{% BrowserCompat 'css.properties.text-align' %}

Use [`text-align`](https://developer.mozilla.org/docs/Web/CSS/text-align) to specify the horizontal alignment of text in a block or table-cell element. This property accepts the keyword values `left`, `right`, `start`, `end`, `center`, `justify`, and `match-parent`.

The values `left` and `right` align the text to the left and right sides of the block, respectively.

Use `start` and `end` to represent the location of the start and end of a line of text in the current writing mode. Therefore, `start` maps to `left` in English, and to `right` in Arabic script which is written right to left (RTL). They're logical alignments, learn more in our [logical properties](/learn/css/logical-properties/) module.

Use `center` to align the text to the center of the block.

The value of `justify` organizes the text and changes word spacings automatically so that the text lines up with both the left and right edges of the block.


<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGrMJBM',
  height: 570
} %}
</figure>

## Change the direction of text
{% BrowserCompat 'css.properties.direction' %}

Use [`direction`](https://developer.mozilla.org/docs/Web/CSS/direction) to set the direction of your text, either `ltr` (left to right, the default) or `rtl` (right to left). Some languages like Arabic, Hebrew, or Persian are written right to left, so `direction: rtl` should be used. For English and all other left-to-right languages, use `direction: ltr`.

{% Aside 'caution' %}
Generally, you should favor using the [HTML attribute `dir`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/dir) instead of `direction`. Check out [this StackOverflow discussion](https://stackoverflow.com/a/5375907) for more details.
{% endAside %}

## Change the flow of text
{% BrowserCompat 'css.properties.writing-mode' %}

Use [`writing-mode`](https://developer.mozilla.org/docs/Web/CSS/writing-mode) to change the way text flows and is arranged. The default is `horizontal-tb`, but you can also set `writing-mode` to `vertical-lr` or `vertical-rl` for text that you want to flow horizontally.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'WNEJWoK',
  height: 680
} %}
</figure>

## Change the orientation of text
{% BrowserCompat 'css.properties.text-orientation' %}

Use [`text-orientation`](https://developer.mozilla.org/docs/Web/CSS/text-orientation) to specify the orientation of characters in your text. The valid values for this property are `mixed` and `upright`. This property is only relevant when [`writing-mode`](#writing-mode) is set to something other than `horizontal-tb`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWMrPGV',
  height: 660
} %}
</figure>

## Add a shadow to text
{% BrowserCompat 'css.properties.text-shadow' %}

Use [`text-shadow`](https://developer.mozilla.org/docs/Web/CSS/text-shadow) to add a shadow to your text. This property expects three lengths (`x-offset`, `y-offset`, and `blur-radius`) and a color.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'jOLxRVe',
  height: 530
} %}
</figure>

Check out [the `text-shadow` section of our module on Shadows](/learn/css/shadows/#text-shadow) to learn more.

## Variable fonts

Typically, “normal” fonts require importing different files for different versions of the typeface, e.g. bold, italic, or condensed. Variable fonts are fonts that can contain many different variants of a typeface in one file.

<figure>
  <video controls autoplay loop muted>
    <source src="https://storage.googleapis.com/web-dev-assets/variable-fonts/roboto-dance.mp4" type="video/mp4">
  </video>
  <figcaption>
    Roboto Flex in random combinations of Width and Weight
  </figcaption>
</figure>

Check out [our article on Variable Fonts](/variable-fonts/) for more details.

## Pseudo-elements

{% Aside 'key-term' %}
A *pseudo-element* is a part of an element that you can target via CSS keywords without having to add more HTML. Check out [our module on pseudo-elements](/learn/css/pseudo-elements) for a deep-dive into this subject!
{% endAside %}

## `::first-letter` and `::first-line` pseudo-elements
{% BrowserCompat 'css.selectors.first-letter' %}

The [`::first-letter`](https://developer.mozilla.org/docs/Web/CSS/::first-letter) and [`::first-line`](https://developer.mozilla.org/docs/Web/CSS/::first-line) pseudo-elements target a text element’s first letter and first line respectively.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'KKvRYNr',
  height: 270
} %}
</figure>

## `::selection` pseudo-element
{% BrowserCompat 'css.selectors.selection' %}

Use the [`::selection`](https://developer.mozilla.org/docs/Web/CSS/::selection) pseudo-element to change the appearance of user-selected text.

When using this pseudo-element, only certain CSS properties can be used: `color`, `background-color`, `text-decoration`, `text-shadow`, `stroke-color`, `fill-color`, `stroke-width`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'MWvGRbx',
  height: 390,
  tab: 'css,result'
} %}
</figure>

## font-variant
{% BrowserCompat 'css.properties.font-variant' %}

The [`font-variant`](https://developer.mozilla.org/docs/Web/CSS/font-variant) property is a shorthand for a number of CSS properties that let you choose font variants like `small-caps` and `slashed-zero`. The CSS properties this shorthand includes are [`font-variant-alternates`](https://developer.mozilla.org/docs/Web/CSS/font-variant-alternates), [`font-variant-caps`](https://developer.mozilla.org/docs/Web/CSS/font-variant-caps), [`font-variant-east-asian`](https://developer.mozilla.org/docs/Web/CSS/font-variant-east-asian), [`font-variant-ligatures`](https://developer.mozilla.org/docs/Web/CSS/font-variant-ligatures), and [`font-variant-numeric`](https://developer.mozilla.org/docs/Web/CSS/font-variant-numeric). Check out the links on each property for more details about its usage.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'eYEroBa',
  height: 260
} %}
</figure>

{% Assessment 'typography' %}

## Resources

* [Font best practices](/font-best-practices/) discusses importing fonts, rendering fonts, and other best practices for using fonts on the web.
* [MDN Fundamental text and font styling](https://developer.mozilla.org/docs/Learn/CSS/Styling_text/Fundamentals).

# Z-index and stacking contexts

Say you've got a couple of elements that are absolutely positioned,
and are supposed to be positioned on top of each other.
You might write a bit of a HTML like this:

```html
<div class="stacked-items">
	<div class="item-1">Item 1</div>
	<div class="item-2">Item 2</div>
</div>
```

But which one sits on top of the other, by default?
To know which item would do that,
you need to understand z-index and stacking contexts.

## Z-index

The [`z-index`](https://developer.mozilla.org/docs/Web/CSS/z-index)
property explicitly sets a layer order for HTML based on the 3D space of the browser—the Z axis.
This is the axis which shows which layers are closer to and further from you.
The vertical axis on the web is the Y axis and the horizontal axis is the X axis.

{% Img
src="image/VbAJIREinuYvovrBzzvEyZOpw5w1/PDglCLEK0OJY5LIHwpkI.svg",
alt="Each axis surrounding the element",
width="760",
height="467" %}

The `z-index` property accepts a numerical value which can be a positive or negative number.
Elements will appear above another element if they have a higher `z-index` value.
If no `z-index` is set on your elements
then the default behaviour is that document source order dictates the Z axis.
This means that elements further down the document sit on top of elements that appear before them.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'GRrMEjZ'
} %}
</figure>

In normal flow,
if you set a specific value for `z-index` and it isn't working,
you need to set the element's `position` value to anything other than `static`.
This is a common place where people struggle with `z-index`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgoRzv'
} %}
</figure>

This isn't the case if you are in a flexbox or grid context, though,
because you can modify the z-index of flex or grid items without adding `position: relative`.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'QWdqMOP'
} %}
</figure>

## Negative z-index

To set an element *behind* another element,
add a negative value for `z-index`.

```css
.my-element {
	background: rgb(232 240 254 / 0.4);
}

.my-element .child {
	position: relative;
	z-index: -1;
}
```

As long as `.my-element` has the initial value for `z-index` of `auto`,
the `.child` element will sit behind it.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'XWpeayj',
  height: 400
} %}
</figure>

Add the following CSS to `.my-element`,
and the `.child` element will not sit behind it.

```css/1-2
.my-element {
  position: relative;
  z-index: 0;
  background: rgb(232 240 254 / 0.4);
}
```

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'bGgorZy',
  height: 400
} %}
</figure>

Because `.my-element` now has a `position` value that's not `static`
and a `z-index` value that's not `auto`,
it has created a new **stacking context**.
This means that even if you set `.child` to have a `z-index` of `-999`,
it would still not sit behind `.my-parent`.

## Stacking context

A stacking context is a group of elements that have a common parent and move up and down the z axis together.

<figure>
{% Codepen {
  user: 'web-dot-dev',
  id: 'JjErOXV',
  height: 600
} %}
</figure>

In this example,
the first parent element has a `z-index` of `1`,
so creates a new stacking context.
Its child element has a `z-index` of `999`.
Next to this parent, there is another parent element with one child.
The parent has a `z-index` of `2` and the child element also has a `z-index` of `2`.
Because both parents create a stacking context,
the `z-index` of all children is based on that of their parent.

The `z-index` of elements inside of a stacking context
are always relative to the parent's current order in its own stacking context.

{% Aside %}
The `<html>` element is a stacking context itself and nothing can ever go behind it.
You can put stuff behind the `<body>` until you create a stacking context with it.
{% endAside %}

## Creating a stacking context

You don't need to apply `z-index` and `position` to create a new
[stacking context](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context).
You can create a new stacking context by adding a value for properties which create a new composite layer
such as `opacity`, `will-change` and `transform`.
You can
[see a full list of properties here](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context).

To explain what a composite layer is, imagine a web page is a canvas.
A browser takes your HTML and CSS and uses these to work out how big to make the canvas.
It then paints the page on this canvas.
If an element was to change—say,
it changes position—the browser then has to go back and re-work out what to paint.

To help with performance,
the browser creates new composite layers which are layered on top of the canvas.
These are a bit like post-it notes:
moving one around and changing it doesn't have a huge impact on the overall canvas.
A new composite layer is created for elements with `opacity`,
`transform` and `will-change` because these are very likely to change,
so the browser makes sure that change is performant as possible by using the GPU to apply style adjustments.

{% Aside %}
You can also create a stacking context by adding a `filter` and setting `backface-visibility: hidden`.
{% endAside %}

## Resources

- [Forcing layers](https://surma.dev/things/forcing-layers/)
- [Animations Guide: Force layer creation](/animations-guide/#force)
- [Understanding z-index](https://ishadeed.com/article/understanding-z-index/)

{% Assessment 'z-index' %}

# Learn Responsive Design

This course takes you on a journey through the many facets of modern responsive web design. 
The first few modules will ease you in with a history of where responsive design came from and a look at the fundamentals of responsive layouts. 
From there, you’ll learn about responsive images, typography, accessibility and more.

Along the way you’ll find out how to make websites responsive to user preferences and device capabilities. 
By the end, you’ll also have an understanding of what the future might hold for responsive design.

Each module has demos and self-assessments for you to test your knowledge.

This course is created for beginner and intermediate designers and developers. 
A basic understanding of HTML and CSS should be enough. 
You don’t need to know any JavaScript. 
If you’re completely new to making websites, there's an 
[introduction to HTML](https://developer.mozilla.org/docs/Learn/HTML/Introduction_to_HTML) 
and another course to help you [learn CSS](/learn/css/).

Here's what you'll learn:

{% include 'partials/course-index.njk' %}

So, are you ready to learn responsive design? 

{% Aside %}
This course was written by [Jeremy Keith](https://twitter.com/adactio), with input and review from [Rachel Andrew](https://twitter.com/rachelandrew), [Una Kravets](https://twitter.com/Una), [Adam Argyle](https://twitter.com/argyleink), and [Camden Bickel](https://twitter.com/camdenbickel).
{% endAside %}

# Accessibility

Allowing your pages to respond to different screen sizes is just one way of making sure your website is accessible to as many people as possible. Consider some of these other factors that you should keep in mind.

## Color vision deficiency

Different people perceive color differently. People with protanopia don't perceive red as a distinct color. With deuteranopia, green is missing. For people with tritanopia, it's blue.

Some tools can give you a general idea of how your color schemes appear to people with different kinds of color vision.

[Firefox's Accessibility tab](https://developer.mozilla.org/docs/Tools/Accessibility_inspector/Simulation) includes a dropdown labeled **Simulate** with a list of options.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/4JFy0QWWiHW0x7X4aCxq.png", alt="Simulated protanopia (no red).", width="800", height="391" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/71Q8AaxD07ryv9TWf6Gd.png", alt="Simulated tritanopia (no blue)", width="800", height="391" %}
<figcaption>
   Viewing a website with simulations of different kinds of color vision.
 </figcaption>
</figure>

In Chrome DevTools, the rendering tab allows you to [emulate vision deficiencies](https://developer.chrome.com/blog/new-in-devtools-83/#vision-deficiencies).

Those are browser-specific tools. It's also possible to emulate different vision types at the operating system level.

On the Mac, go to:

1. System Preferences
2. Accessibility
3. Display
4. Color Filters
5. Enable Color Filters

Select one of the options.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/eKvwhSc6RHvS9KFG7pU6.png", alt="Color filter options in system preferences.", width="780", height="602" %}

In general it's not a good idea to rely purely on color to differentiate between different elements. For example, you can—and should—make your links a different color to the surrounding text. But you should also apply some other styling indicator like underlining the links or making them bold.

{% Compare 'worse' %}
```css
a {
  color: red;
}
```
{% endCompare %}

{% Compare 'better' %}
```css
a {
  color: red;
  font-weight: bold;
}
```
{% endCompare %}

## Color contrast

Some color combinations can cause trouble. If there isn't enough contrast between the foreground color and background color, text becomes difficult to read. Poor color contrast is one of the most common accessibility issues on the web, but fortunately, it's one that you can catch early in the design process.

Here are some tools you can use to test the contrast ratio of your text and background colors:

* [tota11y](https://khan.github.io/tota11y/) is a bookmarklet you can add to your browser's toolbar.
* [VisBug](https://github.com/GoogleChromeLabs/ProjectVisBug) is a browser extension available for all major desktop browsers.
* [Firefox's Accessibility Inspector](https://developer.mozilla.org/docs/Tools/Accessibility_inspector) can check for issues with visual contrast.
* You can also [discover and fix low-contrast text with Chrome DevTools](https://developers.google.com/codelabs/devtools-cvd).
* In Microsoft's Edge browser, you can [test text-color contrast using the color picker](https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/accessibility/color-picker).

It's a good idea to always declare `color` and `background-color` together in your CSS. Don't assume that the background color will be the browser default. People can and do change the colors used by their browser.

{% Compare 'worse' %}
```css
body {
  color: black;
}
```
{% endCompare %}

{% Compare 'better' %}
```css
body {
  color: black;
  background-color: white;
}
```
{% endCompare %}

## High contrast

Some people set their operating systems to use a high-contrast mode. You can try this on your operating system.

On the Mac, go to:

1. System Preferences
2. Accessibility
3. Display

Select the option to increase contrast.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/WRYeXsiJVP4nP1b8xAOr.png", alt="Increase contrast in system preferences.", width="780", height="602" %}

There's a media feature to detect if someone has enabled high contrast mode. The [`prefers-contrast`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-contrast) media feature can be queried for three values: `no-preference`, `less`, and `more`. You can use this information to adjust your site's color palette.
{% BrowserCompat 'css.at-rules.media.prefers-contrast' %}

{% Codepen {
 user: 'web-dot-dev',
 id: 'abLBaya',
 height: 500,
 theme: 'dark',
 tab: 'css,result'
} %}

{% Aside %}
[CSS custom properties](https://developer.mozilla.org/docs/Web/CSS/Using_CSS_custom_properties) are a great way of grouping color declarations. Use the `prefers-contrast` media feature to update your custom property values.
{% endAside %}

People can also set a preference in their operating system to use inverted colors.

On the Mac, go to:

1. System Preferences
2. Accessibility
3. Display

Select the option to invert colors.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/pDi1fFRwChp7xpRbfqRC.png", alt="Invert colors in system preferences.", width="780", height="602" %}

Make sure your website still makes sense for someone browsing with inverted colors. Watch out for box shadows—these may need adjusting when colors are inverted.

## Font size

Color isn't the only thing that people can adjust in their browser, they can also adjust the default font size. As their vision declines, they might adjust the default font size in their browsers or operating systems, bumping up the numbers with the passing of the years.

You can respond to these settings by using relative font sizes. Avoid using units like `px`. Use relative units like `rem` or `ch` instead.

Try changing the default text size setting in your browser. You can do that in your browser preferences. Or you can do it while you're visiting a web page by zooming in. Does your website still work if [the default font size is increased by 200%](https://www.w3.org/WAI/WCAG21/Understanding/resize-text.html)? How about 400%?

Someone visiting your website on a desktop computer with their font size bumped up to 400% should get the same layout as someone visiting your site on a small-screen device.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/rAZIY9rw8FK3tVLseC6v.png", alt="Clearleft dot com.", width="800", height="419" %}
<figcaption>
   The same website viewed on a desktop device and a mobile device. The desktop browser's font size has been increased to 400%.
 </figcaption>
</figure>


## Keyboard navigation

Not everyone uses a mouse or a trackpad to navigate web pages. A keyboard is another way of getting around a page, with the `tab` key being particularly useful. Users can quickly move from one link or form field to the next.

Links styled with the `:hover` and `:focus` [pseudo-classes,](/learn/css/pseudo-classes/) will display those styles regardless of whether someone is using a mouse, a trackpad, or a keyboard. Use the `:focus-visible` [pseudo-class](/learn/css/pseudo-classes/) to style your links for just keyboard navigation. You can make those styles extra noticeable.

```css
a:focus,
a:hover {
  outline: 1px dotted;
}
a:focus-visible {
  outline: 3px solid;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'wvroErW',
 height: 400,
 theme: 'dark',
 tab: 'result'
} %}

As the user tabs from link to link or form field to form field, those elements will be focused in the order they appear in the document structure. This should also match the visual order.

Be careful with the CSS `order` property. You can use this in combination with flexbox and grid to place elements in a different visual order to their order in the HTML. That's a powerful feature but it could confuse people navigating with a keyboard.

{% Codepen {
 user: 'web-dot-dev',
 id: 'XWeNPeY',
 height: 400,
 theme: 'dark',
 tab: 'result'
} %}

Test your web pages by using the `tab` key on your keyboard to make sure that the tabbing order makes sense.

In the **Accessibility** panel of the Firefox browser's developer tools there's an option to **Show Tabbing Order**. Enabling this will overlay numbers on each focusable element.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/4JFy0QWWiHW0x7X4aCxq.png", alt="Visualizing tab order using Firefox's Accessibility Tab.", width="800", height="391" %}


{% Aside %}
Learn more about the problems caused by [content reordering](/content-reordering/).
{% endAside %}

## Reduced motion

Animation and motion are wonderful ways to bring web designs to life. But for some people these movements can be very disorienting and even cause nausea.

There's a feature query that communicates whether the user would prefer less motion. It's called [`prefers-reduced-motion`](/prefers-reduced-motion/). Include it wherever you are using CSS transitions or animations.
{% BrowserCompat 'css.at-rules.media.prefers-reduced-motion' %}

```css
a:hover {
  transform: scale(150%);
}
@media (prefers-reduced-motion: no-preference) {
  a {
    transition-duration: 0.4s;
    transition-property: transform;
  }
}
```

The `prefers-reduced-motion` media query is specifically for movement on the screen. If you are using transitions on an element's color that shouldn't be affected by `prefers-reduced-motion`. It's also ok to transition opacity and cross-fade. Reduced motion doesn't have to mean no animation.

## Voice

People experience the web differently. Not everyone is seeing your website on a screen. Assistive technologies such as screen readers convert the information output to a screen into spoken words.

Screen readers work with all kinds of applications including web browsers. In order for a web browser to communicate usefully with a screen reader, there needs to be useful semantic information in the web page currently being accessed.

Previously, you learned how [icon-only buttons](/learn/design/icons/) need to include an attribute to specify the button's purpose to non-sighted users. This is just one example of the importance of strong foundational HTML.

## Headings

Use headings like `<h1>`, `<h2>`, `<h3>`, etc. sensibly. Screen readers use these headings to generate an outline of your document which can be navigated with keyboard shortcuts.

{% Compare 'worse' %}
```html
<div class="heading-main">Welcome to my page</div>
<div class="heading-secondary">About me</div>
<div class="heading-tertiary">My childhood</div>
<div class="heading-secondary">About this website</div>
<div class="heading-tertiary">How this site was built</div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<h1>Welcome to my page</h1>
  <h2>About me</h2>
    <h3>My childhood</h3>
  <h2>About this website</h2>
    <h3>How this site was built</h3>
```
{% endCompare %}

## Structure

Use landmark elements like `<main>`, `<nav>`, `<aside>`, `<header>`, and `<footer>` to structure your page's contents. Screen-reader users can then jump straight to these landmarks.

{% Compare 'worse' %}
```html
<div class="header">...</div>
<div class="navigation">...</div>
<div class="maincontent">...</div>
<div class="sidebar">...</div>
<div class="footer">...</div>
```
{% endCompare %}

{% Compare 'better' %}
```html
<header>...</header>
<nav>...</nav>
<main>...</main>
<aside>...</aside>
<footer>...</footer>
```
{% endCompare %}

## Forms

Make sure that every form field has an associated `<label>` element. You can associate a label with a form field using the `for` attribute on the `<label>` element and the corresponding `id` attribute on the form field.

{% Compare 'worse' %}
```html
<span class="formlabel">Your name</span>
<input type="text">
```
{% endCompare %}

{% Compare 'better' %}
```html
<label for="name">Your name</label>
<input id="name" type="text">
```
{% endCompare %}

{% Aside %}
For more information in accessibility and forms, see the [Accessibility module in the Learn Forms course](/learn/forms/accessibility/).
{% endAside %}

## Images

Always provide a text description of images using the `alt` attribute.

{% Compare 'worse' %}
```html
<img src="dog.jpg">
```
{% endCompare %}

{% Compare 'better' %}
```html
<img src="dog.jpg" alt="A golden retriever sitting on the grass looking happy.">
```
{% endCompare %}

If the image is purely presentational, you should still include the `alt` attribute but you can give it an empty value.

{% Compare 'worse' %}
```html
<img src="texture.png">
```
{% endCompare %}

{% Compare 'better' %}
```html
<img src="texture.png" alt="">
```
{% endCompare %}

Jake Archibald published an article on [writing great `alt` text](https://jakearchibald.com/2021/great-alt-text/).

## Links

Try to provide descriptive text within links. Avoid using phrases like "click here" or "more."

{% Compare 'worse' %}
```html
<p>To find out more about our latest offers, <a href="offers.html">click here</a>.</p>
```
{% endCompare %}

{% Compare 'better' %}
```html
<p>Find out more about <a href="offers.html"> our latest offers</a>.</p>
```
{% endCompare %}

## ARIA

Using sensible semantic HTML will make your web pages more accessible to assistive technologies like screen readers and also to other audio outputs like voice assistants.

Some interface widgets that don't have a corresponding HTML element: carousels, tabs, accordions, and so on. Those need to be built from scratch with a combination of HTML, CSS, JavaScript, and ARIA.

ARIA stands for Accessible Rich Internet Applications. Its vocabulary allows you to provide semantic information when there isn't a suitable HTML element available.

If you need to create interface elements that aren't yet available as HTML elements, [familiarize yourself with ARIA](https://developer.mozilla.org/docs/Learn/Accessibility/WAI-ARIA_basics).

The more bespoke functionality you add with JavaScript, the more you'll need to understand ARIA. If you stick with native HTML elements, you may not need any ARIA.

If it's at all possible, test with real users of screen readers. Not only will this give you a better understanding of how they navigate the web, it will also take the guesswork out of designing with accessibility in mind.

Testing with actual people is a great way of exposing any assumptions you might be making. In the next module, you'll learn about the different ways people interact with your websites—another area where it's all too easy to make assumptions.

{% Assessment 'accessibility' %}

# Conclusion and next steps

Congratulations! You've made it to the end! We hope that you have enjoyed this overview of responsive design. For more, you can check out the following additional resources:

## Additional resources

- [LearnCSS](/learn/css)
- [CSS Documentation on MDN](https://developer.mozilla.org/docs/Web/CSS)
- [Listen to the CSS Podcast](https://thecsspodcast.libsyn.com)
- [CSS articles on web.dev](/tags/css/)
- [CSS-Tricks](https://css-tricks.com/tag/css/)
- [Layout Land - Youtube](https://www.youtube.com/channel/UC7TizprGknbDalbHplROtag)

## Brought to you by

{% include 'partials/authors-stack.njk' %}

# Icons

Most images are part of your content, but icons are part of your user interface. 
They should scale and adapt in the same way that the text of your UI scales and adapts.

## Scalable Vector Graphics

When it comes to photographic imagery, there are lots of choices for the image format: JPG, WebP, and AVIF. 
For non-photographic imagery, you have a choice between the Portable Network Graphics (PNG) format and the Scalable Vector Graphics (SVG) format.

Both PNGs and SVGs are good at dealing with areas of flat color, and they both allow your images to have transparent backgrounds. 
If you use a PNG you'll probably need to make multiple versions of your image in different sizes and use the `srcset` attribute on your `img` element to [make the image responsive](/learn/design/responsive-images/). If you use an SVG, it's responsive by default.

PNGs (and JPGs, WebP, and AVIF) are bitmap images. Bitmap images store information as pixels. In an SVG, information is stored as drawing instructions. When the browser reads the SVG file the instructions are converted into pixels. Best of all, these instructions are relative. Regardless of the dimensions you use to describe lines and shapes, everything renders at just the right crispness. Instead of creating multiple SVGs of different sizes you can make one SVG that will work at all sizes. There's no need to use the `srcset` attribute.

```html
<img src="image.svg" alt="A description of the image." width="25" height="25">
<img src="image.svg" alt="A description of the image." width="250" height="250">
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'YzrKoWY',
 height: 360,
 theme: 'dark',
 tab: 'html,result'
} %}

XML is used to write the instructions in an SVG file. This is a markup language, like HTML.

```xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="-21 -21 42 42" width="100" height="100">
  <title>Smiling face</title>
  <circle r="20" fill="yellow" stroke="black"/>
  <ellipse rx="2.5" ry="4" cx="-6" cy="-7" fill="black"/>
  <ellipse rx="2.5" ry="4" cx="6" cy="-7" fill="black"/>
  <path stroke="black" d="M -12,5 A 13.5,13.5,0 0,0 12,5 A 13,13,0 0,1 -12,5"/>
</svg>
```

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/3F9ZFc3oOqhrPN6YU0Bd.svg", alt="Smiley face.", width="800", height="800" %}

You can even put SVG inside HTML.

```html
<figure>
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="-21 -21 42 42" width="100" height="100">
    <title>Smiling face</title>
    <circle r="20" fill="yellow" stroke="black"/>
    <ellipse rx="2.5" ry="4" cx="-6" cy="-7" fill="black"/>
    <ellipse rx="2.5" ry="4" cx="6" cy="-7" fill="black"/>
    <path stroke="black" d="M -12,5 A 13.5,13.5,0 0,0 12,5 A 13,13,0 0,1 -12,5"/>
  </svg>
  <figcaption>
  A description of the image.
  </figcaption>
</figure>
```

If you embed an SVG like that, that's one less request that the browser needs to make. There'll be no wait for the image to download because it arrives with the HTML …*in* the HTML! Also, as you'll soon find out, embedding SVGs like this gives you more control over styling them too.

## Icons and text

Icon images often feature simple shapes on a transparent background. SVG is ideal for icons.

If you have a button or a link with text and an icon inside it, the icon is presentational. It's the text that matters. When using an `img` element, an empty `alt` attribute indicates that the image is presentational.

{% Aside %}
An empty `alt` attribute is not the same as a missing `alt` attribute. Always provide an `alt` attribute even if an image is presentational and the `alt` attribute has no content.
{% endAside %}

```html
<button>
<img src="hamburger.svg" alt="" width="16" height="16">
Menu
</button>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'qBPWzam',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

Because CSS is for presentation, you could put the icon in your CSS as a background image.

```html
<button class="menu">
Menu
</button>
```

```css
.menu {
  background-image: url(hamburger.svg);
  background-position: 0.5em;
  background-repeat: no-repeat;
  background-size: 1em;
  padding-inline-start: 2em;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'gOGYNwj',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

If you put the SVG inside your HTML, use the `aria-hidden` attribute to hide it from assistive technology.

```html
<button class="menu">
  <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 80" width="16" height="16">
    <rect width="100" height="20" />
    <rect y="30" width="100" height="20"/>
    <rect y="60" width="100" height="20"/>
  </svg>
  Menu
</button>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'bGobPwz',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

{% Aside %}
If you use the same icon multiple times in one page, it would be inefficient to repeat the entire SVG markup each time. There's an element in SVG called [`use`](https://developer.mozilla.org/docs/Web/SVG/Element/use) which allows you to “clone” part of an SVG, even from a different SVG element.
{% endAside %}

## Standalone icons

Use text inside your buttons and links if you want their purpose to be clear. You can use an icon without any text but don't assume that everyone understands the meaning of a particular icon. When in doubt, test with real users.

If you decide to use an icon without any accompanying text, the icon is no longer presentational. A background image in CSS is not an appropriate way to display the icon. The icon needs to be given an accessible name in HTML.

If you use an `img` element, the icon gets its accessible name from the `alt` attribute.

{% Aside %}
Usually the `alt` attribute describes the contents of the image (“Three horizontal lines.”) but with standalone icons, the `alt` attribute describes the meaning of the image (“Menu”).
{% endAside %}

```html
<button>
<img src="hamburger.svg" alt="Menu"" width="16" height="16">
</button>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'MWEgMbY',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

Another option is to put the accessible name on the link or button itself and declare that the image is presentational. Use the `aria-label` attribute to provide the accessible name.

```html
<button aria-label="Menu">
<img src="hamburger.svg" alt="" width="16" height="16">
</button>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'VwMZJmr',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

If you put the SVG inside your HTML, use the `aria-label` attribute on the link or button to give it an accessible name and use the `aria-hidden` attribute on the icon.

```html
<button aria-label="Menu">
  <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 80" width="16" height="16">
    <rect width="100" height="20" />
    <rect y="30" width="100" height="20"/>
    <rect y="60" width="100" height="20"/>
  </svg>
</button>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'OJxLebB',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

## Styling icons

If you embed your SVG icons directly in your HTML you can style parts of them just like any other element in your page. You can't do that if you use an `img` element to display your icons.

In the following example, the `rect` elements inside the SVG have a `fill` value of `blue` to match the styles for the button's text.

```css
button {
 color: blue;
}
button rect {
  fill: blue;
}
```

You can apply `hover` and `focus` styles too.

```css
button:hover,
button:focus {
  color: red;
}
button:hover rect,
button:focus rect {
  fill: red;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'rNGBEje',
 height: 200,
 theme: 'dark',
 tab: 'html,result'
} %}

## Resources

* If you need to style SVGs that are background images in your CSS, read Una's article on [colorizing SVG backgrounds](https://css-tricks.com/solved-with-css-colorizing-svg-backgrounds/).
* Sara Soueidan has written about [accessible icon buttons](https://www.sarasoueidan.com/blog/accessible-icon-buttons/).
* Scott O'Hara has written about [contextually marking up accessible images and SVGs](https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html).
* If you're using a graphic design tool to export SVGs, use [SVGOMG](https://jakearchibald.github.io/svgomg/) to optimize the output.

Icons are an important part of your site's branding. Next you'll find out how to make other aspects of your branding responsive through the power of [theming](/learn/design/theming).

{% Assessment 'icons' %}

# Interaction

Small screen devices like mobile phones often have touchscreens. Large screen devices like laptops and desktop computers often come with hardware like a mouse or a trackpad. It’s tempting to equate small screens with touch and large screens with pointers.

But the reality is more nuanced. Some laptops have touch screen capabilities. Users can interact with either a touchscreen or a trackpad or both. Likewise it’s possible to use an external keyboard or mouse with a touchscreen device like a tablet.

Instead of trying to infer the input mechanism from screen size, use media features in CSS.

## Pointer

You can test for three possible values with the `pointer` media feature: `none`, `coarse`, and `fine`.

If a browser reports a `pointer` value of `none` the user might be using a keyboard to interact with your website.

If a browser reports a `pointer` value of `coarse` it means the primary input mechanism isn’t very accurate. A finger on a touchscreen is a coarse pointer.

If a browser reports a `pointer` value of `fine` it means the primary input mechanism is capable of fine-grained control. A mouse or stylus is a fine pointer.

You can adjust the size of your interface elements to suit the `pointer` value. Try visiting [this website](https://gui-challenges.web.app/settings/dist/) in different kinds of devices to see how the interface adapts.

In this example, buttons are made larger for coarse pointers:

```css
button {
  padding: 0.5em 1em;
}
@media (pointer: coarse) {
  button {
    padding: 1em 2em;
  }
}
```

It’s possible to also make elements smaller for fine pointers but be careful about doing this:

{% Compare 'worse' %}
```css
@media (pointer: fine) {
  button {
    padding: 0.25em 0.5em;
  }
}
```
{% endCompare %}

Even if someone has a primary input mechanism capable of fine-grained control, think twice before reducing the size of interactive elements. [Fitts’s Law](https://en.wikipedia.org/wiki/Fitts's_law) still applies. A smaller target requires more concentration even with a fine pointer. A larger target area benefits everyone regardless of pointing device.

## Any pointer

The `pointer` media feature reports the fineness of the *primary* input mechanism. But many devices have more than one input mechanism. It’s possible that someone is interacting with your website using both a touchscreen and a mouse at the same time.

The `any-pointer` differs from the `pointer` media feature in that it reports if any pointing device passes the test.

An `any-pointer` value of `none` means that no pointing device is available.

An `any-pointer` value of `coarse` means that at least one pointing device is not very accurate. But that might not be the primary input mechanism.

An `any-pointer` value of `fine` means that at least one pointing device is capable of fine-grained control. But again, this might not be the primary input mechanism.

Because the `any-pointer` media query will report a positive result if *any* of the input mechanisms pass the test, it’s possible for a browser to report a result for `any-pointer: fine` and also report a result for `any-pointer: coarse`. In that case the order of your media queries matters. The last one will take precedence.

In this example, if the device has both a fine and a coarse input mechanism, the coarse styles are applied.

```css
@media (any-pointer: fine) {
  button {
    padding: 0.5em 1em;
  }
}
@media (any-pointer: coarse) {
  button {
    padding: 1em 2em;
  }
}
```

## Hover

The `hover` media feature reports on whether the primary input mechanism can hover over elements. This usually means there’s some kind of cursor on the screen being controlled by a mouse or a trackpad.

Unlike the `pointer` media feature which differentiates between fine and coarse pointers, the `hover` media feature is binary. If the primary input device is capable of hovering over elements it will report a value of `hover`. Otherwise the value is `none`.

In this example, some supplementary icon is available on hover but only if the primary input device is capable of hovering over an element.

```css
button .extra {
  visibility: visible;
}
@media (hover: hover) {
  button .extra {
    visibility: hidden;
  }
  button:hover .extra {
    visibility: visible;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'VwMrYav',
 height: 200,
 theme: 'dark',
 tab: 'result'
} %}

If you use your mouse to hover over that button, the icon will appear. But if you use your keyboard to tab to the button, the icon remains invisible. When you use the keyboard, you’re focusing rather than hovering. A desktop device with a mouse attached will report that the primary input mechanism is capable of hovering, which is true. But anyone using a keyboard while a mouse is attached won’t get the benefit of the `:hover` styles. So it’s a good idea to combine `:hover` and `:focus` styles to cover both interactions.

```css/7-7
button .extra {
  visibility: visible;
}
@media (hover: hover) {
  button .extra {
    visibility: hidden;
  }
  button:is(:hover, :focus) .extra {
    visibility: visible;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'LYzOEZE',
 height: 200,
 theme: 'dark',
 tab: 'result'
} %}

Even if the primary input device is capable of hovering over elements, be careful about hiding information behind a hover interaction. The information becomes less discoverable. Don’t use hover to hide important information or an important interface element.

## Any hover

The `hover` media query only reports on the *primary* input mechanism. Some devices have multiple input mechanisms: touchscreen, mouse, keyboard, trackpad.

Just as `any-pointer` reports on any of the input mechanisms, `any-hover` will be true if any of the available input mechanisms are capable of hovering over elements.

If you decided to reverse the logic in the previous example, you could make the hover styles the default and then remove them if `any-hover` has a value of `none`.

```css
button .extra {
  visibility: hidden;
}
button:hover .extra,
button:focus .extra {
  visibility: visible;
}
@media (any-hover: none) {
  button .extra {
    visibility: visible;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'Bawmyzd',
 height: 200,
 theme: 'dark',
 tab: 'result'
} %}

On a device that has no input mechanism capable of hovering, the extra icon is always visible.

## Virtual keyboards

People use cursors and fingers to explore interfaces but when it comes time to enter information, they need a keyboard. That’s fine if there’s a physical keyboard attached to their device, but if they’re using a touchscreen device it’s a little more complicated. These devices provide on-screen virtual keyboards.

### Input types

Unlike a physical keyboard, virtual keyboards can be tailored to match the expected input. If you provide information about the expected input, devices can serve up the most appropriate virtual keyboard.

[HTML5 input types](https://developer.mozilla.org/docs/Learn/Forms/HTML5_input_types) are a great way of describing your `input` elements. The `type` attribute accepts values such as `email`, `number`, `tel`, `url`, and more.

```html
  <label for="email">Email</label>
  <input type="email" id="email">
```

```html
  <label for="number">Number</label>
  <input type="number" id="number">
```

```html
  <label for="tel">Tel</label>
  <input type="tel" id="tel">
```

```html
  <label for="url">URL</label>
  <input type="url" id="url">
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'zYEPxBX',
 height: 400,
 theme: 'dark',
 tab: 'html, result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/xdbqHZ1fp2O8FpwXWQAH.mp4", controls=true, loop=true %}

### Input modes
{% BrowserCompat 'html.global_attributes.inputmode' %}

[The `inputmode` attribute](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/inputmode) gives you fine-grained control over virtual keyboards. For example, whereas there’s one `input` `type` with a value of `number`, you can use the `inputmode` attribute to differentiate between whole numbers and decimals.

If you’re asking for a whole number, like somebody’s age, use `inputmode="numeric"`.

```html
<label for="age">Age</label>
<input type="number" id="age" inputmode="numeric">
```

If you’re asking for a number that includes decimal places, like a price, use `inputmode="decimal"`.

```html
<label for="price">Price</label>
<input type="number" id="price" inputmode="decimal">
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'mdBqyrO',
 height: 300,
 theme: 'dark',
 tab: 'html, result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/gr0tQXIZDgRNFcExwN8W.mp4", controls=true, loop=true %}

### Autocomplete
{% BrowserCompat 'html.global_attributes.autocomplete' %}

Nobody likes filling in forms. As a designer, you can improve the experience for your users by enabling them to automatically fill in form fields. [The `autocomplete` attribute](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete) provides you with a host of options for improving contact forms, log-in forms, and checkout forms.

```html
<label for="name">Name</label>
<input type="text" id="name" autocomplete="name">
```

```html
<label for="country">Country</label>
<input type="text" id="country" autocomplete="country">
```

```html
<label for="email">Email</label>
<input type="email" id="email" autocomplete="email">
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'oNGogYX',
 height: 400,
 theme: 'dark',
 tab: 'html, result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/6CvIrXjmzMbXX4CNuzCe.mp4", controls=true, loop=true %}

These HTML attributes—`type`, `inputmode`, and `autocomplete`—are small additions to your form fields, but they can make a big difference to the user experience. By anticipating and responding to your user’s device capabilities, you are empowering your users. For more in-depth information, there’s a course dedicated to helping you [learn forms](/learn/forms/).

Next up in this course, it’s time to examine some [common interface patterns](/learn/design/ui-patterns/).

{% Assessment 'interaction' %}

# Internationalization

The World Wide Web is available to everyone in the world—it's right there in the name! 
That means that your website is potentially available to anyone who has access to the internet, 
regardless of where they are, what device they're using, or what languages they speak.

The goal of responsive design is to make your content available to everyone. 
Applying that same philosophy to human languages is the driving force behind internationalization—preparing your content and designs for an international audience.

## Logical properties

English is written from left to right and top to bottom, 
but not all languages are written this way. 
Some languages like Arabic and Hebrew read from right to left, 
and some Japanese typefaces read vertically instead of horizontally. 
To accommodate these writing modes, 
logical properties were introduced in CSS.

If you write CSS, you may have used directional keywords like "left", "right", "top", and "bottom." 
Those keywords refer to the physical layout of the user's device.

[Logical properties](/learn/css/logical-properties/), on the other hand, 
refer to the edges of a box as they relate to the flow of content. 
If the writing mode changes, CSS written with logical properties will update accordingly. 
That's not the case with directional properties.

Whereas the directional property `margin-left` always refers to the margin on the left side of a content box, 
the logical property `margin-inline-start` refers to the margin on the left side of a content box in a left-to-right language, 
and the margin on the right side of a content box in a right-to-left language.

In order for your designs to adapt to different writing modes, avoid directional properties. Use logical properties instead.

{% Compare 'worse' %}
```css
.byline {
  text-align: right;
}
```
{% endCompare %}

{% Compare 'better' %}
```css
.byline {
  text-align: end;
}
```
{% endCompare %}

When CSS has a specific directional value like `left` or `right`, 
there's a corresponding logical property. Where once we had `margin-left` now we also have `margin-inline-start`.

In a language like English where text flows from left to right, 
`inline-start` corresponds to "left" and `inline-end` corresponds to "right".

Likewise, in a language like English where the text is written from top to bottom, 
`block-start` corresponds to "top" and `block-end` corresponds to "bottom."

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/9EcUvMxy9T10EzY4U95b.webp", 
alt="Latin, Hebrew and Japanese are shown rendering placeholder text within a device frame. Arrows and colors follow the text to help associate the 2 directions of block and inline.", width="800", height="577" %}

If you use logical properties in your CSS, you can use the same stylesheet for translations of your pages. 
Even if your pages are translated into languages written from right to left or bottom to top, your design will adjust accordingly. 
You don't need to make separate designs for each language. 
By using logical properties, your design will respond to every writing mode. 
That means your design can reach more people without you having to spend time making separate designs for every language.

Modern CSS layout techniques like [grid](/learn/css/grid) and [flexbox](/learn/css/flexbox) use logical properties by default. 
If you think in terms of `inline-start` and `block-start` instead of `left` and `top` 
then you'll find these modern techniques easier to understand.

Take a common pattern like [an icon next to some text](/learn/css/logical-properties/#solving-the-icon-issue) or a label next to a form field. 
Instead of thinking "the label should have a margin on the right," think "the label should have a margin on the end of its inline axis."

{% Compare 'worse' %}
```css
label {
  margin-right: 0.5em;
}
```
{% endCompare %}

{% Compare 'better' %}
```css
label {
  margin-inline-end: 0.5em;
}
```
{% endCompare %}

{% Codepen {
 user: 'web-dot-dev',
 id: 'gOxXOLK',
 height: 300,
 theme: 'dark',
 tab: 'css,result'
} %}

If that page is translated into a right-to-left language, 
the styles won't need to be updated. 
You can mimic the effect of seeing your pages in a right-to-left language by using the `dir` attribute on your `html` element. 
A value of `ltr` means "left to right." A value of "rtl" means "right to left."

{% Codepen {
 user: 'web-dot-dev',
 id: 'mdMqdOx',
 height: 300,
 theme: 'dark',
 tab: 'html,result'
} %}

If you'd like to experiment with all the permutations of document directions (the block axis) and writing modes (the inline axis), 
here's [an interactive demonstration](https://codepen.io/argyleink/pen/vYNwbgM).

{% Codepen {
 user: 'argyleink',
 id: 'vYNwbgM',
 height: 800,
 theme: 'dark',
 tab: 'result'
} %}

## Identify page language

It's a good idea to identify the language of your page by using the `lang` attribute on the `html` element.

```html
<html lang="en">
```

That example is for a page in English. You can be even more specific. Here's how you declare that a page is using US English:

```html
<html lang="en-us">
```

Declaring the language of your document is useful for search engines. 
It's also useful for assistive technologies like screen readers and voice assistants. 
By providing language metadata you're helping these kinds of speech synthesizers pronounce your content correctly.

The `lang` attribute can go on any HTML element, not just `html`. If you switch languages in your web page, indicate that change. 
In this case, one word is in German:

```html
<p>I felt some <span lang="de">schadenfreude</span>.</p>
```

## Identify a linked document's language

There's another attribute called `hreflang` which you can use on links. 
The `hreflang` takes the same language code notation as the `lang` attribute and describes the linked document's language. 
If there's a translation of your entire page available in German, link to it like this:

```html
<a href="/path/to/german/version" hreflang="de">German version</a>
```

If you use text in German to describe the link to the German version, use both `hreflang` and `lang`. 
Here, the text "Deutsche Version" is marked up as being in the German language, and the destination link is also marked up as being in German:

```html
<a href="/path/to/german/version" hreflang="de" lang="de">Deutsche Version</a>
```

You can also use the `hreflang` attribute on the `link` element. This goes in the `head` of your document:

```html
<link href="/path/to/german/version" rel="alternate" hreflang="de">
```
But unlike the `lang` attribute, which can go on any element, `hreflang` can only be applied to `a` and `link` elements.

## Consider internationalization in your design

When you're designing websites that will be translated into other languages and writing modes, think about these factors:

* Some languages, like German, have long words in common usage. Your interface needs to adapt to these words so avoid designing narrow columns. You can also [use CSS to introduce hyphens](https://developer.mozilla.org/docs/Web/CSS/hyphens).
* Make sure your `line-height` values can accommodate characters like accents and other diacritics. Lines of text that look fine in English might overlap in a different language.
* If you're using a web font, make sure it has a range of characters broad enough to cover the languages you'll be translating into.
* Don't create images that have text in them. If you do, you'll have to create separate images for each language. Instead, separate the text and the image, and use CSS to overlay the text on the image.

## Think internationally

Attributes like `lang` and `hreflang` make your HTML more meaningful for internationalization. 
Likewise, logical properties make your CSS more adaptable.

If you're used to thinking in terms of `top`, `bottom`, `left`, and `right`, 
it might be hard to start thinking of `block start`, `block end`, `inline start` and `inline end` instead. 
But it's worth it. Logical properties are key to creating truly responsive layouts.

{% Assessment 'internationalization' %}

Next, you'll learn how to approach page-level layouts, also known as [macro layouts](/learn/design/macro-layouts).

# Introduction

Right from the start,
the World Wide Web was designed to be agnostic.
It doesn't matter what hardware you've got.
It doesn't matter what operating system your device is running.
As long as you can connect to the internet, the World Wide Web is accessible to you.

In the early days of the web, most people were using desktop computers.
These days the web is available on desktops, laptops, tablets, foldable phones, fridges, and cars.
People rightly expect that websites will look good no matter what device they're using.
Responsive design makes this possible.

Responsive design isn't the first approach to designing websites.
In the years before responsive design, web designers and developers tried many different techniques.

## Fixed-width design

In the early 1990s, when the web was first becoming popular,
most monitors had screen dimensions of 640 pixels wide by 480 pixels tall.
These were convex cathode ray tubes,
not like the flat liquid crystal displays we have now.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/0a8vHe4LgChVZvaZQfYs.png",
alt="The Microsoft website with two simple columns of text plus a navbar.",
width="640", height="480" %}
  <figcaption>The Microsoft website in the late 90s designed for a width of 640 pixels. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>

In the formative days of early web design,
it was a safe bet to design web pages with a width of 640 pixels.
But while other technologies like phones and cameras were miniaturizing,
screens were getting bigger (and eventually, flatter).
Before long, most screens had dimensions of 800 by 600 pixels.
Web designs changed accordingly. Designers and developers started assuming that 800 pixels was a safe default.

<figure>
  {% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/C88van0yWyvbz5l746pB.png", alt="The Microsoft website using a three-column, mostly text-based design.", width="800", height="600" %}
  <figcaption>The Microsoft website in the learly 2000s designed for a width of 800 pixels. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>

Then the screens got bigger again. 1024 by 768 became the default.
It felt like an arms race between web designers and hardware manufacturers.

​​<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/nuHSqBVgInTvLti73Qz2.png", alt="The Microsoft website with a more complex design using images as well as text.", width="800", height="600" %}
<figcaption>The Microsoft website in the mid 2000s designed for a width of 1024 pixels. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>

Whether it was 640, 800, or 1024 pixels,
choosing one specific width to design for was called fixed-width design.

If you specify a fixed width for your layout,
then your layout will only look good at that specific width.
If a visitor to your site has a wider screen than the width you have chosen, then there'll be wasted space on the screen.
You can center the content of your pages to distribute that space more evenly
(instead of having empty space on one side) but you still wouldn't be taking full advantage of the available space.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/t0Zd1eGEJeeqMO8ItsqK.png", alt="A narrow layour with a lot of white space around it.", width="800", height="320" %}
<figcaption>The Yahoo website from the early 2000s as experienced in a browser that's wider than the site's 800 pixel wide design. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>

Similarly, if a visitor arrives with a narrower screen than the width you've chosen,
then your content won't fit horizontally.
The browser generates a crawlbar—the horizontal equivalent of a scrollbar—and the user has to move the whole page left and right to see all the content.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/bnh7fDiGjFhdBHTD5CJ8.png", alt="A website that appears cut-off to the right due to being too wide for the viewport.", width="420", height="640" %}
<figcaption>The Yahoo website from the early 2000s as experienced in a browser that's narrower than the site's 800 pixel wide design. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>

{% Codepen {
 user: 'web-dot-dev',
 id: 'RwZjwoQ',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

## Liquid layouts

While the majority of designers used fixed-width layouts, some chose to make their layouts flexible.
Instead of using fixed widths for your layouts you could make a flexible layout using percentages for your column widths.
These designs work in more situations than a fixed-width layout that only looks right at one specific size.

These were called liquid layouts.
But while a liquid layout will look good across a wide range of widths, it will begin to worsen at the extremes.
On a wide screen the layout looks stretched.
On a narrow screen the layout looks squashed. Both scenarios aren't ideal.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/oBAbgP2JCt2zVENHVCnc.png", alt="A layout that is squashed into a narrow window.", width="420", height="640" %}
<figcaption>Wikipedia's liquid layout from the mid 2000s as experienced in a narrow browser window. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>
​​
<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/zRBSmS1xCgYPTueUBMd9.png", alt="A layout stretched horizontally with very long line lengths.", width="800", height="320" %}
<figcaption>Wikipedia's liquid layout from the mid 2000s as experienced in a wide browser window. Screenshot from <a href="https://archive.org">archive.org</a></figcaption>
</figure>

You can mitigate these problems by using `min-width` and `max-width` for your layout.
But then at any size below the minimum width or above the maximum width you've got the same issues you'd have with a fixed-width layout.
On a wide screen there'd be unused space going to waste.
On a narrow screen, the user would have to move the whole page left and right to see everything.

<figure>
{% Codepen {
 user: 'web-dot-dev',
 id: 'YzxEzpE',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

<figcaption>Open <a href="https://codepen.io/web-dot-dev/pen/YzxEzpE">the liquid layout example</a>
in a new browser window to see how changing the size of the window stretches the design.</figcaption>
</figure>

The word _liquid_ is just one of the terms used to describe this kind of layout.
These kinds of designs were also called fluid layouts or flexible layouts.
The terminology was as fluid as the technique.

## Small screens

In the 21st century, the web continued to get bigger and bigger.
So did monitors. But new screens arrived that were smaller than any desktop device.
With the arrival of mobile phones with fully-featured web browsers, designers faced a dilemma.
How could they ensure their designs would look good on a desktop computer and a mobile phone?
They needed a way of styling their content for screens as small as 240 pixels wide and as large as thousands of pixels wide.

## Separate sites

One option is to make a separate subdomain for mobile visitors.
But then you have to maintain two separate codebases and designs.
And in order to redirect visitors on mobile devices, you'd need to do
[user-agent sniffing](https://en.wikipedia.org/wiki/Browser_sniffing),
which can be unreliable and easily spoofed.
Chrome will be deprecating its user-agent string for privacy reasons.
Also, there's no clear line between mobile and not-mobile. Which site do you send tablet devices to?

## Adaptive layouts

Instead of having separate sites on different subdomains,
you could have a single site with two or three fixed-width layouts.

When media queries first arrived in CSS, they opened the door to making layouts more flexible.
But many developers were still most comfortable making fixed-width layouts.
One technique involved switching between a handful of fixed-width layouts at specified widths.
Some people call this an adaptive design.

Adaptive design allowed designers to provide layouts that looked good at a few different sizes,
but the design never looked quite right when viewed between those sizes.
The problem of excess space persisted although it wasn't as bad as in a fixed-width layout.

Using CSS media queries, you can give people the layout that's closest to their browser width.
But given the variety of device sizes, chances are the layout will look less than perfect for most people.

<figure>
{% Codepen {
 user: 'web-dot-dev',
 id: 'oNeoNYw',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}
<figcaption>Open <a href="https://codepen.io/web-dot-dev/pen/oNeoNYw">the adaptive layout example</a>
in a new browser window to see how changing the size of the window causes the design to jump between layouts.</figcaption>
</figure>

## Responsive web design

If adaptive layouts are a mashup of media queries and fixed-width layouts, responsive web design is a mashup of media queries and liquid layouts.

<figure>
{% Codepen {
 user: 'web-dot-dev',
 id: 'JjyOjbE',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}
<figcaption>Open <a href="https://codepen.io/web-dot-dev/pen/JjyOjbE">the responsive design example</a>
in a new browser window to see how changing the size of the window causes the design to fluidly change layout.</figcaption>
</figure>

The term was coined by [Ethan Marcotte](https://ethanmarcotte.com/) in
[an article in A List Apart](https://alistapart.com/article/responsive-web-design/) in 2010.

Ethan defined three criteria for responsive design:

1. Fluid grids
2. Fluid media
3. Media queries

The layout and images of a responsive site would look good on any device. But there was one problem.

## A `meta` element for `viewport`

Browsers on mobile phones had to deal with websites that were designed with fixed-width layouts for wider screens.
By default mobile browsers assumed that 980 pixels was the width that people were designing for (and they weren't wrong).
So even if you used a liquid layout,
the browser would apply a width of 980 pixels and then scale the rendered web page down to the actual width of the screen.

If you're using responsive design you need to tell the browser not to do that scaling.
You can do that with a `meta` element in the `head` of the web page:

```html
<meta name="viewport" content="width=device-width, initial-scale=1">
```

There are two values, separated by commas.
The first one is `width=device-width`.
This tells the browser to assume the width of the website is the same as the width of the device
(instead of assuming the width of the website is 980 pixels).
The second value is `initial-scale=1`.
This tells the browser how much or how little scaling to do.
With a responsive design, you don't want the browser to do any scaling at all.

<figure>
{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/HahSW2IXIkGux7cMCMpE.png", alt="Images of two mobile phones containing text, one appearing zoomed out due to not having the meta tag in place.", width="800", height="748" %}
  <figcaption>The phone on the left shows how the layout looks before the meta tag is in place, when compared to the layout on the right.</figcaption>
</figure>

With that `meta` element in place, your web pages are ready to be responsive.

## Modern responsive design

Today we have the ability to make websites that are responsive in ways far beyond viewport sizes.
Media features give developers access to user preferences and enable customized experiences.
Container queries enable components to own their own responsive information.
The `picture` element empowers designers to make art-direction decisions based on screen ratios.

{% Assessment 'intro' %}

Responsive design is an exciting, growing world of possibilities.
In the rest of this course, you'll learn about these technologies and how to use them to create beautiful,
responsive websites for everyone.

# Macro layouts

Macro layouts describe the larger, page-wide organization of your interface. 

{% Img src="image/HodOHWjMnbNw56hvNASHWSgZyAf2/HoOnH9yMrSY6MhQdRNRZ.jpeg", 
alt="A wireframe of a two column layout, next to the same layout as one column for a narrow view.", width="800", height="501" %}

Before applying any layout, 
you should make sure that the flow of your content makes sense. 
This single column default ordering is what smaller screens will get.

```html
<body>
  <header>…</header>
  <main>
    <article>…</article>
    <aside>…</aside>
  </main>
  <footer>…</footer>
</body>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'oNeePOX',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

When you arrange these individual page-level components, 
you're designing a macro layout: a high-level view of your page. 
Using media queries, you can supply rules in CSS describing how this view should adjust to different screen sizes.

{% Video src="video/HodOHWjMnbNw56hvNASHWSgZyAf2/3KENjI9FiNARctTiKDak.mp4", autoplay=true, controls=true, loop=true %}

## Grid

[CSS grid](/learn/css/grid/) is an excellent tool for applying a layout to your page. 
In the example above,  say you want a two-column layout once there's enough screen width available. 
To apply this two-column layout once the browser is wide enough, 
use a media query to define the grid styles above a specified breakpoint.

```css
@media (min-width: 45em) {
  main {
    display: grid;
    grid-template-columns: 2fr 1fr;
  }
}
```
{% Aside %}
While it would make more sense to specify `min-inline-size` instead of `min-width`, 
logical properties don't work in media queries yet.
{% endAside %}

{% Codepen {
 user: 'web-dot-dev',
 id: 'vYJJzMK',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

## Flexbox

For this specific layout, you could also use [flexbox](/learn/css/flexbox). 
The styles would look like this:

```css
@media (min-width: 45em) {
  main {
    display: flex;
    flex-direction: row;
  }

  main article {
    flex: 2;
  }

  main aside {
    flex: 1;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'gOxxdym',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

However, the flexbox version requires more CSS. 
Each column has a separate rule to describe how much space it should take up. 
In the grid example, that same information is encapsulated in one rule for the containing element.

## Do you need a media query?

You might not always need to use a media query. 
Media queries work fine when you're applying changes to a few elements, 
but if the layout needs to be updated a lot, your media queries could get out of hand with lots of breakpoints.

Say you've got a page full of card components. 
The cards are never wider than `15em`, and you want to put as many cards on one line as will fit. 
You could write media queries with breakpoints of `30em`, `45em`, `60em`, 
and so on, but that's quite tedious and difficult to maintain.

Instead, you can apply rules so that the cards themselves automatically take up the right amount of space.

```css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));
  grid-gap: 1em;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'QWMMVPm',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

You can achieve a similar layout with flexbox. 
In this case, if there are not enough cards to fill the final row, 
the remaining cards will stretch to fill the available space rather than lining up in columns. 
If you want to line up rows and columns, then use grid.

```css
.cards {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 1em;
}
.cards .card {
  flex-basis: 15em;
  flex-grow: 1;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'abyyaMg',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

By applying some smart rules in flexbox or grid, 
it's possible to design dynamic macro layouts with minimal CSS and without any media queries. 
That's less work for you—you're making the browser do the calculations instead. 
To see some examples of modern CSS layouts that are fluid without requiring media queries, see 
[1linelayouts.com](https://1linelayouts.glitch.me/).

{% Assessment 'macro-layouts' %}

Now that you've got some ideas for page-level macro layouts, 
turn your attention to the components within the page. This is the realm of 
[micro layouts](/learn/design/micro-layouts).

# Media features

Responsive design wouldn't be possible without media queries. Before media queries there was no way of knowing what kind of device people were using to visit your website. Designers had to make assumptions. Those assumptions were encoded into fixed-width designs or liquid layouts.

That all changed with the introduction of [media queries](/learn/design/media-queries/). For the first time designers could meet people halfway. Designers could adjust their layouts to respond to people's devices.

Remember, a media query comprises an optional media type and a mandatory media feature. There hasn't been much change in media types over the years. There are still just four possible values:

```css
@media all
@media screen
@media print
@media speech
```

[Media features](https://developer.mozilla.org/docs/Web/CSS/@media#media_features), on the other hand, have expanded greatly. Designers now can meet users beyond halfway, adapting designs to fit far more than just screen size.
{% BrowserCompat 'css.at-rules.media' %}

## Viewport dimensions

By far the most popular media queries on the web are the ones dealing with viewport width. But even here, you're presented with a choice. You can use the `max-width` media feature to apply styles below a certain width, or you can use the `min-width` media feature to apply styles above a certain width.


```css/4-4
main {
  display: grid;
  grid-template-columns: 2fr 1fr;
}
@media (max-width: 45em) {
  main {
    display: block;
  }
}
```

```css/0-0
@media (min-width: 45em) {
  main {
    display: grid;
    grid-template-columns: 2fr 1fr;
  }
}
```

Personally, I like to use `min-width`. I apply layout styles in an additive way. I introduce new layout rules at each breakpoint instead of undoing previous rules.

This additive approach also works for height. Using `min-height` you can introduce more rules as more viewport height becomes available. For example, you might have a header element that you want to anchor to the top of the browser window if there's enough vertical space.

```css/0-0
@media (min-height: 30em) {
  header {
    position: fixed;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'PoJbdaN',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

But you can use the `max-height` media feature if you prefer. Here, the header is anchored by default, but the stickiness is removed if there isn't enough vertical space.

```css/3-3
header {
  position: fixed;
}
@media (max-height: 30em) {
  header {
    position: static;
  }
}
```

Choosing between `min-` and `max-` prefixes doesn't just apply to [`width`](https://developer.mozilla.org/docs/Web/CSS/@media/width) and [`height`](https://developer.mozilla.org/docs/Web/CSS/@media/height). The [`aspect-ratio`](https://developer.mozilla.org/docs/Web/CSS/@media/aspect-ratio) media feature offers the same choice. It also offers an unprefixed version if you want to apply styles at an exact ratio of width to height.

```css
@media (min-aspect-ratio: 16/9) {
  // The ratio of width to height is at least 16 by 9.
}
@media (max-aspect-ratio: 16/9) {
  // The ratio of width to height is less than 16 by 9.
}
@media (aspect-ratio: 16/9) {
  // The ratio of width to height is exactly 16 by 9.
}
```

Providing different styles for different aspect ratios could quickly get out of hand. If you don't need that fine-grained level of control, the [`orientation`](https://developer.mozilla.org/docs/Web/CSS/@media/orientation) media feature might better suit your needs. It has two possible values: `portrait` or `landscape`.

```css
@media (orientation: portrait) {
  // The width is less than the height.
}
@media (orientation: landscape) {
  // The width is greater than the height.
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'qBXVowV',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/gtBzPVsBu5mtnX8RuSqJ.mp4", controls=true, loop=true %}

Even though the terms "portrait" and "landscape" are most often used to refer to the orientation of mobile devices, the `orientation` media feature isn't device-specific. A full-screen browser window on a typical laptop will have an `orientation` value of `landscape`.

## Displays

Different displays have different pixel densities, measured in `dpi`, dots per inch. You can adjust your styles for different pixel densities using the [`resolution`](https://developer.mozilla.org/docs/Web/CSS/@media/resolution) media feature. Like `aspect-ratio`, `resolution` comes in three varieties: minimum, maximum, and exact.

```css
@media (min-resolution: 300dpi) {
  // The display has a pixel density of at least 300 dots per inch.
}
@media (max-resolution: 300dpi) {
  // The display has a pixel density less than 300 dots per inch.
}
@media (resolution: 300dpi) {
  // The display has a pixel density of exactly 300 dots per inch.
}
```

You may never need to use any `resolution` media queries. Pixel density is usually only an issue for images, and [responsive images](/learn/design/responsive-images/) are a way of dealing with pixel density directly in HTML.

On the other hand, CSS is where you define your animations and transitions. You can adjust those animations and transitions to respond to different refresh rates using the [`update`](https://developer.mozilla.org/docs/Web/CSS/@media/update-frequency) media feature. This media feature reports one of three values: `none`, `slow`, and `fast`.

An `update` value of `none` means there's no refresh rate. A printed page, for example, can't be updated.

An `update` value of `slow` means the display can't refresh quickly. An e-ink display is one example of a screen with a slow refresh rate.

An `update` value of `fast` means the display refreshes fast enough to handle animations and transitions.

```css
@media (update: fast) {
  a {
    transition-duration: 0.4s;
    transition-property: transform;
  }
  a:hover {
    transform: scale(150%);
  }
}
```

Not all aspects of the display are related to hardware capabilities. In [the module on theming](/learn/design/theming/), you saw how to define properties in a [web app manifest](/add-manifest/) file. One of those properties is called `display`, and you can give it a value of `fullscreen`, `standalone`, `minimum-ui`, or `browser`. The corresponding [`display-mode`](https://developer.mozilla.org/docs/Web/CSS/@media/display-mode) media feature allows you to tailor your styles for these different options.

Let's say you've provided a `display` value of `standalone` in your web app manifest. If someone adds your site to their home screen, the site will launch without any browser interface. You might decide to display a back button for those users.

```css
button.back {
  display: none;
}
@media (display-mode: standalone) {
  button.back {
     display: inline;
  }
}
```

## Color

There are numerous media features for querying the color capabilities of a device. If you want to adjust your styles for any display that only outputs shades of grey, you can use the [`monochrome`](https://developer.mozilla.org/docs/Web/CSS/@media/monochrome) media feature without any value.

```css
@media (monochrome) {
  body {
    color: black;
    background-color: white;
  }
}
```

There's a corresponding [`color`](https://developer.mozilla.org/docs/Web/CSS/@media/color) media feature.

```css
@media (color) {
  body {
    color: maroon;
    background-color: linen;
  }
}
```

For color screens, you can write queries with the media features [`color-gamut`](https://developer.mozilla.org/docs/Web/CSS/@media/color-gamut), [`color-index`](https://developer.mozilla.org/docs/Web/CSS/@media/color-index), or [`dynamic-range`](https://www.w3.org/TR/mediaqueries-5/#dynamic-range). All of them report specific details about the color capabilities of the screen.

In this example, color values update in response to the `dynamic-range` media feature, which reports the combination of maximum brightness, color depth, and contrast ratio of the display. The possible values are `standard` or `high`. A high-definition screen that reports a `dynamic-range` value of `high` is given a different color space using the new CSS `color()` function.

```css/3-3
.neon-red {
  color: hsl(355 100% 95%);
}
@media (dynamic-range: high) {
  .neon-red {
    color: color(display-p3 1 0 0);
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'BawQOPQ',
 height: 400,
 theme: 'dark',
 tab: 'result'
} %}

## Interaction

Media features can also report the kind of input mechanism used to interact with your site: `hover`, `any-hover`, `pointer`, and `any-pointer`. See [the module on interaction](/learn/design/interaction/) for more details.

## Preferences

There are a range of media queries that allow you to respond to user preferences: `prefers-color-scheme`, `prefers-contrast`, and `prefers-reduced-motion`. See the modules on [theming](/learn/design/theming/) and [accessibility](/learn/design/accessibility/) for more details.

You can combine media features in one media query. You could scope your animation styles so that they're only applied if the device has a fast refresh rate and the user hasn't expressed a preference for reduced motion.

```css
@media (update: fast) and (prefers-reduced-motion: no-preference) {
  a {
    transition-duration: 0.4s;
    transition-property: transform;
  }
  a:hover {
    transform: scale(150%);
  }
}
```

## More media features

There are more media features on the way.

The [`forced-colors`](https://developer.mozilla.org/docs/Web/CSS/@media/forced-colors) and [`inverted-colors`](https://developer.mozilla.org/docs/Web/CSS/@media/inverted-colors) media features will report whether a device is using a restricted or an inverted color palette.

A [`scripting`](https://developer.mozilla.org/docs/Web/CSS/@media/scripting) media feature will allow you to adjust your CSS based on the availability of JavaScript.

A media feature called [`prefers-reduced-data`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-data) will allow users to specify that they're on a metered connection so you can send smaller or fewer assets.

Other proposals are still being formulated. In the next and final module, you'll learn about a proposal for a media feature that handles different screen configurations.

{% Assessment 'media-features' %}

# Media queries

Designers can adjust their designs to accommodate users. 
The clearest example of this is the form factor of a user's device; its width, 
the device aspect ratio, and so on. Using media queries, designers can respond to these different form factors.

Media queries are initiated with the `@media` keyword (a CSS at-rule), and can be used for a variety of use cases.

## Target different types of output

Websites are often displayed on screens but CSS can also be used to style websites for other outputs too. 
You might want your web pages to look one way on a screen but different when printed out. 
Querying media types makes this possible.

In this example, the background color is set to grey. 
But if the page is printed, the background color should be transparent. 
This saves the user's printer ink.

```css
body {
  color: black;
  background-color: grey;
}

@media print {
  body {
    background-color: transparent;
  }
}
```

You can use the `@media` at-rule in your stylesheet like that, 
or you can make a separate stylesheet and use the `media` attribute on a `link` element:

```html
<link rel="stylesheet" href="global.css">
<link rel="stylesheet" href="print.css" media="print">
```

If you don't specify any media type for your CSS, 
it will automatically have a media type value of `all`. These two blocks of CSS are equivalent:

```css
body {
  color: black;
  background-color: white;
}
```

```css
@media all {
   body {
     color: black;
     background-color: white;
   }
}
```

These two lines of HTML are also equivalent:

```html
<link rel="stylesheet" href="global.css">
```

```html
<link rel="stylesheet" href="global.css" media="all">
```


### Query conditions

You can add conditions to media types. These are called media queries. 
The CSS is applied only if the media type matches and the condition is also true. 
These conditions are called _media features_.

This is the syntax for media queries:

```css
@media type and (feature)
```

You can use media queries on a `link` element if your styles are in a separate stylesheet:

```html
<link rel="stylesheet" href="specific.css" media="type and (feature)">
```

Let's say you want to apply different styles depending on whether the browser window is in landscape mode 
(the viewport width is greater than its height) or portrait mode 
(the viewport height is greater than its width). 
There's a media feature called `orientation` you can use to test that:

```css
@media all and (orientation: landscape) {
   // Styles for landscape mode.
}
@media all and (orientation: portrait) {
   // Styles for portrait mode.
}
```

Or if you prefer to have separate stylesheets:

```html
<link rel="stylesheet" href="landscape.css" media="all and (orientation: landscape)">
<link rel="stylesheet" href="portrait.css" media="all and (orientation: portrait)">
```

In this case the media type is `all`. Because that's the default value, you can leave it out if you want:

```css
@media (orientation: landscape) {
   // Styles for landscape mode.
}
@media (orientation: portrait) {
   // Styles for portrait mode.
}
```

Or using separate stylesheets:

```html
<link rel="stylesheet" href="landscape.css" media="(orientation: landscape)">
<link rel="stylesheet" href="portrait.css" media="(orientation: portrait)">
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'qBXVowV',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/gtBzPVsBu5mtnX8RuSqJ.mp4", autoplay=true, controls=true, loop=true %}

While using separate stylesheets for different media _types_—like `print`—might be okay, 
it's probably not a good idea to use a separate stylesheet for every media _query_. Use `@media` at-rules instead.

## Adjust styles based on viewport size

For responsive design, one of the most useful media features involves the dimensions of the browser viewport. 
To apply styles when the browser window is wider than a certain width, use `min-width`.

```css
@media (min-width: 400px) {
  // Styles for viewports wider than 400 pixels.
}
```

Use the `max-width` media feature to apply styles below a certain width:

```css
@media (max-width: 400px) {
  // Styles for viewports narrower than 400 pixels.
}
```

You can use any CSS [length units](https://developer.mozilla.org/docs/Web/CSS/length) in your media queries. 
If your content is mostly image-based, pixels might make the most sense. 
If your content is mostly text-based, 
it probably makes more sense to use a [relative unit](/learn/css/sizing/#relative-lengths) that's based on text size, like `em` or `ch`:

```css
@media (min-width: 25em) {
  // Styles for viewports wider than 25em.
}
```

You can also combine media queries to apply more than one condition. 
Use the word `and` to combine your media queries:

```css
@media (min-width: 50em) and (max-width: 60em) {
  // Styles for viewports wider than 50em and narrower than 60em.
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'GRvOxaw',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/eDf5v1QMwLX19pcJAgYE.mp4", autoplay=true, controls=true, loop=true %}

## Choose breakpoints based on the content

The point at which a media feature condition becomes true is called a breakpoint. 
It's best to choose your breakpoints based on your content rather than popular device sizes, 
as those are subject to change with every technology release cycle.

In this example, `50em` is the point at which the lines of text become uncomfortably long. 
So a breakpoint is created to make the interface more legible. 
Using the `column-count` property, the text is divided into two columns from that point on.

```css
@media (min-width: 50em) {
  article {
    column-count: 2;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'oNeodgd',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/mrQlcyih7IcZxswI1lMx.mp4", autoplay=true, controls=true, loop=true %}

## Combinations

You can use media queries based on the height of the viewport, not just the width. 
This could be useful for optimizing interface content "above the fold". In the previous example, 
if readers are using a wide but short browser window, 
they have to scroll down one column and then scroll back up to get to the top of the second column. 
It would be safer to only apply the columns when the viewport is both wide enough and tall enough.

You can combine media queries so that the styles only apply when all the conditions are true. 
In this example, the viewport must be at least `50em` wide and `60em` tall in order for the column styles to be applied. 
Those breakpoints were chosen based on the amount of content.

```css
@media (min-width: 50em) and (min-height: 60em) {
  article {
    column-count: 2;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'JjyOvdM',
 height: 1000,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/oKRBxhrHzAzebYwxptsv.mp4", autoplay=true, controls=true, loop=true %}

These examples show how media queries can be used to adapt designs to the form factor of a user's device, 
but these just scratch the surface of possibilities. Media queries can go far beyond width and height, 
accessing user preferences for accessibility features and theme colors. 
Using media queries to make layout adjustments is a great start to a responsive design, which builds on these features and more.

{% Assessment 'media-queries' %}

# Micro layouts

When we think of layouts, we often think of page-level designs. 
But smaller components within the page can have their own self-contained layouts.

Ideally, these component-level layouts will adjust themselves automatically, 
regardless of their position on the page. 
There may be situations where you don't know if a component will be placed into the main content column or the sidebar or both. 
Without knowing for sure where a component will end up, 
you need to make sure that the component can adjust itself to its container.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/hAz94zpnzIQYHjamxtYK.png", 
alt="A two column layout, one wide and one narrow. The media objects are laid out differently depending on whether they're in the wide or narrow column.", width="800", height="410" %}


{% Aside %}
In the future, creating components that can adapt to their container will become much easier with the implementation of 
[Container Queries](https://developer.mozilla.org/docs/Web/CSS/CSS_Container_Queries). 
For now, however, you need to consider the existing ways to create reusable and responsive micro-layouts. 
You can find a preview of how Container Queries fit into existing responsive design methods at the end of this module.
{%endAside%}

## Grid

[CSS grid](/learn/css/grid/) isn't just for page-level layouts. 
It also works well for the components that live within them.

In this example, the `::before` and `::after` [pseudo-elements](​​/learn/css/pseudo-elements/) 
create decorative lines on either side of a heading. 
The heading itself is a grid container. 
The individual elements are laid out so that the lines always fill the available space.

```css
h1 {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1em;
}
h1::before,
h1::after {
  content: "";
  border-top: 0.1em double black;
  align-self: center;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'rNzYvxm',
 height: 200,
 theme: 'dark',
 tab: 'result'
} %}

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/mNjoV2ri3HmsPeRoTpTh.png", alt="Developer tools in Firefox showing a grid overlay.", width="800", height="644" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/7A1UYerc4KNuuWmp3IMJ.png", alt="Developer tools in Chrome showing a grid overlay.", width="800", height="644" %}
 <figcaption>
   Desktop browsers like Firefox and Chrome have developer tools that can show you grid lines and areas overlaid on your design. 
 </figcaption>
</figure>

Learn how to [inspect grid layouts](https://developer.chrome.com/docs/devtools/css/grid/) in Chrome DevTools.

## Flexbox

As the name suggests, [flexbox](/learn/css/flexbox/) allows you to make your components flexible. 
You can declare which elements in your component should have a minimum or maximum size and let the other elements flex to fit accordingly.

In this example, the image takes up one quarter of the available space and the text takes up the other three quarters. 
But the image never gets larger than 200 pixels.

```css
.media {
  display: flex;
  align-items: center;
  gap: 1em;
}
.media-illustration {
  flex: 1;
  max-inline-size: 200px;
}
.media-content {
  flex: 3;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'qBXVYZo',
 height: 300,
 theme: 'dark',
 tab: 'result'
} %}

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/9xyxPbFU4EUtnPGsKdQI.png", alt="Developer tools in Firefox showing a flexbox overlay.", width="800", height="644" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/R7Ucm4OvYLbXGD0I3rw2.png", alt="Developer tools in Chrome showing a flexbox overlay.", width="800", height="644" %}
 <figcaption>
   The developer tools in Firefox and Chrome can help you visualize the shape of your flexbox components. 
 </figcaption>
</figure>

Learn how to [inspect flexbox layouts](https://developer.chrome.com/docs/devtools/css/flexbox/) in Chrome DevTools.

## Container queries

Flexbox allows you to design from the content out. 
You can specify the parameters of your elements (how narrow they should get, how wide they should get) 
and let the browser figure out the final implementation.

But the component itself has no awareness of its context. 
It doesn't know if it's being used in the main content or in a sidebar. 
This can make component layouts trickier than page layouts. 
To be able to apply contextually relevant styles, your components need to know more than the size of the viewport they are inside.

With page layouts, you *do* know the width of the container because the container is the browser viewport; 
media queries report the dimensions of the page-level container.

Now there's an upcoming CSS technology that reports the dimensions of any parent container: 
[container queries](https://developer.mozilla.org/docs/Web/CSS/CSS_Container_Queries).

{% Aside 'caution' %}
Container queries are a new experimental technology that isn't widely available in browsers. 
To test the code below, and see the example working, enable container queries in Chrome. 

Go to `chrome://flags/`, search for **Container Queries**, and enable the `#enable-container-queries` flag.
With the flag enabled, you can [inspect and debug container queries](https://developer.chrome.com/docs/devtools/css/container-queries/) in Chrome DevTools.
{% endAside %}

To start, define which elements will act as containers.

```css
main,
aside {
  container-type: inline-size;
}
```

This means that you want to be able to query the inline dimension. 
For English-language documents, that's the horizontal axis. 
You're going to change styles based on the width of the container.

If a component is inside one of those containers, 
you can apply styles in a way that's quite similar to media queries.

```css
.media-illustration {
  max-width: 200px;
  margin: auto;
}

@container (min-width: 25em) {
  .media {
    display: flex;
    align-items: center;
    gap: 1em;
  }

  .media-illustration {
    flex: 1;
  }

  .media-content {
    flex: 3;
  }
}
```

If a media object is inside a container that's narrower than `25em`, 
the flexbox styles aren't applied. The image and text appear are ordered vertically.

But if the containing element is wider than `25em`, the image and text appear side by side.

Container queries allow you to style components in an independent way. 
The width of the viewport is no longer what matters. 
You can write rules based on the width of the containing element.

{% Img src="image/HodOHWjMnbNw56hvNASHWSgZyAf2/819QcTZ9zW0uVk8tTdGi.png", 
alt="Two containers of different sizes.", width="800", height="624" %}


## Combining queries

You can use media queries for the page layout, and container queries for the components within the page.

Here the overall structure of the page has a `main` element and an `aside` element. 
There are media objects within both elements.

```html
<body>
  <main>
     <div class="media">…</div>
     <div class="media">…</div>
  </main>
  <aside>
     <div class="media">…</div>
  </aside>
</body>
```
A media query applies a grid layout to the `main` and `aside` elements when the viewport is wider than `45em`.

```css
@media (min-width: 45em) {
  body {
    display: grid;
    grid-template-columns: 3fr 1fr;
  }
}
```
The container query rule for the media objects remains the same: 
only apply a horizontal flexbox layout if the containing element is wider than `25em`.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/hAz94zpnzIQYHjamxtYK.png", 
alt="A two column layout, one wide and one narrow. 
The media objects are laid out differently depending on whether they're in the wide or narrow column.", width="800", height="410" %}

{% Aside 'caution' %}
This demo won't work in every browser. In Google Chrome you can find the `#enable-container-queries` flag at `chrome://flags`.
{% endAside %}

{% Codepen {
 user: 'web-dot-dev',
 id: 'RwZjyRv',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

Container queries are a game-changer for micro layouts. 
Your components can be self-contained, independent of the browser viewport.

{% Assessment 'micro-layouts' %}

Previously, you learned about page-level macro layouts. 
Now you know about component-level micro layouts. 
Next, you'll dive deeper into the very building blocks of your content. 
You'll learn how to make your images responsive. But now let's explore responsive typography.

# The picture element

[The previous module](/learn/design/responsive-images/) demonstrated how the `srcset` attribute allows you to provide different-sized versions of the same image. The browser can then decide which is the right version to use. If you want to change the image completely, you'll need the [`picture`](https://developer.mozilla.org/docs/Web/HTML/Element/picture) element.

In the same way that `srcset` builds upon the `src` attribute, the `picture` element builds upon the `img` element. The `picture` element wraps around an `img` element.

```html
<picture>
  <img src="image.jpg" alt="A description of the image.">
</picture>
```

If there is no `img` element nested inside the `picture` element, the `picture` element won't work.

Like the `srcset` attribute, the `picture` element will update the value of the `src` attribute in that `img` element. The difference is that where the `srcset` attribute gives suggestions to the browser, the `picture` element gives commands. This gives you control. 

## `source`

You can specify multiple `source` elements inside a `picture` element, each one with its own `srcset` attribute. The browser then executes the first one that it can.

## Image formats

In this example, there are three different images in three different formats:

```html/1-2
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="A description of the image." 
    width="300" height="200" loading="lazy" decoding="async">
</picture>
```

The first `source` element points to an image in [the new AVIF format](/compress-images-avif/). If the browser is capable of rendering AVIF images, then that's the image file it chooses. Otherwise, it moves on to the next `source` element.

The second `source` element points to an image in [the WebP format](/serve-images-webp/). If the browser is capable of rendering WebP images, it will use that image file.

Otherwise the browser will fall back to the image file in the `src` attribute of the `img` element. That image is a JPEG.

This means you can start using new image formats without sacrificing backward compatibility.

In that example, the `type` attribute told the browser which kind of image format was specified.

## Image sizes

As well as switching between image formats, you can switch between image sizes. Use the `media` attribute to tell the browser how wide the image will be displayed. Put a media query inside the `media` attribute.

```html/1-2
<picture>
  <source srcset="large.png" media="(min-width: 75em)">
  <source srcset="medium.png" media="(min-width: 40em)">
  <img src="small.png" alt="A description of the image." 
    width="300" height="200" loading="lazy" decoding="async">
</picture>
```

Here you're telling the browser that if the viewport width is wider than `75em` it must use the large image. Between `40em` and `75em` the browser must use the medium image. Below `40em` the browser must use the small image.

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/tXME65OZikEMwvPAEgX2.mp4", controls=true, loop=true %}

This is different to using the `srcset` and `sizes` attributes on the `img` element. In that case you're providing suggestions to the browser. The `source` element is more like a command than a suggestion.

You can also use the pixel density descriptor inside the `srcset` attribute of a `source` element.

```html/1-2
<picture>
  <source srcset="large.png 1x" media="(min-width: 75em)">
  <source srcset="medium.png 1x, large.png 2x" media="(min-width: 40em)">
  <img src="small.png" alt="A description of the image." width="300" height="200" loading="lazy" decoding="async"
    srcset="small.png 1x, medium.png 2x, large.png 3x">
</picture>
```

In that example you're still telling the browser what to do at different breakpoints, but now the browser has the option to choose the most appropriate image for the device's pixel density.

{% Codepen {
 user: 'web-dot-dev',
 id: 'PoJYrNB',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

## Cropping

If you only need to serve differently sized versions of the same image, `srcset` is your best option. But if an image doesn't look good at smaller sizes, you can try making a cropped version of the image instead.

The different images might have different width and height ratios to suit their context better. For example, on a mobile browser you may want to serve a crop that's narrow and tall, whereas on a desktop browser, you might want to serve a crop that's wide and short.

Here's an example of a hero image that changes its contents and its shape based on the viewport width. Add `width` and `height` attributes to each `source` element.

```html/1-2
<picture>
  <source srcset="full.jpg" media="(min-width: 75em)" width="1200" height="500">
  <source srcset="regular.jpg" media="(min-width: 50em)" width="800" height="400">
  <img src="cropped.jpg" alt="A description of the image." width="400" height="400" loading="eager" decoding="sync">
</picture>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'eYGOwzp',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/WZLJGIUHqlP1j9s9aJaj.mp4", controls=true, loop=true %}

Remember that you can't change the `alt` attribute depending on the image source. You'll need to write an `alt` attribute that describes both the full size image and the cropped image.

You probably won't need to use the `picture` element for most of your responsive images—the `srcset` and `sizes` attributes on the `img` element cover a lot of use cases. But for those situations when you need more fine-grained control, the `picture` element is a powerful tool.

There's one kind of image where you might not need either solution: icons. [That's what's next](/learn/design/icons/).

{% Assessment 'picture' %}

# Responsive images

Text on the web automatically wraps at the edge of the screen so that it doesn't overflow. It's different with images. Images have an intrinsic size. If an image is wider than the screen, the image will overflow, causing a horizontal scrollbar to appear.

Fortunately, you can take measures in CSS to stop this from happening.

## Constrain your images

In your stylesheet, you can declare that images should never be rendered at a size wider than their containing element using [`max-inline-size`](https://developer.mozilla.org/docs/Web/CSS/max-inline-size).
{% BrowserCompat 'css.properties.max-inline-size' %}

```css
img {
  max-inline-size: 100%;
  block-size: auto;
}
```

{% Aside %}
You can use `max-width` instead of `max-inline-size` if you prefer, but remember it's good to get in the habit of thinking in terms of [logical properties](/learn/design/internationalization/#logical-properties).
{% endAside %}

You can apply the same rule to other kinds of embedded content too, like videos and iframes.

```css
img,
video,
iframe {
  max-inline-size: 100%;
  block-size: auto;
}
```

With that rule in place, browsers will automatically scale down images to fit on the screen.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/RvqAjVGiroJDuBBpYXYV.png", alt="Two screenshots; the first shows an image expanding past the browser width; the second shows the same image constrained within the browser viewport.", width="800", height="763" %}


Adding a [`block-size`](https://developer.mozilla.org/docs/Web/CSS/block-size) value of `auto` means that the aspect-ratio of the images will remain constant.

Sometimes the dimensions of an image might be out of your control—if an image is added through a content management system, for example. If your design calls for a images to have an aspect ratio that's different to the image's real dimensions, use the [`aspect-ratio`](https://developer.mozilla.org/docs/Web/CSS/aspect-ratio) property in CSS.

```css/3-3
img {
  max-inline-size: 100%;
  block-size: auto;
  aspect-ratio: 2/1;
}
```

But then the browser might squash or stretch the image to make it fit your preferred aspect ratio.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/GNEkQTnMZTde5QB2mkvh.jpg", alt="Profile of a happy-looking handsome dog with a ball in its mouth, but the image is squashed.", width="800", height="400" %}

To prevent that happening, use the [`object-fit`](https://developer.mozilla.org/docs/Web/CSS/object-fit) property.
{% BrowserCompat 'css.properties.object-fit' %}

An `object-fit` value of `contain` tells the browser to preserve the image's aspect ratio, even if that means leaving empty space above and below.

```css/4-4
img {
  max-inline-size: 100%;
  block-size: auto;
  aspect-ratio: 2/1;
  object-fit: contain;
}
```

An `object-fit` value of `cover` tells the browser to preserve the image's aspect ratio, even if that means cropping the image at the top and bottom.

```css/4-4
img {
  max-inline-size: 100%;
  block-size: auto;
  aspect-ratio: 2/1;
  object-fit: cover;
}
```

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/VCC9WmZ2BFqLrkRlFViy.jpg", alt="Profile of a happy-looking handsome dog with a ball in its mouth; there is extra space on either side of the image.", width="800", height="400" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/FgeMDACB094Myj6cVCZu.jpg", alt="Profile of a happy-looking handsome dog with a ball in its mouth; the image has been cropped at the top and bottom.", width="800", height="400" %}
 <figcaption>
   The same image with two different values for `object-fit` applied. The first has an `object-fit` value of `contain`. The second has an `object-fit` value of `cover`.
 </figcaption>
</figure>


If the cropping at the top and bottom evenly is an issue, use the [object-position](https://developer.mozilla.org/docs/Web/CSS/object-position) CSS property to adjust the focus of the crop.
{% BrowserCompat 'css.properties.object-position' %}

You can make sure the most important image content is still visible.

```css/5-5
img {
  max-inline-size: 100%;
  block-size: auto;
  aspect-ratio: 2/1;
  object-fit: cover;
  object-position: top center;
}
```

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/mZDZFob5QnBl5YmAHh2A.jpg", alt="Profile of a happy-looking handsome dog with a ball in its mouth; the image has only been cropped at the bottom.", width="800", height="400" %}

## Deliver your images

Those CSS rules tell the browser how you'd like images to be rendered. You can also provide hints in your HTML about how the browser should handle those images.

### Sizing hints

If you know the dimensions of the image you should include `width` and `height` attributes. Even if the image is rendered at a different size (because of your `max-inline-size: 100%` rule), the browser still knows the width to height ratio and can set aside the right amount of space. This will stop your other content jumping around when the image loads.

```html/3-4
<img
 src="image.png"
 alt="A description of the image."
 width="300"
 height="200"
>
```

<figure>
{% Video src="/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/WOQn6K6OQcoElRw0NCkZ.mp4", controls=true, loop=true %}
{% Video src="/video/tcFciHGuF3MxnTr1y5ue01OGLBn2/sFxDb36aEMvTPIyZHz1O.mp4", controls=true, loop=true %}
 <figcaption>
   The first video shows a layout without defined image dimensions. Notice how the text jumps once the images load. In the second video, image dimensions have been provided; space is left for the image so that once they load, the text doesn't jump around.
 </figcaption>
</figure>

### Loading hints

Use the `loading` attribute to tell the browser whether to delay loading the image until it is in or near the viewport. For images below the fold, use a value of `lazy`. The browser won't load lazy images until the user has scrolled far down enough that the image is about to come into view. If the user never scrolls, the image never loads.

```html/5-5
<img
 src="image.png"
 alt="A description of the image."
 width="300"
 height="200"
 loading="lazy"
>
```

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/jazsyaOjXfHS0g8yUijR.mp4", controls=true, loop=true %}

For a hero image above the fold, `loading` should not be used. If your site automatically applies the `loading="lazy"` attribute, you can often set the `eager` attribute (which is the default) to prevent this from being applied:

```html/5-5
<img
 src="hero.jpg"
 alt="A description of the image."
 width="1200"
 height="800"
 loading="eager"
>
```

### Fetch Priority

For important images-such as the [LCP](/lcp/) image, you can further prioritize the loading using [Fetch Priority](/fetch-priority/) by setting the `fetchpriority` attribute to `high`:

```html/5-6
<img
 src="hero.jpg"
 alt="A description of the image."
 width="1200"
 height="800"
 loading="eager"
 fetchpriority="high"
>
```

This will tell the browser to fetch the image right away, and at high priority, rather than waiting until the browser has completed layout when images are normally fetched.

But remember: when you ask the browser to prioritize downloading one resource—like an image—the browser will have to de-prioritize another resource such as a script or a font file. Only set `fetchpriority="high"` on an image if it is truly vital.

### Preloading hints

Some images may not be available in the initial HTML—if they are added by JavaScript, or as a [background image](#background-images) in CSS. You can also use preload to allow these important images to be fetched ahead of time. This can be combined with the `fetchpriority` attribute for really important images:

```html
<link rel="preload" href="hero.jpg" as="image" fetchpriority="high">
```

Again this should be used sparingly to avoid overriding the browsers prioritisation heuristics too much, which may result in performance degredation.

Preloading responsive images based on srcset (which is discussed below) via the `imagesrcset` and `imagesizes` attributes is more advanced and is [supported in some browsers](/preload-responsive-images/), but not all:

<link rel="preload" imagesrcset="hero_sm.jpg 1x hero_med.jpg 2x hero_lg.jpg 3x" as="image" fetchpriority="high">

By excluding the `href` fallback you can ensure browsers that do not support this do not preload the incorrect image.

Preloading based on different image formats based on browser support of those images is not currently supported and may result in extra downloads.

The ideal is to avoid preload where possible, and have the image available in the initial HTML, to avoid repeating code, and to allow access to the full range of options the browser supports.

### Image decoding

There's also a `decoding` attribute you can add to `img` elements. You can tell the browser that the image can be decoded asynchronously. The browser can then prioritize processing other content.

```html/6-6
<img
 src="image.png"
 alt="A description of the image."
 width="300"
 height="200"
 loading="lazy"
 decoding="async"
>
```

You can use the `sync` value if the image itself is the most important piece of content to prioritize.

```html/6-6
<img
 src="hero.jpg"
 alt="A description of the image."
 width="1200"
 height="800"
 loading="eager"
 decoding="sync"
>
```

The `decoding` attribute will not change how fast the image decodes, but merely whether the browser waits for this image decoding to happen before rendering other content.

In most cases this will have little impact, however in certain scenarios it can allow the image or content to be displayed slightly faster. For example, for a large document with lots of elements that take time to render, and with large images that take a while to decode, setting `sync` on important images will tell the browser to wait for the image and render both at once. Alternatively, setting `async` can allow the content to be displayed faster without waiting for the image decode.

However, the better option is usually to try to [avoid excessive DOM sizes](https://developer.chrome.com/docs/lighthouse/performance/dom-size/) and ensure responsive images are used to reduce decoding time meaning the decoding attribute will have little effect.

## Responsive images with `srcset`

Thanks to that `max-inline-size: 100%` declaration, your images will never break out of their containers. But even if it looks fine to have a large image that shrinks to fit, it won't feel fine. If someone uses a small screen device on a low bandwidth network, they'll download unnecessarily large images.

If you make multiple versions of the same image at different sizes, you can let the browser know about them using the [`srcset`](https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-srcset) attribute.

### Width descriptor

You can pass in a list of values separated by commas. Each value should be the URL of an image followed by a space followed by some metadata about the image. This metadata is called a descriptor.

In this example, the metadata describes the width of each image using the `w` unit. One `w` is one pixel.

```html/7-9
<img
 src="small-image.png"
 alt="A description of the image."
 width="300"
 height="200"
 loading="lazy"
 decoding="async"
 srcset="small-image.png 300w,
  medium-image.png 600w,
  large-image.png 1200w"
>
```

The `srcset` attribute doesn't replace the `src` attribute. Instead the `srcset` attribute complements the `src` attribute. You still need to have a valid `src` attribute, but now the browser can replace its value with one of the options listed in the `srcset` attribute.

The browser won't download the larger images unless they're needed. That saves bandwidth.

### Sizes

If you're using the width descriptor, you must also use the [`sizes`](https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-sizes) attribute to give the browser more information. This tells the browser what size you expect the image to be displayed under different conditions. Those conditions are specified in a media query.

The `sizes` attribute takes a comma-separated list of media queries and image widths.

{% Aside %}
It feels strange to have CSS media queries inside an HTML element. It spoils the separation of presentation and structure. But it's the only way to provide the necessary sizing information in time to be effective.
{% endAside %}

```html/10-12
<img
 src="small-image.png"
 alt="A description of the image."
 width="300"
 height="200"
 loading="lazy"
 decoding="async"
 srcset="small-image.png 300w,
  medium-image.png 600w,
  large-image.png 1200w"
 sizes="(min-width: 66em) 33vw,
  (min-width: 44em) 50vw,
  100vw"
>
```
In this example, you're telling the browser that above a viewport width of `66em` to display the image no wider than one third of the screen (inside a three column layout, for example).

For viewport widths between `44em` and `66em`, display the image at half the width of the screen (a two column layout).

For anything below `44em` display the image at the full width of the screen.

This means that the biggest image won't necessarily be used for the widest screen. A wide browser window that can display a multi-column layout will use an image that fits in one column. That image might be smaller than an image used for a single-column layout on a narrower screen.

{% Codepen {
 user: 'web-dot-dev',
 id: 'XWerLJm',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/MkUAq5XQyjlUXLvkT4jL.mp4", controls=true, loop=true %}

### Pixel density descriptor

There's another situation where you might want to provide multiple versions of the same image.

Some devices have high-density displays. On a double-density display you can pack two pixels worth of information into the space of one pixel. This keeps images looking sharp on those kinds of displays.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/OtyGs9nZser6u0DrFYBq.png", alt="Two versions of the same image of a happy-looking handsome dog with a ball in its mouth, one image looking crisp and the other looking fuzzy.", width="800", height="275" %}


Use the density descriptor to describe the pixel density of the image in relationship to the image in the `src` attribute. The density descriptor is a number followed by the letter x: `1x`, `2x`, etc.

```html/7-9
<img
 src="small-image.png"
 alt="A description of the image."
 width="300"
 height="200"
 loading="lazy"
 decoding="async"
 srcset="small-image.png 1x,
  medium-image.png 2x,
  large-image.png 3x"
>
```

If `small-image.png` is 300 by 200 pixels in size, and `medium-image.png` is 600 by 400 pixels in size, then `medium-image.png` can have `2x` after it in the `srcset` list.

You don't have to use whole numbers. If another version of the image is 450 by 300 pixels in size, you can describe it with `1.5x`.

{% Aside %}
You can use *either* width descriptors *or* density descriptors, but not both together.
{% endAside %}

## Presentational images

Images in HTML are content. That's why you always provide an `alt` attribute with a description of the image for screen readers and search engines.

If you embed an image that is purely a visual flourish without any meaningful content, use an empty `alt` attribute.

```html/2-2
<img
 src="flourish.png"
 alt=""
 width="400"
 height="50"
>
```
You must still include the `alt` attribute. A missing `alt` attribute is not the same as an empty `alt` attribute. An empty `alt` attribute conveys to a screen reader that this image is presentational.

Ideally, your presentational or decorative images shouldn't be in your HTML at all. HTML is for structure. CSS is for presentation.

## Background images

Use the `background-image` property in CSS to load presentational images.

```css
element {
  background-image: url(flourish.png);
}
```

You can specify multiple image candidates using the [`image-set`](https://developer.mozilla.org/docs/Web/CSS/image/image-set()) function for `background-image`.

The `image-set` function in CSS works a lot like the `srcset` attribute in HTML. Provide a list of images with a pixel density descriptor for each one.

```css
element {
  background-image: image-set(
    small-image.png 1x,
    medium-image.png 2x,
    large-image.png 3x
  );
}
```
The browser will choose the most appropriate image for the device's pixel density.

There are many factors to consider when you're adding images to your site:

Reserving the right space for each image.
Figuring out how many sizes you need.
Deciding whether the image is content or decorative.

It's worth spending the time to get images right. Poor image strategies are responsible for frustration and annoyance for users. A good image strategy makes your site feel snappy and sharp, regardless of the user's device or network connection.

There's one more HTML element in your toolkit to help you exercise more control over your images: [the `picture` element](/learn/design/picture-element/).

{% Assessment 'images' %}

# Screen configurations

Responsive web design was in many ways a reaction to mobile phones. Before smartphones appeared, very few people seriously considered how websites should look and feel on handheld devices. That changed with the meteoric rise of mobile phones featuring built-in web browsers.

Responsive web design encouraged a mindset that questioned assumptions. Whereas previously it was common to assume that a website would only be viewed on a desktop computer, now it's standard practice to design that same website for phones and tablets as well. In fact, [mobile usage has now eclipsed desktop usage](https://www.statista.com/statistics/277125/share-of-website-traffic-coming-from-mobile-devices/) on the web. 

This responsive mindset will serve you well for the future. It's entirely possible that your websites will be viewed on devices and screens that we can't even imagine today. And this mindset extends beyond screens. Even now people are using devices with no screens to access your content. Voice assistants can use your websites if you are using a strong foundation of semantic HTML.

There's experimentation in the world of screens too. There are devices on the market today with foldable screens. That introduces some challenges for your designs.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/f4vIlX35hgoM8l0cWE9a.jpg", alt="A montage of foldable phones in different configurations.", width="800", height="449" %}

## Dual screens

Users of foldable devices can choose whether they want their web browser to occupy just one of the screens or span across both screens. If the browser spans both screens, then the website on display will be broken up by the hinge between the two screens. It doesn't look great.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/gRdTgrPMARsnUl1iLmie.png", alt="A website spanning across two screens. The horizontal flow of text is interrupted by the hinge between the screens.", width="800", height="545" %}

## Viewport segments

There's an experimental media feature designed to detect if your website is being displayed on a dual-screen device. The proposed name of the media feature is `viewport-segments`. There are two varieties: `horizontal-viewport-segments` and `vertical-viewport-segments`.

{% Aside 'caution' %}
The `viewport-segments` feature is an experimental proposal and the syntax may change. The syntax has already changed from its initial proposal of a `spanning` media feature.
{% endAside %}

If the `horizontal-viewport-segments` media feature reports a value of `2` and `vertical-viewport-segments` reports a value of `1` that means the hinge on the device runs from top to bottom, splitting your content into two side-by-side panels.

```css
@media (horizontal-viewport-segments: 2) and (vertical-viewport-segments: 1) {
  // Styles for side-by-side screens.
}
```

If the `vertical-viewport-segments` media feature reports a value of `2` and `horizontal-viewport-segments` reports a value of `1` then the hinge runs from side to side, dividing your content into two panels, one on top of the other.

```css
@media (vertical-viewport-segments: 2) and (horizontal-viewport-segments: 1) {
  // Styles for stacked screens.
}
```

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/TAs3gDDzcdq6Gsys3fXQ.svg", alt="Diagram demonstrating viewport segments.", width="800", height="488" %}
<figcaption>
   Diagram from <a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Foldables/explainer.md">Microsoft Edge Explainers</a>.
 </figcaption>
</figure>

If both `vertical-viewport-segments` and `horizontal-viewport-segments` report a value of `1` this means the website is being displayed on just one screen, even if the device has more than one screen. This is equivalent to not using any media query.

## Environment variables

The `viewport-segments` media feature by itself won't help you design around that annoying hinge. You need a way of knowing the size of the hinge. That's where [environment](https://developer.mozilla.org/docs/Web/CSS/env()) variables can help.

Environment variables in CSS allow you to factor awkward device intrusions into your styles. For example, you can design around the "notch" on the iPhone X using the environment values `safe-area-inset-top`, `safe-area-inset-right`, `safe-area-inset-bottom` and `safe-area-inset-left`. These keywords are wrapped in an `env()` function.

```css
body {
  padding-top: env(safe-area-inset-top);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
}
```

Environment variables work like custom properties. This means you can pass in a fallback option in case the environment variable doesn't exist.

```css
body {
  padding-top: env(safe-area-inset-top, 1em);
  padding-right: env(safe-area-inset-right, 1em);
  padding-bottom: env(safe-area-inset-bottom, 1em);
  padding-left: env(safe-area-inset-left, 1em);
}
```

For those environment variables to work on the iPhone X, update the `meta` element that specifies `viewport` information:

```html
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
```

Now your page layout will take up the entire viewport and safely pad the document with device-provided inset values.

For foldable screens, six new environment variables are being proposed: `viewport-segment-width`, `viewport-segment-height`, `viewport-segment-top`, `viewport-segment-left`, `viewport-segment-bottom`, `viewport-segment-right`.

{% Aside 'caution' %}
Remember, this is just at the proposal stage right now. The specific syntax for the environment variables may well change.
{% endAside %}

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/Ok2IFh9xJWHSGedPx9Xe.svg", alt="Diagram showing environment variables for dual screens.", width="800", height="420" %}
<figcaption>
   Diagram from <a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Foldables/explainer.md">Microsoft Edge Explainers</a>.
 </figcaption>
</figure>

{% Aside %}
It might seem a little strange to see names proposed with `left`, `right`, `top`, and `bottom`. If you're using logical properties you would expect terms like `inline-start`, `inline-end`, `block-start`, and `block-end`. In this instance though, the names refer to the hardware's physical properties, regardless of the writing mode used by the website being displayed.
{% endAside %}

Here's an example of a layout with two columns, one wider than the other.

```css
@media (min-width: 45em) {
  main {
    display: flex;
    flex-direction: row;
  }
  main article {
    flex: 2;
  }
  main aside {
    flex: 1;
  }
}
```

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/VYjqUCss2sJ6MT8b7BHe.png", alt="The layout is split across two screens with the hinge interrupting the wider column.", width="800", height="545" %}


For dual screens with a vertical hinge, set the first column to be the width of the first screen and the second column to be the width of the second screen.

```css
@media (horizontal-viewport-segments: 2) and (vertical-viewport-segments: 1) {
  main article {
    flex: 1 1 env(viewport-segment-width 0 0);
  }
  main aside {
    flex: 1;
  }
}
```

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/BUXrXQRSkvXz7TTzWFLx.png", alt="The layout is split evenly across two screens with no visible interruption.", width="800", height="545" %}


Treat dual screens as an opportunity. Perhaps one screen could be used to display scrollable text content while the other displays a fixed element like an image or a map.

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/F08tJySy3ZeePoCzzw1Z.svg", alt="Diagram illustrating a location service split over two screens, with the map on one screen and directions on the other.", width="800", height="426" %}
<figcaption>
   Diagram from <a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Foldables/explainer.md">Microsoft Edge Explainers</a>.
 </figcaption>
</figure>

## The future

Will foldable displays become the next big thing? Who knows. No one could've predicted how popular mobile devices would become so it's worth having an open mind about future form factors.

Above all, it's worth ensuring that your websites can respond to whatever the future may bring. That's what responsive design gives you: not just a set of practical techniques, but a mindset that will serve you well as you build the web of tomorrow.

{% Assessment 'screen-configurations' %}

# Theming

Even branding can be responsive. 
You can adjust the presentation of your website to match the user's preference. 
But first, here's how to extend your website's branding to include the browser itself.  

## Customize the browser interface

Some browsers allow you to suggest a theme color based on your website's palette. 
The browser's interface adapts to your suggested color. Add the color in a `meta` element named `theme-color` in the `head` of your pages.

```html
<meta name="theme-color" content="#00D494">
```

{% Aside %}
It feels a little strange to put styling information like this in HTML rather than CSS, 
but this allows the browser to update its interface as soon as the page is loading rather than waiting for the CSS. 
{% endAside %}

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/bM78eiZbOqwZ5doqKyaQ.png", alt="Clearleft dot com.", width="800", height="520" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/kN9Un2PoYIKdVzH9I2Ac.png", alt="Resilient Web Design dot com.", width="800", height="520" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/b8AUE0DLJX5uLhJH9kaE.png", alt="The Session dot org.", width="800", height="520" %}
 <figcaption>
   Three websites are viewed in the Safari browser. Each one has its own theme color that extends into the browser interface. 
 </figcaption>
</figure>

You can update the value of `theme-color` using JavaScript. But use this power wisely. 
It can be overwhelming for users if their browser's color scheme changes too often. 
Think about subtle ways to adjust the theme color. If the changes are too jarring, users will leave in annoyance.

You can also specify a theme color in a [web app manifest](https://developer.mozilla.org/docs/Web/Manifest) file. 
This is a JSON file with metadata about your website.

Link to the manifest file from the `head` of your documents. Use a `link` element with a `rel` value of `manifest`.

```html
<link rel="manifest" href="/manifest.json">
```

In the manifest file, list your metadata using key/value pairs.

```json
{
  "short_name": "Clearleft",
  "name": "Clearleft design agency",
  "start_url": "/",
  "background_color": "#00D494",
  "theme_color": "#00D494",
  "display": "standalone"
}
```

If a visitor decides to add your website to their home screen, 
the browser will use the information in your manifest file to display an appropriate shortcut.

{% Aside %}
Find out more about how to [add a web app manifest](/add-manifest/).
{% endAside %}

## Provide a dark mode

Many operating systems allow users to specify a preference for a light or a dark color palette, 
which is a good idea to optimize your site to your user's theme preferences. 
You can access this preference in a media feature called `prefers-color-scheme`.

```css
@media (prefers-color-scheme: dark) {
  // Styles for a dark theme.
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'wvrwLgN',
 height: 400,
 theme: 'dark',
 tab: 'css, result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/hpMyDvtHUyLPz0ltO6SS.mp4", controls=true, loop=true %}

Specify theme colors with the `prefers-color-scheme` media feature within the `meta` element.

```html
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)">
```

You can also use the `prefers-color-scheme` media feature inside SVG. 
If you use an SVG file for your favicon, it can be adjusted for dark mode. 
[Thomas Steiner](/authors/thomassteiner/) wrote about 
[`prefers-color-scheme` in SVG favicons for dark mode icons](https://blog.tomayac.com/2019/09/21/prefers-color-scheme-in-svg-favicons-for-dark-mode-icons/).

## Theming with custom properties

If you use the same color values in multiple places throughout your CSS, it could be quite tedious to repeat all your selectors within a `prefers-color-scheme` media query.

```css
body {
  background-color: white;
  color: black;
}
input {
  background-color: white;
  color: black;
  border-color: black;
}
button {
  background-color: black;
  color: white;
}
@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
  input {
    background-color: black;
    color: white;
    border-color: white;
  }
  button {
    background-color: white;
    color: black;
  }
}
```

Use CSS custom properties to store your color values. 
Custom properties work like variables in a programming language. You can update the value of a variable without updating its name.

If you update the values of your custom properties within a `prefers-color-scheme` media query, 
you won't have to write all your selectors twice.

```css
html {
  --page-color: white;
  --ink-color: black;
}
@media (prefers-color-scheme: dark) {
  html {
    --page-color: black;
    --ink-color: white;
  }
}
body {
  background-color: var(--page-color);
  color: var(--ink-color);
}
input {
  background-color: var(--page-color);
  color: var(--ink-color);
  border-color: var(--ink-color);
}
button {
  background-color: var(--ink-color);
  color: var(--page-color);
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'qBPWzrj',
 height: 440,
 theme: 'dark',
 tab: 'css,result'
} %}

See [building a color scheme](/building-a-color-scheme/) for more advanced examples of theming with custom properties.

## Images

If you are using SVGs in your HTML, you can apply custom properties there too.

```css
svg {
  stroke: var(--ink-color);
  fill: var(--page-color);
}
```

Now your icons will change their colors along with the other elements on your page.

If you want to tone down the brightness of your photographic images when displayed in dark mode, you can apply a filter in CSS.

```css
@media (prefers-color-scheme: dark) {
  img {
    filter: brightness(.8) contrast(1.2);
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'PoJYrpy',
 height: 600,
 theme: 'dark',
 tab: 'result'
} %}

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/j4Hkz0lwHv1HOr3Qd6Wc.png", alt="Three photographs at normal brightness.", width="800", height="210" %}
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/ChcCHA1JLRX4F2IaLOXR.png", alt="Three photographs with slightly less brightness.", width="800", height="210" %}
 <figcaption>
   The effect is subtle, but you can tone down the brightness of images in dark mode. 
 </figcaption>
</figure>

For some images, you might want to swap them out completely in dark mode. 
For example, you might want to show a map with a darker color scheme. 
Use the `<picture>` element containing a `<source>` element with the `prefers-color-scheme` media query.

```html
<picture>
  <source srcset="darkimage.png" media="(prefers-color-scheme: dark)">
  <img src="lightimage.png" alt="A description of the image.">
</picture>
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'MWEgMmw',
 height: 600,
 theme: 'dark',
 tab: 'html,result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/8Sz0XmotUrwnbprrHtoZ.mp4", controls=true, loop=true %}

<figure>
{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/aX6PmKj8pQudiWgt4x31.png", alt="Two maps of Broolyn, one using light colors and the other using dark colors.", width="782", height="398" %}
 <figcaption>
   Two versions of the same map, one for light mode and one for dark mode. 
 </figcaption>
</figure>


## Forms

Browsers provide a default color palette for form fields. 
Let the browser know that your site offers both a dark and a light mode. 
That way, the browser can provide the appropriate default styling for forms.

Add this to your CSS:

```css
html {
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}
```

You can also use HTML. Add this in the `head` of your documents:

```html
<meta name="supported-color-schemes" content="light dark">
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'dyVbBWZ',
 height: 400,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/6YuAM0ZCNhGNAjpI8fyT.mp4", controls=true, loop=true %}

Use the [`accent-color`](/accent-color/) property in CSS to style checkboxes, radio buttons, and some other form fields.

```css
html {
  accent-color: red;
}
```

It's common for dark themes to have subdued brand colors. You can update the `accent-color` value for dark mode.

```css
html {
  accent-color: red;
}
@media (prefers-color-scheme: dark) {
  html {
    accent-color: pink;
  }
}
```

It makes sense to use a custom property for this so you can keep all your color declarations in one place.

```css
html {
  color-scheme: light;
  --page-color: white;
  --ink-color: black;
  --highlight-color: red;
}
@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
    --page-color: black;
    --ink-color: white;
    --highlight-color: pink;
  }
}
html {
  accent-color: var(--highlight-color);
}
body {
  background-color: var(--page-color);
  color: var(--ink-color);
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'WNZeqjB',
 height: 400,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/Dl00EnG4mwTbSQIkYBF9.mp4", controls=true, loop=true %}

{% Aside %}
For more on tinting elements with theme colors, see the section on [more tinting](/accent-color/#extra-more-tinting).
{% endAside %}

Providing a dark mode is just one example of adapting your site to suit your user's preferences. 
Next you'll learn how to make your site adaptable to all sorts of [accessibility](/learn/design/accessibility/) considerations.

{% Assessment 'theming' %}

# Typography

If you don't specify any styles for your text, browsers will apply their own default styles. These are called _User Agent stylesheets_, and may vary from browser to browser. Users can set their own preferences for displaying text too.

If you don't specify a line length, browsers will wrap lines of text at the edge of the screen. So text on the web is responsive by default—it flows to fit the user's viewport.

But just because text fits on a screen doesn't mean it's comfortable to read. Good typography is all about presenting your text in an appropriate way. There's more to typography than choosing suitable fonts to use. You need to consider the user's preferences, the size of the text, line length, and the distance between the lines of text.

{% Aside %}
You may even need to consider the primary language of your user, as you may need to leave room for accents and other special characters. Learn more about this in the [internationalization](/learn/design/internationalization) module.
{% endAside %}

## Text size

It's difficult to know what size text on the web should be.

If someone is using a small screen, it might be a safe bet that their screen will be fairly close to their eyes—a hand's length away.

But as screens get larger and larger, it's harder to make that connection. A laptop-size screen will probably be fairly near to the viewer, but a widescreen desktop monitor is around the same size as a television screen. People sit an arm's length away from a desktop screen but they sit much further away from a television.

Still, while you can't know for certain how far away someone is from a screen, you can try to use text sizes that will hopefully turn out to be appropriate. Use smaller text sizes for smaller screens and larger text sizes for larger screens.

You can use media queries to change the `font-size` property as the screen size gets wider.

```css
@media (min-width: 30em) {
  html {
    font-size: 125%;
  }
}

@media (min-width: 40em) {
  html {
    font-size: 150%;
  }
}

@media (min-width: 50em) {
  html {
    font-size: 175%;
  }
}

@media (min-width: 60em) {
  html {
    font-size: 200%;
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'WNZeBWY',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/cH8IU9hV7FGCgN0roNiU.mp4", controls=true, loop=true %}

## Scaling text

Switching between fixed text sizes at specific breakpoints is quite jumpy. A more responsive approach is to let the user's device width influence the text size.

The `vw` unit in CSS stands for “viewport width.” Connecting font sizes to the 
 viewport's width means that the text will grow and shrink in proportion to the browser width. This makes it difficult to predict what the text size will be at any specific width, but you know that the text size will be appropriate for the user's browser width.

It's important that you don't use the `vw` by itself in a font-size declaration.

{% Compare 'worse' %}

```css
html {
  font-size: 2.5vw;
}
```

{% endCompare %}

If you do, the user won't be able to resize the text. The text will be resizable if you mix in a relative unit—like `em`, `rem` or `ch`. The CSS [`calc()`](https://developer.mozilla.org/docs/Web/CSS/calc()) function is perfect for this.

{% Compare 'better' %}

```css
html {
  font-size: calc(0.75rem + 1.5vw);
}
```

{% endCompare %}

Let the browser do the math. This makes it difficult to predict exactly what the text size will be at any specific width, but you know that the text size will be in the right range. The user's browser takes care of figuring out the exact text size calculations.

{% Codepen {
 user: 'web-dot-dev',
 id: 'zYEOQQG',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/x5h7TqkGHJIPa61wPvAs.mp4", controls=true, loop=true %}

But now there's a possibility that the text will get *too* small on narrow screens and *too* big on wide screens.

## Clamping text

You probably don't want your text to shrink and grow to extremes. You can control where the scaling starts and ends using the CSS [`clamp()`](https://developer.mozilla.org/docs/Web/CSS/clamp()) function. This “clamps” the scaling to a specific range.

The `clamp()` function is  like the `calc()` function but it takes three values. The middle value is the same as what you pass to `calc()`. The opening value specifies the minimum size, in this case 1rem so as to not go below the user's preferred font size. The closing value specifies the maximum size.

```css
html {
  font-size: clamp(1rem, 0.75rem + 1.5vw, 2rem);
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'wvrwbbx',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

Now the text size shrinks and grows in proportion to the user's screen but the text size will never go below `1rem` or above `2rem`.

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/vVwP2L0z90zXL28iPYL4.mp4", controls=true, loop=true %}

## Line length

The web is not print, but we can learn lessons from the world of print and apply them on the web.

In his classic book [*The Elements of Typographic Style*](http://webtypography.net/2.1.2), Robert Bringhurst had this to say on line length (or measure):

> Anything from 45 to 75 characters is widely regarded as a satisfactory line length for a single-column page set in a serifed text face in a text size. The 66-character line (counting both letters and spaces) is widely regarded as ideal. For multiple column work, a better average is 40 to 50 characters.

You can't set a line length directly in CSS. There is no `line-length` property. But you can stop text from getting too wide by limiting how wide the container can be. The [`max-inline-size`](https://developer.mozilla.org/docs/Web/CSS/max-inline-size) property is perfect for this.

Don't set your line-lengths with a fixed unit like `px`. Users can scale their font size up and down and your line lengths should adjust accordingly. Use a [relative unit](/learn/css/sizing/#relative-lengths) like `rem` or `ch`.

{% Compare 'worse' %}

```css
article {
  max-inline-size: 700px;
}
```

{% endCompare %}

{% Compare 'better' %}

```css
article {
  max-inline-size: 66ch;
}
```

{% endCompare %}

Using `ch` units for width will cause new lines to wrap at the 66th character at that font size.

{% Codepen {
 user: 'web-dot-dev',
 id: 'MWEgddN',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/9Nxi6HuU28aQhxtzXq7l.mp4", controls=true, loop=true %}

## Line height

Although there is no `line-length` property in CSS, there is a [`line-height`](https://developer.mozilla.org/docs/Web/CSS/line-height) property.

Shorter lines of text can have larger `line-height` values. But if you use large `line-height` values for long lines of text, it's hard for the reader's eye to move from the end of one line to the start of the next line.

```css
article {
  max-inline-size: 66ch;
  line-height: 1.65;
}
blockquote {
  max-inline-size: 45ch;
  line-height: 2;
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'oNGvRrZ',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/di6psFbT6JhlwjtMm68j.mp4", controls=true, loop=true %}

Use unitless values for your `line-height` declarations. This ensures that the line height is relative to the `font-size`.

{% Compare 'worse' %}

```css
line-height: 24px;
```

{% endCompare %}

{% Compare 'better' %}

```css
line-height: 1.5;
```

{% endCompare %}

## Combinations and scale

Remember to prioritize hierarchy as you build your user interfaces for better clarity and page flow. A great way to do this is with [a typography scale built into your design system](https://material.io/design/typography/the-type-system.html#type-scale).

## Web fonts

A typeface is like a voice for your words. For the longest time on the web there were very few font options. System fonts were the only options. But now you can choose a web font that matches the feel of your content.

Use `@font-face` to tell browsers where to find your web font files. Use woff2 as your web font format. It's well supported and has the best performance gains.

```css
@font-face {
  font-family: Roboto;
  src: url('/fonts/roboto-regular.woff2') format('woff2');
}
body {
  font-family: Roboto, sans-serif;
}
```

But every web font file you add could potentially degrade the user experience as it increases page load time. Remember, design isn't just about how the final pixels look. How fast those pixels get painted is a critical part of the user experience. An experience that feels fast is a good user experience.

## Font loading

You can request that browsers start downloading a font file as soon as possible. Add a `link` element to the `head` of your document that references your web font file. A `rel` attribute with a value of `preload` tells the browser to prioritize that file. An `as` attribute with a value of `font` tells the browser what kind of file this is. The `type` attribute allows you to be even more specific.

```html
<link href="/fonts/roboto-regular.woff2" type="font/woff2" 
  rel="preload" as="font" crossorigin>
```

You need to include the `crossorigin` attribute even if you are hosting the font files yourself.

Use the CSS [`font-display`](https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display) property to tell the browser how to manage the switchover from a system font to a web font. You could choose to show no text at all until the web font is loaded. You could choose to display the system font immediately and then switch over to the web font once it loads. Both strategies have their downsides. If you wait until the web font is downloaded before showing any text, users may find themselves staring at a blank page for a frustratingly long time. If you show the text in a system font first and then switch over to the web font, users may experience a jarring shifting of content on the page.

{% Aside %}
You can mitigate the jarring effect of text shifting around by using [`size-adjust`](/css-size-adjust/) in your `@font-face` rule.
{% endAside %}

A good compromise is to wait for a short while before displaying any text. If the web font loads before that time is up, the text is displayed using the web font with no content shifts. If the web font still hasn't loaded after the time is up, the text is displayed using the system font so at least the user can read the content.

Use a `font-display` value of `swap` if you still want the web font to replace the system font whenever the web font finally loads.

```css
body {
  font-family: Roboto, sans-serif;
  font-display: swap;
}
```

Use a `font-display` value of `fallback` if you want to stick with the system font once text has been rendered.

```css
body {
  font-family: Roboto, sans-serif;
  font-display: fallback;
}
```

## Variable fonts

If you are using lots of different weights or styles of the same typeface, you may end up using lots of separate font files—a separate font file for each weight or style.

[Variable fonts](/variable-fonts/) solve this problem by using one file. Instead of having separate files for regular, bold, extra bold, and so on, a variable font file is responsive. It contains all the information it needs to be displayed across a spectrum of weights or styles.

{% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Ecr5godvTKunVXP7W8aU.png", alt="The letter 'A' shown in different weights.", width="800", height="218" %}


This means that a single variable font file is larger than a single regular font file, but a single variable font file will probably be smaller than multiple regular font files. If you're using lots of different weights, a variable font could give you a big performance gain.

{% Aside %}
If you're styling elements using the `system-ui` value for `font-face` property, you might get all the benefits of variable fonts without downloading any font files. [More and more system fonts are now variable fonts](/more-variable-font-options-in-chromium-83/).
{% endAside %}
 
Good typography on the web isn't just about the type choices that you make as a designer. Responsive typography is also about respecting the user's device and network connection. The end result is a design that feels right no matter how it's being viewed.

Now that you've mastered responsive text, it's time to dive into [responsive images](/learn/design/responsive-images).

{% Assessment 'typography' %}

# User interface patterns

A design viewed on a small screen shouldn't look like a shrunk-down version of a large-screen layout. Likewise, a design viewed on a large screen shouldn't look like a blown-up version of a small-screen layout. Instead, the design needs to be flexible enough to adapt to all screen sizes. A successful responsive design makes the most of every form factor.

This means that some interface elements may need to look quite different depending on the context they're viewed in. You might need to apply very different CSS to the same HTML codebase to make the most of different screen sizes. That can be quite a design challenge!

Here are some common challenges that you might face.

## Navigation

Displaying a list of navigation links is quite straightforward on a large screen. There's plenty of space to accommodate those links.

On a small screen, space is at a premium. When you're designing for this situation, it's tempting to hide navigation behind a button. The problem with this solution is that users have to then take two steps to get anywhere: open the menu, then choose an option. Until the menu is opened, the user is left wondering "where can I go?”

Try to find a strategy that avoids hiding your navigation. If you have a relatively small number of items, you can style the navigation to look good on small screens.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/s1fif52p8RcE758OkSvB.png", alt="The same website with five navigation links viewed in a mobile browser and viewed in a tablet browser. The navigation is visible on both devices.", width="800", height="409" %}

That pattern won't scale if your navigation has lots of links. The navigation will look cluttered if the links wrap onto two or three lines on a small screen.

One possible solution is to keep links on one line but truncate the list at the edge of the screen. Users can swipe horizontally to reveal the links that aren't immediately visible. This is the overflow pattern.

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/jNM3gZrkksJc6banrxcE.mp4", controls=true %}

The advantage of this technique is that it scales to any device width and any number of links. The disadvantage is that users might miss links that aren't initially visible. If you use this technique for your main navigation, make sure the first few links are the most important ones and visually indicate that there are more items in the list. The previous example uses a gradient for this indicator.

As a last resort you could choose to have your navigation hidden by default and provide a toggle mechanism for users to show and hide the contents. This is called progressive disclosure.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/DiGHrNu300JMj8i9X01U.png", alt="The same website with five navigation links viewed in a mobile browser and viewed in a tablet browser. The navigation is visible on the tablet, but hidden on the mobile device.", width="800", height="409" %}

Make sure the button that toggles the display of the navigation is labeled. Don't rely on an icon to be understood.

{% Img src="image/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/cyuj5HvE6x9c8OBiM527.png", alt="Three unlabelled icons: the first is three horizontal lines; the second is three by three grid; the third is three circles arranged vertically.", width="640", height="240" %}

An unlabelled icon is "mystery meat” navigation—users won't know what's in there until they bite into it. Provide a text label to let users know what the button will reveal.

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/jzRDWQyKNcV1JNBU6mYS.mp4", controls=true, loop=true %}

## Carousels

What's true of navigation is also true of other content: try not to hide anything anyway. A carousel is a common method of hiding content away. It can look quite neat, but there's a good chance that your users will never discover the hidden content. Carousels are better at solving organizational problems—like what content should feature on the homepage—than at serving users.

That said, when space is at a premium, carousels can prevent a page getting too long and cluttered. You could employ a hybrid approach: show content in a carousel for small screens, but display the same content in a grid for larger screens.

For narrow screens, display items in a row using flexbox. The row of items will extend beyond the edge of the screen. Use `overflow-x: auto` to allow horizontal swiping.

```css
@media (max-width: 50em) {
  .cards {
    display: flex;
    flex-direction: row;
    overflow-x: auto;
    scroll-snap-type: inline mandatory;
    scroll-behavior: smooth;
  }
  .cards .card {
    flex-shrink: 0;
    flex-basis: 15em;
    scroll-snap-align: start;
  }
}
```

{% Aside %}
The logical version of `overflow-x` is [`overflow-inline`](https://developer.mozilla.org/docs/Web/CSS/overflow-inline) which would better match with the value for `scroll-snap-type`. This example uses the physical version for better cross-browser support.
{% endAside %}

The [`scroll-snap`](/css-scroll-snap/) properties ensure that the items can be swiped in a way that feels smooth. Thanks to `scroll-snap-type: inline mandatory`, the items snap into place.

When the screen is large enough—wider than `50em` in this case—switch over to grid and display the items in rows and columns, without hiding anything.

```css
@media (min-width: 50em) {
  .cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));
  }
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'XWeNPzY',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Video src="video/KT4TDYaWOHYfN59zz6Rc0X4k4MH3/jw00jziSxqLm3JBYRk5o.mp4", controls=true %}

Crucially, an item in the carousel view doesn't take up the full width. If it did, there would be no indication that more content is available beyond the edge of the viewport.

Carousels are another example of the overflow pattern in action. If you have many items that people can browse through, you could keep using the overflow pattern even on large screens, including televisions. This [media scroller](https://gui-challenges.web.app/media-scroller/dist/) uses multiple carousels to manage a significant amount of options.

Again, the `scroll-snap` properties ensure that the interaction feels smooth. Also, notice that the images in the carousel have `loading="lazy"` applied to them. In this case, the images aren't below the fold, they're beyond the edge, but the same principle applies: if the user never swipes as far as that item, the image won't be downloaded, saving on bandwidth.

{% Codepen {
 user: 'argyleink',
 id: 'bGgyOGP',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

{% Aside %} 
The previous example shows a more complete demo, you can read more about it in the article [building a media scroller component](/building-a-media-scroller-component/).
{% endAside %}

With the addition of JavaScript, you can add interactive controls to a carousel. You could even make it automatically cycle through items. But think long and hard before doing that—autoplaying might work if the carousel is the only content on the page, but an autoplaying carousel is incredibly annoying if someone is trying to interact with other content (like reading text, for example). You can read more [carousel best practices](/carousel-best-practices/).

{% CodePattern '/web-vitals-patterns/carousels/carousel-autoplay/' %} 

## Data tables

The `table` element is perfect for structuring tabular data; rows and columns of related information. But if the table gets too large, it could break your small-screen layout.

You can apply the overflow pattern to tables. In this example, the table is wrapped in a `div` with a class of `table-container`.

```css
.table-container {
  max-inline-size: 100%;
  overflow-x: auto;
  scroll-snap-type: inline mandatory;
  scroll-behavior: smooth;
}
.table-container th, 
.table-container td {
  scroll-snap-align: start;
  padding: var(--metric-box-spacing);
}
```

{% Codepen {
 user: 'web-dot-dev',
 id: 'MWEbqQQ',
 height: 500,
 theme: 'dark',
 tab: 'result'
} %}

## Guidelines

The overflow pattern is a good compromise for small screens but make sure it's clear that the off-screen content is reachable. Consider placing a shadow or a gradient over the edge where content is truncated.

Progressive disclosure is a useful way to save space, but be careful about using it for very important content. It's better suited to secondary actions. Ensure the interface element that triggers the disclosure is clearly labeled—don't rely on iconography alone.

Design for smaller screens first. It's easier to adapt small-screen designs to larger screens than the other way around. If you design for a large screen first, there's a danger that your small-screen design will feel like an afterthought.

For more layout and UI element patterns, explore the web.dev [Patterns](/patterns) section.

When you're adapting interface elements to different screen sizes, media queries are very useful for figuring out the dimensions of the device. But media features like `min-width`and `min-height` are just the beginning. Next, you'll discover a whole host of other media features.

# Learn Forms

This course breaks down HTML forms into easy to understand pieces. 
Over the next few modules, you'll learn how an HTML form works and how to use them effectively in your projects. 
Use the menu pane by the **Learn Forms** logo to navigate the modules.

You'll learn how to build a basic HTML form, about HTML form elements, 
styling forms, help users re-entering data, 
ensuring the form is accessible, and secure, how to test your forms, and about specific form types. 

Each module is full of interactive demos and self-assessments for you to test your knowledge.

This course is suitable for beginners and advanced HTML developers. 
The first few modules help you get started with building HTML forms, 
the other modules give more detail. 
You can go through the series from start to finish to get a general understanding of HTML forms, 
or pick a specific module you want to learn more about. 

## Prerequisites

Before starting this course, you should know about HTML. 
For those new to web development, 
check out the [intro to HTML](https://developer.mozilla.org/docs/Learn/HTML/Introduction_to_HTML) 
course from MDN to learn all about how to write markup.

## Demos

For most demos, we use [CodePen](https://codepen.io/).

Looking at the demos, you might wonder where the styles come from. 
We use a general stylesheet included in all demos, so only the relevant styles are shown there. 
In CodePen, you can select included CSS files from Settings.

## Form controls and form fields

A **form control** is an element that enables user interaction and data entry or selection: 
an `<input>`, `<select>`, `<textarea>` or `<button>`.

Sometimes **form field** is used to refer to form controls, 
in particular elements for text entry: `<input>` and `<textarea>`.

## Here's what you'll learn

{% include 'partials/course-index.njk' %}

So, are you ready to learn about forms? [Let's get started](/learn/forms/form-element/).

{% Aside %}  
This course is written and edited by forms community experts: 
[Michael Scharnagl](https://twitter.com/justmarkup), 
[Sam Dutton](https://twitter.com/sw12), 
and [Rachel Andrew](https://twitter.com/rachelandrew). <a href="https://twitter.com/rob_dodson">Rob Dodson</a> and <a href="https://twitter.com/jiwoong">Jiwoong Lee</a> shepherded the UX and production build, along with help from <a href="https://twitter.com/devnook">Ewa Gasperowicz</a> and <a href="https://twitter.com/samthor">Sam Thorogood</a>. 
{% endAside %}

# Accessibility

The form you build is for people.
People use different devices.
Some use a mouse, some a touch device, some the keyboard,
some a device controlled by eye movements.
Some use a screen reader, some a small screen, some use text enlargement software.
Everybody wants to use your form. Learn how to make your form accessible and usable for everyone.

## Ensure users understand the purpose of a form field

There are many [form controls](/learn/forms/fields) you can choose from.
What do they all have in common?
Every form control must have an associated `<label>` element.
The `<label>` element describes the purpose of a form control.
The `<label>` text is visually associated with the form control, and read out by screen readers.

In addition, tapping or clicking the `<label>` focuses the associated form control,
making it a larger target.

{% Aside %}
The next time you add a form control, add the `<label>` first. Think about the purpose of the
  form control, and describe the purpose to the user. Make it easy for people to enter valid data
  quickly and accurately.
{% endAside %}

## Use meaningful HTML to access built-in browser features

In theory, you could build a form using only `<div>` elements.
You can even make it look like a native `<form>`.
What's the problem with using
[non-semantic](https://developer.mozilla.org/docs/Glossary/Semantics) elements?

Built-in form elements provide a lot of built-in features. Let's have a look at an example.

{% Codepen {
  user: 'web-dot-dev',
  id: '2f56a723b5045ea990d38c2c170c3037',
  height: 450,
  tab: 'html,result'
} %}

Visually, the `<input>` (the first one in the example) and the `<div>` look the same.
You can even insert text for both, as the `<div>` has a
[`contenteditable`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/contenteditable) attribute.
There are lots of differences, though, between using an appropriate `<input>` element and a `<div>`
  looking like an `<input>`.

A screen reader user doesn't recognize the `<div>` as an input element,
and isn't able to complete the form.
All the screen reader user hears is 'Name',
with no indication that the element is a form control for adding text.

Clicking on `<div>Name</div>` doesn't focus the `<div>` that goes with it, whereas the `<label>` and
  the `<input>` are connected by using the `for` and `id` attributes.

After submitting the form, the data entered in the `<div>` isn't included in the request.
While attaching the data with JavaScript is possible,
an `<input>` does that by default.

Built-in form elements have other features.
For example, with appropriate form elements and the correct `inputmode` or `type`,
an on-screen keyboard shows appropriate characters. Using the `inputmode` attribute on a `<div>`
  cannot do that.

## Ensure users are aware of the expected data format

You can define various validation rules for a form control.
For example, say a form field should always have at least eight characters.
You use the `minlength` attribute, indicating the validation rule to browsers.
How can you ensure users also know about the validation rule? Tell them.

{% Codepen {
  user: 'web-dot-dev',
  id: 'b03a4c83688c1b02ab12f9873f1f6614',
  height: 350,
  tab: 'html,result'
} %}

Add information about the expected format directly beneath the form control.
To make it clear for assistive devices,
use the `aria-describedby` attribute on the form control,
and an `id` on the error message with the same value, to connect both.

## Help users find the error message for a form control

In a previous module about [validation](/learn/forms/validation),
you learned how to show error messages in case of invalid data entry.

```html
<label for="name">Name</label>
<input type="text" name="name" id="name" required>
```

For example, if a field has a `required` attribute, and invalid data is entered, the browser shows
an error message next to the form control when the form is submitted. Screen readers also announce the error message.

You can also define your own error message:

{% Codepen {
  user: 'web-dot-dev',
  id: 'b7ed22a0539f9beef4dc03380f51f224',
  height: 300,
  tab: 'html,result'
} %}

This example needs more changes to connect the error message to the form control.

A simple approach is to use the `aria-describedby`
attribute on the form control that matches the `id` on the error message element.
Then, use [`aria-live="assertive"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/ARIA_Live_Regions) for the error message.
ARIA live regions announce an error to screen reader users the moment the error is shown.

The problem with this approach for forms with multiple fields,
is that `aria-live` will usually only announce the first error in the case of multiple errors.
As explained in [this article about multiple `aria-live` announcements on the same action](https://gaurav5430.medium.com/quick-accessibility-wins-multiple-aria-live-on-single-action-caveat-b79a6f41e7cc) you could create a single message by concatenating all the errors. Another approach would be to announce that there are errors, then announce individual errors when the field is focused.

## Ensure users recognize errors

Sometimes designers color the invalid state red,
using the `:invalid` pseudo-class.
However, to communicate an error or success,
you should never rely only on color.
For people with red-green color blindness,
a green and a red border look almost the same.
It's impossible to see if the message is related to an error.

In addition to color, use an icon, or prefix your error messages with the error type.

```html
<span class="error">
  <strong>Error:</strong>Please use at least eight characters.
</span>
```

## Help users to navigate your form

You can change the visual order of form controls with CSS.
A disconnect between visual order and keyboard navigation (DOM order)
is problematic for screen reader and keyboard users.

Learn more about how to ensure
[visual order on the page follows DOM order](/visual-order-follows-dom/).

## Help users to identify the currently focused form control

Use your keyboard to navigate through
[this form](https://codepen.io/web-dot-dev/pen/c4ab903b77cdfc05dac4707fca69b997).
Did you recognize that the styling of the form controls changed once they were active?
This is the default focus style.
You can override it with the
[`:focus`](https://developer.mozilla.org/docs/Web/CSS/:focus) CSS pseudo-class.
Whatever styles you use inside `:focus`,
always make sure the visual difference between the default state and the focus state is recognizable.

{% Aside %}
If you want to remove the default `:focus` styles but still show focus indicators for keyboard users,
you can use the [`:focus-visible`](/style-focus/#use-focus-visible-to-selectively-show-a-focus-indicator) CSS pseudo-class.
{% endAside %}

Learn more about
[designing focus indicators](https://www.sarasoueidan.com/blog/focus-indicators/).

## Ensure your form is usable

You can identify many common issues by filling out your form with different devices.
Use only your keyboard, use a screen reader (such as
[NVDA](https://www.nvaccess.org/) on Windows or
[VoiceOver](https://en.wikipedia.org/wiki/VoiceOver) on Mac),
or zoom the page to 200%.
Always test your forms on different platforms,
especially devices or settings you don't use every day.
Do you know someone using a screen reader,
or someone using text enlargement software? Ask them to fill out your form.
Accessibility reviews are great, testing with real users is even better.

Learn more about doing an
[accessibility review](/how-to-review/)
and how to [test with real users](/learn/forms/usability-testing).

## Resources

- [WebAIM: Creating Accessible Forms](https://webaim.org/techniques/forms)
- [WCAG: autocomplete accessibility benefits](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html)
- [Focus Indicators](https://www.sarasoueidan.com/blog/focus-indicators/)

# Address forms

Filling in an address can be time-consuming and frustrating. 
What is an **Address line 2**? 
You may not have a surname, so what should you enter in a **Surname** field? 
Avoid these confusions and help users fill out address forms.

{% Codepen {  
  user: 'web-dot-dev',  
  id: '6af9430bd0fc87b3850bb187409ce312',  
  height: 650  
} %}

## Ensure your address form is easy to use

Many forms use one field for first name and one for surname. 
However, some people don't have a surname, or their names don't have two parts, 
so how should they fill in the surname field? Use a single `<input>` for the name field. 
Learn more about [handling different name formats](/learn/forms/internationalization/#ensure-your-form-can-handle-different-name-formats).

{% Aside 'caution' %}  
Never restrict the allowed characters for names to 
[Latin-only](https://en.wikipedia.org/wiki/Latin_alphabet). 
Allow [Unicode characters](/payment-and-address-form-best-practices/#unicode-matching) 
for the name `<input>` to ensure everybody can fill in their name.  
{% endAside %}

Also use a single `<input>` for the street address–not every address has a street number.

{% Aside %}  
According to [research](https://baymard.com/blog/address-line-2), 
**Address line 2** can be confusing for users. 
Consider using a `<textarea>` for the whole address, 
or hide the **Address line 2** field behind a reveal `<button>`.  
{% endAside %}

Be careful with form control descriptions. 
For example, users in the US say **ZIP**, in the UK **postcode**. 
Use `<label for="zip">ZIP or postal code (optional)</label>` 
to make sure users know what data to enter. 
Make the postal code field optional–not every address has a postal code.

{% Aside %}  
You can use services like 
[Place Autocomplete](https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform) or 
[Loqate](https://www.loqate.com/en-us/) to help users look up addresses. 
Consider [avoiding postcode address lookup](/payment-and-address-form-best-practices/#postal-code-address-lookup), 
and only provide address lookup as an extra option: don't force people to use it.  
{% endAside %}

## Help users enter their address

The `autocomplete` attribute can help users re-enter their address: 
* `autocomplete="name"`
* `autocomplete="street-address"`
* `autocomplete="postal-code"`
* `autocomplete="country"`

{% Aside %}  
There are two possible `autocomplete` values for the country: 
* `country`: country or territory code
* `country-name`: country or territory name 

Use `autocomplete="country"` for `<select>` where the `value` for the `<option>` is the country code. 
Want to use an `<input>` for the country name? Use `autocomplete="country-name"`.  
{% endAside %}

You can define multiple values separated by a space for `autocomplete`. 
Say you have a form with a shipping address and another form for a billing address. 
To tell the browser which postal code is for the billing address, 
you can use `autocomplete="billing postal-code"`. 
For the shipping address, use `shipping` as the first value.

Change the label for the `Enter` key on on-screen keyboards with the `enterkeyhint` attribute. 
Use `enterkeyhint="done"` for the last form control, and `enterkeyhint="next"` for the other form controls.

## Resources

-  [Payment and address forms best practices](/payment-and-address-form-best-practices)
-  [Form Usability: Getting ‘Address Line 2' Right](https://baymard.com/blog/address-line-2)

# Form attributes in depth

HTML element attributes can enhance your `<form>` and form controls.

## Help users fill in form controls

To make it easier for users to fill out forms, 
use an appropriate `type` attribute for your `<input>` elements. 

Browsers display a user interface appropriate for the `type`, 
such as a date picker for an `<input>` of type `date`. 
Browsers on mobile devices show an adapted on-screen keyboard, 
such as a telephone number keypad for `type="tel"`.

Some `<input>` types also change validation rules for an element when its form is submitted. 
`<input type="url">`, for example, is only valid if it's not empty and the value is a URL.

## Ensure users enter data

There are different attributes for providing an appropriate on-screen keyboard on touch devices. 
The first option is to use the `type` attribute, as mentioned above. 

Another option is the `inputmode` attribute supported on 
[Android and iOS](https://caniuse.com/?search=inputmode). 
In contrast to the `type` attribute, the `inputmode` attribute only changes the on-screen keyboard 
provided, not the behavior of the element itself. Using `inputmode` is a good option if you want to 
keep the default user interface and the default validation rules of an `<input>`, but still want an 
optimized on-screen keyboard.

{% Aside 'caution' %}
Use `type="number"` only for incremental fields such as the quantity of a product. 
Browsers show an up/down arrow for `type="number"` which makes no sense for telephone numbers, 
payment card or account numbers. 
For telephone numbers, use `type="tel"`. For other numbers, use `inputmode="numeric"` to get a numeric on-screen keyboard.
{% endAside %}

{% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bi7J9Z1TLP4IsQLyhbQm.jpg",
alt="Two screenshots of Android phones, showing a keyboard appropriate for entering an email addresses (using type=email) and for entering a telephone number (with type=tel).", width="800", height="696" %}

You can change the `Enter` key on on-screen keyboards with the `enterkeyhint` attribute. 
For example, `enterkeyhint="next"` or `enterkeyhint="done"` changes the button label to an appropriate icon. 
This helps make it clearer for users what happens when they submit the current form.

{% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/QoY8Oynpw0CqjPACtCdG.png",
alt="Two screenshots of an address form on Android showing how the enterkeyhint input attribute changes the enter key button icon.", width="800", height="696" %}

{% Aside 'warning' %}
Automatically focusing a form control using the `autofocus` attribute can confuse people, 
including screen reader users and people with cognitive impairments. Therefore, our advice is that you should not use the `autofocus` attribute.
{% endAside %}

## Ensure users can submit a form

Say, you fill out a `<form>`, click the **Submit** button, but nothing happens. 
The issue may be that the button has been disabled with the `disabled` attribute. 
It's a common pattern to disable the **Submit** button until the form is valid.

In theory this sounds sensible, but you shouldn't disable a **Submit** button while waiting on 
complete and valid user input. Instead, highlight invalid data when it's entered, and highlight 
problematic fields to the user when they submit the form. 

However, you may want to disable the **Submit** button once the form is successfully submitted, but 
not yet processed. Learn more about [disabled buttons](https://www.smashingmagazine.com/2021/08/frustrating-design-patterns-disabled-buttons/#when-disabled-buttons-and-states-work-well).

## Help users by showing the data they previously entered

Imagine you have a checkout form with multiple steps. 
How do you ensure the previously entered values are still there when the user returns to a previous step? 
Use the `value` attribute to show values already completed.

```html
<label for="name">Name</label>
<input value="Hilda" name="name" id="name" type="text">
```

There are multiple  ways to retrieve the value of a form control in JavaScript. 
You can use the 
[`value`](https://developer.mozilla.org/docs/Web/HTML/Element/input#attr-value) property, or you can access the value with 
[`getAttribute('value')`](https://developer.mozilla.org/docs/Web/API/Element/getAttribute). 
There is one big difference, 
the `value` property always returns the current value, 
and using `getAttribute()` always returns the initial value.

[Try it out](https://codepen.io/web-dot-dev/pen/20359edfc39a65c291c3c186a33ab0db?editors=0011)! 
Change the text of the name field and watch the console. 
Notice how the `value` property returns the currently visible text, 
while `getAttribute('value')` always returns the initial value.

Learn more about the difference between 
[DOM attributes and DOM properties](https://stackoverflow.com/questions/6003819/what-is-the-difference-between-properties-and-attributes-in-html/6004028#6004028).

{% Aside %}
To get all form control values use 
[`FormData`](https://developer.mozilla.org/docs/Web/API/FormData). 
The `FormData` object is a set of key/value pairs representing the form controls, 
and the format is the same as the 
[`submit()`](https://developer.mozilla.org/docs/Web/API/HTMLFormElement/submit) method uses.
{% endAside %}

For `<input>` elements of type `checkbox` or `radio` use the `checked` attribute. 
Add it if the user selected an option and remove it otherwise.

## Ensure users understand the expected format

The value of the `placeholder` attribute is a hint for what kind of information is expected. 

```html
<label for="name">Name</label>
<input type="text" name="name" id="name" placeholder="Karin">
```

This may confuse users, 
as it may seem illogical why a form control appears to be already prefilled. 
In addition, adding a placeholder can make it difficult to see which form fields still need to be completed. 
Furthermore, the default style of placeholder text can be hard to read.

In general, be cautious when using the `placeholder` attribute and never use the `placeholder` attribute to explain a form control. 
Use the `<label>` element instead. 
Learn more about 
[why you should consider avoiding the `placeholder` attribute](https://www.smashingmagazine.com/2018/06/placeholder-attribute/).

A better way to give users a hint about what kind of information is expected is to use an extra HTML element 
beneath the form control to add an explanation or example.

{% Codepen {
  user: 'web-dot-dev',
  id: '90199b1fdcbfbcea425686884344352d',
  height: 300
} %}

## Ensure form controls are ready for validation

There are various HTML attributes available to activate built-in validation. 
Use the `required` attribute to prevent the submission of empty fields. 
Additional validations can be enforced with the `type` attribute. 
For example, the value of a required `<input>` of `type="url"` must be a URL.

To ensure a user enters a minimum number of characters, 
use the `minlength` attribute. 
To disallow any value with more than a maximum number of characters, 
use the `maxlength` attribute. 
For numeric input types such as `<input type="number">`, use the `min` and `max` attribute instead.

Find out more about validation: [Help users enter the right data in forms](/learn/forms/validation/).

{% Assessment 'attributes' %}

## Resources

- [`<input>` HTML attributes](https://developer.mozilla.org/docs/Web/HTML/Element/input#attributes)
- [Global HTML attributes](https://developer.mozilla.org/docs/Web/HTML/Global_attributes)

# Help users avoid re-entering data in forms

After learning about the
[form element](/learn/forms/form-element) and how to make a form
[interactive](/learn/forms/form-fields),
let's see how you can help users avoid re-entering data.

## Make the most of autofill

Filling out forms can be time-consuming.
For example, re-entering your address repeatedly on every site where you want to buy something is not a great shopping experience.

Autofill can help you here.
You enter your address once.
From now on, your browser will offer you the option to fill in the same address for other forms automatically.

You moved to another city?
Don't worry about getting the old address as an option forever.
You can edit the address data your browser has saved for you to keep it up-to-date.

{% Aside %}
Browsers also help with remembering data. You sign up for a site.
For the password field, you get the option to generate and store a secure password.
If you want to log in later at the same site, your browser offers you the option to fill in the stored password.
{% endAside %}

## How does autofill work in the browser?
{% BrowserCompat 'html.global_attributes.autocomplete' %}

An address field can look very different on different sites.
How does a browser know that it is an address field?

Browsers use
heuristics to identify an address field.
What are the values of the `name`, `type`, and `id` attributes?
Is there an [`autocomplete` attribute](/learn/forms/auto#autocomplete) present on the form control?

Based on this information,
browsers can offer the option to autofill a field with previously entered data of the same type.
Browsers can even offer to autofill an entire form.

## Help browsers with autofill

Let's see what you can do to help browsers offer the correct autofill options.

### Use sensible attribute values

As you learned, browsers can identify the data type by looking at the attributes of a form control.

```html
<label for="email">Email</label>
<input type="email" name="email" id="email">
```
Do you have a field where users should enter their email address?
Use `email` as a value for the `name`, `id`, and `type` attribute.
Three hints for the browser that this is an email field.

### The autocomplete attribute {: #autocomplete}

There are other examples where it can still be hard for browsers to identify the data type solely from the `name`, `id`, and `type` attributes.
You can help here by using the `autocomplete` attribute.

{% Codepen {
  user: 'web-dot-dev',
  id: '9a2262c52b978968f6ce181f32357f31',
  height: 300,
  tab: 'html,result'
} %}

Have you entered a name before in the browser you're using?
The browser will probably offer you the option to fill it in again for this field in the demo.

You can learn more about using
[autocomplete and autofill](/learn/forms/autofill) in a later module.

{% Assessment 'auto' %}

## Resources

- [The autocomplete attribute](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete)
- [Autofill: What web devs should know, but don't](https://cloudfour.com/thinks/autofill-what-web-devs-should-know-but-dont)

# Autofill

Having to re-enter your address for the tenth time is tiring. 
Browsers, and you, as a developer, can help users enter data faster, and avoid re-entering data. 
This module teaches you how autofill works, and how `autocomplete` and other element attributes can 
ensure that browsers offer appropriate autofill options.

## How does autofill work?

In the [intro to autofill](/learn/forms/auto), you already learned the basics of autofill. 
But why do browsers offer autofill?

Filling out forms isn't an interesting activity, 
but still something you do often. 
Over time, you fill out many forms, 
and you often fill in the same data. 
One way to help users fill out forms faster is by offering them the option 
to automatically fill in form fields with previously entered data. That's autofill. 

How do browsers know what data to autofill? 
Let's have a look at an example form field to find out.

```html
<label for="name">Name</label>
<input name="name" id="name">
```

If you submit this form field, 
browsers store the value (the data you entered) along with the value of the `name` attribute (name). 
Some browsers also look at the `id` attribute when storing and filling in data.

Say, weeks later, you fill out another form on another website. 
This site also contains a form field with `name="name"`. 
Your browser can now offer autofill, because a value for name is already stored.

{% Aside %}
Use the [`:autofill`](https://developer.mozilla.org/docs/Web/CSS/:autofill) 
CSS pseudo-class to style form controls that the browser has autofilled. 
Use `:autofill` and the prefixed version `:-webkit-autofill` for best browser compatibility.
{% endAside %}

Autofill is especially useful in forms you regularly use, 
such as sign-up and sign-in, payment, checkout, 
and forms where you have to enter your name or address.

Let's see how you can help browsers offer the best autofill options by using appropriate values for the `autocomplete` attribute.
Help users to enter their address
There are many possible values for `autocomplete`. Let's have a look at addresses first.

{% Codepen {
  user: 'web-dot-dev',
  id: 'f6eac7a585a34d0c2de36a365eaa8662',
  height: 600,
  tab: 'result,html'
} %}

Does your browser already have an address saved for you? 
Great! After you interact with the first field in the address form, 
the browser shows you a list of saved addresses. 
You can choose one, and the browser fills in all fields related to the address. 
Autofill makes filling out forms fast and easy.

Not every address form has the same fields, 
and the order of fields also varies. 
Using the correct values for `autocomplete` ensures that the browser fills in the correct values for a form. 
There are values for `country`, `postal-code`, and 
[many more](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete#values).

{% Aside %}
You can define multiple values separated by a space for `autocomplete`. 
Say, you have a form with a shipping address and another form for a billing address. 
To tell the browser which is the postal code for the billing address, 
you can use `autocomplete="billing postal-code"`. 
For the shipping address, use `shipping` as the first value.
{% endAside %}

## Ensure users can sign in fast and use secure passwords

Many people aren't good at remembering passwords. 
The 
[most common password](https://en.wikipedia.org/wiki/List_of_the_most_common_passwords) is '123456', 
followed by other easy-to-remember combinations. 
How can you use secure and unique passwords without remembering them all? 

Browsers have built-in passwords managers to generate, save, and fill in passwords for you. 
Let's see how you can help browsers with autofilling emails and managing passwords.

{% Codepen {
  user: 'web-dot-dev',
  id: 'e7e95d2d671d577b0a141aaab4388b28',
  height: 380
} %}

You can use `autocomplete="email"` for an email field, 
so users get the autofill option for an email address.

As this is a sign-up form, users shouldn't get the option to fill in previously used passwords. 
You can use `autocomplete="new-password"` to ensure browsers offer the option to generate a new password.

{% Aside %}
To ensure a secure sign-up form it may be better to use a 
[third-party identity provider](/sign-up-form-best-practices/#federated-login), 
instead of building your own 
[authentication](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) system.
{% endAside %}

On the sign-in form, you can use `autocomplete="current-password"` 
to tell browsers to offer the option to fill in previously saved passwords for this website. 

You can set up two-factor authentication on many websites. 
In addition to the password, a one-time code is sent via SMS or a two-factor authentication app. 

Wouldn't it be great if the code you received in the SMS message was suggested by the on-screen keyboard, 
and you could directly select it to fill in the value? On Safari 14 or later, you can use 
[`autocomplete="one-time-code"`](https://developer.apple.com/documentation/security/password_autofill/enabling_password_autofill_on_an_html_input_element) to achieve this. 
On Chrome on Android, you can use the 
[WebOTP API](/web-otp) to achieve this with JavaScript.

Learn more about how to verify phone numbers on the web with the 
[SMS OTP form best practices](/sms-otp-form/).

{% Aside 'caution' %}
SMS isn't the most secure method of authentication by itself, 
because phone numbers can be recycled and hijacked. 
Consider using other two-factor authentication methods or multifactor authentication.

Learn more about 
[multifactor authentication](https://cheatsheetseries.owasp.org/cheatsheets/Multifactor_Authentication_Cheat_Sheet.html).
{% endAside %}

## Help users fill in their credit card information

On many e-commerce websites, you can use your credit card to purchase products. 
Sites may use third-party payment platforms that provide their own forms, 
but if you do need to build your own payment forms, 
make sure people can easily fill in payment information.

You can use the `autocomplete` attribute again, 
to ensure browsers offer the correct autofill options. 

There are values for the credit card number `cc-number`, credit card expiration date `cc-exp`, 
and [all other information needed](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete#values) for a credit card payment.

Use a single input for numbers 
such as credit card numbers and telephone numbers, 
to ensure browsers offer autofill. 
Use standard form elements, for example, 
a `<select>` for the payment card dates, 
instead of custom elements, to ensure autocomplete is available.

Learn more about 
[helping users to avoid re-entering payment data](/learn/forms/payment/#help-users-enter-their-payment-details).

## Ensure autofill works for all your fields

In addition to addresses, account information, and credit card information, 
there are many more fields where browsers can help users with autofill. 

When adding a telephone field to your form check if you can use any of the 
[available values](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete#values) for autocomplete. 
Found an appropriate value for your form field? Add it. 

Using suitable values for the `autocomplete` attribute helps browsers offer the best autofill option, 
and helps users fill out forms faster.

## Help browsers understand that a field shouldn't be autofilled 

You learned how autofill works, how you can help browsers with autofill, 
and why autofill makes it convenient for users to fill out forms. 
Sometimes, though, you don't want browsers to offer autofill. Let's have a look.

```html
<label for="one-time-code">One-time code</label>
<input autocomplete="off" type="text" name="one-time-code" id="one-time-code">
```

One place where autofill isn't helpful is when entering one-off, 
unique values such as a one-time code field. 
The value is different every time, 
and the browser shouldn't save values or offer an autofill option. 
You can use `autocomplete="off"` for such fields to prevent autofill.

{% Aside %}
Autofill and autocomplete provide accessibility benefits. 
Using autofill, people don't have to remember information or manually re-enter data. 

For more information, see the 
[W3C accessibility guidelines](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html)
{% endAside %}

Another use case for `autocomplete="off"` is a honeypot field (see [previous module](/learn/forms/security-privacy/#a-honeypot)). 
Even though the field isn't visible, browsers may autofill it with the rest of the fields. 
Turning autofill off ensures a real user isn't identified as a bot, 
due to the field being completed automatically.

{% Aside %}
You learned how important it is to use unique, and secure passwords. 
In-browser password managers ensure that you use strong passwords. 
Therefore browsers will still offer autofill options for passwords, even though `autocomplete="off"` is used, 
to allow these password managers to do their job. 

Learn more about 
[the autocomplete attribute and sign-in fields](https://developer.mozilla.org/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion#the_autocomplete_attribute_and_login_fields).
{% endAside %}

You should only disable autofill if you are sure it will help users.

{% Assessment 'autofill' %}

## Resources

- The [autocomplete attribute](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete).
- [Payment and address form best practices](/payment-and-address-form-best-practices)

# Conclusion and next steps

Congratulations! You've made it to the end.
So far, you've learned a lot about forms,
and hopefully you feel more comfortable now building your own forms.

What's next? One of the best ways to learn is to try out what you've learned:
implement an HTML form of your own.
To continue to build your HTML forms knowledge, here are some additional resources to explore:

## Additional resources

- [HTML forms guide on MDN](https://developer.mozilla.org/docs/Learn/Forms)
- [Learn CSS](/learn/css)
- [WebAIM: Creating Accessible Forms](https://webaim.org/techniques/forms)
- [Payment and address forms best practices](/payment-and-address-form-best-practices)
- [Sign-up form best practices](/sign-up-form-best-practices)
- [Sign-in form best practices](/sign-in-form-best-practices)
- [Best Practices For Mobile Form Design](https://www.smashingmagazine.com/2018/08/best-practices-for-mobile-form-design/)
- [OWASP Cheat Sheet series](https://owasp.org/www-project-cheat-sheets/): best practices for privacy and security.
- [NIST Identity Guidelines](https://pages.nist.gov/800-63-3/sp800-63-3.html): US National Institute of Standards and Technology guidelines for passwords and other identity topics.
- [12 best practices for user account, authorization and password management](https://cloud.google.com/blog/products/gcp/12-best-practices-for-user-account): outlines core back-end principles for managing user accounts.
- [Passwords Evolved: Authentication Guidance for the Modern Era](https://www.troyhunt.com/passwords-evolved-authentication-guidance-for-the-modern-era/): detailed password guidance from Troy Hunt, creator of [haveibeenpwned.com](https://haveibeenpwned.com/),
- [We Didn't Encrypt Your Password, We Hashed It. Here's What That Means](https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/): also from Troy Hunt — here he explains the difference between encryption and hashing.

## Brought to you by

{% include 'partials/authors-stack.njk' %}

# Test forms across devices and platforms

You can fill out a form in many ways.
People might use your form on their smartphone while standing in a crowded bus,
or with a screen reader, or from an old laptop.
Let's see how you can ensure your form works on different devices, and in different contexts.

## Ensure your form works for keyboard users

A good first test to ensure your form is accessible is to fill out your form using only your keyboard.
Open your form and try to navigate with the `tab` key.
Is it clear what form field is currently active?
To help users understand which form field is active,
you can use focus indicators.

{% Codepen {
  user: 'web-dot-dev',
  id: 'be0759d9436d84426a795a9ae399eff9',
  height: 300
} %}

[Try it out](https://codepen.io/web-dot-dev/pen/be0759d9436d84426a795a9ae399eff9).
Use your `tab` key to navigate to the input.
Do you see the outline when the input is active?
That's the focus indicator.
You can add focus indicators using the
[`:focus`](https://developer.mozilla.org/docs/Web/CSS/:focus) CSS pseudo-class.

```css
input:focus {
  outline: 4px solid #222;
}
```

Learn more about
[designing accessible focus indicators](https://www.sarasoueidan.com/blog/focus-indicators/).

{% Aside %}
If you want to remove the default `:focus` styles but still show focus indicators for keyboard users,
you can use the `:focus-visible` CSS pseudo-class.

Learn more about
[`:focus-visible`](/style-focus/#use-focus-visible-to-selectively-show-a-focus-indicator).
{% endAside %}

## Help users navigate your form

Another good test of usability and accessibility is to ensure that the logical tab order follows the visual tab order.
How can you test the tab order?
Tab completely through your form.
Do you notice any illogical navigation jumps?
Make sure the DOM order matches the visual order.

Learn more about how to
[ensure visual order on the page follows DOM order](/visual-order-follows-dom/).

## Help users complete your form on touch devices

Great! You made sure your form works with the keyboard.
Now, let's see how you can ensure it also works on touch devices such as mobile phones.

Open your form on your touch device,
fill in all fields and submit the form.
Did you have to tap multiple times to select a form control?
The issue may be that the tap areas are too small.
Make sure the
[tap target size](/accessible-tap-targets/) of a button is at least 48px,
and that each `<input>` and `<select>` is large enough to tap into.
You can also help users navigate your form on touch devices by adding enough spacing between form controls.

## Ensure users get an optimized keyboard

In previous modules, you learned how to activate a different on-screen keyboard
using the `type` or `inputmode` attributes.

{% Codepen {
  user: 'web-dot-dev',
  id: '88f1ffed62ef6bdd513351823b7aaa0f',
  height: 300,
  tab: 'html,result'
} %}

Open
[the demo](https://codepen.io/web-dot-dev/pen/88f1ffed62ef6bdd513351823b7aaa0f)
on your phone and tap in the telephone number field.
Notice that numbers are shown by default on the on-screen keyboard,
along with other characters you may need for a telephone number.
Use `type="tel"` to get an on-screen keyboard optimized for entering telephone numbers.

{% Img src="image/ZDZVuXt6QqfXtxkpXcPGfnygYjd2/nX50IOaBUCP8mcHqr3CT.jpg",
alt="Two screenshots of an input element with type='tel' on iOS and Android, showing how the type attribute changes the on-screen keyboard.", width="800", height="696" %}

Use a phone to [try it out for yourself](https://codepen.io/web-dot-dev/pen/88f1ffed62ef6bdd513351823b7aaa0f),
and see if you can easily enter every character needed to fill in a telephone number.
If you're curious how the on-screen keyboard works for another `type`, try `type="email"` in the [demo](https://codepen.io/web-dot-dev/pen/88f1ffed62ef6bdd513351823b7aaa0f).

## Make sure form buttons aren't hidden

Imagine that you filled out a long form,
and you're ready to submit it. But where is the **Submit** button?
It may be behind the browser toolbar, located at the bottom of the screen.
One way to ensure that buttons are visible is to use the [`env()`](https://developer.mozilla.org/docs/Web/CSS/env()) CSS function.
Learn how to
[ensure buttons aren't obscured by device user interfaces](https://developer.mozilla.org/docs/Web/CSS/env()#using_env_to_ensure_buttons_are_not_obscured_by_device_ui).

## Ensure your form works on different platforms

Try to test your forms on as many devices as possible.
Have an old laptop? Open the default browser on it and test your form.
Your friend has a tablet? Borrow it and test your form there as well.

Does some styling look different in one browser?
You can learn how to ensure your
[styles work across platforms](/learn/forms/styling) in a later module.

[BrowserStack](https://www.browserstack.com) offers free test accounts for open source projects,
and [Browserling](https://www.browserling.com) offers a free trial to test on different browsers,
devices and operating systems.

## Help users complete your forms in different contexts

People don't just use different browsers, devices and operating systems.
People also use your forms in different contexts.
Try it out! Is the sun shining outside right now? Take your phone and go outside.
Using your form in bright light is a good way to test if contrast ratios are usable.

Learn more about
[color and contrast accessibility](/color-and-contrast-accessibility/).

## Ensure your form works with poor connectivity

Say you travel somewhere on a train.
You open a web page on your phone.
You wonder how loading a website can take so long 😕.

You can simulate slow connections and different network types with
[WebPageTest](https://webpagetest.org/easy) or
[DevTools](https://developer.chrome.com/docs/devtools/device-mode/#network).

Learn more about
[testing with low bandwidth and high latency](/performance-poor-connectivity/#testing).

## Help users use your form when they are on the go

Imagine that you're walking to an appointment.
Suddenly, your phone rings, you answer the call, and at the same time,
get an alert from your insurance company to complete the application form you started.
You open the form, trying to fill it out while still walking and talking.

Remember that people will use your forms in many different contexts.
In stressful situations, while doing other things, while on the go.
You can help users by ensuring your form is easy to use.

Try setting yourself a time limit to complete your form.
Try to simulate imperfect conditions where you can test your form.

## Make sure to share test results

Document all tests, and share the results with your team.
This will help prioritize action items,
to ensure everybody in your team is aware of the most important tasks.

Learn more about
[sharing test results](/performance-audit-share/).

{% Assessment 'cross-platform-testing' %}

## Resources

- [WebPageTest](https://webpagetest.org/easy): Website Performance and Optimization Tests
- [Testing with low bandwidth and high latency](/performance-poor-connectivity/#testing)
- [Sharing test results](/performance-audit-share/)

# Gathering data

In this module, you learn how to define goals, analyze your forms, measure changes, 
and get notified about new issues.

## Ensure you identify issues, problems, and goals

As a first step, you need a way to identify issues and goals. 
One way is to use [analytics](/learn/forms/testing/#analytics) 
to get an overview of where your form may need improvements. 

After analytics is up and running for your site, 
you can monitor 
[bounce rate](https://support.google.com/analytics/answer/1009409?hl=en) 
and other metrics for every page with a form within your site. 
If the bounce rate is high, users may be leaving your site without submitting the form. 
There are many potential reasons why this happens: 
for example, the form may be too complicated, or it's unclear what data should be entered.

{% Aside %}
Always respect the privacy of your users, with analytics data as well as form data. 
Collect the minimum amount of data you require and be transparent with your users about what data you are collecting. 
There are also 
[privacy and data protection laws](/learn/forms/security-privacy/#help-users-access-their-personal-data) that you must follow. 
In some countries, you need consent from a user before you can collect data. 
{% endAside %}

To get a clearer picture of a high bounce rate, you can define 
[goals](https://support.google.com/analytics/answer/1012040) 
to identify in detail where users leave your form.

A [goal funnel](https://support.google.com/analytics/answer/1012040?hl=en&ref_topic=6150889#funnels_for_destination_goals&zippy=%2Cin-this-article)
 (or _conversion funnel_) is a series of interactions that lead to a goal such as a completed purchase (a _conversion_). 
 Each goal funnel consists of individual steps such as opening a shopping cart page or proceeding to a checkout page.

The goal funnel for your form might look like this:

1. The user opens page A with the form.
1. The user fills out the name field.
1. The user fills out the postal code field.
1. The user submits the form.
1. The user navigates to page B. 

Goal funnels can give you an overview of where users leave your form, and where you need to improve it.

As well as using analytics to track page metrics such as time-on-page or exit rates, 
you can also monitor [events](https://support.google.com/analytics/answer/1033068?hl=en#zippy=%2Cin-this-article). 
These allow you to track individual interactions, 
such as button clicks or interactions with form fields. 
For example, you can set up a [custom event](https://developers.google.com/analytics/devguides/collection/analyticsjs/events), 
which fires when a user fills out a specific `<input>`. 
Or you can track the percentage of your users who submit a form. 

## Analyze your forms

You can create custom events for almost every interaction, and monitor form completion step-by-step. 
This isn't always necessary though: 
it's better to start with a small number of custom events, 
and only add more if you need more details to find an issue with your form.

Focus first on the most important goals, such as successful checkout. 
You can always expand your goals later if more details are needed. 
Identify your main goals, measure achievement of these goals, analyze the data, identify potential changes, 
adapt your form and measure again.

## Ensure that you fix problems with your form

Say you identified an issue with your form. What should you do next? 
First, you need to correct the issue and deploy a new version of your form. 
After some days, it's now time to measure how effective the change was.

Did the bounce rate decrease for your form? 
Great, now look at the goal funnel to see which parts improved. 
Are a high proportion of users still leaving before they fill in the postal code, for example? 
Adapt your goal funnel steps if necessary, deploy further changes, 
and analyze your form again until you are happy with the outcome.

## Get notified when there are problems

How can you get notified about potential issues without constantly checking your analytics dashboard? 
You can set up [alerts](https://support.google.com/analytics/answer/1033021). 
A common alert is about traffic drops. 
You can monitor your form pages, and get notified when the traffic is unusually low for a day. 
Or, coming back to bounce rates, you can set up an alert if the bounce rate for a page increases significantly.

Alerts help you identify issues fast, and ensure you don't miss new problems with your form.

Want to get a summary of your site's analytics? You can create 
[reports](https://support.google.com/analytics/answer/1010054), 
and get notified via email. This is a good way to monitor form usage.

## Resources

- [Google Analytics: Bounce rates](https://support.google.com/analytics/answer/1009409?hl=en)
- [Google Analytics: Alerts](https://support.google.com/analytics/answer/1033021)
- [Google Analytics: Event measuring](https://developers.google.com/analytics/devguides/collection/analyticsjs/events)

# Design basics

In the first section, you learned how to build a basic form.
This section is all about best practices.
In this module, learn about user experience (UX),
and why a well-implemented user interface (UI) can make a big difference.

## Creating user-friendly interfaces

Filling out forms can be time-consuming and frustrating.
It doesn't have to be.
To guarantee a great UX, make sure the UI is intuitive.
Ensure you deliver optimal form structure and graphic design (layout, spacing, font size and color),
and logical UI (such as label wording and appropriate input types).
Let's have a look at how you can improve your form and make it easy to use.

## Labels

Do you remember what the `<label>` element is for?
A label describes a form control.
A visible and well-written label helps the user understand the purpose of a form control.

### Use a label for every form control

Do you want to add a new form control to your form?
Start by adding the label for the new field.
This way, you don't forget to add it.

Adding labels first also helps you to focus on the form's goals–what data do I need here?
Once this is clear, you can focus on helping the user enter data and complete the form.

{% Aside 'caution' %}
Never misuse the `placeholder` attribute as a label.
The placeholder is meant for giving a hint about the type of data you should enter,
not for describing a form control.

Learn more about why you should consider
[avoiding placeholders](https://www.smashingmagazine.com/2018/06/placeholder-attribute/).
{% endAside %}

### Label wording

Say that you want to describe an email field. You could do so as follows:

```html
<label for="email">Enter your email address</label>
```

Or you could describe it like this:

```html
<label for="email">Email address</label>
```

Which description do you choose?

For our example, the wording 'Email address' is preferred,
since short labels are easier to scan, reduce visual clutter,
and help users to understand what data is needed faster.

## Label position

With [CSS](/learn/css),
you can position a label on the top, bottom, left, and right of a form control.
Where do you place it?

[Research shows](https://ai.googleblog.com/2014/07/simple-is-better-making-your-web-forms.html)
that best practice is to
[position the label above the form control](https://www.uxmatters.com/mt/archives/2006/07/label-placement-in-forms.php),
so the user can scan a form quickly and see which label belongs to which form control.

## Designing forms

Good form design can
[significantly reduce form abandonment rates](https://baymard.com/blog/checkout-flow-average-form-fields).
Help users enter data by using the appropriate element and input type
There are various
[form elements and input types](/learn/forms/fields) you can choose from.
To offer the best UX, use the most suitable element and input type for your use case.
If the user should fill in multiple lines of text, use the `<textarea>` element.
Where they need to accept your site's terms and conditions, use `<input type="checkbox">`.

{% Aside %}
Depending on the `type` or `inputmode` attribute (more about this
[later](/learn/forms/attributes#inputmode))
a different on-screen keyboard is shown on touch devices.
If you use `type="tel"`, users on touch devices get a keyboard showing only the characters needed to enter a telephone number.
By using `type="email"` the mobile device displays a keyboard optimized for entering an email address.
{% endAside %}

You should also visually differentiate between different types of form controls.
A button should look like a button.
An input like an input.
Make it easy for users to recognize the purpose of a form control.
For example, If something looks like a link, clicking on it should open a new page,
and not submit a form.

{% Codepen {
  user: 'web-dot-dev',
  id: 'c369bda56ae3bc88aa0116614f79e40d',
  height: 400
} %}

### Help users navigate forms

An extravagant layout can be fun, but may get in the way of completing a form.

In particular,
[research shows](https://baymard.com/blog/avoid-multi-column-forms)
that it's best to use only a single column.
Users don't want to spend time searching where the next form control is.
By using one column, there is only one direction to follow.

{% Aside %}
Always ensure that forms are accessible for people who use only the keyboard to navigate websites—either through preference or circumstance.
Test your form by only using keyboard navigation.
The tab order should follow the visual order.
You can view the
[source order in Chrome DevTools](https://developer.chrome.com/blog/new-in-devtools-92/#source-order).
{% endAside %}

### Help users interact with forms

To avoid accidental taps and clicks,
and help users interact with your form, make your buttons big enough.
The recommended
[tap target size](/accessible-tap-targets/) of a button is at least 48px.
You should also add enough spacing between form controls using the `margin`
CSS property to help avoid accidental interactions.

The default size of form controls is too small to be really usable. You should increase the size by using `padding` and changing the default `font-size`.

{% Aside %}
Use at least `1rem` (which for most browsers has a default value of 16px)
as the `font-size` for your form controls.
This [prevents a page zoom](https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/)
on iOS Safari when a form control is focused.
{% endAside %}

You can define different sizes for different pointing devices,
for example, a mouse, using the  `pointer` CSS media feature.

```css
// pointer device, for example, a mouse
@media (pointer: fine) {
  input[type="checkbox"] {
    width: 15px;
    height: 15px;
  }
}

// pointer device of limited accuracy, for example, a touch-based device
@media (pointer: coarse) {
  input[type="checkbox"] {
    width: 30px;
    height: 30px;
  }
}
```

Learn more about the
[`pointer` CSS media feature](https://developer.mozilla.org/docs/Web/CSS/@media/pointer).

### Show errors where they happen

To make it straightforward for users to find out which form control needs their attention,
display error messages next to the form control they refer to.
When displaying errors on form submission, make sure to navigate to the first invalid form control.

### Make it clear to users what data to enter

Make sure users understand how to enter valid data.
Do they need to enter at least eight characters for a password? Tell them.

```html
<label for="password">Password (required)</label>
<input required minlength="8" type="password" id="password" name="password" aria-describedby="password-minlength">
<span id="password-minlength">Enter at least eight characters</span>
```

### Make it clear to users which fields are required

```html
<label for="name">Name (required)</label>
<input name="name" id="name" required>
```

If a field is mandatory, make it obvious! [The Anatomy of Accessible Forms](https://www.deque.com/blog/anatomy-of-accessible-forms-required-form-fields/) explains alternatives for indicating 
required fields. If most fields in a form are required, it may be better to 
[indicate optional fields](https://www.lukew.com/ff/entry.asp?725).

How can you connect error messages to form controls to make them accessible for screen readers?
You can learn about this in [the next module](/learn/forms/accessibility).

{% Assessment 'design-basics' %}


## Resources

- [Create Amazing Forms](/learn/forms/)
- [Best Practices For Mobile Form Design](https://www.smashingmagazine.com/2018/08/best-practices-for-mobile-form-design/)
- [Baymard Institute: E-Commerce UX Research](https://baymard.com/blog)
- [Don't Make Me Think](https://en.wikipedia.org/wiki/Don%27t_Make_Me_Think)

# Form fields in depth

To provide the best possible user experience,
make sure to use the element and element `type` that's most appropriate for the data the user is entering.

### Help users fill in text

To provide users with a form field for inserting text, use the `<input>` element.
It's the best choice for single words and short texts.
For longer text, use the `<textarea>` element.
This allows multiple lines of text,
and makes it easier for the user to see the text they entered, as the element is scrollable and resizable.

{% Aside %}
A `<textarea>` is resizable by default. You can disable the resizing with CSS and the `resize` property: `resize: none`.

However, people may want to see the text they entered all at once.
At least keep the option to resize an `<textarea>` vertically.
Use `resize: vertical` to ensure users can resize vertically but not horizontally.

Learn more about [why disabling resize on `<textarea>` is bad for UX](https://catalin.red/css-resize-none-is-bad-for-ux/).
{% endAside %}

### Ensure users enter data in the correct format

Do you want to help users fill in a telephone number?
Change the `type` attribute to `type="tel"` for the `<input>`.
Users on mobile devices get an adapted on-screen keyboard,
ensuring they can enter the telephone number faster and more easily.

For an email address, use `type="email"`.
Again, an adapted on-screen keyboard is shown.
Use the `required` attribute to make the form field mandatory.
When the form is submitted, the browser checks that the input has a value and that it's valid: in this case,
that it's a well-formatted email address.

Learn more about the different [input types](https://developer.mozilla.org/docs/Web/HTML/Element/input#input_types).
These also provide built-in [validation features](/learn/forms/validation).

### Help users fill in dates

When do you want to start your next trip?
To help users fill in dates, use `type="date"`.
Some browsers show the format as a placeholder such as `yyyy-mm-dd`,
demonstrating how to enter the date.

All modern browsers provide custom interfaces for selecting dates in the form of a date picker.

{% Codepen {
  user: 'web-dot-dev',
  id: '93693a7c2ce3d39ec5aa9088159b0601',
  height: 300
} %}

### Help users select an option

To ensure users can select or unselect one possible option, use `type="checkbox"`.
Do you want to offer multiple options?
Depending on your use case, there are various alternatives.
First, let's look at possible solutions if users should only be able to choose a single option.

You can use multiple `<input>` elements with `type="radio"` and the same `name` value. Users see all options at once, but can only choose one.

{% Codepen {
  user: 'web-dot-dev',
  id: '617e51cdae8adeca641d289da1a3e8a2',
  height: 300
} %}

Another option is to use the `<select>` element.
Users can scroll through a list of available options and choose one.

{% Codepen {
  user: 'web-dot-dev',
  id: '7225931596b7eeafc448ad55d9c980fd',
  height: 300
} %}

For some use cases, such as choosing a range of numbers,
`<input>` of type `range` may be a good option.

{% Codepen {
  user: 'web-dot-dev',
  id: '242b1ec7ea180c4995711ceabd749c59',
  height: 300
} %}

{% Aside %}
You can use the [`accent-color`](/accent-color/) CSS property to change the color of form controls,
including `<input type="range">`.
{% BrowserCompat 'css.properties.accent-color' %}
{% endAside %}

Do you need to offer the ability to select multiple options?
Use a `<select>` element with the `multiple` attribute or multiple `<input>` elements of type `checkbox`.

You may also use an `<input>` in combination with the [`<datalist>`](https://developer.mozilla.org/docs/Web/HTML/Element/datalist) element.
This gives you a combination of a text field and a list of `<option>` elements.

{% Aside 'codelab' %}
How would you tackle the selection of multiple items?
Try to implement different versions.
Use a `<select>` element, `<datalist>` element,
[multi-select custom element](https://github.com/samdutton/multi-input), or build something completely different.
{% endAside %}

### Ensure users can fill in different types of data

There are more input types for specific use cases.

There is an `<input>` of type `color` to provide users with a color picker in supported browsers,
and there are various other types as well. To ensure users can enter their password, use `<input>`
with `type="password"`. Every character entered is obscured by an asterisk ("*") or a dot ("•"),
to ensure the password can't be read.

Do you want to include a unique security token in the form data?
Use `<input>` with `type="hidden"`.
The value of an `<input>` of type `hidden` can't be seen or modified by users.

To enable users to upload and submit files, use `<input>` with `type="file"`.

{% Codepen {
  user: 'web-dot-dev',
  id: '74f2d88b9185b8fa880ea5a92f48f690',
  height: 300
} %}

{% Aside %}
An `<input>` of type `file` can also allow multiple uploads at once.
You can also specify which file formats are allowed.

Learn more about [`<input type="file">`](https://developer.mozilla.org/docs/Web/HTML/Element/input/file).
{% endAside %}

You can also define [custom elements](/more-capable-form-controls/#form-associated-custom-elements) if you have a special use case,
where no built-in element or type is suitable.

## Help users fill out your form

There are many form elements and types, but which one should you choose?

For some use cases, it's straightforward to choose the appropriate element and type,
such as `<input type="date">`. For others, it depends.
For example, you can use multiple `<input>` elements with `type="checkbox"` or a `<select>` element.
Learn more about [choosing between listboxes and dropdown lists](https://www.nngroup.com/articles/listbox-dropdown/).

In general, make sure to
[test your form with real users](/learn/forms/usability-testing) to find the best form element and type.

{% Assessment 'fields' %}

## Resources

- [The `<input>` element](https://developer.mozilla.org/docs/Web/HTML/Element/Input)
- [The `<textarea>` element](https://developer.mozilla.org/docs/Web/HTML/Element/textarea)
- [The `<select>` element](https://developer.mozilla.org/docs/Web/HTML/Element/select)
- [`<input>` types](https://developer.mozilla.org/docs/Web/HTML/Element/input#input_types)
- [Custom form elements](/more-capable-form-controls/#form-associated-custom-elements)

# The form element in depth

In a previous module, you learned [how to use the `<form>` element](/learn/forms/form-element).
In this module, you learn how a form works, and when to use a form.

## Should you use a `<form>` element?
{% BrowserCompat 'html.elements.input' %}

You don't always need to put form controls in a `<form>` element.
For example, you might provide a `<select>` element for users to choose a product category.
You don't need a `<form>` element here, as you're not storing or processing data on your backend.

However, in most cases when you store or process data from users,
you should use the `<form>` element.
As you will learn in this module, using a `<form>` gives you a lot of built-in functionality from browsers that you would otherwise have to build yourself.
A `<form>` also has many accessibility features built-in by default.
If you want to avoid a page reload when a user submits a form,
you can still use the `<form>` element, but enhance it with
[JavaScript](/learn/forms/javascript#ensure-users-can-submit-a-form-without-leaving-a-page).

{% Aside %}
It's possible to replicate form functionality with JavaScript, but a purely script-based approach is
unlikely to be as robust, accessible and future-proof as a built-in `<form>`.

Find out [why not everybody has JavaScript](https://kryogenix.org/code/browser/everyonehasjs.html).
{% endAside %}

## How does a `<form>` work?

You learned that a `<form>` is the best way to handle user data.
You may wonder now, how does a form work?

The `<form>` is a container for interactive form controls.

```html
<form method="post">
  <label for="name">Name</label>
  <input type="text" name="name" id="name">
  <button formaction="/name">Save</button>
</form>
```

## How does form submission work?

When you submit a `<form>`, the browser checks the `<form>` attributes. The data is sent as a `GET`
  or `POST` request according to the `method` attribute. If no `method` attribute is present, a
  `GET` request is made to the URL of the current page.

How can you access and process the form data?
The submitted data can be handled by JavaScript on the frontend using a `GET` request,
or by code on the backend using a `GET` or `POST` request.
Learn more about
[request types and transferring form data](/learn/forms/form-element/#where-is-the-data-processed).

{% Aside %}
The **Submit** button may have a `formmethod` attribute.
If this is the case, the value defined there is used.
{% endAside %}

When the form is submitted, the browser makes a request to the URL that is the value of the `action` attribute.
In addition, the browser checks if the **Submit** button has a `formaction` attribute.
If this is the case, the URL defined there is used.

Furthermore, the browser looks up additional attributes on the `<form>` element,
for example, to decide if the form should be validated (`novalidate`),
autocomplete should be used (`autocomplete="off"`) or what encoding should be used (`accept-charset`).

[Try to build a form](https://codepen.io/web-dot-dev/pen/c7d89671f738240187a86cda1074d554) where users can submit their favorite color.
The data should be sent as a `POST` request, and the URL where the data will be processed should be `/color`.

{% Details %}
{% DetailsSummary 'h3' %} Show form {% endDetailsSummary %}
One possible solution is using this form:

```html
<form method="post" action="/color">
    <label for="color">What is your favorite color?</label>
    <input type="text" name="color" id="color">
    <button>Save</button>
</form>
```

{% endDetails %}

## Ensure users can submit your form

There are two ways to submit a form.
You can click the **Submit** button, or press `Enter` while using any form control.

{% Aside %}
Use an actionable name for your **Submit** button,
for example, 'Proceed to Payment' or 'Save Changes', rather than just 'Submit'.

Don't disable the **Submit** button while still awaiting valid user input,
but consider disabling it once the form has been submitted,
preventing multiple requests to your server.

Learn more about [Submit button best practices](/payment-and-address-form-best-practices/#html-button).
{% endAside %}

You can add a **Submit** button in various ways.
One option is to use a `<button>` element inside your form.
As long as you don't use `type="button"` it works as a **Submit** button.
Another option is to use `<input type="submit" value="Submit">`.

{% Aside %}
You can use the [`enterkeyhint`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/enterkeyhint)
attribute to change the label of the `Enter` key for on-screen keyboards. This helps make it clearer
for users what happens when they submit the current form.
{% endAside %}

A third option is to use `<input type="image" alt="Submit" src="submit.png">`,
to create a graphical **Submit** button.
However, now that you can create graphical buttons with CSS, it's not recommended to use `type="image"`.

{% Aside %}
Always give users as much time as they want to submit a form.
Defining timeouts on your form will cause data loss, and frustrates your users.

For more information, see
[W3C form timeout guidelines](https://www.w3.org/WAI/WCAG21/Understanding/timeouts.html).
{% endAside %}

## Enable users to submit files

Use `<input type="file">` to enable people to upload and submit files if necessary.

```html
<label for="file">Choose file to upload</label>
<input type="file" id="file" name="file" multiple>
```

First, add an `<input>` element with `type="file"` to your form.
Add the `multiple` attribute if users should be able to upload multiple files.

{% Codepen {
  user: 'web-dot-dev',
  id: '6a600920c65a81e55576c6b52b4e5efa',
  height: 300,
  tab: 'html,result'
} %}

One more change is needed to ensure users can upload files—set the `enctype` attribute on your form.
The default value is `application/x-www-form-urlencoded`.

```html
<form method="post" enctype="multipart/form-data">
…
</form>
```
To make sure files can be submitted, change it to `multipart/form-data`.
Without this encoding, files can't be sent with a `POST` request.

{% Assessment 'form' %}

## Resources

- [The form HTML element](https://developer.mozilla.org/docs/Web/HTML/Element/form)
- [Submit button best practices](/payment-and-address-form-best-practices/#html-button)

# Use forms to get data from users

Imagine you want to ask people on your website about their favorite animal.
As a first step, you need a way to collect the data.

How do you do this with HTML?

{% Glitch 'learn-forms-get-started' %}

In HTML, you can build this using the form element (`<form>`),
an `<input>` with a `<label>`, and a submit `<button>`.

{% Aside %}
You may wonder where the styles for this example are coming from.
They are coming from a general stylesheet
[included in all demos](/learn/forms#demos).

Interested in styling forms? You can learn about this in a later
[module](/learn/forms/styling).
{% endAside %}

## What is a form element?

```html
<form>
  <label for="animal">What is your favorite animal?</label>
  <input type="text" id="animal" name="animal">
  <button>Save</button>
</form>
```

The form element consists of the start tag `<form>`,
optional attributes defined in the start tag, and an end tag `</form>`.

Between the start and end tag, you can include form elements like `<input>` and `<textarea>`
for different types of user input.
You will learn more about [form elements](/learn/forms/form-fields) in the next module.

{% Aside %}
Use HTTPS to protect all websites and forms,
not only if you handle sensitive data. This way, all data is encrypted.

Find out more: [Secure connections with HTTPS](/secure/#secure-connections-with-https).
{% endAside %}

## Where is the data processed?

When a form is submitted (for example, when the user clicks the **Submit** button),
the browser makes a request.
A script can respond to that request and process the data.

{% Aside %}
A script (running on the server or the client) is needed to process the form.
It may [validate](/learn/forms/validation) the data, save it into a database,
or do other operations based on the form data.
{% endAside %}

By default, the request is made to the page where the form is shown.

Say you want a script running at `https://web.dev`
to process the form data—how would you do that?
[Try it out](https://codepen.io/web-dot-dev/pen/fbf90faccc7a22e208c2a507f33be598?editors=1100)!

{% Details %}

{% DetailsSummary 'h3' %} Toggle answer {% endDetailsSummary %}

You can select the location of the script by using the `action` attribute.

```html
<form action="https://example.com/animals">
...
</form>
```

{% endDetails %}

The preceding example makes a request to `https://example.com/animals`.
A script on the `example.com` backend can handle requests to `/animals`
and process data from the form.

## How is the data transferred?

By default, form data is sent as a `GET` request,
with the submitted data appended to the URL.
If a user submits 'frog' in the example above, the browser makes a request to the following URL:

```html
https://example.com/animals?animal=frog
```

In this case, you can access the data on the frontend or the backend by getting the data from the URL.

If you want, you can instruct the form to use a `POST` request by changing the method attribute.

```html
<form method="post">
...
</form>
```

Using `POST`, the data is included in the
[body of the request](https://developer.mozilla.org/docs/Web/HTTP/Methods/POST#example).

The data will not be visible in the URL and can only be accessed from a frontend or backend script.

### What method should you use?

There are use cases for both methods.

For forms that process sensitive data use the `POST` method.
The data is encrypted (if you use  HTTPS) and only accessible by the backend script that processes the request.
The data is not visible in the URL. A common example is a sign-in form.

If the data is shareable, you can use the `GET` method.
This way the data will be added to your browser history as it is included in the URL.
Search forms often use this. This way you can bookmark a search result page.

Now that you've learned about the form element itself, it's time to learn about 
[form fields](/learn/forms/form-fields) to make your forms interactive.

{% Assessment 'form-element' %}

## Resources

[The `<form>` element](https://developer.mozilla.org/docs/Web/HTML/Element/form).

# Help users enter data in forms

To make a form interactive, you need to add form elements.
There are controls to enter and select data, elements that describe controls,
elements that group fields, and buttons to submit a form.

## What are form elements?

{% Codepen {
  user: 'web-dot-dev',
  id: 'a4a252d5c8511f94c0f56cabd2e73178',
  height: 400,
  tab: 'html,result'
} %}

You see two `<input>` elements, `<input type="text">` and `<input type="file">`. Why do they look different?

Based on the element name and the [type](/learn/forms/form-fields#type) attribute,
browsers show different user interfaces, use different
[validation](/learn/forms/validation) rules,
and provide many other features.
Using the appropriate form control helps you build better forms.

{% Aside %}
The default styles of form controls differ between browsers,
operating systems, and platforms.
You will learn in a later module how to [style forms](/learn/forms/styling) cross-platform.
{% endAside %}

## Labels for form elements

Say you want to add an input where the user can enter their favorite color.
For this, you need to add an [`<input>` element](/learn/forms/form-fields/#input) to your form.
But, how does the user know that they should fill in their favorite color?

To describe form controls, use a `<label>` for each form control.

```html
<label for="color">What is your favorite color?</label>
<input type="text" id="color" name="color">
```

The `for` attribute on the label element matches the `id` attribute on the input.

{% Aside %}
Describe every form control with a `<label>` rather than using some other HTML element.
This makes the form control accessible to screen readers, and provides a bigger target, since you 
can tap or click the label to set focus on the control.

[Click the label](https://codepen.io/web-dot-dev/pen/3ce69644635734a084f45350993f4170) in our demo 
to try this out.
{% endAside %}

## Capturing user input {: #input}

As the name suggests, the `<input>` element is used to gather input from users.

```html
<label for="color">What is your favorite color</label>
<input type="text" id="color" name="color">
```

As mentioned before, the `id` attribute connects the `<input>` to the `<label>`.
What about the name and type attribute in this example?

### The name attribute

Use the `name` attribute to identify the data the user enters with the control.
If you submit the form, this name is included in the request.
Say that you named a form control `mountain` and the user entered `Gutenberg`,
the request includes this information as `mountain=Gutenberg`.

[Try to change](https://codepen.io/web-dot-dev/pen/a9ec1be360c53c5284da27a92fbd7248)
the name of the form control to `hill`.
If you do this correctly, and submit the form, `hill` is visible in the URL.

### The input type {: #type}

There are different
[types of form controls](https://developer.mozilla.org/docs/Web/HTML/Element/input#input_types), all 
with useful built-in features that work across different browsers and platforms. Based on the `type` 
attribute, the browser renders different user interfaces, shows different on-screen keyboards, uses 
different validation rules, and more. Let's see how to change the type.

{% Codepen {
  user: 'web-dot-dev',
  id: '6a3705c993516bb294dbcddb084f0ba4',
  height: 300
} %}

By using `type="checkbox"` the browser now renders a checkbox instead of a text field.
The checkbox also comes with additional attributes.
You can set the `checked` attribute, to show it as checked.

{% Aside %}
The default value for `type` is `text`. This means that if you simply want a text `<input>`, you can 
leave out the `type` attribute.
{% endAside %}

There are various other [types](/learn/forms/fields) you can choose.
We have a detailed look in a later module.

## Allow multiple lines of text

Say, you need a field where a user can write a comment.
For this, wouldn't it be great if they can enter multiple lines of text?
This is the purpose of the `<textarea>` element.

```html
<label for="comment">Comment</label>
<textarea id="comment" name="comment"></textarea>
```

## Pick from a list of options

How do you give users a list of options to select from?
You can use a `<select>` element to achieve this.

{% Aside %}
If you want to enable text input with additional predefined options,
you can also use an `<input>` element together with the 
[datalist element](https://developer.mozilla.org/docs/Web/HTML/Element/datalist).
You can try out datalist examples [here](https://simpl.info/datalist/).
{% endAside %}

```html
<label for="color">Color</label>
<select id="color" name="color">
  <option value="orange">Orange</option>
  <option value="pink">Pink</option>
</select>
```

First, you add a `<select>` element.
As with all other form controls, you connect it to a `<label>` with the `id` attribute
and give it a unique name using the `name` attribute.

In between the start and end tag of the `<select>` element,
you can add multiple `<option>` elements, each representing one selection.

Each option has a unique `value` attribute, so you can tell them apart when processing the form data.
The text inside the option element is the human-readable value.

If you submit the form using this `<select>` without changing the selection,
the request will include `color=orange`. But how does the browser know which option should be used?

The browser uses the first option in the list, unless:
- One `<option>` element has the `selected` attribute.
- The user chooses another option.

{% Codepen {
  user: 'web-dot-dev',
  id: '7225931596b7eeafc448ad55d9c980fd',
  height: 300
} %}

## Pre-select an option

With the `selected` attribute you can pre-select one option.
This becomes the default, regardless of the order in which `<option>` elements are defined.

{% Codepen {
  user: 'web-dot-dev',
  id: '5324a9e3d1c3c695932ee95378b63436',
  height: 300,
  tab: 'html,result'
} %}

## Grouping form controls

Sometimes you need to group form controls. You can use the `<fieldset>` element to do that.

```html
<fieldset>
    <legend>What is your favorite web technology</legend>

    <label for="html">HTML</label>
    <input type="radio" name="webfeature" value="html" id="html">

    <label for="css">CSS</label>
    <input type="radio" name="webfeature" value="css" id="css">
</fieldset>
```
Did you notice the `<legend>` element inside the `<fieldset>` element? What do you think it is used for?

If your answer is "to describe the group of form controls", you're right!

Every `<fieldset>` element requires a `<legend>` element,
just as every form control needs an associated `<label>` element.
The `<legend>` also has to be the very first element in the `<fieldset>`.
After the `<legend>` element, you can define the form controls which should be part of the group.

## Submitting a form

After learning how to add form controls, and group them, you may wonder how a user can submit a form?

The first option is to use a `<button>` element.

```html
<button>Submit</button>
```

After a user clicks the **Submit** button,
the browser makes a request to the URL specified in the `<form>` element's
[action attribute](/learn/forms/form-element#where-is-the-data-processed)
with all data from the form controls.

{% Aside 'warning' %}
Every `<button>` element inside a form works as a **Submit** button by default.

Sometimes you don't want this: for example,
when using a `<button>` to toggle visibility for a password field.
To disable the default **Submit** behavior, you can add `type="button"` to the `<button>`.
This tells the browser that the `<button>` should not submit the form.
{% endAside %}

You can also use an `<input>` element with `type="submit"` instead of a `<button>` element.
The input looks and behaves just like a `<button>`. Instead of using a `<label>` element to describe 
the `<input>`, use the `value` attribute instead.

```html
<input type="submit" value="Submit">
```

In addition, a form can also be submitted by using the `Enter` key when a form field has focus. 

{% Assessment 'form-fields' %}

## Resources

- [The label element](https://developer.mozilla.org/docs/Web/HTML/Element/label)
- [The input element](https://developer.mozilla.org/docs/Web/HTML/Element/input)
- [The textarea element](https://developer.mozilla.org/docs/Web/HTML/Element/textarea)
- [The select element](https://developer.mozilla.org/docs/Web/HTML/Element/select)
- [The fieldset element](https://developer.mozilla.org/docs/Web/HTML/Element/fieldset)
- [The button element](https://developer.mozilla.org/docs/Web/HTML/Element/button)

# Identity

{% Aside 'warning' %}  
User account [authentication](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) 
is a complex issue in terms of privacy and security. 
To guarantee the safety of user accounts, it may be better to use a 
[third-party identity provider](/sign-up-form-best-practices/#federated-login), 
instead of building your own secure authentication system.

Learn more about 
[best practices for account authentication, and password management](https://cloud.google.com/blog/products/identity-security/account-authentication-and-password-management-best-practices).  
{% endAside %}

## Help users sign up

The sign-up form is often the first interaction with a form on your website. 
Good sign-up form design is critical, and a secure form is essential. 

{% Aside %}  
Only require sign-up if you really need to. 
If you only want to store information between navigations, 
consider [using client-side storage](/storage-for-the-web/). 
For checkout forms, add a guest checkout by default. 
You can ask new customers if they want to sign up after they've completed a purchase, 
or when they enter address details.  
{% endAside %}

Let's look at a sign-up form, and how you can help users sign up on your website.

{% Codepen {  
  user: 'web-dot-dev',  
  id: '42a33b97484873a214f8a945a3b55f71',  
  height: 450  
} %}

Keep the sign-up form minimal and only show the required form controls to create an account. 
Don't double up your form controls to help users get their account details right. 
Send a confirmation email instead.

### Help users fill in their account details

You can help users fill in their account details by using the appropriate `autocomplete` attribute. 
Use `autocomplete="email"` for the email field, and `autocomplete="new-password"` for a new-password field. 

Learn more about [autofilling input controls](/learn/forms/autofill).

{% Aside 'warning' %}  
Don't disallow pasting into password fields. 
It's annoying for users, encourages passwords that are memorable and less secure, 
and makes it harder for password managers to suggest and autofill a secure password.

Learn more about why you should always 
[allow pasting passwords](https://www.ncsc.gov.uk/blog-post/let-them-paste-passwords).  
{% endAside %}

You can also help users enter a secure password by offering a reveal-password `<button>`.  
Learn more about the [reveal-password pattern](/learn/forms/javascript#ensure-users-can-see-the-password-they-entered).

### Ensure your sign-up form is secure

Never store or transmit passwords in plain text. 
Make sure to [salt and hash](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#Use_a_cryptographically_strong_credential-specific_salt) 
passwords—and [don't try to invent your own hashing algorithm](https://www.schneier.com/blog/archives/2011/04/schneiers_law.html).

Offer [multi-factor authentication](https://cheatsheetseries.owasp.org/cheatsheets/Multifactor_Authentication_Cheat_Sheet.html), 
especially if you store personal or sensitive data. 
[SMS OTP best practices](/sms-otp-form) and 
[Enabling Strong Authentication with WebAuthn](https://developer.chrome.com/blog/webauthn/) 
explain how to implement multi-factor authentication.

Ensure users don't use compromised passwords. 
For example, use the API from [Have I Been Pwned](https://haveibeenpwned.com/API/) 
to detect compromised passwords, 
and suggest your users fill in a different new password, 
or warn them if their password becomes compromised.

## Help users sign in

Let's see how to build a sign-in form to ensure users can easily sign in to your website.

{% Codepen {  
  user: 'web-dot-dev',  
  id: '89610184f6c51990ab9484b593e1d951',  
  height: 500  
} %}

Make the location of sign-up and sign-in buttons obvious. 
Ensure your form is usable on touch devices:

-  The [tap target size](/accessible-tap-targets/) of buttons is at least 48px.
-  The `font-size` of your form elements is big enough (`20px` is about right on mobile).
-  There is enough space (`margin`) between form controls, and that inputs are large enough (use at least `padding: 15px` on mobile).

### Help users fill in their email and password

Help browsers and password managers autofill account details. 
Use `autocomplete="email"` for the email field, 
and `autocomplete="current-password"` for a current password field.

To help users manually fill in their account details, use `type="email"` 
for the email field to show the appropriate on-screen keyboard on mobile devices. 

Use the `required` attribute for your email and password field so you can warn of invalid values when the user submits the form. 
Consider using [real-time validation](/learn/forms/javascript#ensure-users-are-notified-about-errors-in-real-time) 
to help users correct invalid data as soon as they have entered it, rather than waiting for form 
submission.

### Ensure users can see the password they entered

The text you fill in for `<input type="password">` is obscured by default, 
to respect the privacy of users. 
Help users to enter their password, 
by showing a `<button>` to toggle the visibility of the entered text.

{% Codepen {  
  user: 'web-dot-dev',  
  id: 'bd8577c5380c436dba2788c7a2c8652a',  
  height: 300  
} %}

Learn more about 
[implementing a password-reveal `<button>`](/learn/forms/javascript/#ensure-users-can-see-the-password-they-entered).

## Ensure your sign-in and sign-up forms are usable

Test your sign-in and sign-up forms regularly with real people to make sure that authentication works as expected. 
Use analytics and [real user measurement (RUM)](/user-centric-performance-metrics/) to collect field data, 
and tools such as [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/) 
and [PageSpeed Insights](https://pagespeed.web.dev/) to run tests yourself. 
Learn more about [testing for usability](/learn/forms/usability-testing) and 
[gathering analytics data](/learn/forms/data).

Ensure your forms work in different browsers and on different platforms. 
Test your form on different screen sizes, using only your keyboard, 
or using a screen reader such as 
[VoiceOver](https://www.youtube.com/watch?v=5R-6WvAihms&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&index=6) on Mac or 
[NVDA](https://www.nvaccess.org/) on Windows.

## Help users change their account settings

Make sure that users can change every account setting, 
including email addresses, passwords, and usernames.

Make it transparent what data you are storing, 
and help users download all their personal data at any time. 
Ensure users can delete their account if that's what they want. 
Account management features such as these may be a legal requirement in some regions.

### Ensure users can update their passwords

Make it easy for users to update their password.

{% Codepen {  
  user: 'web-dot-dev',  
  id: 'dd3ac6198324f644774583c02bf0fbd8',  
  height: 450  
} %}

Ask users for the current password before changing it, 
and send an email about a password change with the option to revert and lock the account.  

Add the option to request a new password, 
and consider providing a [`.well-known` URL](/change-password-url/) for requesting a new password.

## Resources

-  [Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
-  [Understanding the root cause of account takeover](https://security.googleblog.com/2017/11/new-research-understanding-root-cause.html)
-  [Password security: Complexity vs. length](https://resources.infosecinstitute.com/topic/password-security-complexity-vs-length/)
-  [Sign-up form best practices](/sign-up-form-best-practices)
-  [Sign-in form best practices](/sign-in-form-best-practices)
-  [Effective password management | Session](https://www.youtube.com/watch?v=4Ve2kw_AN84)

# Internationalization and localization

If you're reading this, you're using the World Wide Web.
Your forms may be used by people speaking different languages,
people from different countries, and people with different cultural backgrounds.
Learn how to prepare your form for internationalization and localization.

## Ensure your form works in different languages

Let's see how you can make sure your form works with different languages.

The first step to make your site localization-ready is to define the language attribute `lang` on the `<html>` element.
This attribute enables screen readers to invoke the correct pronunciation,
and helps browsers offer a translation of the page if the defined language is not the default browser language.

```html
<html lang="en-us">
```

Learn more about the [`lang`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang) attribute.

Say you translated a form to German.
How can you make sure search engines and browsers know about the translated version?
You can add `<link>` elements in your site's  `<head>` describing the alternate versions.

```html
<link rel="alternate" title="The form element"
  href="https://example.com/en/form" hreflang="en">
<link rel="alternate" title="Das Formularelement"
  href="https://example.com/de/form" hreflang="de">
```

## Help users who speak another language to use your form

You can't translate your form into every language,
but you can ensure translation tools can translate it for you.

{% Aside %}
Try it out! Enter the URL of your form in
[Google Translate](https://translate.google.com),
choose a language, and translate it.
All visible content of your site will be translated.
This is a good test to see if every text is translatable.
{% endAside %}

To ensure translation tools translate all the text on your form,
make sure all text is defined in HTML and is visible.
Some tools also work with content defined in JavaScript, but to improve compatibility,
try to include as much text as possible in HTML.

{% Aside %}
Avoid using the `aria-label` attribute to describe elements.
Many translation tools aren't able to translate the `aria-label` attribute.

Learn more why `aria-label` [doesn't translate](https://adrianroselli.com/2019/11/aria-label-does-not-translate.html).
{% endAside %}

## Ensure your form works with different writing systems

Different languages use different writing systems and character sets.
Some scripts are written from left to right, and some from right to left.

### Make spacing independent of writing systems

To ensure your form works for different writing systems,
you can use [CSS logical properties](https://developer.mozilla.org/docs/Web/CSS/CSS_Logical_Properties).

{% Codepen {
  user: 'web-dot-dev',
  id: '043b19ee429ea0834022967e2207d6b9',
  height: 300
} %}

The input has a border thickness of `1px` on all sides,
except on the left side, where the border is `4px` thick.
Now, edit the [CodePen](https://codepen.io/web-dot-dev/pen/043b19ee429ea0834022967e2207d6b9) and change the writing system to right to left
by adding `dir="rtl"` to the `<main>` element

{% Aside %}
The `dir` attribute indicates the direction of an element's text.
If the complete site uses the same writing system,
define the `dir` attribute on the `<html>` element.
In CodePen you don't have access to the `<html>` element,
which is why you need to add it to `<main>`.

You can also use the CSS `direction` property to achieve the same result.
{% endAside %}

The thick border is now on the right side.
That's because we defined the border using a logical property.

```css
input {
  border-inline-start-width: 4px;
}
```

Learn more about [logical properties](/learn/css/logical-properties/).

## Ensure your form can handle different name formats

Say you have a form where the user should fill in their name.
How would you add the field to your form?

You could add one field for the first name and one for the surname. However, names are different
around the world: for example, some people don't have a surname—so how should they fill in the
surname field?

To make it quick and easy to enter names—and to ensure everybody can enter their name, whatever the
format—use a single form field for names wherever possible.

Learn more about [personal names](https://www.w3.org/International/questions/qa-personal-names).

If you have a name with [non-Latin characters](/payment-and-address-form-best-practices/#unicode-matching),
you may have encountered the issue that your name is reported as `invalid` in some forms. When you
build forms, make sure to allow all possible characters—and do not assume that a name only consists
of Latin characters.

## Allow a variety of address formats

The headquarters of Google is at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.

This address includes the street number, street, city, state, postal code, and country.
In your country, the address format may be totally different.
How can you ensure everybody can enter their address in your form?

One way is to use generic inputs.

{% Codepen {
  user: 'web-dot-dev',
  id: '4d4096f67fe84bc2a8c7640974a0fb21',
  height: 700
} %}

Learn more about other ways to work with
[international address fields](https://www.uxmatters.com/mt/archives/2008/06/international-address-fields-in-web-forms.php).

{% Assessment 'internationalization' %}

## Resources

- [W3C Internationalization articles and tutorials](https://www.w3.org/International/articlelist)
- [Frank's Compulsive Guide to Postal Addresses](http://www.columbia.edu/~fdc/postal/) provides useful links and extensive guidance for address formats in over 200 countries.
- [DataHub.io](https://datahub.io/core/country-list) is a tool for downloading country codes and names.

# JavaScript

You can use JavaScript to respond to user interactions on your form, reveal additional form fields, submit a form, and much more.

### Help users fill in additional form controls

Imagine that you built a survey form. After a user selects one option,
you want to show an additional `<input>` to ask a specific question related to the selection.
How can you only show the relevant `<input>` element?

{% Codepen {
  user: 'web-dot-dev',
  id: '8e1e7a38790c75c267a978efa1d8e937',
  height: 350
} %}

You can use JavaScript to reveal an `<input>` only when the associated `<input type="radio">` is currently selected.

```js
if (event.target.checked) {
    // show additional field
} else {
   // hide additional field
}
```

{% Aside 'caution' %}
Make sure your form is still usable
[if JavaScript isn't available](https://kryogenix.org/code/browser/everyonehasjs.html).
The core experience should be the same for all users, with JavaScript used only as an enhancement.
{% endAside %}

Let's look at the
[JavaScript code](https://codepen.io/web-dot-dev/pen/8e1e7a38790c75c267a978efa1d8e937?editors=0010) for the demo.
Have you noticed the `aria-controls`, and `aria-expanded` attributes?
Use these
[ARIA attributes](https://developer.mozilla.org/docs/Web/Accessibility/ARIA)
to help screen reader users understand when an additional form control is shown or hidden.

{% Aside 'caution' %}
The `aria-expanded` attribute for `<input type="radio">` isn't
[correctly announced by every screen reader](https://accessibility.blog.gov.uk/2021/09/21/an-update-on-the-accessibility-of-conditionally-revealed-questions/).
{% endAside %}

### Ensure users can submit a form without leaving a page

Imagine you have a comment form. When a reader adds a comment and submits the form,
it would be ideal if they could immediately see the comment without a page refresh.

To achieve this, listen to the `onsubmit` event, then use `event.preventDefault()` to prevent the default behavior,
and send the `FormData` using the [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API).
{% BrowserCompat 'api.fetch' %}

{% Aside %}
`FormData` is a set of key/value pairs representing form fields and their values.
You can add all your form fields to the `FormData` object, or only send some form fields and their values.
{% endAside %}

{% Codepen {
  user: 'web-dot-dev',
  id: 'b499a861d7b1fee74464a690cf0ff97e',
  height: 400,
  tab: 'js,result'
} %}

Your backend script can check if a `POST` request appears to be from the browser
(using the `action` attribute of a form element, where `method="post"`) or from JavaScript,
such as a `fetch()` request.

```js
if (req.xhr || req.headers.accept.indexOf('json') !== -1) {
    // return JSON
} else {
    // return HTML
}
```

Always notify screen reader users about dynamic content changes.
Add an element with the `aria-live="polite"` attribute to your HTML,
and update the content of the element after a change.
For example, update the text to 'Your comment was successfully posted', after a user submits a comment.

Learn more about [ARIA live regions](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/ARIA_Live_Regions).

## Validation with JavaScript

### Ensure error messages align with your site style and tone

The wording of default error messages differs between browsers.
How can you make sure the same message is shown to all users,
and that the message aligns with your site's [style and tone](https://developers.google.com/style/tone)?
Use the [`setCustomValidity()`](https://developer.mozilla.org/docs/Web/API/HTMLObjectElement/setCustomValidity)
method of the [Constraint Validation API](https://developer.mozilla.org/docs/Web/API/Constraint_validation)
to define your own error messages.

{% Codepen {
  user: 'web-dot-dev',
  id: '7ea31257d7cd8fc28792c7f5cdaba97b',
  height: 300,
  tab: 'js,result'
} %}

{% Aside %}
Make sure to translate and localize your error messages if you have a multi-language website.
{% endAside %}

### Ensure users are notified about errors in real time

The built-in HTML features for form validation are great for notifying users
about invalid form fields before the data is sent to your backend.
Wouldn't it be great to notify users as soon as they leave a form field?

{% Codepen {
  user: 'web-dot-dev',
  id: 'b7ed22a0539f9beef4dc03380f51f224',
  height: 300,
  tab: 'js,result'
} %}

Listen for the
[`blur`](https://developer.mozilla.org/docs/Web/API/Element/blur_event)
event which fires when an element loses focus, and use the
[`ValidityState`](https://developer.mozilla.org/docs/Web/API/ValidityState) interface to detect if a form control is invalid.

### Ensure users can see the password they entered

The text entered for `<input type="password">` is obscured by default,
to respect the privacy of users.
Help users to enter their password, by showing a `<button>` to toggle the visibility of the entered text.

{% Codepen {
  user: 'web-dot-dev',
  id: 'bd8577c5380c436dba2788c7a2c8652a',
  height: 300
} %}

[Try out the demo](https://codepen.io/web-dot-dev/pen/bd8577c5380c436dba2788c7a2c8652a). Toggle the
visibility of the entered text, by using the **Show Password** `<button>`.
How does this work? Clicking on **Show Password**,
changes the `type` attribute of the password field from `type="password"` to `type="text"`,
and the `<button>` text changes to 'Hide Password'.

{% Aside 'codelab' %}
[Try to improve the **Show Password** `<button>`](https://codepen.io/web-dot-dev/pen/bd8577c5380c436dba2788c7a2c8652a).
Where would you position the `<button>`?
Could you use only an icon and still make sure the `<button>` is accessible?
{% endAside %}

It's important to make the **Show Password** button accessible.
Connect the `<button>` with the `<input type="password">` using the `aria-controls` attribute.

{% Aside 'caution' %}
The `aria-controls` attribute is not supported by every screen reader,
but for those that do support it, it's a great enhancement.
{% endAside %}

To notify screen reader users if the password is currently shown or hidden,
use a hidden element with `aria-live="polite"`, and change its text accordingly.
It's important to enable screen reader users to know when a password is displayed and visible to someone else looking at their screen.

```html
<span class="visually-hidden" aria-live="polite">
    <!-- Dynamically change this text with JavaScript -->
</span>
```

{% Aside %}
Microsoft Edge shows a built-in password reveal control for `<input type="password">`. To prevent having two reveal buttons, hide the built-in control with:

```css
::-ms-reveal {
  display: none
}
```

Learn more about [customizing the password reveal button](https://docs.microsoft.com/en-us/microsoft-edge/web-platform/password-reveal).
{% endAside %}

Learn more about [implementing a show password option](https://technology.blog.gov.uk/2021/04/19/simple-things-are-complicated-making-a-show-password-option/).

## Resources

- [FormData](https://developer.mozilla.org/docs/Web/API/FormData)
- [Constraint Validation API](https://developer.mozilla.org/docs/Web/API/Constraint_validation)
- [`<input type="password">`](https://developer.mozilla.org/docs/Web/HTML/Element/input/password)

# Payment forms

{% Aside %}  
This module is about payment forms and doesn't explain how to implement transactions on your site. 
You can add payment functionality by implementing [Web Payments](/payments/), 
or using a third-party payment platform.  
{% endAside %}

The payment form is often the last step before completing a purchase. 
To maximize conversions, ensure your payment form is user-friendly and secure.

{% Codepen {  
  user: 'web-dot-dev',  
  id: '0f0da240784a36da7fa958018af29f3f',  
  height: 500  
} %}

## Ensure users know what to fill in

Keep your payment form as simple as possible, 
showing only required fields.

{% Aside %}  
You don't need to add a selector for the card type—that's worked out automatically by the payment processor from the card number. 
However, you may want to enhance your card number field by indicating the card type based on the entered number. 
You can use a [regex](https://gist.github.com/michaelkeevildown/9096cd3aac9029c4e6e05588448a8841) to test the card type, 
and show the brand logo next to the card number `<input>`.  
{% endAside %}

Indicate the payment amount. 
The **Submit** button is ideal for that.

```html  
<button>Pay $300.00</button>  
```

Use self-explanatory wordings for your `<label>` elements. 
For example, use 'Security code', 
instead of an acronym like 'CVV' that's only used by some brands.

{% Aside %}  
Use a single `<input>` for each of the name and card number fields. Keep the user in typing mode, 
and don't waste their time by forcing them to jump between multiple name or card number fields.  
{% endAside %}

## Help users enter their payment details

To maximize conversions, ensure users can fill out your payment form as quickly as possible.

Use `inputmode="numeric"` for the card number and security code fields 
to show an optimized on-screen keyboard for entering numbers.

{% Aside 'caution' %}  
Use `type="number"` only for incremental fields, 
for example, the quantity of a product. 
Browsers show an up/down arrow for `type="number"` 
which makes no sense for payment card numbers.   
{% endAside %}

Add appropriate `autocomplete` values for your payment form controls to ensure browsers offer autofill. 
Use `autocomplete="cc-name"` for the name, 
`autocomplete="cc-number"` for the card number, and `autocomplete="cc-exp"` for the expiry date.

{% Aside %}  
You can help users fill in the correct format for expiry date by using an 
[input mask](https://css-tricks.com/input-masking/). 
Test with real users, using only your keyboard, 
and a screen reader such as [VoiceOver](https://www.youtube.com/watch?v=5R-6WvAihms&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&index=6) 
on Mac or [NVDA](https://www.nvaccess.org/) on Windows to ensure the input is still accessible.  
{% endAside %}

## Ensure users enter data in the correct format

Use the `required` attribute for every `<input>` to ensure users fill out the complete form. 

Payment card security codes can be three or four digits. 
Use `minlength="3"` and `maxlength="4"` to only allow three and four digits.

Ensure users only enter numbers for the card number and security code. 
Use `pattern="[0-9 ]+"` to allow users to include spaces when entering a card number, 
since this is how the numbers are displayed on the physical cards. 

{% Aside %}  
Payment card brands use different formats, 
for example, for card numbers and security codes. 
Always test your payment form with every card type you support. 
Ensure your validation rules consider every possible format.  
{% endAside %}

## Resources

-  [Payment and address forms best practices](/payment-and-address-form-best-practices).
-  [Web Payments](/payments/).

# Security and privacy

When you create a form, you work with user data.
Your number one concern should be to ensure that user data is kept private and transferred securely.
Let's have a look at what can be done.

{% Aside %}
A secure form means that all data is encrypted, kept secure, and no unauthorized access can happen.

To ensure privacy, only save the data you need,
only save personal data after consent, ensure the user is in full control of their data,
and never share user data with others without the user's consent.
{% endAside %}

## Ensure your form is secure

As a first step, make sure to request as little data as possible.
Don't ask for data you don't need,
and always question whether you need all of the requested data.
Less data means less risk, less cost, and less liability.
In addition, reducing the number of fields in a form makes it less complex,
easier to fill out, and can reduce abandonment rates.

[Always use HTTPS](/secure/#secure-connections-with-https),
especially for pages that include a form.
With HTTPS, data is encrypted when coming from the server and when going back to the server.

Say you're sitting in a café using public Wi-Fi.
You open an e-commerce site and fill in your credit card information to purchase something.
If the website uses HTTP, anyone (with the skills to do so)
on the same public Wi-Fi could see your credit card information.
If the website uses HTTPS, the data is encrypted and therefore protected from anyone trying to access it.

On your site, you should also make sure to redirect any HTTP requests to HTTPS.
Learn more about
[how to redirect all traffic to HTTPS](https://geekflare.com/http-to-https-redirection/).

## Help users to keep their data private

In the [first module](/learn/forms/form-element), you learned about two possible ways to transfer data:
using a `GET` request and using a `POST` request.

With a `GET` request, form data is included as a [query string](https://en.wikipedia.org/wiki/Query_string)
in the request URL. If you submit a form that uses a `GET` request,
the browser adds the request URL including form data to your browsing history.
Convenient if you want to look up past form submissions,
for example for a search form. Not great at all,
if sensitive data is submitted,
and everybody with access to your browser history or local network can see this information.

Use `POST` requests for every form where data that's personal or otherwise sensitive may be submitted.
This way, the data is only visible to the backend script processing it.

What about saving and processing personal data directly in the browser?
You could use client storage, for example, `localStorage` to store personal data in the browser.
With regard to privacy, this is less than ideal.
Again, everyone with access to your browser is able to read this information.
You should only store encrypted values for personal data.

## Ensure users can safely sign up and sign in

User account [authentication](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
is a complex issue in terms of privacy and security.
It may be better to use a
[third-party identity provider](/sign-up-form-best-practices/#federated-login),
instead of building your own secure authentication system.

Learn more about
[best practices for account authentication, and password management](https://cloud.google.com/blog/products/identity-security/account-authentication-and-password-management-best-practices).

{% Aside %}
If you do choose to build your own authentication system, make sure to follow best practice for password management:

- Never store or transmit passwords in plain text.
Make sure to salt and hash passwords—and
[don't try to invent your own hashing algorithm](https://www.schneier.com/blog/archives/2011/04/schneiers_law.html).
- Ensure users enter [secure passwords](https://pages.nist.gov/800-63-3/sp800-63b.html#5-authenticator-and-verifier-requirements).
- Don't allow [compromised passwords](/sign-up-form-best-practices/#no-compromised-passwords).
- Don't force [password updates](/sign-up-form-best-practices/#no-forced-password-updates).
- Make it simple for users to change or reset passwords.
{% endAside %}

## Help users access their personal data

Many regions have laws and regulations regarding data protection and privacy,
including the
[CCPA](https://en.wikipedia.org/wiki/California_Consumer_Privacy_Act) in California and the
[PDPA](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3244203) in India.
Every website available in the European Union (EU) has to follow
[General Data Protection Regulation](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) (GDPR),
even if the site is not based in the EU.

GDPR sets guidelines for the collection and processing of personal information from people living in the EU.
Consent is required to process personal data,
users can request personal information that you store at any time,
and you have to officially announce data leaks.
A good thing for the user, as this helps to ensure that their privacy is respected. Learn more about
[GDPR](https://www.smashingmagazine.com/2018/02/gdpr-for-web-developers/).

Make sure your users know how you plan to process personal data.
Transparency is the key to trust.
Users should always be able to access, modify,
and delete all data you saved for them.

## Ensure users can update their personal data

Make it easy for users to update their personal data, including passwords,
email addresses, and usernames. Notify users about changes to their stored personal data,
and ensure users can revoke changes.
For example, send an email to the previous and new email address after users change their email address.

{% Aside %}
Separate the concept of user account and user identity to simplify implementing third-party identity provision.
Allow users to change their username and link multiple identities to a single user account,
for example if they sign up with an email and password, then sign up with a third-party identity provider.
{% endAside %}

Make it easy for users to delete their account, including all associated data,
and where relevant, make it possible to download data.
Account deletion is a
[legal requirement](https://ec.europa.eu/info/law/law-topic/data-protection_en) in some regions.

{% Aside %}
Link to your privacy policy on each page with a form,
especially if personal data is processed.
{% endAside %}

Require an additional authentication step,
for example, re-entering the current password,
to view or change personal information on your site.

Find out more:
[Web Application Privacy Best Practices](https://www.w3.org/TR/app-privacy-bp/).

## Ensure all data is in good shape

In a previous module, you learned about [validation on the frontend](/learn/forms/validation).
Frontend validation is important, but users might still be able to submit invalid data. As a next
step, you must also validate the data [on the backend](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html)
before saving the data in your database. This ensures that no invalid data is saved in your database.

Validation helps to ensure that the data format is valid,
but you should still not trust data entered by users.
How can you safely output the data? To prevent
[Cross Site Scripting](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) (XSS),
and ensure all data is safe to include in HTML, you must sanitize data before output.

Learn more about [sanitizing data before output](https://benhoyt.com/writings/dont-sanitize-do-escape/)
and, where possible, use the [Sanitizer API](/sanitizer/).

## Ensure all submissions come from real people

To help protect your data, you have various options to prevent spam submissions from
[bots](https://en.wikipedia.org/wiki/Internet_bot#Malicious_bots).

The first option is to use a service such as
[reCAPTCHA](https://www.google.com/recaptcha/about/),
to distinguish between real people and bots.
This requires you to include a JavaScript snippet on your page,
and add extra attributes to your **Submit** button.

reCAPTCHA performs various checks to find out if you are a human.
For example, it may ask you to identify images.
Automated software, such as a bot, cannot accomplish these challenges and can't submit the form.

{% Aside %}
Always make sure your spam protections are accessible.
Try them out by using a screen reader, and by only using your keyboard.
The best spam protection is useless if it makes the form unusable for real people.
{% endAside %}

### A honeypot

{% Codepen {
  user: 'web-dot-dev',
  id: 'c8e82763c4ce344eb23dfd3ef621b662',
  height: 400,
  tab: 'html,result'
} %}

Another option is to use a so-called 'honeypot': a visually hidden form field.
Humans won't see a honeypot field, but bots will fill it in.
On the backend, your processing script can check if the field was completed.
If it was, the submission was probably from a bot, and you can ignore it.

There are also services like
[Akismet](https://akismet.com), which can help you with spam protection.
The Akismet filter works by combining information about spam captured on all participating sites,
and then using those spam rules to block future spam.
Akismet is transparent to the user, and catches most spam.

{% Assessment 'security-privacy' %}

## Resources

- [Digital Identity Guidelines](https://pages.nist.gov/800-63-3/sp800-63b.html)
- [Database Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Database_Security_Cheat_Sheet.html)

# Styling forms

To ensure that your form is accessible to as many people as possible, use the elements built for the 
job: `<input>`, `<textarea>`, `<select>`, and `<button>`. This is the baseline for a usable form.

{% Codepen {
  user: 'web-dot-dev',
  id: '9d0576454b3b2d0fc001addab70d25bc',
  height: 250
} %}

The default browser styles don't look great! Let's change that.

{% Aside %}
Progressive enhancement is a strategy that provides a baseline of essential content and features for as many users as possible. 
It ensures the best possible experience for users on modern browsers.

You start with content, use 
[semantic HTML](https://developer.mozilla.org/docs/Glossary/Semantics#semantics_in_html), 
add future-proof CSS, and add robust JavaScript as a last step.
{% endAside %}

## Ensure form controls are readable for everyone

The default font size for form controls in most browsers is too small. 
To ensure your form controls are readable, change the font size with CSS:

{% Codepen {
  user: 'web-dot-dev',
  id: '477f5e58a406c6f86bfbfc9da1f18a69',
  height: 300
} %}

Increase the `font-size` and `line-height` to improve readability.

```css
.form-element {
  font-size: 1.3rem;
  line-height: 1.2;
}
``` 

{% Aside %}
For `font-size` use relative units such as `em` (relative to the base size of the element's parent) 
or `rem` (relative to the base size of the document) to ensure that size responds to user preference. 
Users can change the base `font-size` and all elements with a relative `font-size` will adjust 
automatically. For `line-height` use a [unitless value](https://meyerweb.com/eric/thoughts/2006/02/08/unitless-line-heights/) 
such as `1.5`, to keep the line height relative to the font size.

Learn more about 
[pixels vs. relative units in CSS](https://www.24a11y.com/2019/pixels-vs-relative-units-in-css-why-its-still-a-big-deal/).
{% endAside %}

## Help users navigate through your form

As a next step, change the layout of your form, and increase the spacing of form elements, 
to help users understand which elements belong together.

{% Codepen {
  user: 'web-dot-dev',
  id: 'f2aca03916816074010e896f064f456a',
  height: 450
} %}

The `margin` CSS property increases space between elements, 
and the `padding` property increases space around the element's content.

For the general layout, use [Flexbox](/learn/css/flexbox/) or [Grid](/learn/css/grid/). 
Learn more about [CSS layout methods](/learn/css/layout/).

## Ensure form controls look like form controls

Make it easy for people to fill out your form by using well-understood styles for your form controls. 
For example, style `<input>` elements with a solid border. 

{% Aside %}
The default `<input>` border color is too light in many browsers. 
The lack of contrast can make the element hard to see, especially on mobile. 
[Open this demo](https://codepen.io/web-dot-dev/pen/9d0576454b3b2d0fc001addab70d25bc) in Chrome on Android to see the default styles.
{% endAside %}

{% Codepen {
  user: 'web-dot-dev',
  id: 'd0740e968b5c72a0cf180359e80f5efc',
  height: 500
} %}


```css
input,
textarea {
  border: 1px solid;
}
```

## Help users submit your form

Consider using a `background` for your `<button>` to match your site style, 
and override or remove the default `border` styles.

{% Codepen {
  user: 'web-dot-dev',
  id: 'f0052d40806fd750362fa0abaab01dcf',
  height: 500
} %}

{% Aside %}
In modern browsers, you can style a `<button>` like any other element, 
so you should always use a semantic `<button>`, or `<input type="submit">`. 
Using the element built for the job provides many built-in usability and accessibility 
benefits that you won't get when using a generic element such as a `<div>`. 
You'll learn about the built-in features in other modules.

Learn more about 
[reverting the default style of a `<button>`](https://archive.hankchizljaw.com/wrote/introducing-the-button-element/#heading-oh-these-are-hard-to-style-though).
{% endAside %}

## Help users understand the current state

Browsers apply a default style for `:focus`. 
You can override the styles for `:focus` to match the color to your brand. 

```css
button:focus {
    outline: 4px solid green;
}
```

{% Aside %}
Only remove the `outline` on `:focus` if you also add other appropriate focus styles, 
to ensure that  default and focus styles are distinguishable.

Learn more about 
[designing focus indicators](https://www.sarasoueidan.com/blog/focus-indicators/).
{% endAside %}

{% Assessment 'styling' %}

## Resources

- [Learn CSS](/learn/css)
- [CSS layout methods](/learn/css/layout)
- [Designing focus indicators](https://www.sarasoueidan.com/blog/focus-indicators/)
- [Reverting the default style of a `<button>`](https://archive.hankchizljaw.com/wrote/introducing-the-button-element/#heading-oh-these-are-hard-to-style-though).

# Styling form controls

In this module you learn how to style form controls, and how to match your other site styles. 

{% Aside 'caution' %}
Styling HTML form controls can be a challenge, 
but you should still use built-in elements wherever possible. 
Elements such as `<input>` and `<button>` are widely supported across browsers and platforms, 
and have built-in features that enhance usability and accessibility, 
which you don't need to implement yourself. Using a `<div>` instead doesn't provide these benefits. 
{% endAside %}

## Help users select an option

### The `<select>` element

The default styles of a `<select>` element don't look great, and the appearance is inconsistent between browsers. 

{% Codepen {
  user: 'web-dot-dev',
  id: 'eea33ada7ec976aa5791a5cd14756c34',
  height: 300
} %}

{% Aside %}
You can also use an `<input>` in combination with the 
[`<datalist>`](https://developer.mozilla.org/docs/Web/HTML/Element/datalist) element. 
This gives you a combination of a text field and a list of `<option>` elements. 
You can see examples of [`<datalist>`](http://simpl.info/datalist) here.
{% endAside %}

First, let's change the arrows. 

```css
select {
    -moz-appearance: none;
    -webkit-appearance: none;
    appearance: none;
    background-color: #fff;
    background-image: url(arrow.png);
    background-repeat: no-repeat;
    background-position: right .7em top 50%, 0 0;
    background-size: .65em auto;
}
```

To remove the default arrows of a `<select>` element, 
use the CSS [`appearance`](https://developer.mozilla.org/docs/Web/CSS/appearance) property. 
To show the arrow of your choice, define the arrow as a `background`.

{% Aside %}
To ensure the best cross-browser compatibility, 
you must also include the prefixed versions of `appearance`: `-moz-appearance` and `-webkit-appearance`. 

[Learn more about vendor prefixes](https://developer.mozilla.org/docs/Glossary/Vendor_Prefix#css_prefixes).
{% endAside %}

You should also change the `font-size` to at least `1rem` 
(which for most browsers has a default value of 16px) for your `<select>` element. 
Doing so will prevent a page zoom on iOS Safari when the form control is focused.

You can, of course, also change the element colors to match your brand colors. 
After adding some more styles for spacing, `:hover`, and `:focus`, 
the appearance of the `<select>` element is now consistent between browsers. 

See this in the following demo from 
[Styling a Select Like It’s 2019](https://www.filamentgroup.com/lab/select-css.html)

{% Codepen {
  user: 'web-dot-dev',
  id: '2f6101907a292463bccd8d7a72d09554',
  height: 300
} %}

What about the `<option>` element? The `<option>` element is a so-called 
[replaced element](https://developer.mozilla.org/docs/Web/CSS/Replaced_element) whose representation is outside the scope of CSS. 
As of this writing, you can't style the `<option>` element.

{% Aside %}
There is an ongoing proposal to allow web developers to style and extend built-in web UI controls, 
including `<select>` and `<option>` elements. This would make it easier to style form controls in the future.

Learn more about [Open UI](https://open-ui.org).
{% endAside %}

### Checkboxes and Radio buttons

The appearance of `<input type="checkbox">` and `<input type="radio">` varies across browsers. 

{% Codepen {
  user: 'web-dot-dev',
  id: '74d28931d0c0e9aacc89f62380f365e4',
  height: 400
} %}

Open the [demo](https://codepen.io/web-dot-dev/pen/74d28931d0c0e9aacc89f62380f365e4) on various browsers to see the difference. 
Let's see how to make sure that checkboxes and radio buttons match your brand and look the same cross-browser.

In the past, developers could not style `<input type="checkbox">` and `<input type="radio">` controls directly. 
[Checkboxes and radio buttons can be styled via their pseudo elements](https://www.scottohara.me/blog/2021/09/24/custom-radio-checkbox-again.html), now.
Or the following replacement technique can be used to create custom styles for these elements.

First, hide the default checkbox and radio button visually.

```css
input[type="radio"],
input[type="checkbox"] {
   position: absolute;
   opacity: 0;
}
```

It's important to use `position: absolute` in combination with `opacity: 0` instead of `display: none` or `visibility: hidden` 
so that the controls are only visually hidden. This will ensure they are still exposed by the browser's 
[accessibility tree](/the-accessibility-tree/). Note that further styling may be needed to ensure that the visually hidden
form controls remain positioned "on top" of their replacement elements. Doing so will help ensure that hovering over one of these
elements, when a screen reader is on, or when using touch devices with screen readers enabled, the visually hidden controls will
be discoverable if exploring by touch, and the screen reader's visible focus indicator will generally appear in the location the controls
are rendered on screen.

To show your custom checkboxes and radio buttons, you have different options. 
You use the `::before` CSS pseudo-element and the CSS `background` property, or use inline SVG images. 

```css
input[type="radio"] + label::before {
  content: "";
  width: 1em;
  height: 1em;
  border: 1px solid black;
  display: inline-block;
  border-radius: 50%;
  margin-inline-end: 0.5em;
}

input[type="radio"]:checked + label::before {
  background: black;
}
```

{% Aside %}
Styled form controls must be easy to understand and use. People are used to a checkbox that looks 
like a checkbox, so make sure when you style a form control that users still understand how to use it. 
{% endAside %}

There are a lot of possibilities with CSS to ensure checkboxes and radio buttons match your brand styles.

{% Codepen {
  user: 'web-dot-dev',
  id: '433b6d50b9d7d706e31ee5a638790c3d',
  height: 400
} %}

Learn more about 
[styling `<input type="checkbox">`, and `<input type="radio">`](https://www.sarasoueidan.com/blog/inclusively-hiding-and-styling-checkboxes-and-radio-buttons/) 
and [custom checkbox styles](https://moderncss.dev/pure-css-custom-checkbox-style/).

## How to use your site's colors for form controls

Do you want to bring your site styles to form controls with one line of code? 
You can use the [`accent-color`](/accent-color/) CSS property to achieve this.

```css
checkbox {
  accent-color: orange;
}
```

{% Aside %}
As of this writing, only Chrome, Firefox and Edge support `accent-color`. 
To ensure cross-browser compatibility, 
you might want to use workarounds until `accent-color` is supported in all platforms.
{% endAside %}

{% Assessment 'styling-form-controls' %}

## Resources

- [Accent color](/accent-color/)
- [Styling the `<select>` element](https://www.filamentgroup.com/lab/select-css.html)
- [The Accessibility of Styled Form Controls](https://scottaohara.github.io/a11y_styled_form_controls/)
- [Open UI](https://open-ui.org)

# Test your forms

In previous modules, you learned how to build a form,
help users avoid re-entering data,
and how to validate form data.
How can you now make sure the form is usable?
You can test and analyze your form to answer this question.

## Does your form work on other devices?

You begin by confirming that your form is working on your own device.
However, there are many types of devices your users may use.
How can you test if your form works with other devices?

First, test your form on a desktop device.
Then try only using your keyboard.
Next, test it on a phone.
You have now tested your form with different input methods (keyboard, touch, and mouse),
different screen sizes,
different browsers and different operating systems.

Do you have more devices you can test on? Test your form on all of them.
The more different devices, browsers, browser versions, and operating systems you can test on, the better!

You can also use a test service to test your form on lots of different browsers,
different browser versions, different devices, and different operating systems.
[BrowserStack](https://www.browserstack.com) offers free test accounts for open source projects,
to enable testing on different browsers, devices and operating systems.

## How can you test if your form works for others?

Your first form is ready. You spend a lot of time making sure it works well.
How can you confirm that your form is usable for everybody else?
As a first step, you can ask your friends and colleagues to fill out your form.

Sit next to each other or share a screen.
This way, you can see how they interact with your form. Watch them fill out the form.
Ask them to say out loud what they're doing and if they're experiencing any problems.
After they complete the task, ask them questions.
Was it clear what they should fill out?
Did they have any issues filling out the form?
Was anything unclear?
These questions help you build even better forms.

{% Aside %}
People from all over the world will use your form.
Do you have an address field in your form?
Google a city you always wanted to visit, and search for a restaurant there.
Now enter the address of the restaurant in your address field.
The format of the address may be totally different from the address format where you live.
Test with different data to ensure your form can handle diverse formats.
{% endAside %}

## How can you measure how your form performs?

You confirmed that your form is usable for other people.
As a next step, you should measure how your form performs.
There are free tools available for this. Let's have a look at some of them.

{% Aside %}
You should always measure before and after you change your form.
This way, you can compare the results, measure the impact of your change, and demonstrate improvements.
{% endAside %}

### PageSpeed Insights (PSI)

PSI measures the performance of your site and gives you hints on how to improve it.

[Try it out](https://pagespeed.web.dev/):
PageSpeed provides a performance report using
[lab and field data](https://developers.google.com/speed/docs/insights/v5/about/).
A fast site is the first sign that your form is usable.
Your site isn't fast yet? PSI shows you recommendations on how to improve performance.

Look again at the report of your site you tested before with PSI.
See the information about [Core Web Vitals](/vitals/) (CWV)?
This is a summary if your site fulfills the CWV criteria.
CWV helps you understand how users experience a web page.

### Lighthouse

Lighthouse helps you identify performance,
search engine optimization (SEO),
best practice, and accessibility issues.

There are different ways to use
[Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/).
One option is to run it directly in
[DevTools](https://developer.chrome.com/docs/lighthouse/overview/#devtools).
Open the URL with your form in Chrome,
[open DevTools](https://developer.chrome.com/docs/devtools/shortcuts/#open),
switch to the Lighthouse tab, and run the audit.

The performance metrics from PSI are displayed.
In addition, Lighthouse checks your site against SEO, best practice, and accessibility issues.
Forgot to connect a label to a form control?
Lighthouse warns you and provides you with a guide to correct the issue.

### Tools to identify common issues

There are many tools to identify common issues.
One way is to use the
[Form troubleshooter extension](https://chrome.google.com/webstore/detail/form-troubleshooter/lpjhcgjbicfdoijennopbjooigfipfjh).
It warns you about missing `autocomplete` attributes,
non-standard attributes, missing or empty labels, and more.

You can also use an accessibility evaluation tool like
[WAVE](https://wave.webaim.org) or
[axe](https://www.deque.com/axe/). These tools notify you about missing labels,
missing connections between labels and form controls, insufficient color contrasts,
and many more accessibility issues.

{% Aside %}
All these tools help you find common issues,
but they aren't able to detect all issues.
Always test your forms manually and with real people.
{% endAside %}

## How can you monitor form experience?

Monitoring real user experience of your forms helps you identify new issues quickly.
Let's see how you can monitor your form.

{% Aside %}
Lab data is measured with a controlled test under ideal conditions.
Field data comes from real people.
With field data, you get metrics for real usage in real-world conditions.

People use different browsers, operating systems, screen resolutions, and connection speeds.
They use different devices. With field data, you collect metrics from a variety of different conditions.

Learn more about
[why lab and field data can be different](/lab-and-field-data-differences/).
{% endAside %}

### PSI

One way to monitor experience is to use PSI again.
You can use the
[PSI API](https://developers.google.com/speed/docs/insights/v5/get-started)
to build your own monitoring tool:
[The PageSpeed Insights API](https://addyosmani.com/blog/pagespeed-insights-api/)
explains how to do this.

PSI includes data from the
[Chrome User Experience Report](https://developer.chrome.com/docs/crux/) (CrUX) dataset,
if available for the given URL.
This way, you can also see field data directly in the report.

### Lighthouse

Lighthouse can be used as a command line tool,
as a [Node module](https://www.npmjs.com/package/lighthouse),
or with the [Lighthouse CI tools](https://github.com/GoogleChrome/lighthouse-ci).
[Performance monitoring with the Lighthouse CI](/lighthouse-ci/)
explains adding Lighthouse to a continuous integration system, such as GitHub Actions.

There are many more
[tools](/vitals-tools-workflow/) available to measure and monitor your site.
Some are available as web tools, some let you run the audit on your command line,
and some offer an API to integrate them into your tools.

## How to analyze your form

You tested your form with real users, and learned how to measure and monitor it.
How can you collect statistics about your users and how they interact with your form?
You can use an analytics tool. Let's have a look at one and how this works.

### Analytics

One tool you can use is
[Google Analytics](https://developers.google.com/analytics) (GA).
After setting it up, you get a JavaScript snippet you include in each page on your site.
From this point on, you can find out how people use your site.

How many people visit the page with your form on it?
How many fill out the form and move to the next page?
You get answers to these questions by using analytics tools.

{% Aside %}
Monitoring the real-world experience of your users is sometimes called Real User Monitoring
(RUM).

RUM collects performance metrics directly from the end user's browser.
RUM data shows you how your site performs, and how real users interact with it.
{% endAside %}

You can also set up more advanced analytics reports.
Want to track how many users click the **Submit** button?
You can define and integrate
[events](https://developers.google.com/analytics/devguides/collection/gtagjs/events) to analyze this.

A wide range of analytics tools is available.
Some are minimalistic, some offer a lot of options for individualization.
Try out a range of tools to find the best for your needs.

{% Assessment 'testing' %}

## Resources

- [Getting started with measuring Web Vitals](/vitals-measurement-getting-started/)
- [Core Web Vitals](/vitals)
- [Why lab and field data can be different](/lab-and-field-data-differences/)
- [Google Analytics: About Events](https://support.google.com/analytics/answer/1033068?hl=en#zippy=%2Cin-this-article)

# How to test forms for usability

Usability testing is a technique to evaluate a device or product, such as a web form. 
By testing your form on real users, you can identify issues that automated tools may not find. 
You learn first-hand where you need to improve your form.

To conduct a usability test, 
you give a person a task such as asking them to complete a form, 
watch them doing the task, then ask them to 'think aloud'. 
During the test, you take notes about their interactions. 
After the test, you ask questions. This way, you find out where your form needs improvements.  

## Test your forms with real people

First, you need to find people who can test your form. 
Ask family members, friends, and colleagues to test your form. 

{% Aside %}
Testing doesn't have to be difficult. To improve your forms you don't need a usability lab and 
complex reporting methodologies!

Testing with one single other person is likely to help you improve your forms. 
Testing with two or more is even better. Take simple notes and make changes accordingly.
{% endAside %}

Try to get as diverse a range of testers as possible: 
in particular, think about age, and technical experience. 

Users may be situationally, temporarily, or permanently impaired. 
For example, a user could have a vision impairment that makes it difficult for them to read text without sufficient contrast, 
or a user may have a temporary arm injury that requires them to fill out the form with one hand. 

Testing with a diverse range of people helps you find usability issues you may not be aware of. 
Learn more about [inclusive design](https://www.microsoft.com/design/inclusive/), 
the linked site provides personas and sample activities to help you with inclusive UX testing.

For a high-traffic site, 
you should work with an accessibility consulting company 
that can provide comprehensive testing with assistive technologies and expert advice on fixing any issues found.

## Identify issues

You found people to test your form. How does a usability test work in practice? 

Ask people to complete specific tasks. 
Say you want to test your form. 
Ask them to fill out your form. 
Are they able to locate the form from the homepage? 
Are they able to successfully submit the form? 
Ask them about their experience. 
As they fill out the form, ask them to explain what they're doing and any issues they encounter.

## Ensure your form is accessible

How can you make sure your form is accessible to all your users?

The best way to ensure your form works as expected is by testing it with real people. 
Ask a friend or colleague to complete your form. 
You may be surprised how differently other people use your form, 
and what is important for them.

Finding people with different needs, who can test your form, 
isn't always possible. 
You should, however, always do an accessibility review of your own. 
For example, you can 
[emulate vision deficiencies](https://developer.chrome.com/blog/new-in-devtools-83/#vision-deficiencies), 
use a screen reader on your phone or computer, 
or use only your keyboard to fill out your form. 
Try navigating your form via a screen reader such as 
[VoiceOver on Mac](https://www.youtube.com/watch?v=5R-6WvAihms&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&index=6) or 
[NVDA](https://www.nvaccess.org/) on Windows.

Learn more about 
[doing an accessibility review](/how-to-review/).

## Measure and monitor impact of changes

After testing with real people and gathering feedback, 
it's time to adapt your form to the needs of your users. 
How can you be sure the new version is better than the previous one? 

You can ask the same people who tested your form before, to test your form again. 
Give them the same tasks, and ask the same questions afterwards. 
Was it easier to use this time? Did they encounter any new issues?

You tested your forms at home or in the office. 
How can you test and monitor the experience of your end users? 
Use analytics, and [real user measurement (RUM)](/user-centric-performance-metrics/). 
Implement [goal funnels](https://support.google.com/analytics/answer/6180923?hl=en) 
in analytics to check if changes reduce form abandonment and the time it takes for users to complete your form.

## Test different form designs with end users

One way to get results quicker is by doing A/B testing. You create two versions of your form, and randomly provide one version or the other to your users: some people get version A, and some get version B. Comparing results for the two versions helps you decide which version to use for later iterations. 

Learn more about [A/B testing](https://www.smashingmagazine.com/2010/06/the-ultimate-guide-to-a-b-testing/).

## Resources

- [Discount Usability Testing](https://www.nngroup.com/articles/discount-usability-20-years/)
- [Hallway Usability Testing](https://digital.gov/2014/02/19/10-tips-for-better-hallway-usability-testing/)
- [Doing an accessibility review](/how-to-review/)

# Help users enter the right data in forms

Browsers have built-in features for validation to check that users have entered data in the correct format.
You can activate these features by using the correct elements and attributes.
On top of that, you can enhance form validation with CSS and JavaScript.

{% Aside %}
This module is about form validation on the frontend.
You must also make sure to validate data before storing or sharing it on your backend server:
[find out more](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html).
{% endAside %}

## Why should you validate your forms?

You learned in the previous module how to help users avoid having to repeatedly
[re-enter information](/learn/forms/auto) in forms.
How can you help users enter data that's valid?

It's frustrating to fill out a form without knowing which fields are required,
or the constraints of those fields.
For example, you enter a username and submit a form—only to find out that usernames must have at least eight characters.

You can help users with that by defining validation rules and communicating them.

## Help users from accidentally missing required fields

You can use HTML to specify the correct format and constraints for data entered in your forms.
You also need to specify which fields are mandatory.

{% Codepen {
  user: 'web-dot-dev',
  id: '1e3e72e4376292ab80ecd8955529806b',
  height: 300
} %}

Try to submit this form without entering any data.
Do you see an error message attached to the `<input>` telling you that the field is required?

This happens because of the `required` attribute.

```html
<label for="name">Name (required)</label>
<input required type="text" id="name" name="name">
```

{% Aside %}
Different browsers use different text for error messages.
The wording is also dependent on the browser language of the user.
If you use Safari and your preferred browser language is German,
you get a different error message than a user in Chrome with English as their chosen browser language.

Find out how to
[change the default error messages with JavaScript](#javascript)
later in this module.
{% endAside %}

You already learned that you can use many more types, for example, `type="email"`.
Let's have a look at a required email `<input>`.

{% Codepen {
  user: 'web-dot-dev',
  id: '061add379d5159560d2bc6bc037d82da',
  height: 300
} %}

Try to submit this form without entering any data.
Is there any difference from the demo before?
Now insert your name in the email field and try to submit.
You see a different error message. How is that possible?
You get a different message because the value you entered isn't a valid email address.

The `required` attribute tells the browser that the field is mandatory.
The browser also tests if the entered data matches the format of the `type`.
The email field shown in the example is only valid if it's not empty and if the entered data is a valid email address.

## Help the user enter the correct format

You learned how to make a field mandatory.
How would you instruct the browser that a user must enter at least eight characters for a form field?

{% Codepen {
  user: 'web-dot-dev',
  id: '0901d502bbe2cc7c4aa0bd73068ddd96',
  height: 300
} %}

Give the demo a try.
After your change, you should not be able to submit the form if you enter less than eight characters.

{% Details %}

{% DetailsSummary 'h3' %} Toggle answer {% endDetailsSummary %}

```html
<label for="password">Password (required)</label>
<input required minlength="8" type="password" id="password" name="password">
```

The name of the attribute is `minlength`.
Set the value to `8` and you have the desired validation rule.
If you want the opposite, use `maxlength`.

{% Aside %}
For numerical input types use `min` and `max` to achieve the same result.
{% endAside %}

{% endDetails %}

## Communicate your validation rules

```html
<label for="password">Password (required)</label>
<input required minlength="8" type="password" id="password"
  name="password" aria-describedby="password-minlength">
<div id="password-minlength">Enter at least eight characters</div>
```

Make sure all users understand your validation rules.
For this, connect the form control with an element that explains the rules.
To do so, add an `aria-describedby` attribute to the element with the `id` of the form.

## Pattern attribute

Sometimes you want to define more advanced validation rules.
Again, you can use an HTML attribute.
It's called `pattern`, and you can define a
[regular expression](https://regex101.com/) as the value.

```html
<label for="animal">What is your favorite animal? (required)</label>
<input required pattern="[a-z]{2,20}" type="text" id="animal" name="animal">
```

Here, only lowercase letters are allowed;
the user has to enter at least two characters, and not more than twenty.

How would you change the `pattern` to also allow uppercase letters?
[Try it out](https://codepen.io/web-dot-dev/pen/bc12240b7cb5b52076621d73a8a29cf6).

{% Details %}

{% DetailsSummary 'h3' %} Toggle answer {% endDetailsSummary %}

The correct answer is `pattern="[a-zA-Z]{2,20}"`.

{% endDetails %}

## Add styles

You have now learned how to add validation in HTML.
Wouldn't it be great if you could also style form controls based on the validation status?
This is possible with CSS.

## How to style a required form field

Show the user that a field is mandatory before they interact with your form.

{% Codepen {
  user: 'web-dot-dev',
  id: '5a5de1e7dbdcdba86d19e30d42291a27',
  height: 300,
  tab: 'css,result'
} %}

You can style `required` fields with the `:required` CSS pseudo class.

```css
input:required {
  border: 2px solid;
}
```

## Style invalid form controls

Do you remember what happens if data entered by the user is invalid?
The error message attached to the form control appears.
Wouldn't it be great to adapt the appearance of the element when this happens?

{% Codepen {
  user: 'web-dot-dev',
  id: 'd6bb0f27d1faac3ffd3b594a81fad396',
  height: 300,
  tab: 'css,result'
} %}

You can use the `:invalid` [pseudo-class](/learn/css/pseudo-classes/)
to add styles to invalid form controls.
In addition, there is also the `:valid` pseudo-class for styling valid form elements.

{% Aside %}
Sometimes designers color the invalid state red,
using the `:invalid` pseudo-class.
However, to communicate error or success you should never rely only on color.
For people with red-green color blindness a green and a red border look almost the same.
It's impossible for them to see if there was an error or success. Add text or an icon to make it obvious.
{% endAside %}

There are more ways to adapt your styles based on validation.
In the module about [CSS](/learn/forms/styling) you will learn more about styling forms.

{% Aside %}
In practice `:invalid` is tricky to work with.
Invalid form fields are already marked as `:invalid` before user interaction,
which may confuse users. The `:user-invalid` pseudo-class solves this issue,
as the styles are only applied after user interaction.

Learn more about [`:user-invalid`](https://developer.mozilla.org/docs/Web/CSS/:user-invalid).
{% endAside %}

## Validation with JavaScript {: #javascript}

To further enhance validation of your forms you can use the
[JavaScript Constraint Validation API](https://developer.mozilla.org/docs/Web/API/Constraint_validation).

### Provide meaningful error messages

You learned before that error messages are not identical in every browser.
How can you show the same message to everyone?

To achieve this, use the
[`setCustomValidity()`](https://developer.mozilla.org/docs/Web/API/HTMLObjectElement/setCustomValidity)
method of the Constraint Validation API.
Let's see how this works.

```js
const nameInput = document.querySelector('[name="name"]');

nameInput.addEventListener('invalid', () => {
    nameInput.setCustomValidity('Please enter your name.');
 });
```

Query the element where you want to set the custom error message.
Listen to the `invalid` event of your defined element.
There you set the message with `setCustomValidity()`.
This example shows the message `Please enter your name.` if the input is invalid.

{% Codepen {
  user: 'web-dot-dev',
  id: '7ea31257d7cd8fc28792c7f5cdaba97b',
  height: 300
} %}

[Open the demo](https://codepen.io/web-dot-dev/pen/7ea31257d7cd8fc28792c7f5cdaba97b) in different browsers,
you should see the same message everywhere.
Now, try to remove the JavaScript and try again.
You see the default error messages again.

There is much more you can do with the Constraint Validation API.
You’ll find a detailed look at using
[validation with JavaScript](/learn/forms/javascript#validation-with-javascript) in a later module.

How to validate in real-time
You can add real-time validation in JavaScript by listening to the `onblur` event of a form control,
and validate the input immediately when a user leaves a form field.

{% Codepen {
  user: 'web-dot-dev',
  id: 'b7ed22a0539f9beef4dc03380f51f224',
  height: 300,
  tab: 'js,result'
} %}

Click the form field in the [demo](https://codepen.io/web-dot-dev/pen/b7ed22a0539f9beef4dc03380f51f224), 
enter "web" and click somewhere else on the page.
You see the native error message for `minlength` below the form field.

Learn more about implementing
[real-time validation with JavaScript](/learn/forms/javascript#ensure-users-are-notified-about-errors-in-real-time) in an upcoming module.

{% Assessment 'validation' %}

## Resources

- [Disable the payment button once the form is submitted](/codelab-payment-form-best-practices/#step-4:-disable-the-payment-button-once-the-form-is-submitted)
- [Add CSS to make the form work better](/codelab-sign-up-form-best-practices/#step-2:-add-css-to-make-the-form-work-better)

# Learn HTML

Welcome to HTML!  HyperText Markup Language, or HTML, is the backbone of the web, providing the content, as well as the structure of that content, that you see displayed in your web browser.

Unless you're reading a PDF or a printed version of this page, this content is made up of various HTML elements and text. HTML is the content layer of the web. HTML elements are the nodes that make up the [Document Object Model](https://developer.mozilla.org/docs/Web/API/Document_Object_Model).

[Cascading Style Sheets](/learn/css/) provide the look and feel, or presentation layer of the page. [JavaScript](https://developer.mozilla.org/docs/Learn/JavaScript) is the behavior layer, often used to manipulate the objects within a document. Sites that are built with JavaScript frameworks are really just manipulating HTML. In turn, it's important to mark up your HTML in a way that scripts can easily parse and that assistive technologies can easily understand. This means writing HTML code with modern standards.

# Overview

This HTML course for web developers provides a solid overview for developers, from novice to expert level HTML. If you're completely new to HTML, you will learn how to build structurally sound content. If you've been building websites for years, this course may fill in gaps in knowledge that you didn't even know you had.

Along this journey, we will be building the structure for [MachineLearningWorkshop.com](https://machinelearningworkshop.com). No machines were harmed in the creation of this series.

**This is not a complete reference**. Each section introduces the section topic with brief explanations and examples, providing you an opportunity to explore further. There will be links to topic references, such as [MDN](https://developer.mozilla.org) and [WHATWG](https://html.spec.whatwg.org/multipage/) specifications, and other [web.dev](/learn) articles. While this is not an accessibility course, each section will include accessibility best practices and specific issues, with links to deeper dives on the topic. Each section will have a short assessment to help people confirm their understanding.

Here's what you'll learn:

{% include 'partials/course-index.njk' %}

So, are you ready to learn HTML? [Let's get started](/learn/html/overview/).

{% Aside %}
This course was written by [Estelle Weyl](https://front-end.social/@estelle), with input and review from [Rachel Andrew](https://twitter.com/rachelandrew), and [Jhey Tompkins](https://twitter.com/jh3yy).
{% endAside %}

# HTML APIs

In the introduction to this series it says "HTML elements are the nodes that make up the [Document Object Model](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)."
We've discussed the type of element nodes. In this section we discuss element APIs that enable querying those nodes.

## The DOM and AOM

The DOM is an API for accessing and manipulating documents. The DOM is the tree of all the nodes in the document.
Some nodes can have children, others can't. The tree includes elements, along with their attributes, and text nodes.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/xsvSa8YkwHyPWNnQ8Tpi.png", alt="MLW Node tree showing elements and text nodes.", width="800", height="431" %}

Browser tools don't provide tree visualizations like the one above, but you can see the nodes in the element inspector.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/rX9myUwejCW2Ab0xUu0l.png", alt="The DOM/ARIA.", width="800", height="836" %}

The tree representation that can be inspected in browser developer tools is the [accessibility tree](/learn/accessibility/aria-html/#the-accessibility-tree). The AOM is based
off the DOM; similarly, the accessibility tree contains objects representing all the markup elements, attributes, and text
nodes:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/KMEuk7ub4ejE7zdr5Vyk.png", alt="An example of AOM.", width="800", height="527" %}

## HTML Element APIs

The middle letter of DOM is "object." Just like the `person` or `car` object example from most intro to object-oriented programming
classes, every node in the document tree is an object that can be manipulated with JavaScript.

The browser provides numerous
APIs providing natively supported methods, events, and property querying and updating.
Element nodes contain information about all the attributes set on the element. You can use HTML interfaces to access
information about an element's attributes. For example, we can use [`HTMLImageElement.alt`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/alt)
get the `alt` attributes of all the images:

```js
let allImages = document.querySelectorAll('img');
allImages.forEach((imageInstance) => {
  console.log(imageInstance.alt);
});
```

HTML interfaces provide more than just access to an element's attributes; you can access a lot more information. We can
find the read-only [`HTMLElement.offsetHeight`](https://developer.mozilla.org/docs/Web/API/HTMLElement/offsetHeight) to get the height of each section in our page, relative to the layout.

```js
let allSections = document.querySelectorAll('section');
allSections.forEach((sectionInstance) => {
  console.log(sectionInstance.offsetHeight);
});
```

If the user changes their device orientation or otherwise changes the width of the viewport, the height of each `<section>`
will change and the DOM properties will automatically update with it.

The HTML interface APIs is not limited to accessing attribute values. The DOM provides insight into the current state of the UI.
HTML APIs can access all of that information. You can access the length of a video, where a view is in the current playback,
and if the video (or audio) has finished playing with [`HTMLMediaElement.duration`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/duration),
[`HTMLMediaElement.currentTime`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/currentTime), and
[`HTMLMediaElement.ended`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/ended) respectively.

## Available element interfaces

Most HTML element we've covered thus far in this series and have yet to cover, other than some [sectioning elements](/learn/html/headings-and-sections/), have
an associated DOM interface. The base interface for all elements is aptly named [Element](https://developer.mozilla.org/docs/Web/API/Element).
The [`HTMLElement`](https://developer.mozilla.org/docs/Web/API/HTMLElement) inherits from Element and all HTML element-specific
interfaces inherit from it. Some element-specific interfaces are implemented by multiple, similar elements.

The interfaces include:

* [`HTMLAnchorElement`](https://developer.mozilla.org/docs/Web/API/HTMLAnchorElement) - `<a>`
* [`HTMLAreaElement`](https://developer.mozilla.org/docs/Web/API/HTMLAreaElement) - `<area>`
* [`HTMLAudioElement`](https://developer.mozilla.org/docs/Web/API/HTMLAudioElement) - `<audio>`
* [`HTMLBaseElement`](https://developer.mozilla.org/docs/Web/API/HTMLBaseElement) - `<base>`
* [`HTMLButtonElement`](https://developer.mozilla.org/docs/Web/API/HTMLButtonElement) - `<button>`
* [`HTMLCanvasElement`](https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement) - `<canvas>`
* [`HTMLDataElement`](https://developer.mozilla.org/docs/Web/API/HTMLDataElement) - `<data>`
* [`HTMLDataListElement`](https://developer.mozilla.org/docs/Web/API/HTMLDataListElement) - `<datalist>`
* [`HTMLDetailsElement`](https://developer.mozilla.org/docs/Web/API/HTMLDetailsElement) - `<details>`
* [`HTMLDialogElement`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement) - `<dialog>`
* [`HTMLEmbedElement`](https://developer.mozilla.org/docs/Web/API/HTMLEmbedElement) - `<embed>`
* [`HTMLFieldSetElement`](https://developer.mozilla.org/docs/Web/API/HTMLFieldSetElement) - `<fieldset>`
* [`HTMLFormElement`](https://developer.mozilla.org/docs/Web/API/HTMLFormElement) - `<form>`
* [`HTMLHtmlElement`](https://developer.mozilla.org/docs/Web/API/HTMLHtmlElement) - `<html>`
* [`HTMLIFrameElement`](https://developer.mozilla.org/docs/Web/API/HTMLIFrameElement) - `<iframe>`
* [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement) - `<img>`
* [`HTMLInputElement`](https://developer.mozilla.org/docs/Web/API/HTMLInputElement) - `<input>`
* [`HTMLLabelElement`](https://developer.mozilla.org/docs/Web/API/HTMLLabelElement) - `<label>`
* [`HTMLLegendElement`](https://developer.mozilla.org/docs/Web/API/HTMLLegendElement) - `<legend>`
* [`HTMLLIElement`](https://developer.mozilla.org/docs/Web/API/HTMLLIElement) - `<li>`
* [`HTMLLinkElement`](https://developer.mozilla.org/docs/Web/API/HTMLLinkElement) - `<link>`
* [`HTMLMapElement`](https://developer.mozilla.org/docs/Web/API/HTMLMapElement) - `<map>`
* [`HTMLMediaElement`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement) - `<audio>`, `<video>`
* [`HTMLMenuElement`](https://developer.mozilla.org/docs/Web/API/HTMLMenuElement) - `<menu>`
* [`HTMLMetaElement`](https://developer.mozilla.org/docs/Web/API/HTMLMetaElement) - `<meta>`
* [`HTMLMeterElement`](https://developer.mozilla.org/docs/Web/API/HTMLMeterElement) - `<meter>`
* [`HTMLModElement`](https://developer.mozilla.org/docs/Web/API/HTMLModElement) - `<ins>`, `<del>`
* [`HTMLObjectElement`](https://developer.mozilla.org/docs/Web/API/HTMLObjectElement) - `<object>`
* [`HTMLOListElement`](https://developer.mozilla.org/docs/Web/API/HTMLOListElement) - `<ol>`
* [`HTMLOptGroupElement`](https://developer.mozilla.org/docs/Web/API/HTMLOptGroupElement)- `<optgroup>`
* [`HTMLOptionElement`](https://developer.mozilla.org/docs/Web/API/HTMLOptionElement) - `<option>`
* [`HTMLOutputElement`](https://developer.mozilla.org/docs/Web/API/HTMLOutputElement) - `<output>`
* [`HTMLPictureElement`](https://developer.mozilla.org/docs/Web/API/HTMLPictureElement) - `<picture>`
* [`HTMLProgressElement`](https://developer.mozilla.org/docs/Web/API/HTMLProgressElement) - `<progress>`
* [`HTMLQuoteElement`](https://developer.mozilla.org/docs/Web/API/HTMLQuoteElement) - `<q>`, `<blockquote>`, `<cite>`
* [`HTMLScriptElement`](https://developer.mozilla.org/docs/Web/API/HTMLScriptElement) - `<script>`
* [`HTMLSelectElement`](https://developer.mozilla.org/docs/Web/API/HTMLSelectElement) - `<select>`
* [`HTMLSlotElement`](https://developer.mozilla.org/docs/Web/API/HTMLSlotElement) - `<slot>`
* [`HTMLSourceElement`](https://developer.mozilla.org/docs/Web/API/HTMLSourceElement) - `<source>`
* [`HTMLStyleElement`](https://developer.mozilla.org/docs/Web/API/HTMLStyleElement) -  `<style>`
* [`HTMLTableCellElement`](https://developer.mozilla.org/docs/Web/API/HTMLTableCellElement) - `<td>`, `<th>`
* [`HTMLTableColElement`](https://developer.mozilla.org/docs/Web/API/HTMLTableColElement) - `<col>`, `<colgroup>`
* [`HTMLTableElement`](https://developer.mozilla.org/docs/Web/API/HTMLTableElement) - `<table>`
* [`HTMLTableRowElement`](https://developer.mozilla.org/docs/Web/API/HTMLTableRowElement) - `<tr>`
* [`HTMLTableSectionElement`](https://developer.mozilla.org/docs/Web/API/HTMLTableSectionElement) - `<thead>`, `<tbody>`, `<tfoot>`
* [`HTMLTemplateElement`](https://developer.mozilla.org/docs/Web/API/HTMLTemplateElement) - `<template>`
* [`HTMLTextAreaElement`](https://developer.mozilla.org/docs/Web/API/HTMLTextAreaElement) - `<textarea>`
* [`HTMLTimeElement`](https://developer.mozilla.org/docs/Web/API/HTMLTimeElement) - `<time>`
* [`HTMLTitleElement`](https://developer.mozilla.org/docs/Web/API/HTMLTitleElement) - `<title>`
* [`HTMLTrackElement`](https://developer.mozilla.org/docs/Web/API/HTMLTrackElement) - `<track>`
* [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement) - `<video>`

The naming convention is "HTML" followed by an element or grouping of elements in upper camel case, followed by "Element",
but the element or grouping of elements part follows no exact pattern. Don't worry. There is no need to memorize these.
It's just important to know that they exist so you can look them up when you need to.

If you have a collection of elements, there are also come collection interfaces. For example, the
[`HTMLCollection.namedItem()`](https://developer.mozilla.org/docs/Web/API/HTMLCollection/namedItem) method returns the first
element in the collection whose `id` or `name` attribute matches the parameter, or null if no element matches.

Over 30 elements don't have an associated DOM interface other than `HTMLElement` including `<address>`, `<article>`,
`<section>`, `<nav>`, `<header>`, `<footer>`, `<aside>`, and `<hgroup>`. Many elements that don't support any non-deprecated,
non-global attributes have element specific interfaces, like `HTMLPElement` (the `<p>` element) and [`HTMLUnknownElement`](https://developer.mozilla.org/docs/Web/API/HTMLUnknownElement)
( `<😃>` or any other elements that are not defined), but those interfaces don't implement any additional properties or methods
on top of the properties and methods inherited from `HTMLElement`, and are not listed above.

### Redundant API methods and properties

If an interface has the same method or property name as and interface it inherits, the inheriting method or property overwrites
the inherited one. When we accessed the `alt` and `offsetHeight` properties above with `imageInstance.alt` and `sectionInstance.offsetHeight`
respectively, the code didn't identify which API was being accessed.

Generally, as with these two examples, this isn't an issue. But, it can be. For example, the [`HTMLCollection.length`](https://developer.mozilla.org/docs/Web/API/HTMLCollection/length)
is read only, while the inheriting [`HTMLOptionsCollection`](https://developer.mozilla.org/docs/Web/API/HTMLOptionsCollection) interface's
length property (returned only by the `options` property of `<select>`) can also be used to set collection size.

## Other interfaces

There are additional interfaces that enable manipulating the branch locations of DOM nodes. The [`EventTarget`](https://developer.mozilla.org/docs/Web/API/EventTarget) interface, which provides
us with [`addEventListener()`](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) and [`removeEventListener()`](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener), is inherited by the [`Node`](https://developer.mozilla.org/docs/Web/API/Node) and [`Window`](https://developer.mozilla.org/docs/Web/API/Window) interfaces. In turn, the Element, Document, and DocumentFragment (which we saw in [custom elements](/learn/html/template)) interfaces inherit from Node, and the HTMLElement interface inherits from Element.

### The `node` interface

Every type of DOM node is represented by an interface based on [`Node`](https://developer.mozilla.org/docs/Web/API/Node),
which provides information and methods as elements relate to the DOM tree. The `Node` interface enables querying and adding nodes to the node tree.

Douglas Crockford's famous "walk the DOM" function, makes use of Node's [`firstChild`](https://developer.mozilla.org/docs/Web/API/Node/firstChild)
and the [`nextSibling`](https://developer.mozilla.org/docs/Web/API/Node/nextSibling) properties.

```javascript
const walk_the_DOM = function walk(node, callback) {
  callback(node);
  node = node.firstChild;
  while (node) {
    walk(node, callback);
    node = node.nextSibling;
  }
};
```

We used Node's [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) and
[`cloneNode()`](https://developer.mozilla.org/docs/Web/API/Node/cloneNode) methods in defining [custom elements](/learn/html/template).
The Node interface provides many useful properties and methods for querying and manipulating the DOM.

```javascript
customElements.define('star-rating',
  class extends HTMLElement {
    constructor() {
      super(); // Always call super first in constructor
      const starRating = document.getElementById('star-rating-template').content;
      const shadowRoot = this.attachShadow({
        mode: 'open'
      });
      shadowRoot.appendChild(starRating.cloneNode(true));
    }
  });
```

The [`attachShadow()`](https://developer.mozilla.org/docs/Web/API/Element/attachShadow) method is a method of the Element
interface. There is also a [`shadowRoot`](https://developer.mozilla.org/docs/Web/API/ShadowRoot) interface for the
[Shadow DOM API](https://developer.mozilla.org/docs/Web/Web_Components/Using_shadow_DOM) rendered separately from a
document's main DOM tree.

### The `Document` and `HTMLDocument` interfaces

The [`Document`](https://developer.mozilla.org/docs/Web/API/Document) interface inherits from `Node`. It represents the
web page loaded in the browser, whether the document is HTML, SVG, XML, MathML, or other. The `Document` interface also
inherits from the `HTMLDocument` interface.

The `document` enables quick access to node types and the ability to create collections of specific element types, such as
`document.body` and `document.styleSheets`. The HTMLDocument enables accessing information relevant to the document that
are not found in HTML nodes, such as the [`Document.location`](https://developer.mozilla.org/docs/Web/API/Document/location),
[`Document.lastModified`](https://developer.mozilla.org/docs/Web/API/Document/lastModified), and [`Document.Cookie`](https://developer.mozilla.org/docs/Web/API/Document/cookie).

Several APIs are available based on features surfaced through the document interface, including the [Drag and Drop API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API)
and the [FullScreen API](https://developer.mozilla.org/docs/Web/API/Fullscreen_API). Both inherit from `Element`.

### The `Window` interface

The Window interface includes globally available items beyond the DOM that can be used to manipulate the DOM. Window provides
functions, namespaces, objects, and constructors documented in MDN's [JavaScript](https://developer.mozilla.org/docs/Web/JavaScript/Reference)
and [DOM References](https://developer.mozilla.org/docs/Web/API/Document_Object_Model).

The Window interface is the API for the object containing the document. The global `window` object is the window in which the
script is running. Every browser tab contains its own Window object. The Window interface can query the contents of the tab
as well as the overall window and device. For example, the [`resizeTo()`](https://developer.mozilla.org/docs/Web/API/Window/resizeTo)
method can be used to resize the browser window, the [`devicePixelRatio`](https://developer.mozilla.org/docs/Web/API/Window/devicePixelRatio)
property provides access to the device display pixels. When accessing information about the tab the content
is in rather than the DOM tree the tab displays, the window is likely the interface you're looking for.

Several APIs are available based on features surfaced through the Window interface, including the [Web Workers](https://developer.mozilla.org/docs/Web/API/Worker)
and [IndexedDB](https://developer.mozilla.org/docs/Web/API/IndexedDB_API) APIs.

{% Assessment 'apis' %}

# Attributes

Attributes were briefly discussed in [Overview of HTML](/learn/html/overview/#attributes); it's time for a deep dive.

Attributes are what make HTML so powerful. Attributes are space-separated names and name/value pairs appearing in the opening tag,
providing information about and functionality for the element.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/17yQeLEUX6s88IbDJreQ.png", alt="The opening tag, attributes, and closing tag, labelled on an HTML element.", width="800", height="210" %}

Attributes define the behavior, linkages, and functionality of elements. Some attributes are global, meaning they can appear
within any element's opening tag. Other attributes apply to several elements but not all, while other attributes are element-specific,
relevant only to a single element. In HTML, all attributes except boolean, and to some extent enumerated attributes, require a value.

If an attribute value includes a space or special characters, the value must be quoted. For this reason, and for improved legibility,
quoting is always recommended.

While HTML is not case-sensitive, some attribute values are. Values that are part of the HTML specification are case-insensitive.
Strings values that are defined, such as class and id names, are case-sensitive. If an attribute value is case-sensitive in HTML,
it is case-sensitive when used as part of an [attribute selector](https://developer.mozilla.org/docs/Web/CSS/Attribute_selectors) in CSS and in JavaScript; otherwise, it's not.

```html
<!-- the type attribute is case insensitive: these are equivalent -->
<input type="text">
<input type="TeXt">

<!-- the id attribute is case sensitive: they are not equivalent -->
<div id="myId">
<div id="MyID">
```

## Boolean attributes

If a boolean attribute is present, it is always true. Boolean attributes include `autofocus`, `inert`, `checked`, `disabled`,
`required`, `reversed`, `allowfullscreen`, `default,` `loop`, `autoplay`, `controls`, `muted`, `readonly`, `multiple,` and `selected`.
If one (or more) of these attributes is present, the element is disabled, required, readonly, etc. If not present, it isn't.

Boolean values can either be omitted, set to an empty string, or be the name of the attribute; but the value doesn't have to actually
be set to the string `true`. All values, including `true`, `false`, and `😀`, while invalid, will resolve to true.

These three tags are equivalent:

```html
<input required>
<input required="">
<input required="required">
```

If the attribute value is false, omit the attribute. If the attribute is true, include the attribute but don't provide a value.
For example, `required="required"` is not a valid value in HTML; but as `required` is boolean, invalid values resolve to true.
But as invalid enumerated attributes don't necessarily resolve to the same value as missing values, it is easier to get into the
habit of omitting values than it is to remember which attributes are boolean versus enumerated and potentially provide an invalid value.

When toggling between true and false, add and remove the attribute altogether with JavaScript rather than toggling the value.

```js
const myMedia = document.getElementById("mediaFile");
myMedia.removeAttribute("muted");
myMedia.setAttribute("muted");
```

Note that in XML languages, like SVG, all attributes need to include a value, including boolean attributes.

## Enumerated attributes

Enumerated attributes are sometimes confused with boolean attributes. They are HTML attributes that have a limited set of predefined valid values.
Like boolean attributes, they have a default value if the attribute is present but the value is missing. For example, if you include `<style contenteditable>`,
it defaults to `<style contenteditable="true">`.

Unlike boolean attributes, though, omitting the attribute doesn't mean it's false; a present attribute with a missing value
isn't necessarily true; and the default for invalid values isn't necessarily the same as a null string. Continuing the example,
`contenteditable` defaults to `inherit` if missing or invalid, and can be explicitly set to `false`.

The default value depends on the attribute. Unlike boolean values, attributes aren't automatically "true" if present. If you
include `<style contenteditable="false">`, the element is not editable. If the value is invalid, such as `<style contenteditable="😀">`,
or, surprisingly, `<style contenteditable="contenteditable">`, the value is invalid and defaults to `inherit`.

In most cases with enumerated attributes, missing and invalid values are the same. For example, if the `type` attribute on an `<input>`
is missing, present but without a value, or has an invalid value, it defaults to `text`. While this behavior is common, it is not a rule.
Because of this, it's important to know which attributes are boolean versus enumerated; omit values if possible so you don't get them wrong, and look up the value as needed.

## Global attributes

Global attributes are attributes that can be set on any HTML element, including elements in the `<head>`. There are more than
[30 global attributes](https://developer.mozilla.org/docs/Web/HTML/Global_attributes#list_of_global_attributes). While these can all, in theory, be added to any HTML element, some global attributes have no effect
when set on some elements; for example, setting `hidden` on a `<meta>` as meta content is not displayed.

### `id`

The global attribute `id` is used to define a unique identifier for an element. It serves many purposes, including:
- The target of a link's fragment identifier.
- Identifying an element for scripting.
- Associating a form element with its label.
- Providing a label or description for assistive technologies.
- Targeting styles with (high specificity or as attribute selectors) in CSS.

The `id` value is a string with no spaces. If it contains a space, the document won't break, but you'll have to target the
`id` with escape characters in your HTML, CSS, and JS. All other characters are valid. An `id` value can be `😀` or `.class`,
but is not a good idea. To make programming easier for your current and future self, make the `id`'s first character a letter,
and use only ASCII letters, digits, `_`, and `-`. It's good practice to come up with an `id` naming convention and then stick to it,
as `id` values are case-sensitive.

The`id` should be unique to the document. The layout of your page probably won't break if an `id` is used more than once,
but your JavaScript, links, and element interactions may not act as expected.

#### Link fragment identifier

The navigation bar includes four links. We will cover the link element later, but for now, realize links are not restricted
to HTTP-based URLs; they can be fragment identifiers to sections of the page in the current document (or in other documents).

On the machine learning workshop site, the navigation bar in the page header includes four links:

{% Codepen {
user: 'web-dot-dev',
id: 'GRGzbXR',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

The href attribute provides the hyperlink that activating the link directs the user to. When a URL includes a hash mark (`#`)
followed by a string of characters, that string is a fragment identifier. If that string matches an `id` of an element in the
web page, the fragment is an anchor, or bookmark, to that element. The browser will scroll to the point where the anchor is defined.

These four links point to four sections of our page identified by their `id` attribute. When the user clicks on any of the
four links in the navigation bar, the element linked to by the fragment identifier, the element containing the matching id
minus the `#`, scrolls into view.

The `<main>` content of the machine learning workshop has four sections with ids. When the site visitor clicks on one of the
links in the `<nav>`, the section with that fragment identifier scrolls into view. The markup is similar to:


```html
<section id="reg">
  <h2>Machine Learning Workshop Tickets</h2>
</section>

<section id="about">
  <h2>What you'll learn</h2>
</section>

<section id="teachers">
  <h2>Your Instructors</h2>
  <h3>Hal 9000 <span>&amp;</span> EVE</h3>
</section>

<section id="feedback">
  <h2>What it's like to learn good and do other stuff good too</h2>
</section>
```

Comparing the fragment identifiers in the `<nav>` links, you'll note that each matches the `id` of a `<section>` in `<main>`.
The browser gives us a free "top of page" link. Setting `href="#top"`, case-insensitive, or simply `href="#"`, will scroll
the user to the top of the page.

The hash-mark separator in the `href` is not part of the fragment identifier. The fragment identifier is always the last
part of the URL and is not sent to the server.

#### CSS selectors

In CSS, you can target each section using an id selector, such as `#feedback` or, for less [specificity](https://developer.mozilla.org/docs/Web/CSS/Specificity), a case-sensitive
[attribute selector](/learn/css/selectors/#attribute-selector), `[id="feedback"]`.

#### Scripting

On MLW.com, there is an easter egg for mouse users only. Clicking the light switch toggles the page on and off.

The markup for the light switch image is:
```html
<img src="svg/switch2.svg" id="switch"
  alt="light switch" class="light" />
```
The `id` attribute can be used as the parameter for the [`getElementById()`](https://developer.mozilla.org/docs/Web/API/Document/getElementById) method and, with a `#` prefix, as part of a
parameter for the [`querySelector()`](https://developer.mozilla.org/docs/Web/API/Document/querySelector) and [`querySelectorAll()`](https://developer.mozilla.org/docs/Web/API/Document/querySelectorall) methods.

```js
const switchViaID = document.getElementById("switch");
const switchViaSelector = document.querySelector("#switch");
```

Our one JavaScript function makes use of this ability to target elements by their `id` attribute:

```html
<script>
  /* switch is a reserved word in js, so we us onoff instead */
  const onoff = document.getElementById('switch');
  onoff.addEventListener('click', function(){
    document.body.classList.toggle('black');
  });
</script>
```

#### `<label>`

The [HTML `<label>` element](https://developer.mozilla.org/docs/Web/HTML/Element/label) has a `for` attribute that takes as its value the `id` of the form control with which it is associated.
Creating an explicit label by including an `id` on every form control and pairing each with the label's `for` attribute ensures
that every form control has an associated label.

{% Codepen {
user: 'web-dot-dev',
id: 'JjZxQOB',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

While each label can be associated with exactly one form control, a form control may have more than one associated label.

{% Codepen {
user: 'web-dot-dev',
id: 'dyKaBda',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

If the form control is nested between the `<label>` opening and closing tags, the `for` and `id` attributes
aren't required: this is called an "implicit" label. Labels let all users know what each form control is for.

```html
<label>
  Send me a reminder <input type="number" name="min"> before the workshop resumes
</label>.
```

The association between `for` and `id` makes the information available to users of assistive technologies. In addition,
clicking anywhere on a label gives focus to the associated element, extending the control's click area. This isn't just helpful
to people with dexterity issues making mousing less accurate; it also helps every mobile device user with fingers wider than a radio
button.

{% Codepen {
user: 'web-dot-dev',
id: 'BaVMgxo',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

In this code example, the fake fifth question of a fake quiz is a single select multiple-choice question. Each form control has an explicit
label, with a unique `id` for each. To ensure we don't accidentally duplicate an id, the id value is a combination of the question number and the value.

When including radio buttons, as the labels describe the value of the radio buttons, we encompass all the same-named buttons in a `<fieldset>`
with the `<legend>` being the label, or question, for the entire set.

#### Other accessibility uses

The use of `id` in accessibility and usability is not limited to labels. In [introduction to text](/learn/html/text-basics), a `<section>`
was converted into region landmark by referencing the `id` of an `<h2>` as the value of the `<section>`'s `aria-labelledby` to provide
the accessible name:

```html
<section id="about" aria-labelledby="about_heading">
<h2 id="about_heading">What you'll learn</h2>
```

There are over 50 `aria-*` states and properties that can be used to ensure accessibility. [`aria-labelledby`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby), [`aria-describedby`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-describedby),
[`aria-details`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-details), and [`aria-owns`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-owns) take as their value a space-separated `id` reference list. [`aria-activedescendant`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-activedescendant), which
identifies the currently focused descendant element, takes as its value a single `id` reference: that of the single element
that has focus (only one element can be focused at a time).

{% Aside %}
Using `aria-labelledby`, you can create a reverse association from a form control to multiple labels, including text not
nested in a `<label>`, whether the text labels more than one form control or not. If a control has both `<label>` and `aria-labelledby`, the `aria-labelledby`
has precedence; users will not hear the `<label>` text unless the `aria-labelledby` includes the id of the label.
{% endAside %}

### `class`

The `class` attribute provides an additional way of targeting elements with CSS (and JavaScript), but serves no other purpose
in HTML (though frameworks and component libraries may use them). The class attribute takes as its value a space-separated list
of the case-sensitive classes for the element.

{% Aside %}
Elements can be selected with CSS selectors and DOM methods based on their element names, attributes, attribute values,
position within the DOM tree, etc. Semantic HTML provides meaningful hooks, making the addition of class names often unnecessary.
The unique difference between including a class name and using [`document.getElementsByClassName()`](https://developer.mozilla.org/docs/Web/API/Document/getElementsByClassName) versus targeting elements
based on attributes and page structure with the more robust document.querySelectorAll() is that the former returns a live node list, the latter
is static.
{% endAside %}

Building a sound semantic structure enables the targeting of elements based on their placement and function. Sound structure
enables the use of descendant element selectors, relational selectors, and attribute selectors. As you learn about attributes
throughout this section, consider how elements with the same attributes or attribute values can be styled. It's not that you
shouldn't use the class attribute, it's just that most developers don't realize they often don't need to.

Thus far, MLW has not used any classes. Can a site be launched without a single class name? We'll see.

### `style`

The `style` attribute enables applying inline styles, which are styles applied to the single element on which the attribute is set.
The `style` attribute takes as its value CSS property value pairs, with the value's syntax being the same as the contents of a
CSS style block: properties are followed by a colon, just like in CSS, and semicolons end each declaration, coming after the value.

The styles are only applied to the element on which the attribute is set, with descendants inheriting inherited property values if not
overridden by other style declarations on nested elements or in `<style>` blocks or style sheets. As the value comprises the equivalent of the contents
of a single style block applied to that element only, it can't be used for generated content, to create keyframe animations, or to apply any
other at-rules.

While `style` is indeed a global attribute, using it is not recommended. Rather, define styles in a separate file or files.
That said, the `style` attribute can come in handy during development to enable quick styling such as for testing purposes. Then take the
'solution' style and stick it in your linked [CSS](/learn/css) file.

### `tabindex`

The `tabindex` attribute can be added to any element to enable it to receive focus. The `tabindex` value defines whether it
gets added to the tab order, and, optionally, into a non-default tabbing order.

The `tabindex` attribute takes as its value an integer. A negative value (the convention is to use `-1`) makes an element capable
of receiving focus, such as via JavaScript, but does not add the element to the tabbing sequence. A `tabindex` value of `0` makes
the element focusable and reachable via tabbing, adding it to the default tab order of the page in source code order. A value of `1`
or more puts the element into a prioritized focus sequence and is not recommended.

On this page, there is a share functionality using a `<share-action>` custom element acting as a `<button>`. The `tabindex` of zero
is included to add the custom element into the keyboard default tabbing order:

```html
<share-action authors="@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, twitter" role="button" tabindex="0">
  <svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
    <use href="#shareIcon" />
  </svg>
  <span>Share</span>
</share-action>
```

The [`role` of `button`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/button_role) informs screen reader users that this element should behave like a button. JavaScript is used to ensure
the button functionality promise is kept; including handling both [click](https://developer.mozilla.org/docs/Web/API/Element/click_event) and [keydown](https://developer.mozilla.org/docs/Web/API/Element/keydown_event) events as well as handling Enter and Space key keypresses.

Form controls, links, buttons, and [content editable](#contenteditable) elements are able to receive focus; when a keyboard user hits the tab key,
focus moves to the next focusable element as if they had `tabindex="0"` set. Other elements are not focusable by default. Adding the `tabindex`
attribute to those elements enables them to receive focus when they would otherwise not.

If a document includes elements with a `tabindex` of `1` or more, they are included in a separate tab sequence. As you'll notice in the codepen,
tabbing begins in a separate sequence, in order of lowest value to highest value, before going through those in the regular sequence in source order.

{% Codepen {
user: 'web-dot-dev',
id: 'ExRGBPE',
height: 300,
theme: dark,
tab: 'html,result'
} %}

Altering the tabbing order can create a really bad user experience. It makes it difficult to rely on assistive technology—keyboards and screen readers alike—to navigate
your content. It is also difficult as a developer to manage and maintain. Focus is important; there is an entire module discussing focus and focus order.

### `role`

The [`role` attribute](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles) is part of the [ARIA specification](https://w3c.github.io/aria/#introroles),
rather than the [WHATWG HMTL specification](https://html.spec.whatwg.org/#global-attributes:attr-aria-role). The `role` attribute can
be used to provide semantic meaning to content, enabling screen readers to inform site users of an object's expected user interaction.

There are a few common UI widgets, such as [comboboxes](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/combobox_role),
[menubars](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/menubar_role), [tablists](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/tablist_role),
and [treegrids](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/treegrid_role), that have no native HTML equivalent.
For example, when creating a tabbed design pattern, the [`tab`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/tab_role), `tablist` and
[`tabpanel`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/tabpanel_role) roles can be used. Someone who can physically see
the user-interface has learned by experience how to navigate the widget and make different panels visible by clicking on associated tabs.
Including the `tab` role with `<button role="tab">` when a group of buttons is used to show different panels lets the screen reader user know
that the `<button>` that currently has focus can toggle a related panel into view rather than implementing typical button-like functionality.

The `role` attribute doesn't change browser behavior or alter keyboard or pointer device interactions—adding `role="button"`to a `<span>`
does not turn it into a `<button>`. This is why using semantic HTML elements for their intended purpose is recommended. However, when using
the right element is not possible, the `role` attribute enables informing screen reader users when a non-semantic element has been retrofitted
into a semantic element's role.

### `contenteditable`

An element with the `contenteditable` attribute set to `true` is editable, is focusable, and is added to the tab order as if
`tabindex="0"` were set. `Contenteditable` is an enumerated attribute supporting the values `true` and `false`, with a default value of `inherit`
if the attribute is not present or has an invalid value.

These three opening tags are equivalent:

```html
<style contenteditable>
<style contenteditable="">
<style contenteditable="true">
```

If you include `<style contenteditable="false">`, the element is not editable (unless it's by default editable, like a `<textarea>`).
If the value is invalid, such as `<style contenteditable="😀">` or `<style contenteditable="contenteditable">`, the value defaults to `inherit`.

To toggle between states, query the value of the [HTMLElement.isContentEditable](https://developer.mozilla.org/docs/Web/API/HTMLElement/contentEditable) readonly property.

```js
const editor = document.getElementById("myElement");
if(editor.contentEditable) {
  editor.setAttribute("contenteditable", "false");
} else {
  editor.setAttribute("contenteditable", "");
}
```

Alternatively, this property can be specified by setting `editor.contentEditable` to `true`, `false`, or `inherit`.

Global attributes can be applied to all elements, even `<style>` elements. You can use attributes and a bit of CSS to make a live CSS editor.

```css
<style contenteditable>
style {
  color: inherit;
  display:block;
  border: 1px solid;
  font: inherit;
  font-family: monospace;
  padding:1em;
  border-radius: 1em;
  white-space: pre;
}
</style>
```

Try changing the `color` of the `style` to something other than `inherit`. Then try changing the `style` to a `p` selector.
Don't remove the display property or the style block will disappear.

<style contenteditable>
style {
  color: inherit;
  display:block;
  border: 1px solid;
  font: inherit;
  font-family: monospace;
  padding: 1em;
  border-radius: 1em;
  white-space: pre;
}
</style>

## Custom attributes

We've only touched the surface of HTML global attributes. There are even more attributes that apply to only one or a limited set of elements.
Even with hundreds of defined attributes, you may have a need for an attribute that isn't in the specification. HTML has you covered.

You can create any custom attribute you want by adding the [`data-`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/data-*) prefix. You can name your attribute anything that starts with `data-`
followed by any lowercase series of characters that don't start with `xml` and don't contain a colon (`:`).

While HTML is forgiving and won't break if you create unsupported attributes that don't start with `data`, or even if you start
your custom attribute with `xml` or include a `:`, there are benefits to creating valid custom attributes that begin with `data-`.
With custom data attributes you know that you aren't accidentally using an existing attribute name. Custom data attributes are future-proof.

While browsers won't implement default behaviors for any specific `data-` prefixed attribute, there is a built-in dataset API
to iterate through your custom attributes. Custom properties are an excellent way of communicating application-specific information
via JavaScript. Add custom attributes to elements in the form of `data-name` and access these through the DOM using `dataset[name]`
on the element in question.

```html
<blockquote data-machine-learning="workshop"
  data-first-name="Blendan" data-last-name="Smooth"
  data-formerly="Margarita Maker" data-aspiring="Load Balancer"
  data-year-graduated="2022">
  HAL and EVE could teach a fan to blow hot air.
</blockquote>
```

You can use `getAttribute()` using the full attribute name, or you can take advantage of the simpler [`dataset`](https://developer.mozilla.org/docs/Web/API/HTMLElement/dataset) property.

```js
el.dataset[machineLearning]; // workshop
e.dataset.machineLearning; // workshop
```

The `dataset` property returns a `DOMStringMap` object of each element's `data-` attributes. There are several custom attributes
on the `<blockquote>`. The dataset property means you don't need to know what those custom attributes are in order to access their
names and values:

```js
for (let key in el.dataset) {
  customObject[key] = el.dataset[key];
}
```

The attributes in this article are global, meaning they can be applied to any HTML element (though they don't all have an impact on
those elements). Up next, we take a look at the two attributes from the intro image that we didn't address—`target` and `href`—and
several other element-specific attributes as we take a deeper look into links.

{% Assessment 'attributes' %}

# Audio and Video

As you learned in the [images](/learn/html/images/) module, HTML enables embedding media into a web page. In this section,
we look at audio and video files, including how to embed them, user controls, providing a static image placeholder for your videos,
and best practices, including making audio and video files accessible.

## `<audio>` and `<video>`

The [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video) and [`<audio>`](https://developer.mozilla.org/docs/Web/HTML/Element/audio)
elements can be used to embed media players directly with the `src` attribute or can be used as the container element for a series of [`<source>`](https://developer.mozilla.org/docs/Web/HTML/Element/source) elements,
each providing a `src` file suggestion. While `<video>` can be used to embed an audio file, the `<audio>` element is preferable for embedding
sound files.

The opening `<video>` and `<audio>` tags can contain several other attributes including
`controls`, `autoplay`, `loop`, `mute`, `preload`, and the global attributes. The `<video>` element also supports the `height`, `width`, and
`poster` attributes.

```html
<video src="videos/machines.webm" poster="images/machine.jpg" controls>
  <p>Watch <a href="https://youtube.com/link">video on Youtube</a>
</video>
```

This `<video>` example has a single source with the `src` attribute linking to the video source. The `poster` attribute
provides an image to display as the video loads. Finally, the `controls` attribute provides user video controls.

Fallback content is included between the opening and closing tags. If the user agent doesn't support `<video>` (or `<audio>` this content is shown. The closing `</video>` tag is required, even if there is no content between the two
(but there should always be fallback content , right?).

If no `src` attribute is included on the opening `<video>` or `<audio>` tags, include one or more [`<source>`](https://developer.mozilla.org/docs/Web/HTML/Element/source) elements,
each with a `src` attribute to a media file. The following example includes three media file options, fallback content,
and English and French subtitles between the opening and closing tags.

```html
<video controls poster="images/machine.jpg">
  <source src="videos/machines.webm" type="video/webm">
  <source src="videos/machines.mp4" type="video/mp4">
  <source src="videos/machines.ogv" type="video/ogg">
  <track label="English" kind="subtitles" srclang="en" src="vtt/subtitles-en.vtt" default />
  <track label="Francais" kind="subtitles" srclang="fr" src="vtt/subtitles-fr.vtt" />
  <p>Watch <a href="https://youtube.com/link">video on Youtube</a>
</video>
```

Each `<source>` child includes a `src` attribute pointing to the resource and the `type` attribute informs the browser
of the linked file's [media type](https://developer.mozilla.org/docs/Web/Media/Formats/Containers). This prevents the browser
from fetching media files it wouldn't be able to decode.

Within the `type` attribute, you can include a [`codecs`](https://developer.mozilla.org/docs/Web/Media/Formats/codecs_parameter) parameter,
which specifies exactly how the resource is encoded. Codecs give you a way of including media optimizations that are not yet supported
in all browsers. The codec is separated from the media type with a semicolon. For example, the codec can be written using
intuitive syntax, such as `<source src="videos/machines.webm" type="video/webm;codecs=vp8,vorbis">` which indicates that the
WebM files contain VP8 video and vorbis audio. Codecs can also be more difficult to decipher, such as `<source src="videos/machines.mp4" type="video/mp4; codecs=avc1.4d002a">`
which indicates that the MP4 encoding is Advanced Video Coding Main Profile Level 4.2. Explaining this syntax is well beyond
the scope of this lesson. Jake Archibald has a post explaining [how to determine the codec parameter for an AV1 video](https://jakearchibald.com/2022/html-codecs-parameter-for-av1/)
if you want to learn more.

When displaying a video, by default, the first frame of the video is shown as the still shot when it becomes available.
This is something that can be controlled. The `poster` attribute enables the source of an image to show while the video is downloading
and until it is played. If the video plays and is subsequently paused, the poster is not re-shown.

Make sure to define the aspect ratio of your video, because when the video loads, a size difference
between the poster and the video will cause a reflow and repaint.

Always include the [boolean](/learn/html/attributes/#boolean-attributes) `controls` attribute. This makes the user controls
visible, providing users with the ability to control audio levels, mute the audio completely, and expand the video to fullscreen.
Omitting `controls` creates a bad user experience, especially if the boolean `autoplay` attribute is included. Note that some
browsers will not heed the `autoplay` attribute directive if the boolean `muted` attribute is omitted because autoplaying a
media file is generally a bad user experience, even when muted and with visible controls.

## Tracks

Between the opening and required closing tags of both audio and video, include one or more [`<track>`](https://developer.mozilla.org/docs/Web/HTML/Element/track)
elements to specify timed text tracks. The following example includes two `<track>` files, providing timed text subtitles in both English and French.

```html
<track label="English" kind="subtitles" srclang="en" src="vtt/subtitles-en.vtt" default />
<track label="Français" kind="subtitles" srclang="fr" lang="fr-fr" src="vtt/subtitles-fr.vtt" />
```

The track files, specified in the `src` attribute, should be in [WebVTT format](https://developer.mozilla.org/docs/Web/API/WebVTT_API) (.vtt).
The files should be on the same domain as the HTML document, unless the [`crossorigin`](https://developer.mozilla.org/docs/Web/HTML/Attributes/crossorigin)
attribute is included.

There are five enumerated values for the track `kind` attribute: `subtitles`, `captions`, `descriptions`, `chapters`, and other `metadata`.

Include `subtitles` along with the `srclang` attribute for dialogue transcription and translations. The value of each `label` attribute
is displayed as an option to the user. The content of the selected VTT option is displayed over the video. The appearance of the
subtitles can be styled by targeting the [::cue/ ::cue()](https://developer.mozilla.org/docs/Web/CSS/::cue).

The value `kind="caption"` should be reserved for transcription and translations that include sound effects and other relevant audio information.
This isn't just for deaf viewers. Maybe a user can't find their headphones so they turned on the captions. Or maybe they didn't
quite catch the last few talking points from a favorite podcast, so they want to read the transcript to confirm their understanding.
Having alternative ways to access audio and video content is both important and convenient.

The `kind="description"` is for text descriptions of the visual content in the video for users who can't see the video, whether
they are using a system without a screen such as Google Home or Alexa, or are blind.

{% Aside %}

The [audio and video](/learn/accessibility/video-audio/) section of [learn accessibility](/learn/accessibility/) goes into
more detail about [captions](/learn/accessibility/video-audio/#captions), [transcripts](/learn/accessibility/video-audio/#transcripts),
and [audio descriptions](/learn/accessibility/video-audio/#audio-descriptions).

{% endAside %}

[Providing captions and subtitles](https://developer.mozilla.org/docs/Web/Guide/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video)
using the [WebVTT format](https://developer.mozilla.org/docs/Web/API/WebVTT_API) makes the video accessible to people with
impaired hearing. Remember, disability is a mismatch between a person and their current environment. Impaired hearing can be due
to the user being in a loud environment, having faulty speakers or broken headphones, or because the user has some hearing loss or
is deaf. Ensuring your content is accessible helps many more people than you think; it helps everyone.

## Background video considerations

Your marketing or design team may want your site to include a background video. Generally, this means that they want a muted,
auto-playing, looping video with no controls. The HTML may look something like this:

```html
<video autoplay loop muted poster="images/machine.jpg" role="none">
  <source src="videos/machines.webm" type="video/webm">
  <source src="videos/machines.mp4" type="video/mp4">
  <source src="videos/machines.ogv" type="video/ogg">
</video>
```

Background videos are not accessible. Content should not be conveyed through background videos without providing users with full
control over playback and access to all captions. As this video is purely decorative, it includes the [ARIA role](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles)
of [`none`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/none_role) and omits any fallback content.
To improve the performance of always muted videos, [remove the audio track](https://gist.github.com/liangfu/97f877e311210fa0ae18a31fdd92982e) from your media sources.

If your video plays for five seconds or less, accessibility guidelines don't require a pausing mechanism, but anything
with the boolean `loop` attribute will loop forever by default, exceeding this five-second, or any other, time limit. For good
user experience, always include a method of pausing the video. This is most easily done by including `controls`.

## Custom media controls

To display custom video or audio controls, rather than the browser built-in controls, include the `controls` attribute. Then use
JavaScript to add custom media controls and remove the controls attribute. For example, you can add a `<button>` that toggles
the play state of an audio file.

```html
<button id="playPause" aria-controls="idOfAudio"
  data-pause-text="Pause audio"
  data-play-text="Play audio">Pause audio</button>
```

This example includes a button with `dataset` attributes containing the text that will be updated as the visitor toggles
between play and pause states. The `aria-controls` attribute is included with the `id` of the element controlled by the button;
in this case, the audio. Each button that controls the audio has an event handler.

To create customized controls, use [`HTMLMediaElement.play()`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/play) and
[`HTMLMediaElement.pause()`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement/pause). When toggling the play state,
also toggle the text of the button:

```js
const pauseButton = document.getElementById('playPause');

pauseButton.addEventListener("click", pauseAndPlay, false);

function pauseAndPlay() {
  console.log(this);
  const media = document.getElementById(this.getAttribute('aria-controls'));

  if (media.paused) {
    media.play();
    this.innerText = this.dataset.pauseText;
  } else {
    media.pause();
    this.innerText = this.dataset.playText;
  }
}
```

By including the `controls` attribute, the user has a way to control the audio (or video) even if JavaScript fails.
Only remove the controls attribute once a replacement button has been instantiated.

```js
document.querySelector('[aria-controls]').removeAttribute('controls');
```

Always include external controls when users can't access the controls, such as with background videos that have their controls hidden
behind site content. It is important to understand the basics of [media accessibility requirements](https://www.w3.org/WAI/WCAG21/Understanding/time-based-media) to accommodate users with
different environmental and sensory needs, including the millions of people with hearing loss and visual impairments.
We've just touched on the [`HTMLMediaElement`](https://developer.mozilla.org/docs/Web/API/HTMLMediaElement) which provides several properties, methods, and events that are inherited by both the
[HTMLVideoElement](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement) and
[HTMLAudioElement](https://developer.mozilla.org/docs/Web/API/HTMLAudioElement), with `HTMLMediaElement` adding a few properties,
methods, and events of its own. There are several other [Media APIs](https://developer.mozilla.org/docs/Web/Media#apis),
including a [TextTrack API](https://developer.mozilla.org/docs/Web/API/TextTrack). You can use the [Media Capture and Streams](https://developer.mozilla.org/docs/Web/API/Media_Capture_and_Streams_API)
and [MediaDevices](https://developer.mozilla.org/docs/Web/API/MediaDevices) APIs to [record audio from a user's microphone](/patterns/media/microphone-record/)
or [record a user's screen](/patterns/media/screen-record/). The [Web Audio API](https://developer.mozilla.org/docs/Web/API/Web_Audio_API)
enables [manipulating live and pre-recorded](/patterns/media/audio-effects/) audio and streaming, saving, or sending the audio to the `<audio>` element.

{% Assessment 'audio-video' %}

# Conclusion and next steps

If you have been following this course in order, you have made it to the end of Learn HTML! You've learned a lot, from the basics of the language, through to many of the finer details.

## Additional resources

The other courses on this site take a deeper look at some of the things you have already covered, and introduce other subjects needed in your life as a web developer:

- [Learn CSS](/learn/css/)
- [Learn Accessibility](/learn/accessibility/)
- [Learn Forms](/learn/forms/)
- [Learn Images](/learn/images/)
- [Learn Responsive Design](/learn/design/)
- [Learn PWA](/learn/pwa/)

In all of our courses we heavily link to MDN Web Docs, and the [HTML section](https://developer.mozilla.org/docs/Web/HTML) of the documentation is an excellent resource.

# Details and summary

A disclosure widget is a user interface control that hides and shows content. If you are reading this on web.dev, and your
viewport is less than 106 ems wide, clicking on the "On this page" above this paragraph reveals the table of contents for
this section. If you don't see it, shrink the browser to view the table of contents navigation on this page as a
disclosure widget.

The [accordion](https://en.wikipedia.org/wiki/Accordion_(GUI)) graphical user interface is a series of vertically stacked
disclosure widgets. A common use case for the accordion UI is the Frequently Asked Questions (FAQ) page on many sites.
An accordion FAQ contains a list of visible questions; clicking on a question expands, or "discloses", the answer to that question.

[jQuery](https://jqueryui.com/accordion/) has included an accordion UI pattern since at least 2009. The original JavaScript-free
accordion solution included making each FAQ question a `<label>` followed by the checkmark it labeled, and then displaying `<div>`
answer when the checkmark was checked. The CSS looked something like this:

```css
#FAQ [type="checkbox"] + div.answer {
  /* all the answer styles */
  display: none;
}
#FAQ [type="checkbox"]:checked + div.answer {
  display: block;
}
```

Why the history? Disclosure widgets, such as accordions, without JavaScript or form control hacks, are a relatively recent
addition; the [`<details>`](https://developer.mozilla.org/docs/Web/HTML/Element/details) and [`<summary>`](https://developer.mozilla.org/docs/Web/HTML/Element/summary)
elements have only been fully supported in all modern browsers since January 2020. You can now create functioning, albeit less
than attractive, disclosure widgets using only semantic HTML. The `<details>` and `<summary>` elements are all you need: they are a built-in way to handle
expanding and collapsing content. When a user clicks or taps a `<summary>`, or releases the <kbd>Enter</kbd> key when
the `<summary>` has focus, the contents of the parent `<details>` toggle to visible!

{% Codepen {
user: 'web-dot-dev',
id: 'MWqgjQr'
} %}

Like all semantic content, you can progressively enhance the default features and appearance. In this case, a tiny bit of
CSS has been added, but nothing else:

{% Codepen {
user: 'web-dot-dev',
id: 'ExeYgQd'
} %}

You'll note, these Codepens contain no JavaScript.
## Toggling visibility: the `open` attribute

The `<details>` element is the disclosure widget container. The `<summary>` is the summary or legend for its parent `<details>`. The
summary is always displayed, acting as a button that toggles the display of the rest of the parent’s contents. Interacting
with the `<summary>` toggles the display of the self-labeled summary siblings by toggling the `<details>`' element's `open` attribute.

The `open` attribute is a boolean attribute. If present, no matter the value or lack thereof, it indicates that all the `<details>`
contents are shown to the user. If the `open` attribute is not present, only the contents of the `<summary>` are shown.

Because the `open` attribute is added and removed automatically as the user interacts with the control, it can be used in CSS to
style the element differently based on its state.

You can create an accordion with a list of multiple `<details>` elements, each with a `<summary>` child. Omitting the `open` attribute
in your HTML means the `<details>` will all be collapsed, or closed, with just the summary headings visible when the page loads;
each heading being the opener for the rest of the contents in the parent `<details>`. If you include the `open` attribute in your HTML, the `<details>`
will render expanded, with the contents visible, when the page loads.

The hidden content in the collapsed state is searchable in some browsers but not others, even though the collapsed content
is not part of the DOM. If you search in Edge or Chrome, the details containing a search term will expand to display
the occurrence. This behavior is not replicated in Firefox or Safari.

The `<summary>` must be the first child of a `<details>` element, representing a summary, caption, or legend for the rest
of the contents of the parent `<details>` element in which it is nested. The `<summary>` element's contents can be any heading
content, plain text, or HTML that can be used within a paragraph.

## Toggling the summary marker

In the two earlier Codepens, you'll note the arrow to the [inline-start](https://developer.mozilla.org/docs/Web/CSS/CSS_Logical_Properties)
side of the summary. A disclosure widget is typically presented on-screen using a small triangle that rotates (or twists)
to indicate open/closed status, with a label next to the triangle. The contents of the `<summary>` element label the disclosure widget.
The rotating arrow at the top of each section is a [`::marker`](https://developer.mozilla.org/docs/Web/CSS/::marker) set on the
`<summary>` element. Like list items, the `<summary>` element supports the [`list-style`](https://developer.mozilla.org/docs/Web/CSS/list-style)
shorthand property and its longhand properties, including [`list-style-type`](https://developer.mozilla.org/docs/Web/CSS/list-style-type).
You can style the disclosure triangle with CSS, including changing the marker used from a triangle to any other bullet type, including
an image with [`list-style-image`](https://developer.mozilla.org/docs/Web/CSS/list-style-image).

To apply other styles, use a selector similar to [`details summary::marker`](/learn/css/pseudo-elements/#marker). The
`::marker` [pseudo-element](/learn/css/selectors/#pseudo-element) only accepts a limited number of styles. Removing the
`::marker` and replacing it with the easier-to-style [`::before`](https://developer.mozilla.org/docs/Web/CSS/::before) is
common practice, with CSS styles changing the style of the generated content slightly based on the presence (or absence)
of the open attribute. You can remove the disclosure widget icon by setting `list-style: none` or set the [content](https://developer.mozilla.org/docs/Web/CSS/content)
of the marker to `none`, but always include visual indicators to inform sighted users that the summary content is a toggle
button that will show and hide content upon activation.

```css
details summary::before {
  /* all the styles */
}
details[open] summary::before {
  /* changes applied when open only */
}
```

{% Codepen {
user: 'web-dot-dev',
id: 'jOvNMxL'
} %}

This example removes the default marker, and adds generated content to create a `+` when the details are closed and a `-`
when the details are open.

If you want the details block open by default, include the `open` attribute on the opening `<details>` tag. You can also add space
between each dialog and transition the rotation of the marker created with generated content to improve the appearance:

{% Codepen {
user: 'web-dot-dev',
id: 'yLxBajp'
} %}

## How errors are handled

If you don't include a `<summary>`, the browser will create one for you: with a marker and the word "details". This summary
is part of a [shadow root](/learn/html/template/#shadow-dom), and therefore will not have author CSS summary styles applied. Unfortunately, Safari does not include
the details in the [keyboard focus order](https://bugs.webkit.org/show_bug.cgi?id=249904).

If you do include a `<summary>`, but it is not the first element in the `<details>`, the browser still displays the summary
as it should. It will also not fail if you include a link, label, or other interactive element within the summary, but browsers
handle interactive content within interactive content differently. For example, if you include a link in a summary, some browsers
will add both the summary and the link to the default tabbing order, but other browsers will not focus on the link by default.
If you click on a `<label>` nested in a `<summary>`, some browsers will give focus to the associated form control; other browsers
will give focus to the form control and toggle the `<details>` open or closed.

{% Codepen {
user: 'web-dot-dev',
id: 'QWVLKxg'
} %}

## The `HTMLDetailsElement` interface
Like all HTML elements, the [`HTMLDetailsElement`](https://developer.mozilla.org/docs/Web/API/HTMLDetailsElement) inherits all
properties, methods, and events from [`HTMLElement`](https://developer.mozilla.org/docs/Web/API/HTMLElement), and adds the
[`open`](https://developer.mozilla.org/docs/Web/API/HTMLDetailsElement/open) instance property and a [`toggle`](https://developer.mozilla.org/docs/Web/API/HTMLDetailsElement/toggle_event)
event. The [`HTMLDetailsElement.open`](https://developer.mozilla.org/docs/Web/API/HTMLDetailsElement/open) property is a boolean
value reflecting the [`open`](https://developer.mozilla.org/docs/Web/HTML/Element/details#attr-open) HTML attribute, indicating
whether or not the element's contents (not counting the `<summary>`) are to be shown to the user. The toggle event is fired
when the `<details>` element is toggled open or closed. You can listen to this event using [`addEventListener()`](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener).

If you want to write a script to close the opened details when the user opens any other details, remove the open attribute
using [`removeAttribute("open")`](https://developer.mozilla.org/docs/Web/API/Element/removeAttribute):

{% Codepen {
user: 'web-dot-dev',
id: 'PodYGBz'
} %}

This is the only example to use JavaScript. You probably don't need JavaScript except for this functionality of closing other
opened disclosure widgets.

Remember, `<details>` and `<summary>` can be heavily styled and can even be used to [create tool tips](https://css-tricks.com/exploring-what-the-details-and-summary-elements-can-do/).
But, if you're going to use these semantic elements for use cases in which the native semantics are a mismatch, always ensure that you [maintain accessibility](https://www.scottohara.me//blog/2022/09/12/details-summary.html).
HTML for the most part is by default accessible. Our job as developers is to ensure our content stays accessible.

{% Assessment 'details' %}

# Dialog

A modal dialog is a special type of pop-up box on a web page: a pop-up that interrupts the user to focus on itself. There are
some valid [use cases for popping up a dialog](https://www.nngroup.com/articles/modal-nonmodal-dialog/), but great consideration
should be made before doing so. Modal dialogs force users to focus on specific content, and, temporarily at least, ignore
the rest of the page.

Dialogs can be either modal (only the content in the dialog can be interacted with) or non-modal (it's still possible to interact
with content outside of the dialog). Modal dialogs are displayed on top of the rest of the page content. The rest
of the page is [inert](learn/html/focus/) and, by default, obscured by a semi-transparent backdrop.

The semantic HTML [`<dialog>`](https://developer.mozilla.org/docs/Web/HTML/Element/dialog) element to create a dialog
comes with semantics, keyboard interactions, and all the properties and methods of the [`HTMLDialogElement`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement) interface.

## Modal dialogs

Here is an example of a modal `<dialog>`. Open the dialog with the "Open modal dialog" button. Once opened, there are three ways to close the dialog: the escape key, submitting a form with
a button that has the [`formmethod="dialog"`](https://developer.mozilla.org/docs/Web/HTML/Element/button#attr-formmethod)
set (or if the form itself has `method="dialog"` set), and the [`HTMLDialogElement.close()`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement/close) method.

{% Codepen {
user: 'web-dot-dev',
id: 'BaOBLNy'
} %}

The `HTMLDialogElement` has three main methods, along with all the methods inherited from [`HTMLElement`](/learn/html/apis).

```js
dialog.show() /* opens the dialog */
dialog.showModal() /* opens the dialog as a modal */
dialog.close() /* closes the dialog */
```

Because this `<dialog>` was opened via the [`HTMLDialogElement.showModal()`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement/showModal)
method, it is a modal dialog. Opening a modal dialog deactivates and obscures everything other than the dialog itself. If you
hover over the UI outside of the dialog, you’ll note all the elements are behaving as if [`pointer-events: none;`](https://developer.mozilla.org/docs/Web/CSS/pointer-events)
was set; even the button that opens the dialog doesn’t react to interactions.

When the dialog is opened, focus moves into the dialog. Focus is set on the first element in the sequential keyboard navigation order within that dialog.
If you hit the `tab` key repeatedly, you’ll note that only the content within the dialog can get focus while the modal dialog is
open. Everything outside of the modal dialog is inert as long as the dialog is open.

When a dialog is closed, modal or not, focus is returned to the element that opened the dialog. If you programmatically
open a dialog not based on user action, reconsider. If you must, ensure that focus is put back where it was prior to the dialog opening,
especially if the user dismisses the dialog without interacting with it.

There is a global [`inert`](/learn/html/focus/#the-inert-attribute) attribute that can be used to disable an element and all of its descendants, other than any active
dialog. When a modal dialog is opened using `openModal()`, the inertness or deactivation comes for free; the attribute
isn’t explicitly set.

The backdrop that obscures everything other than the dialog can be styled using the [`::backdrop`](https://developer.mozilla.org/docs/Web/CSS/::backdrop)
pseudo-element. The backdrop is only displayed when a `<dialog>` is displayed with the `.showModal()` method. This pseudo-element
matches all the backdrops, including the one displayed when the [FullScreen API](https://developer.mozilla.org/docs/Web/API/Fullscreen_API) is used,
such as when viewing a video in full-screen mode which doesn’t have the same aspect ratio as the screen or monitor.

## Non-modal dialogs

The `HTMLDialogElement.show()` similarly opens a dialog, but without adding a backdrop or causing anything to become inert.
The escape key does not close non-modal dialogs. Because of this, it is even more important to ensure you include a method
of closing the non-modal dialog. In doing so, if the closer is outside the dialog, realize the focus will go to the element
that opened the dialog, which may not be the best user experience.

{% Codepen {
user: 'web-dot-dev',
id: 'bGKQvza'
} %}

While a button to close the dialog is not officially required by the specification, consider it as required. The escape key
will close a modal dialog, but not a non-modal one. A visible button that is able to receive focus improves accessibility and
user experience.

## Closing a dialog

You don’t need the `HTMLDialogElement.close()` method to close a dialog. You don’t need JavaScript at all. To close the `<dialog>`
without JavaScript, include a form with a dialog method by either setting `method="dialog"` on the `<form>` or `formmethod="dialog"`
on the button.

When a user submits via the `dialog` method, the state of user-entered data is maintained. While there is a submit event—the
form goes through constraint validation (unless `novalidate` is set)—the user data is neither cleared nor submitted.
A close button without JavaScript can be written as:

```html
<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>
```

You may have noticed the [`autofocus`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/autofocus) attribute
set on the close `<button>` in this example. Elements with `autofocus` attribute set within a `<dialog>` will not receive
focus on page load (unless the page is loaded with the dialog visible). They will, however, get focus when the dialog is opened.

By default, when a dialog is opened, the first focusable element within the dialog will receive focus unless a different
element within the dialog has the `autofocus` attribute set. Setting the `autofocus` attribute on the close button ensures
it receives focus when the dialog is opened. But including [`autofocus` within a `<dialog>`](/learn/html/focus/#autofocus)
should only be done with much consideration. All the elements in the sequence coming before the autofocused element are skipped.
We discuss this attribute further in [the focus lesson](/learn/html/focus/).

The [`HTMLDialogElement`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement) interface includes a [`returnValue`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement/returnValue)
property. Submitting a form with a `method="dialog"` sets the `returnValue` to the `name`, if any, of the submit button used to
submit the form. If we had written `<button type="submit" name="toasty">close</button>`, the `returnValue` would be `toasty`.

When a dialog is opened, the boolean [`open`](https://developer.mozilla.org/docs/Web/HTML/Element/dialog#attr-open) attribute
is present, meaning the dialog is active and can be interacted with. When a dialog is opened by adding the `open` attribute rather
than via `.show()` or `.showModal()`, the dialog will be modal-less. The [`HTMLDialogElement.open`](https://developer.mozilla.org/docs/Web/API/HTMLDialogElement/open)
property returns `true` or `false`, depending on whether the dialog is available for interaction—not whether it is modal or not.

While JavaScript is the preferred method of opening a dialog, including the `open` attribute on page load, and then removing
it with `.close()`, can help ensure the dialog is available even when JavaScript is not.

## Additional details

### Don't use `tabindex`

The element that is activated to open the dialog and the close button contained in it (and possibly other content) can receive
focus and are interactive. The `<dialog>` element is not interactive and doesn’t receive focus. Do not add the `tabindex` property
to the dialog itself.

### ARIA roles

The implicit role is [`dialog`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/dialog_role). If the dialog
is a confirmation window communicating an important message that requires a confirmation or other user response, set [`role="alertdialog"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/alertdialog_role).
The dialog should also have an accessible name. If visible text can provide for the accessible name, add `aria-labelledby="idOfLabelingText"`.

### CSS defaults

Note that browsers provide default styling for `dialog`. Firefox, Chrome, and Edge set `color: CanvasText;` `background-color: Canvas;`
and Safari sets `color: black; background-color: white;` in their user-agent stylesheets. The `color` is inherited
from `dialog` and not from `body` or `:root`, which may be unexpected. The `background-color` property is not inherited.

{% Assessment 'dialog' %}

# Document structure

HTML documents include a document type declaration and the `<html>` root element. Nested in the `<html>` element are the document head and document body. While the head of the document isn't visible to the sighted visitor, it is vital to make your site function. It contains all the meta information, including information for search engines and social media results, icons for the browser tab and mobile home screen shortcut, and the behavior and presentation of your content. In this section, you'll discover the components that, while not visible, are present on almost every web page.

To create the MachineLearningWorkshop.com (MLW) site, start by including the components that should be considered essential for every web page: the type of document, the content's human language, the character set, and, of course, the title or name of the site or application.

## Add to every HTML document

There are several features that should be considered essential for any and every web page. Browsers will still render content if these elements are missing, but include them. Always.

### `<!DOCTYPE html>`

The first thing in any HTML document is the preamble. For HTML, all you need is `<!DOCTYPE html>`. This may look like an HTML element, but it isn't. It's  a special kind of node called "doctype". The doctype tells the browser to use standards mode. If omitted, browsers will use a different rendering mode known as [quirks mode](https://developer.mozilla.org/docs/Web/HTML/Quirks_Mode_and_Standards_Mode). Including the doctype helps prevent quirks mode.

### `<html>`

The `<html>` element is the root element for an HTML document. It is the parent of the `<head>` and `<body>`, containing everything in the HTML document other than the doctype. If omitted it will be implied, but it is important to include it, as this is the element on which the language of the content of the document is declared.

### Content language

The `lang` language attribute added to the `<html>` tag defines the main language of the document. The value of the [`lang` attribute](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang#language_tag_syntax) is a two- or three-letter ISO language code followed by the region. The region is optional, but recommended, as a language can vary greatly between regions. For example, French is very different in Canada (`fr-CA`) versus Burkina Faso (`fr-BF`). This language declaration enables screen readers, search engines, and translation services to know the document language.

The `lang` attribute is not limited to the `<html>`tag. If there is text within the page that is in a language different from the main document language, the `lang` attribute should be used to identify exceptions to the main language within the document.  Just like when it is included in the head, the `lang` attribute in the body has no visual effect. It only adds semantics, enabling assistive technologies and automated services to know the language of the impacted content.

In addition to setting the language for the document and exceptions to that base language, the attribute can be used in CSS selectors.  `<span lang="fr-fr">Ceci n'est pas une pipe.</span>` can be targeted with the attribute and language selectors [`[lang|="fr"]`](https://developer.mozilla.org/docs/Web/CSS/Attribute_selectors#attrvalue_3) and [`:lang(fr)`](https://developer.mozilla.org/docs/Web/CSS/:lang).

### `<head>`

Nested between the opening and closing `<html>` tags, we find the two children: `<head>` and `<body>`:

```html
<!DOCTYPE html>
<html lang="en-US">
  <head>
  </head>
  <body>
  </body>
</html>
```

The `<head>`, or document metadata header, contains all the metadata for a site or application. The body contains the visible content. The rest of this section focuses on the components found nested inside the opening and closing `<head></head>`

## Required components inside the `<head>`

The document metadata, including the document title, character set, viewport settings, description, base URL, stylesheet links, and icons, are found in the `<head>` element. While you may not need all these features, always include character set, title, and viewport settings.

### Character encoding

The very first element in the `<head>` should be the `charset` character encoding declaration. It comes before the title to ensure the browser can render the characters in that title and all the characters in the rest of the document.

The [default encoding](https://html.spec.whatwg.org/multipage/parsing.html#documentEncoding) in most browsers is `windows-1252`, depending on the locale. However, you should use [`UTF-8`](https://developer.mozilla.org/docs/Glossary/UTF-8), as it enables the one- to four-byte encoding of all characters, even ones you didn't even know existed. Also, it's the encoding type required by HTML5.

To set the character encoding to UTF-8, include:

```html
<meta charset="utf-8" />
```

By declaring `UTF-8` (case-insensitive), you can even include emojis in your title (but please don't).

The character encoding is inherited into everything in the document, even `<style>` and `<script>`. This little declaration means you can include emojis in class names and the selectorAPI (again, please don't).  If you do [use emojis](https://readabilityguidelines.co.uk/images/emojis/), make sure to use them in a way that enhances usability without harming accessibility.

### Document title

Your home page and all additional pages should each have a unique title. The contents for the document title, the text between the opening and closing `<title>` tags, are displayed in the browser tab, the list of open windows, the history, search results, and, unless redefined with [`<meta>` tags](/learn/html/metadata), in social media cards.

```html
<title>Machine Learning Workshop</title>
```

### Viewport metadata

The other meta tag that should be considered essential is the [viewport](/learn/design/intro/#a-meta-element-for-viewport) meta tag, which helps site responsiveness, enabling content to render well by default, no matter the viewport width. While the [viewport meta tag](https://developer.mozilla.org/docs/Web/HTML/Viewport_meta_tag) has been around since June 2007, when the first iPhone came out, it's only recently been [documented in a specification](https://drafts.csswg.org/css-viewport/#viewport-meta).  As it enables controlling a viewport's size and scale, and prevents the site's content from being sized down to fit a 960px site onto a 320px screen, it is definitely recommended.

```html
<meta name="viewport" content="width=device-width" />
```

The preceding code means "make the site responsive, starting by making the width of the content the width of the screen". In addition to `width`, you can set zoom and scalability, but they both default to accessible values. If you want to be explicit, include:

```html
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1" />
```

Viewport is part of the [Lighthouse accessibility audit](/meta-viewport/); your site will pass if it is scalable and has no maximum size set.

So far, the outline for our HTML file is:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Machine Learning Workshop</title>
    <meta name="viewport" content="width=device-width" />
  </head>
  <body>

  </body>
</html>
```

## Other `<head>` content

There's a lot more that goes into the `<head>`. All the metadata, in fact.  Most of the elements you'll find in the `<head>` are covered here, while saving a plethora of the `<meta>` options for the next chapter.

You've seen the meta character set and the document title, but there is a lot more metadata outside of `<meta>` tags that should be included.

### CSS

The `<head>` is where you include styles for your HTML. There is a [learning path dedicated to CSS](/learn/css/) if you want to learn about styles, but you do need to know how to include them in your HTML documents.

There are three ways to include CSS: `<link>`, `<style>`, and the `style` attribute.

The main two ways to include styles in your HTML file are by including an external resource using a `<link>` element with the `rel` attribute set to `stylesheet`, or including CSS directly in the head of your document within opening and closing `<style>` tags.

The `<link>` tag is the preferred method of including stylesheets. Linking a single or a few external style sheets is good for both developer experience and site performance: you get to maintain CSS in one spot instead of it being sprinkled everywhere, and browsers can cache the external file, meaning it doesn't have to be downloaded again with every page navigation.

The syntax is `<link rel="stylesheet" href="styles.css">`, where styles.css is the URL of your stylesheet. You'll often see `type="text/css"`. Not necessary! If you are including styles written in something other than CSS, the `type` is needed, but since there isn't any other type, this attribute isn't needed. The `rel` attribute defines the relationship: in this case `stylesheet`. If you omit this, your CSS will not be linked.

You'll discover a few other `rel` values shortly, but let's first discuss other ways of including CSS.

If you want your external style sheet styles to be within a cascade layer but you don't have access to edit the CSS file to put the layer information in it, you'll want to include the CSS with [`@import`](https://developer.mozilla.org/docs/Web/CSS/@import) inside a `<style>`:

```html
<style>
  @import "styles.css" layer(firstLayer);
</style>
```

When using `@import` to import style sheets into your document, optionally into cascade layers, the `@import` statements must be the first statements in your `<style>` or linked stylesheet, outside of the character set declaration.

While cascade layers are still fairly new and you might not spot the `@import` in a head `<style>`, you will often see custom properties declared in a head style block:

```html
<style>
  :root {
    --theme-color: #226DAA;
  }
</style>
```

{% Aside %}
Styles, the presentation layer, are the purview of CSS, here we are considering how to attach your styles to the content layer, your HTML. If the CSS of the preceding code interests you, look up [cascade layers](https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Cascade_layers) and [custom properties](https://developer.mozilla.org/docs/Web/CSS/Using_CSS_custom_properties).
{% endAside %}

Styles, either via `<link>` or `<style>`, or both, should go in the head. They will work if included in the document's body, but you want your styles in the head for performance reasons. That may seem counterintuitive, as you may think you want your content to load first, but you actually want the browser to know how to render the content when it is loaded. Adding styles first prevents the unnecessary repainting that occurs if an element is styled after it is first rendered.

Then there's the one way of including styles you'll never use in the `<head>` of your document: inline styles. You'll probably never use inline styles in the head because the user agents' style sheets hide the head by default. But if you want to make a CSS editor without JavaScript, for example, so  you can test your page's custom elements, you can make the head visible with `display: block`,  and then hide everything in the head, and then with an inline `style` attribute, make a content-editable style block visible.

```html
<style contenteditable style="display: block; font-family: monospace; white-space: pre;">
  head { display: block; }
  head * { display: none; }
  :root {
    --theme-color: #226DAA;
  }
</style>
```

While you can add inline styles on the `<style>`, it's way more fun to style your `<style>` in your `style`. I digress.

### Other uses of the `<link>` element

The `link` element is used to create relationships between the HTML document and external resources. Some of these resources may be downloaded, others are informational. The type of relationship is defined by the value of the `rel` attribute.  There are currently [25 available values for the `rel` attribute](https://html.spec.whatwg.org/multipage/links.html#linkTypes) that can be used with `<link>`,  `<a>` and `<area>`, or `<form>`, with a few that can be used with all. It's preferable to include those related to meta information in the head and those related to performance in the `<body>`.

You'll include three other types in your header now: `icon`, `alternate`, and `canonical`. (You'll include a fourth type,  [`rel="manifest"`, in the next module](/learn/html/metadata/)).

#### Favicon

Use the `<link>` tag, with the `rel="icon"` attribute/value pair to identify the favicon to be used for your document. A favicon is a very small icon that appears on the browser tab, generally to the left of the document title. When you have an unwieldy number of tabs open, the tabs will shrink and the title may disappear altogether, but the icon always remains visible. Most favicons are company or application logos.

If you don't declare a favicon, the browser will look for a file named `favicon.ico` in the top-level directory (the website's root folder). With `<link>`, you can use a different file name and location:

```html
<link rel="icon" sizes="16x16 32x32 48x48" type="image/png" href="/images/mlwicon.png" />
```

The preceding code says "use the `mlwicon.png` as the icon for scenarios where a 16px, 32px, or 48px makes sense." The sizes attribute accepts the value of `any` for scalable icons or a space-separated list of square `widthXheight` values; where the width and height values are 16, 32, 48, or greater in that geometric sequence, the pixel unit is omitted, and the X is case-insensitive.

```html
<link rel="apple-touch-icon" sizes="180x180" href="/images/mlwicon.png" />
<link rel="mask-icon" href="/images/mlwicon.svg" color="#226DAA" />
```

There are two special non-standard kind of icons for Safari browser: `apple-touch-icon` for iOS devices and `mask-icon` for pinned tabs on macOS. `apple-touch-icon` is applied only when the user adds a site to home screen: you can specify multiple icons with different `sizes` for different devices. `mask-icon` will only be used if the user pins the tab in desktop Safari: the icon itself should be a monochrome SVG, and the `color` attribute fills the icon with needed color.

While you can use `<link>` to define a completely different image on each page or even each page load, don't. For consistency and a good user experience, use a single image! Twitter uses the blue bird: when you see the blue bird in your browser tab, you know that tab is open to a Twitter page without clicking on the tab. Google uses different favicons for each of its different applications: there's a mail icon, a calendar icon, for example. But all the Google icons use the same color scheme. Again, you know exactly what the content of an open tab is simply from the icon.

#### Alternate versions of the site

We use the `alternate` value of the `rel` attribute to identify translations, or alternate representations, of the site.

Let's pretend we have versions of the site translated into French and Brazilian Portuguese:

```html
<link rel="alternate" href="https://www.machinelearningworkshop.com/fr/" hreflang="fr-FR" />
<link rel="alternate" href="https://www.machinelearningworkshop.com/pt/" hreflang="pt-BR" />
```

When using `alternate` for a translation, the `hreflang` attribute must be set.

The alternate value is for more than just translations. For example, the `type` attribute can define the alternate URI for an RSS feed when the `type` attribute is set to `application/rss+xml` or `application/atom+xml`. Let's link to a pretend PDF version of the site.

```html
<link rel="alternate" type="application/x-pdf" href="https://machinelearningworkshop.com/mlw.pdf" />
```

If the `rel` value is `alternate stylesheet`, it defines an [alternate stylesheet](https://developer.mozilla.org/docs/Web/CSS/Alternative_style_sheets) and the `title` attribute must be set giving that alternate style a name.

#### Canonical

If you create several translations or versions of Machine Learning Workshop, search engines may get confused as to which version is the authoritative source. For this, use `rel="canonical"` to identify the preferred URL for the site or application.

Include the canonical URL on all of your translated pages, and on the home page, indicating our preferred URL:

```html
<link rel="canonical" href="https://www.machinelearning.com" />
```

The `rel="canonical"` canonical link is most often used for cross-posting with publications and blogging platforms to credit the original source; when a site syndicates content, it should include the canonical link to the original source.

### Scripts

The `<script>` tag is used to include, well, scripts. The default type is JavaScript. If you include any other scripting language, include the `type` attribute with the mime type, or `type="module"` if it's a [JavaScript module](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Modules#applying_the_module_to_your_html). Only JavaScript and JavaScript modules get parsed and executed.

The `<script>` tags can be used to encapsulate your code or to download an external file. In MLW, there is no external script file because contrary to popular belief, you don't need JavaScript for a functional website, and, well, this is an HTML learning path, not a JavaScript one.

You will be including a tiny bit of JavaScript to create an [Easter egg](https://www.webopedia.com/definitions/easter-egg/) later on:

```html
<script>
  document.getElementById('switch').addEventListener('click', function() {
    document.body.classList.toggle('black');
  });
</script>
```

This snippet creates an event handler for an element with the id of `switch`. With JavaScript, you don't want to reference an element before it exists.  It doesn't exist yet, so we won't include it yet. When we do add the light switch element, we'll add the `<script>` at the bottom of the `<body>` rather than in the `<head>`. Why? Two reasons. We want to ensure elements exist before the script referencing them is encountered as we're not basing this script on a [DOMContentLoaded event](https://developer.mozilla.org/docs/Web/API/Document/DOMContentLoaded_event). And, mainly, JavaScript is not only [render-blocking](https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources/), but the browser stops downloading all assets when scripts are downloaded and doesn't resume downloading other assets until the JavaScript has finished execution. For this reason, you will often find JavaScript requests at the end of the document rather than in the head.

There are two attributes that can reduce the blocking nature of JavaScript download and execution: `defer` and `async`. With `defer`, HTML rendering is not blocked during the download, and the JavaScript only executes after the document has otherwise finished rendering. With `async`, rendering isn't blocked during the download either, but once the script has finished downloading, the rendering is paused while the JavaScript is executed.

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/bMpXQsshdEYqlmwV2wBW.png", alt="loading when using async and defer.", width="800", height="365" %}

To include MLW's JavaScript in an external file, you could write:

```html
<script src="js/switch.js" defer></script>
```

Adding the [`defer`](https://developer.mozilla.org/docs/Learn/JavaScript/First_steps/What_is_JavaScript#script_loading_strategies) attribute defers the execution of the script until after everything is rendered, preventing the script from harming performance. The `async` and `defer` attributes are only valid on external scripts.

### Base

There is another element that is only found in the `<head>.` Not used very often, the `<base>` element allows setting a default link URL and target. The `href` attribute defines the base URL for all relative links.

The `target` attribute, valid on `<base>` as well as on links and forms, sets where those links should open. The default of `_self` opens linked files in the same context as the current document. Other options include `_blank`, which opens every link in a new window, the `_parent` of the current content, which may be the same as self if the opener is not an iframe,  or `_top`, which is in the same browser tab, but popped out of any context to take up the entire tab.

Most developers add the `target` attribute to the few, if any, links they want to open in a new window on the links or form themselves, rather than using `<base>`.

```html
<base target="_top" href="https://machinelearningworkshop.com" />
```

If our website found itself nested within an iframe on a site like Yummly, including the `<base>` element would mean when a user clicks on any links within our document, the link will load popped out of the iframe, taking up the whole browser window.

One of the drawbacks of this element is that anchor links are resolved with `<base>`. The `<base>` effectively converts the link `<a href="#ref">` to `<a target="_top" href="https://machinelearningworkshop.com#ref">`,  triggering an HTTP request to the base URL with the fragment attached.

A few other things to note about `<base>`: there can be only one `<base>` element in a document, and it should come before any relative URLs are used, including possible script or stylesheet references.

The code now looks like this:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Machine Learning Workshop</title>
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" src="css/styles.css" />
    <link rel="icon" type="image/png" href="/images/favicon.png" />
    <link rel="alternate" href="https://www.machinelearningworkshop.com/fr/" hreflang="fr-FR" />
    <link rel="alternate" href="https://www.machinelearningworkshop.com/pt/" hreflang="pt-BR" />
    <link rel="canonical" href="https://www.machinelearning.com" />
  </head>
  <body>

    <!-- <script defer src="scripts/lightswitch.js"></script>-->
  </body>
</html>
```

### HTML comments

Note that the script is wrapped between some angle brackets, dashes, and a bang. This is how you comment out HTML. We'll leave the script commented out until we have the actual content on the page.  Anything between `<!--` and `-->` will not be visible or parsed. HTML comments can be put anywhere on the page, including the head or body, with the exception of scripts or style blocks, where you should use JavaScript and CSS comments, respectively.

You have covered the basics of what goes in the `<head>`, but you want to learn more than the basics. In the next sections, we will learn about meta tags, and how to control what gets displayed when your website is linked to on social media.

{% Assessment 'document-structure' %}

# Focus

Interactive elements, including [form controls](/learn/html/forms/), [links](/learn/html/links/), and buttons, are by
default focusable and tabbable. Tabbable elements are part of the document's sequential focus navigation order. Other elements
are inert, meaning they are not interactive. With HTML attributes, it is possible to make interactive elements inert and to
make inert elements interactive.

{% Aside %}
For usability reasons, always ensure that the user knows which element has focus. Include CSS [`:focus`](https://developer.mozilla.org/docs/Web/CSS/:focus),
[`:focus-visible`](https://developer.mozilla.org/docs/Web/CSS/:focus-visible), and, optionally, [`:focus-within`](https://developer.mozilla.org/docs/Web/CSS/:focus-within)
styles. This is so important: there are Learn sections devoted to focus styles in both the [CSS](/learn/css/focus/) and [Accessibility](/learn/accessibility/focus/) learning paths.
{% endAside %}

By default, the navigation focus order is the same as the visual order, which is the source code order. There are HTML
attributes that can alter this order and CSS properties that can alter the visual order of content. Changing the tabbing
order with HTML or visual rendering order with CSS can harm user experience.

Don't alter the perceived and actual tabbing order with CSS and HTML. As the following two examples demonstrate, tab orders
that differ from the visually expected order are confusing to users and bad for user experience.

In this example, the value of the [`tabindex`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/tabindex) attribute
has made the tab order chaotic:

{% Codepen {
user: 'web-dot-dev',
id: 'GRXKqGz',
tab: 'result'
} %}

In this example, CSS has created a divergence between the tabbing order and the visual order of the content:

{% Codepen {
user: 'web-dot-dev',
id: 'KKxPMBV',
tab: 'result'
} %}

The [`flex-flow: row-reverse;`](https://developer.mozilla.org/docs/Web/CSS/flex-flow) declaration has reversed the visual order.
In addition, the CSS [order](https://developer.mozilla.org/docs/Web/CSS/order) property was applied to the sixth word, "This", which visually moved that
one word. The tabbing sequence is the order of the code, which no longer matches the visual order, creating a disconnect
for keyboard users.

{% Aside %}
CSS features, including [flexbox](https://developer.mozilla.org/docs/Learn/CSS/CSS_layout/Flexbox), [grid](https://developer.mozilla.org/docs/Web/CSS/CSS_Grid_Layout),
[positioning](https://developer.mozilla.org/docs/Learn/CSS/CSS_layout/Positioning), [transforms](https://developer.mozilla.org/docs/Web/CSS/translate),
and [multi-column](https://developer.mozilla.org/docs/Learn/CSS/CSS_layout/Multiple-column_Layout), can alter the visual order of
content. Always ensure your content maintains a logical tabbing order on all viewport sizes. Test your content by tabbing
through it with a keyboard: with shift + tab to move backwards through the content. Always ensure it's apparent which element
currently has focus with CSS, and avoid accessibility problems by not reordering focusable elements with CSS.
{% endAside %}

## Making inert elements interactive

The `contenteditable` and `tabindex` attributes, being global attributes, can be added to any element, making them focusable
in the process. Focusable elements can also be focused with a mouse or pointer, by having the [`autofocus`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/autofocus)
attribute set, or by script, such as with [`element.focus()`](https://developer.mozilla.org/docs/Web/API/HTMLElement/focus).

### The `tabindex` attribute

The global [`tabindex`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/tabindex) attribute, introduced in
[attributes](/learn/html/attributes/#tabindex), enables elements that otherwise would not be able to receive focus to get
focus, usually with the Tab key, hence the name.

The `tabindex` attribute takes as its value an integer. A negative value makes an element focusable but not tabbable. A
`tabindex` value of `0` makes the element focusable and tabbable, adding the element on which it is applied to the sequential
focus navigation order in source code order. A value of 1 or greater makes the element focusable and tabbable,
but adds it to a prioritized tabbing sequence, and, as we saw above, should be avoided.

On this page, the share button, `<share-action>`, is a [custom element](/learn/html/template/). The `tabindex="0"` adds this not-normally focusable
element into the keyboard default tabbing order:

```html
<share-action authors="@front-end.social/@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, mastodon" role="button" tabindex="0">
  <svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
    <use href="#shareIcon" />
  </svg>
  <span>Share</span>
</share-action>
```

{% Aside %}

The [`role="button"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/button_role) informs screen reader
users that this element should behave like a [`<button>`](https://developer.mozilla.org/docs/Web/HTML/Element/button).
When creating custom elements which mimic existing semantic elements, including an [ARIA role](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles)
is appropriate and expected. The element must provide all the features of the element being replicated. This can be done by extending the replicated
element, such as extending the [`HTMLButtonElement`](https://developer.mozilla.org/docs/Web/API/HTMLButtonElement), or by adding
`tabindex="0"` and using JavaScript to program *all* the functionality of the element it is mimicking, including handling
pointer events and the Enter and Space key presses. If `<button>` had been used for the button instead of creating a custom element,
the `tabindex` and `role` attributes would have been unnecessary, and the browser would have provided the pointer and keyboard events.
{% endAside %}

There's another custom element on this page: the [local navigation](/learn/html/navigation/#local-navigation) has a custom
element with a negative `tabindex` value:

```html
<web-navigation-drawer type="standard" tabindex="-1">
```

A `tabindex` attribute with a negative value makes the element focusable but not tabbable. The element is capable of receiving
focus, such as via [`HTMLElement.focus()`](https://developer.mozilla.org/docs/Web/API/HTMLElement/focus), but it is not part
of the sequential focus navigation order. The convention for non-tabbable, focusable elements is to use `tabindex="-1"`. Note that
if you add `tabindex="-1"` to an interactive element, it will no longer be tabbable.

The [`element.focus()`](https://developer.mozilla.org/docs/Web/API/HTMLElement/focus) method can be used to set focus to
focusable elements. Note that the browsers scroll focused elements into view. For this reason, avoid the use of
`element.focus({preventScroll:true})`, as focusing on a non-visible element will give a bad user experience.

If you want to query the document to find out which element currently has focus, use the read-only [`Document.activeElement`](https://developer.mozilla.org/docs/Web/API/Document/activeElement) property.

Elements with a `tabindex` of `1` or greater are included in a separate tab sequence. As you'll notice in the Codepen,
tabbing begins in a separate sequence, in order of lowest value to highest value, before going through those in the regular sequence
(no `tabindex` set, or `tabindex="0"`) in source order:

{% Codepen {
user: 'web-dot-dev',
id: 'WNgexPv'
} %}

`tabindex` with a positive value puts the element into a prioritized focus sequence, which can lead to focus order chaos.
Avoid [modifying the DOM order with `tabindex`](/using-tabindex/). Not only can altered tabbing orders create bad user
experiences, they are difficult for developers to manage and maintain.

### The `contenteditable` attribute

The [`contenteditable`](/learn/html/attributes/#contenteditable/) attribute was discussed earlier. Setting `contenteditable="true"` on any element makes it editable,
focusable, and part of the tab order. The focus behavior is similar to setting `tabindex="0"`, but not the same. Nested
`contenteditable` elements are focusable but not tabbable. To make a nested `contenteditable` element tabbable, add `tabindex="0"`,
which will add it to the sequential focus navigation order.

## Giving focus to interactive elements

### The `autofocus` attribute

While the boolean [`autofocus`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/autofocus) is a global attribute
that can be set on any element, it doesn't make an inert element interactive. When the page loads, the first focusable element
with the `autofocus` attribute set will receive focus, as long as that element is displayed and not nested in a [`<dialog>`](/learn/html/dialog/).

Automatically setting focus on content can be confusing. Setting `autofocus` on a form control means that the form control
will scroll into view on page load. All your users, including screen reader users and users with small viewports, may not
"see" the instructions for the form, possibly even scrolling past the form control's normally visible label. The `autofocus`
attribute doesn't alter the document's sequential focus navigation order. The elements in the sequence coming before the
autofocused element are simply skipped. For these reasons, it is not advised to include the `autofocus` attribute.

The exception to the "don't use `autofocus`" recommendation is including the `autofocus` attribute within `<dialog>` elements.
When a dialog is opened, the browser will automatically focus on the first focusable interactive element within the `<dialog>`,
meaning `autofocus` to an element is not necessary. If you want to be sure a specific interactive element within the dialog receives
focus when the dialog opens, add the `autofocus` attribute to that element.

```html
<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>
```

The `autofocus` attribute set on the close `<button>` ensures it receives focus when the dialog is opened. As the first element
in the dialog, it would have received focus in any case. By default, when a dialog is opened, the first focusable element within
the dialog will receive focus unless a different element within the dialog has the `autofocus` attribute set.

## Making interactive elements inert

There are also HTML attributes that can remove interactive elements from the tabbing sequence. Including a negative `tabindex`
to focusable elements, adding the `disabled` attribute to supporting form controls, and adding the global `inert` attribute
to a container all make elements un-tabbable. These three attributes are NOT interchangeable.

### Negative `tabindex` value

As we learned above, a `tabindex` attribute with a negative value makes an element focusable but not tabbable. While adding
`tabindex="0"` to a focusable-by-default element, including links, buttons, form controls, and elements that are `contenteditable`
is not necessary; including a `tabindex` with a negative value removes normally tabbable elements from the sequential focus
navigation order.

A negative `tabindex` value prevents keyboard users from focusing on interactive elements, but doesn't disable the element. Pointer
users can still focus on the element. To disable an element, use the `disabled` attribute.

### Disabled

The boolean [disabled](https://developer.mozilla.org/docs/Web/HTML/Attributes/disabled) attribute makes the form controls on
which it is applied and their descendants, if any, unfocusable. Disabled form controls can't be focused, don't get click events,
and are not submitted upon form submission. Note `disabled` is not a global attribute. It applies to `<button>`, `<input>`,
`<optgroup>`, `<option>`, `<select>`, `<textarea>`, form-associated custom elements, and [`<fieldset>`](https://developer.mozilla.org/docs/Web/HTML/Element/fieldset).
When set on `<optgroup>` or `<fieldset>`, all the child form controls are disabled, except for the contents of the `<fieldset>`'s first [`<legend>`](https://developer.mozilla.org/docs/Web/HTML/Element/legend).

The same elements that support `disabled` are also targetable with the [`:disabled`](https://developer.mozilla.org/docs/Web/CSS/:disabled)
and [`:enabled`](https://developer.mozilla.org/docs/Web/CSS/:enabled) pseudoclasses. Elements that are disabled with the
`disabled` attribute are generally styled as light gray via the user-agent stylesheet, even if an [`accent-color`](https://developer.mozilla.org/docs/Web/CSS/accent-color)
is set.

Being a boolean attribute, the presence of the attribute disables the otherwise enabled element; you can't set it to `false`.
To re-enable a disabled element, the attribute has to be removed, generally via [`Element.removeAttribute('disabled')`](https://developer.mozilla.org/docs/Web/API/Element/removeAttribute).

The [`HTMLInputElement.disabled`](https://developer.mozilla.org/docs/Web/API/HTMLInputElement/disabled) property lets you check
if an input is disabled. As `disabled` is not a global attribute, it's not inherited from the HTMLElement, but every supporting
element interface, like [`HTMLSelectElement`](https://developer.mozilla.org/docs/Web/API/HTMLSelectElement/disabled),
[`HTMLTextareaElement`](https://developer.mozilla.org/docs/Web/API/HTMLTextAreaElement#instance_properties), has the same read-only property.

The `disabled` attribute does not apply to normally `inert` elements that are made focusable via `tabindex` or `contenteditable`.
It also doesn't apply to the `<form>` element itself. To disable these, the global `inert` attribute can be used.

### The `inert` attribute

When the `inert` global boolean attribute is added to an element, that element and all nested content become disabled—neither
clickable nor tabbable—and removed from the accessibility tree. While `inert` can be applied to any element, it is generally
used for sections of content, such as offscreen or otherwise hidden content.

When applying `disabled` to form controls, the browser provides default styling and can be styled using the [`:disabled`](https://developer.mozilla.org/docs/Web/CSS/:disabled)
pseudo class. The `inert` attribute provides no visual indicators and has no matching pseudoclass (though the `[inert]` [attribute selector](/learn/css/selectors/#attribute-selector) matches).

Using `inert` on visible content without styles indicating the inertness can lead to poor user experience. As inert content
is not available to screen reader users, it can lead to confusion when sighted screen reader users see content on screen
that is not available to the accessibility tools. Make inertness very apparent via CSS.

Make sure that the focus never moves to non-visible content. Anything rendered off-screen that does not automatically
come into view when focused should be made [inert](https://developer.chrome.com/articles/inert/). If content is hidden,
but comes into view when focused, like the [skip to content link](/learn/html/navigation/#skip-to-content-link) on this page,
it does not need to be made inert.

## Check your understanding

{% Assessment 'focus' %}

# Forms

Most sites and applications include a web form. Joke sites, like [DoWebsites<wbr>Need<wbr>To<wbr>Look<wbr>Exactly<wbr>The<wbr>Same<wbr>In<wbr>Every<wbr>Browser.com](http://dowebsitesneedtolookexactlythesameineverybrowser.com/),
may not have a form, but even [Machine<wbr>Learning<wbr>Workshop.com](https://machinelearningworkshop.com/) (MLW), which originated as an April Fool's day joke, has a form,
albeit a fake one. MLW's main "call to action" is a registration form for machines to sign up for a workshop. This form
is contained in a `<form>` element.

The [HTML `<form>` element](https://developer.mozilla.org/docs/Web/HTML/Element/form) identifies a document [landmark](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles#3._landmark_roles) containing
interactive controls for submitting information. Nested in a `<form>` you'll find all the interactive (and non-interactive)
form controls that make up that form.

HTML is powerful. This section focuses on the power of HTML, covering what HTML can do without adding JavaScript.
Using form data client-side to update the UI in some way generally involves [CSS](https://codepen.io/jcoulterdesign/pen/NOMeEb) or JavaScript, which is not discussed here.
There is an entire [Learn Forms](/learn/forms/) course. We won't duplicate that section here, but we will introduce
several form controls and the HTML attributes that empower them.

With forms, you can enable users to interact with your website or application, validate the information entered, and submit
the data to a server. HTML attributes can enable requiring the user to select form controls or enter a value. HTML
attributes can define specific criteria that the value must match to be valid. When the user tries to submit the form,
all the form control values go through [client-side constraint validation](#) and can prevent submission
until the data matches the required criteria; all without JavaScript. You can also turn this feature off: setting the [`novalidate`](https://developer.mozilla.org/docs/Web/HTML/Element/form#attr-novalidate)
attribute on the `<form>` or, more often, `formnovalidate` on a button, saving the form data for later completion,
prevents validation.

## Submitting forms

Forms are submitted when the user activates a submit button nested within the form. When using `<input>` for buttons, the
'value' is the button's label, and is displayed in the button. When using `<button>`, the label is the text between the opening
and closing `<button>` tags. A submit button can be written either of two ways:

```html
<input type="submit" value="Submit Form">
<button type="submit">Submit Form</button>
```

For a very simple form, you need a `<form>` element, with some form inputs inside, and a submit button. However, there is
more to submitting a form than that.

The attributes of the `<form>` element set the [HTTP method](/learn/forms/form-element/#how-is-the-data-transferred) by
which the form is submitted and the URL that processes the form submission. Yes, forms can be submitted, processed, and
a new page can be loaded without any JavaScript. The [`<form>` element](/learn/forms/form/) is that powerful.

The `<form>` element's [`action`](https://developer.mozilla.org/docs/Web/HTML/Element/form#attr-action) and [`method`](https://developer.mozilla.org/docs/Web/HTML/Element/form#attr-method)
attribute values define the URL that processes the form data and the HTTP method used to submit the data, respectively.
By default, the form data gets sent to the current page. Otherwise, set the `action` attribute to the URL of where the data should be sent.

The data sent is made up of name/value pairs of the form's various form controls. By default, this includes all the form
controls nested within the form that have a `name`. However, with the `form` attribute, it is possible to include form controls
outside the `<form>` and to omit form controls nested within the `<form>`. Supported on form controls and `<fieldset>`,
the `form` attribute takes as its value the `id` of the form the control it is associated with, not necessarily the form it
is nested in. This means form controls don't need to be physically nested in a `<form>`.

{% Aside 'warning' %}
Be careful though: using the `form` attribute makes it possible to disassociate a form control from its form by including
it with an empty or erroneous value.
{% endAside %}

The `method` attribute defines the HTTP protocol of the request: generally `GET` or `POST`. With `GET`, the form data is sent as a
parameter string of `name=value` pairs, appended to the `action`'s URL.

With `POST`, the data is appended to the body of the HTTP request. When sending secure data, such as passwords and credit card
information, always use `POST`.

There is also a `DIALOG` method. If a `<form method="dialog">` is within a `<dialog>`, submitting the form will close the dialog;
there is a submit event though the data is neither cleared nor submitted. Again, without JavaScript. This is discussed in
[the dialog section](/learn/html/dialog/). Just note, because this doesn't submit the form, you probably want to
include both `formmethod="dialog"`and `formnovalidate` on the submit button.

Form buttons can have more than the attributes described at the start of this section. If the button includes a `formaction`,
`formenctype`, `formmethod`, `formnovalidate`, or `formtarget` attribute, the values set on the button activating the form
submission take precedence over the `action`, [`enctype`](/learn/forms/form/#enable-users-to-submit-files), `method`, and [`target`](/learn/html/attributes/)
set on the `<form>`. Constraint validation occurs prior to form submission, but only if there is neither a
`formnovalidate` on the activated submit button nor a `novalidate` on the `<form>`.

To capture which button was used to submit a form, give
the button a `name`.  Buttons with no name or value don't get sent with the form data on form submission.

## After submitting the form

When the user submits a completed online form, the names and values of the relevant form controls get submitted. The name is the value of the `name` attribute. The values come from the contents of the `value` attribute or the value entered or picked by the user. The value of a `<textarea>` is its inner text.
The value of a `<select>` is the selected `<option>`'s `value` or, if the `<option>` doesn't include a `value` attribute, the value is the selected option's inner text.

```html
<form method="GET">
  <label for="student">Pick a student:</label>
  <select name="student" id="student">
    <option value="hoover">Hoover Sukhdeep</option>
    <option>Blendan Smooth</option>
    <option value="toasty">Toasty McToastface</option>
  </select>
  <input type="submit" value="Submit Form">
</form>
```

<form method="GET">
  <label for="student">Pick a student:</label>
  <select name="student" id="student">
    <option value="hoover">Hoover Sukhdeep</option>
    <option>Blendan Smooth</option>
    <option value="toasty">Toasty McToastface</option>
  </select>
  <input type="submit" value="Submit Form">
</form>

Selecting "Hoover Sukhdeep" (or doing nothing, as the browser displays and therefore selects the first option value by default)
and then clicking the submit button will reload this page, setting the URL to:

```html
https://web.dev/learn/html/forms?student=hoover
```

Because the second option doesn't have a `value` attribute, the inner text is submitted as the value. Selecting "Blendan Smooth"
and clicking the submit button will reload this page, setting the URL to:

```html
https://web.dev/learn/html/forms?student=Blendan+Smooth
```

When a form is submitted, the information sent includes the names and values of all named form controls that have a `name`
except non-selected checkboxes, non-selected radio buttons, and the names and values of any buttons other than the one that
submitted the form. For all other form controls, if the form control has a name, but no value was entered or defaulted, the
form control's `name` gets submitted with an empty value.

There are [22 input types](https://developer.mozilla.org/docs/Web/HTML/Element/Input#input_types), so we can't cover them all.
Just note that including a value is optional, and often a bad idea, when you want the user to enter information.
For `<input>` elements where the user can't edit the value, you should always include a value, including for input
elements with a type of `hidden`, `radio`, `checkbox`, `submit`, `button`, and `reset`.

Using unique `name`s for form controls makes server-side data processing simpler and is recommended, with checkboxes and
radio buttons being exceptions to this rule.

## Radio buttons

If you have ever noticed that when you select a radio button within a group of radio buttons, only one can be selected at
a time, this is due to the `name` attribute. This only-one-can-be-selected effect is created by giving each radio button
in a group the same `name`.

{% Codepen {
user: 'web-dot-dev',
id: 'JjBQJEv'
} %}

A `name` should be unique to the group: if you accidentally use the same `name` for two separate groups, selecting a radio
button in the second group will deselect any selection made in the first group with the same `name`.

The `name` along with the `value` of the selected radio button are submitted with the form. Make sure each radio button has
a relevant (and usually unique) `value`. The values of the non-selected radio buttons are not sent.

You can have as many radio groups on a page as you like, with each group working independently, as long as each has a
unique-to-the-group `name`.

If you want to load the page with one of the radio buttons in a same-named group selected, include the `checked` attribute.
This radio button will match the [`:default`](https://developer.mozilla.org/docs/Web/CSS/:default) CSS pseudo-class,
even if the user selects a different radio. The currently selected radio button matches the [`:checked`](https://developer.mozilla.org/docs/Web/CSS/:checked)
pseudo-class.

If the user is required to pick a radio control from a group of radio buttons, add the [`required`](https://developer.mozilla.org/docs/Web/HTML/Attributes/required) attribute to at least one
of the controls. Including `required` on a radio button in a group makes a selection required for form submission, but it
doesn't have to be the radio with the attribute that gets selected to be valid. Also, indicate clearly in the `<legend>`
that the [form control is required](https://www.deque.com/blog/anatomy-of-accessible-forms-required-form-fields/). The labeling of groups of radio buttons along with each individual button is described
later on.

## Checkboxes

It's valid for all checkboxes within a group to have the same `name`. Only selected checkboxes have their `name` and `value`
submitted with the form. If you have multiple checkboxes with the same name selected, the same name will be submitted with
(hopefully) different values. If you have multiple form controls with the same name, even if they are not all checkboxes,
they will all get submitted, separated by ampersands.

If you don't include a `value` on a checkbox, the value of the selected checkboxes will default to `on`, which probably isn't
helpful. If you have three checkboxes named `chk` and they're all checked, the form submission will not be decipherable:

```html
https://web.dev/learn/html/forms?chk=on&chk=on&chk=on
```

To make a checkbox required, add the `required` attribute. Always inform the user when a checkbox must be checked, or when
any form control is required. Adding `required` to a checkbox only makes that checkbox required; it does not impact other
checkboxes with the same name.

## Labels and fieldsets

In order for users to know how to fill out a form, the form has to be accessible. Every form control must have a label.
You also want to label groups of form controls. While individual input, select, and text areas are labeled with `<label>`,
groups of form controls are labeled by the contents of the [`<legend>`](https://developer.mozilla.org/docs/Web/HTML/Element/legend) of
the [`<fieldset>`](https://developer.mozilla.org/docs/Web/HTML/Element/fieldset) that groups them.

In the previous examples, you may have noticed that each form control except the submit button had a `<label>`. Labels
provide form controls with accessible names. Buttons get their accessible name from their content or value. All the other
form controls require an associated `<label>`. If there is no associated label, the browser will still render your form controls,
but users will not know what information is expected.

To explicitly associate a form control with a `<label>`, include the `for` attribute on the [`<label>`](https://developer.mozilla.org/docs/Web/HTML/Element/label): the value being the
`id` of the form control it is associated with.

```html
<label for="full_name">Your name</label>
<input type="text" id="full_name" name="name">
```

<label for="full_name">Your name</label>
<input type="text" id="full_name" name="name">

Associating labels with form controls has several benefits. Labels make form controls accessible to screen reader users by
providing the control with an accessible name. Labels are also "hit areas"; they make the site more usable for users with
dexterity issues by increasing the area. If you're using a mouse, try clicking anywhere on the label "Your name". Doing
so gives the input focus.

To provide implicit labels, include the form control between the opening and closing `<label>` tags. This is equally
accessible from both a screen reader and pointer device perspective, but doesn't provide the styling hook like the explicit
label.

```html
<label>Your name
  <input type="text" name="name">
</label>
```

<label>Your name
  <input type="text" name="name">
</label>

As labels are "hit areas", don't include interactive elements within an explicit label, or any other interactive components
other than the labeled form control in an implicit label. For example, if you include a link in a label, while the browser
will render the HTML, your users will be confused if they click on the label to enter a form control but are redirected to
a new page.

Generally, the `<label>` comes before the form control except in the case of radio buttons and checkboxes. This isn't required.
It's just the common UX pattern. The Learn Forms series has [information about form design](/learn/forms/design-basics/).

For groups of radio buttons and checkboxes, the label provides the accessible name for the form control it is associated with;
but the group of controls and their labels also need a label. To label the group, group all of the elements into a
`<fieldset>`, with the `<legend>` providing the label for the group.

```html
<fieldset>
  <legend>Who is your favorite student?</legend>
  <ul>
    <li>
      <label>
        <input type="radio" value="blendan" name="machine"> Blendan Smooth
      </label>
    </li>
    <li>
      <label>
        <input type="radio" value="hoover" name="machine"> Hoover Sukhdeep
      </label>
    </li>
    <li>
      <label>
        <input type="radio" value="toasty" name="machine"> Toasty McToastface
      </label>
    </li>
  </ul>
</fieldset>
```

{% Codepen {
user: 'web-dot-dev',
id: 'OJEggda'
} %}

In this example, the implicit `<label>`s each label a radio button and the `<legend>` provides the label for the group of radio buttons.
Nesting a `<fieldset>` inside another `<fieldset>` is standard practice. For example, if a form is a survey of many questions
divided into groups of related questions, the “favorite student" `<fieldset>` may be nested in another `<fieldset>` labeled as
"Your favorites":

```html
<fieldset>
  <legend>Your favorites:</legend>
  <ul start="6">
    <li>
      <fieldset>
        <legend>Who is your favorite student?</legend>
        <ul>
          <li>
            <!-- the rest of the code here -->
```

These elements' default appearances have led to their underuse, but [`<legend>` and `<fieldset>` can be styled](https://developer.mozilla.org/docs/Web/HTML/Element/fieldset#styling_with_css) with CSS.
In addition to all the global attributes, `<fieldset>` also supports the `name`, `disabled`, and `form` attributes.
When you disable a fieldset, all nested form controls are disabled. Neither the `name` nor the `form` attributes have
much use on the `<fieldset>`. The `name` can be used to access the fieldset with JavaScript, but the fieldset itself
is not included in submitted data (the named form controls nested within are included).

{% Aside %}
You can learn more about forms and accessibility in the [forms module of Learn Accessibility](/learn/accessibility/forms/).
{% endAside %}

## Input types and dynamic keyboard

As noted earlier, there are [22 different types of inputs](https://developer.mozilla.org/docs/Web/HTML/Element/Input#input_types).
In some cases, when a user is on a device with a dynamic keyboard that displays only as needed, such as a phone, the input
type used determines the type of keyboard displayed. The default keyboard shown can be optimized for the type of input required.
For example, type `tel` will show a keypad optimized for entering telephone numbers; `email` includes the `@` and `.`; and the
dynamic keyboard for `url` includes a colon and the slash symbol. Unfortunately, the iPhone still doesn't include `:` in
the default dynamic keyboard for `url` input types.

Keyboards for `<input type="tel">` on iPhone and two different Android phones:

<div style="display: flex; flex-wrap: wrap;">
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/BK9EPsgyPy0Wt2jmp0lp.png", alt="iPhone keyboard showing input type=tel.", width="194", height="400", style="max-width: 194px; margin: 0 auto;" %}
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/8ECZmU9gqR4X6ppGk3v4.png", alt="Android keyboard showing input type=tel.", width="194", height="400", style="max-width: 194px; margin: 0 auto;" %}
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/dODUYXx0VDxVwBMP0e59.png", alt="Android keyboard showing input type=tel.", width="194", height="400", style="max-width: 194px; margin: 0 auto;" %}
</div>

Keyboards for `<input type="email">` on iPhone and two different Android phones:

<div style="display: flex; flex-wrap: wrap;">
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/Zd2yPTG7QT74AIvyCJrU.png", alt="iPhone keyboard showing input type=email.", width="194", height="400", style="max-width: 194px; margin: 0 auto;"  %}
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/bofzFSrrNK55RW1FesAg.png", alt="Android keyboard showing input type=email.", width="194", height="400", style="max-width: 194px; margin: 0 auto;"  %}
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/4ZwT1lrxJ4owTP0FjGWf.png", alt="Android keyboard showing input type=email.", width="194", height="400", style="max-width: 194px; margin: 0 auto;"  %}
</div>

## Accessing the microphone and camera

The file input type `<input type="file">` enables uploading files via forms. Files can be of any type, defined and limited
by the [`accept`](https://developer.mozilla.org/docs/Web/HTML/Attributes/accept) attribute. The list of acceptable file types can be a comma-separated list of file extensions, a global type,
or a combination of global types and extensions. For example, `accept="video/*, .gif"` accepts any video files or animated gifs.
Use "`audio/*`" for sound files, "`video/*`" for video files, and "`image/*`" for image files.

The enumerated [`capture`](https://developer.mozilla.org/docs/Web/HTML/Attributes/capture) attribute, defined in the
[media capture specification](https://w3c.github.io/html-media-capture/#the-capture-attribute), can be used if a new media
file is to be created using the user's camera or microphone. You can set the value to `user` for the user-facing input devices
or `environment` for the phone's back camera or microphone. Generally, using `capture`, without a value, works because the user
is going to pick which input device they want to use.

```html
<label for="avatar">A recent photo of yourself:</label>
<input type="file" capture="user" accept="image/*" name="avatar" id="avatar">
```

## Built-in validation

Again, without including any JavaScript, HTML can prevent forms with invalid values from being submitted.

There are some CSS selectors that match form controls based on the presence of HTML attributes including [`:required`](https://developer.mozilla.org/docs/Web/CSS/:required)
and [`:optional`](https://developer.mozilla.org/docs/Web/CSS/:optional) if the boolean [`required`](https://developer.mozilla.org/docs/Web/HTML/Attributes/required)
is set or not; [`:default`](https://developer.mozilla.org/docs/Web/CSS/:default) if [`checked`](https://developer.mozilla.org/docs/Web/HTML/Element/input#checked)
is hard-coded; and [`:enabled`](https://developer.mozilla.org/docs/Web/CSS/:enabled) or [`:disabled`](https://developer.mozilla.org/docs/Web/CSS/:disabled),
depending on whether the element is interactive and if the [`disabled`](https://developer.mozilla.org/docs/Web/HTML/Attributes/disabled)
attribute is present. The [`:read-write`](https://developer.mozilla.org/docs/Web/CSS/:read-write) pseudoclass matches elements with
[`contenteditable`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/contenteditable) set and
form controls that are by default editable, such as `number`, `password`, and `text` input types (but not checkbox,
radio buttons, or the `hidden` type, among others). If a normally writable element has the [`readonly`](https://developer.mozilla.org/docs/Web/HTML/Attributes/readonly)
attribute set, it will match [`:read-only`](https://developer.mozilla.org/docs/Web/CSS/:read-only) instead.

As the user enters information into form controls, the CSS UI selectors, including [`:valid`](https://developer.mozilla.org/docs/Web/CSS/:valid),
[`:invalid`](https://developer.mozilla.org/docs/Web/CSS/:invalid), [`:in-range`](https://developer.mozilla.org/docs/Web/CSS/:in-range), and
[`:out-of-range`](https://developer.mozilla.org/docs/Web/CSS/:out-of-range) will toggle on and off depending on the state. When the user
exits a form control, either the not-yet fully supported [`:user-invalid`](https://developer.mozilla.org/docs/Web/CSS/:user-invalid) or
[`:user-valid`]((https://developer.mozilla.org/docs/Web/CSS/:user-valid)) pseudo-class will match.

You can use CSS to provide cues about whether form controls are required and valid as the user interacts with the form.
You can even use CSS to prevent users from being able to click the submit button until the form is valid:

```css
form:invalid [type="submit"] {
  opacity: 50%;
  pointer-events: none;
}
```

This CSS snippet is an anti-pattern. While your UI may feel intuitive and clear, many users attempt to submit a form to
enable error messaging. Making a submit button appear disabled in this way doesn't allow for constraint validation, a
feature many users rely on.

Applied CSS is updated continuously based on the current state of the UI. For example, when you include input types with
constraints, such as `email`, `number`, `url` and date types, if the value is non-null (not empty) and the current
value is not a valid email, number, url, date or time, the [`:invalid` CSS pseudo-class](https://developer.mozilla.org/docs/Web/CSS/:invalid) will be a match. This constant
updating is different from built-in HTML constraint validation, which only occurs when the user attempts to submit the form.

Built-in constraint validation is only relevant to constraints set with HTML attributes. While you can style an element based
on the `:required` and `:valid`/`:invalid` pseudoclasses, the browser supplied error messages stemming from errors based on
the `required`, `pattern`, `min`, `max`, and even `type` attributes, come at form submission.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/C3UYbvnyGYyLhCqReM8M.png", alt="An error message indicating that a multi-choice field is required.", width="738", height="354" %}

When we attempt to submit the form without picking the required favorite student, constraint validation prevents form submission
because of a [`validityState.valueMissing`](https://developer.mozilla.org/docs/Web/API/ValidityState/valueMissing) error.

If any of the `validityState` properties return `true`, submission is blocked, and the browser displays an error message
in the first incorrect form control, giving it focus. When the user activates a form submission and there are invalid values,
the first invalid form control will show an error message and receive focus. If a required control has no value set, if a
numeric value is out of range, or if a value is not of the type required by the `type` attribute, the form will not validate,
will not submit, and an error message will appear.

If a `number`, date, or time value is below the minimum `min` set or above the maximum `max` set the control will be [`:out-of-range`](https://developer.mozilla.org/docs/Web/CSS/:out-of-range) (and `:invalid`), and
the user will be informed of the [`valididityState.rangeUnderflow`](https://developer.mozilla.org/docs/Web/API/ValidityState/rangeUnderflow),
[`validityState.rangeOverflow`](https://developer.mozilla.org/docs/Web/API/ValidityState/rangeUnderflow)  error when they
try to submit the form. If the value is out of step with the
`step` value, whether explicitly set or defaulting to `1`, the control will be `:out-of-range` (and `:invalid`) and there will be a
[`validityState.stepMismatch`](https://developer.mozilla.org/docs/Web/API/ValidityState/stepMismatch) error. The error appears as a bubble and by default provides helpful information on how to rectify the mistake.

There are similar attributes for the length of values: the [`minlength`](https://developer.mozilla.org/docs/Web/HTML/Attributes/minlength)
and [`maxlength`](https://developer.mozilla.org/docs/Web/HTML/Attributes/maxlength) attributes will alert the user of an error
with the [`validityState.tooLong`](https://developer.mozilla.org/docs/Web/API/ValidityState/tooLong) or
[`validityState.tooShort`](https://developer.mozilla.org/docs/Web/API/ValidityState/tooShort) on submission.
The `maxlength` also prevents the user from entering too many characters.

Using the `maxlength` attribute can lead to a poor user experience. It's generally a better experience to allow the user
to enter more than the allowed character length providing a counter, optionally in the form of an
[`<output>`](https://developer.mozilla.org/docs/Web/HTML/Element/output) element, which is not submitted with the form,
enabling them to edit down the text until the output shows the maximum allowed length has not been exceeded. The `maxlength`
can be included in your HTML; like everything we've discussed, it works without JavaScript. Then, on load, the value of
the maxlength attribute can be used to create this character counter in JavaScript.

Some input types appear to have default constraints, but don't. For example, the `tel` input type provides for a numeric
telephone keypad on devices with dynamic keyboards, but doesn't constrain valid values. For this, and other input types,
there is the `pattern` attribute. You can specify a regular expression the value needs to match to be considered valid.
If a value is the empty string, and the value is not required, it will not cause a [`validityState.patternMismatch`](https://developer.mozilla.org/docs/Web/API/ValidityState/patternMismatch)
error. If required and empty, the default error message for `validityState.valueMissing`will be shown to the user, rather than
the `patternMismatch`.

For emails, the [`validityState.typeMismatch`](https://developer.mozilla.org/docs/Web/API/ValidityState/typeMismatch) is probably too
forgiving for your needs. You will likely want to include the [`pattern`](https://developer.mozilla.org/docs/Web/HTML/Attributes/pattern)
attribute so intranet email addresses without a [TLD](https://developer.mozilla.org/docs/Glossary/TLD) aren't accepted as valid.
The pattern attribute enables providing a regular expression that the value must match. When requiring a pattern match,
ensure it is very clear to the user what is expected.

All of this can be done without a single line of JavaScript, but being an HTML API, you can use JavaScript to include
custom messages during constraint validation. You can also use JavaScript to update how many characters are left, show
a progression bar for password strength, or any other number of ways to [dynamically improve completion](/learn/forms/javascript/#validation-with-javascript).

## Example

{% Codepen {
user: 'web-dot-dev',
id: 'ExeYjPB'
} %}

This example has a form within a `<dialog>` with a nested `<form>` with three form controls and two submit buttons, with
clear labels and instructions.

The first submit button closes the dialog. Use `formmethod="dialog"` to override the form's default method, and close the
`<dialog>` without submitting the data or erasing it. You must also include the `formnovalidate` otherwise the browser will
try to validate checking that all the required fields have a value. The user may want to close the dialog and form without
entering any data; validation would prevent this. Include `aria-label="close"` because “X" is a known visual cue but is
not a descriptive label.

The form controls all have implicit labels, so you don't need to include `id` or `for` attributes. The input elements both
have the required attribute making them required. The number input has the `step` explicitly set to demonstrate how `step` is
included. As `step` defaults to `1`, this attribute can be omitted.

The `<select>` has a default value making the `required` attribute unnecessary. Instead of including the `value` attribute
on each option, the value defaults to the inner text.

The submit button at the end sets the forms method to POST. When clicked, the validity of each value will be checked. If all
values are valid, the form data will be submitted, the dialog will close, and the page may redirect to `thankyou.php`,
which is the action URL. If any values are missing, or if the numeric value has a step mismatch or is out of range, a
relevant browser defined error message will appear, the form will not be submitted, and the dialog will not close.
The default error messages can be customized with the [`validityState.setCustomValidity('message here')`](/learn/forms/javascript/#validation-with-javascript)
method. Just note that if you set a custom message, the message must be explicitly set to the empty string when everything
is valid or the form will not submit.

{% Aside %}

These `<input>` elements include a slash at the end, also called a "self-closing tag", which is a misnomer. The slash on
void elements is a feature of XML, including SVG and XHTML, but not HTML. Browsers ignore it, [Prettier](https://prettier.io/)
requires it, and the HTML Validator throws a warning when encountered.

As the slash makes it easier to read markup and some template engines require it, many view including this slash as a good
habit. Others view this slash as against the spec, which it isn't, a waste of two bytes, which it arguably might be, and a
possible cause of problems. The slash only causes problems if you neither quote your attributes nor put a space between the
attribute and the end of the tag. In this case, the slash will be part of the attribute value. Because of this unquoted
attribute issue, including the slash may actually encourage quoting attributes, which most developers consider to be a best
practice.

As you learn HTML, it is helpful to code in as legible a manner as possible, which includes "closing" all tags and quoting all
attributes. As you become more familiar with all the intricacies of HTML and your comfort level improves, you may change your
habits to no longer adding a slash to void elements, omitting optional closing tags, and even omitting implicit tags altogether,
and leaving quotes off attributes that allow for it. The important thing, whether you are coding CSS, HTML, JavaScript, or other,
is to be consistent in your coding style.

{% endAside %}

## Other considerations

There is an entire section devoted to [helping your users enter the right data in forms](/learn/forms/validation/). For good
user experience, it is important to prevent users from making errors by including instructions and providing hints as necessary.
While this section covers how HTML alone can provide validation client-side, validation must be both client-side and
server-side. [Validation can be provided in](/learn/forms/validation/) unobtrusive ways during form completion, such as adding a
check mark when the value is correct. Do not provide error messaging before the form control is complete though. If the user
does make a mistake, inform the user where the mistake is and what they got wrong.

In [designing forms](/learn/forms/internationalization/), it is important to consider that not everyone is like you. Someone
may have a single letter as a last name (or no last name at all), may not have a zip code, might have a three-line street address,
may not have a street address. They may be viewing a translated version of your form.

Form controls, their labels, and the error messages should be visible on the screen, accurate and meaningful, programmatically
determinable, and programmatically associated with the appropriate form element or group. The [`autocomplete`](/learn/forms/autofill/#how-does-autofill-work)
attribute can and should be used to enable faster form completion and improve accessibility.

HTML provides all the tools for making basic form controls accessible. The more interactive a form element or process is,
the more attention needs to be given to accessibility with respect to focus management, setting and updating ARIA names, roles,
and values, where necessary, and ARIA live announcements as required. But, as we've learned here, with HTML alone, you can get a
long way to your goal of accessibility and validity without resorting to ARIA or JavaScript.

{% Assessment 'forms' %}

# Headings and sections

In the last section you learned how, even if you don't know what the words on a page mean, when semantic elements provide the document with meaningful structure, others—the search engine, assistive technologies, a future maintainer, a new team member—will understand the outline of the document.

In this section, you'll discover document structure; you'll recap the sectioning elements from the previous section; and mark up the outline for your application.

Choosing the right elements for the job as you code means you won't have to refactor or comment out your HTML. If you think about using the right element for the job, you'll most often pick the right element for the job. If you don't, you probably won't.

Now that you [understand markup semantics](/learn/html/semantic-html/)  and are aware of why choosing the right element is important, once you learn about all the different elements, you will generally pick the right element without much, if any, additional effort.

## Site `<header>`

Let's build a site header. You'll start with non-semantic markup, and work your way to a good solution so that you can learn the benefits of the HTML section and heading elements along the way.

If you put little to no thought into the semantics for our header, you might use code like this:

```html
<!-- start header -->
<div id="pageHeader">
  <div id="title">Machine Learning Workshop</div>
  <!-- navigation -->
  <div id="navigation">
    <a href="#reg">Register</a>
    <a href="#about">About</a>
    <a href="#teachers">Instructors</a>
    <a href="#feedback">Testimonials</a>
  </div>
  <!-- end navigation bar -->
</div>
<!-- end of header -->
```

CSS can make (almost) any markup look right. But using the non-semantic `<div>` for everything actually creates extra work. To target multiple `<div>`s with CSS, you end up using ids or classes to identify the content. The code also includes a comment for each closing `</div>` to indicate which opening tag each `</div>` closed.

While the `id` and `class` attributes provide hooks for styling and JavaScript, they add no semantic value for the screen reader and (for the most part) the search engines.

You can include `role` attributes to provide semantics to create a good accessibility object model (AOM) for screen readers:

```html
<!-- start header -->
<div role="banner">
  <div role="heading" aria-level="1">Machine Learning Workshop</div>
  <div role="navigation">
    <a href="#reg">Register</a>
    <a href="#about">About</a>
    <a href="#teachers">Instructors</a>
    <a href="#feedback">Testimonials</a>
  </div>
  <!-- end navigation bar -->
<div>
<!-- end of header -->
```

This at least provides semantics and enables using attribute selectors in the CSS, but it still adds comments to identify which `<div>` each `</div>` closes.

If you know HTML, all you have to do is think about the purpose of the content. Then you can write this code semantically without using `role` and without needing to comment the closing tags:

```html
<header>
  <h1>Machine Learning Workshop</h1>
  <nav>
    <a href="#reg">Register</a>
    <a href="#about">About</a>
    <a href="#teachers">Instructors</a>
    <a href="#feedback">Testimonials</a>
  </nav>
</header>
```

This code uses two semantic landmarks: `<header>` and `<nav>`.

This is the main header. The `<header>` element isn't always a landmark. It has different semantics depending on where it is nested. When the `<header>` is top level, it is the site `banner`, a landmark role, which you may have noted in the `role` code block. When a `<header>` is nested in  `<main>`, `<article>`,  or `<section>`, it just identifies it as the header for that section and isn't a landmark.

The `<nav>` element identifies content as navigation. As this `<nav>` is nested in the site heading, it is the main navigation for the site. If it was nested in an `<article>` or `<section>`, it would be internal navigation for that section only. By using semantic elements, you built a meaningful [accessibility object model](https://developer.mozilla.org/docs/Glossary/Accessibility_tree), or AOM. The AOM enables the screen reader to inform the user that this section consists of a major navigation block that they can either navigate through or skip.

Using `</nav>` and `</header>` closing tags removes the need for comments to identify which element each end tag closed. In addition, using different tags for different elements removes the need for `id` and `class` hooks. The CSS selectors can have low [specificity](/learn/css/specificity/); you can probably target the links with `header nav a` without worrying about conflict.

You have written a header with very little HTML and no classes or ids. When using semantic HTML, you don't need to.

## Site `<footer>`

Let's code the site footer.

```html
<footer>
  <p>&copy;2022 Machine Learning Workshop, LLC. All rights reserved.</p>
</footer>
```

Similar to `<header>`, whether the footer is a landmark depends on where the footer is nested. When it is the site footer, it is a landmark, and should contain the site footer information you want on every page, such as a copyright statement, contact information, and links to your privacy and cookie policies. The implicit `role` for the site footer is `contentinfo`. Otherwise, the footer has no implicit role and is not a landmark, as shown in the following screenshot of the AOM in Chrome (which has an `<article>` with a `<header>` and `<footer>`  between the `<header>` and `<footer>`).

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/A6uTEfG3muxX7namzXW5.png", alt="The Accessibility Object Model in Chrome.", width="800", height="374" %}

In this screenshot, there are two footers: one in an `<article>` and one top level. The top level footer is a landmark with the implicit role of `contentinfo`. The other footer isn't a landmark. Chrome shows it as `FooterAsNonLandmark`; Firefox shows it as `section`.

That doesn't mean you shouldn't use `<footer>`. Let's say you have a blog. The blog has a site footer with an implicit `contentinfo` role. Each blog post can also have a `<footer>`. On your blog's main landing page, the browser, search engine, and screen reader know the main footer is the top-level footer, and that all the other footers are related to the posts in which they are nested.

When a `<footer>` is a descendant of an `<article>`, `<aside>`, `<main>`, `<nav>`, or `<section>`, it's not a landmark. If the post appears on its own, depending on the markup, that footer might get promoted.

Footers are often where you will find contact information, wrapped in `<address>`, the contact address element. This is one element that is not very well named; it is used to enclose the contact information for individuals or organizations, not physical mailing addresses.

```html
<footer>
  <p>&copy;2022 Machine Learning Workshop, LLC. All rights reserved.</p>
  <address>Instructors: <a href="/hal.html">Hal</a> and <a href="/eve.html">Eve</a></address>
</footer>
```

## Document structure

This module starts with the `<header>` and `<footer>`, because they are unique in only sometimes being landmark, or "sectioning", elements. Let's cover the "full time" sectioning element by discussing the most common page layouts:

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/LJs8vlTVDYBmM6t1z6rD.png", alt="A layout with a header, three columns, and a footer.", width="800", height="607" %}

A layout with a header, two sidebars, and a  footer, is known as the [holy grail layout](/patterns/layout/holy-grail/). There are many ways to mark up this content, including:

```html
<body>
  <header>Header</header>
  <nav>Nav</nav>
  <main>Content</main>
  <aside>Aside</aside>
  <footer>Footer</footer>
</body>
```

If you are creating a blog, you might have a series of articles in `<main>`:

```html
<body>
  <header>Header</header>
  <nav>Nav</nav>
  <main>
    <article>First post</article>
    <article>Second post</article>
  </main>
  <aside>Aside</aside>
  <footer>Footer</footer>
</body>
```

When employing semantic elements, browsers are able to create meaningful accessibility trees, enabling screen reader users to more easily navigate. Here, a `banner` and `contentinfo` are provided through a site `<header>` and `<footer>`.  The new elements added here include `<main>`, `<aside>`, and `<article>`; also, `<h1>` and `<nav>` that you used earlier, and `<section>`, which you haven't used yet.

### `<main>`

There's a single `<main>` landmark element. The `<main>` element identifies the main content of the document. There should be only one `<main>` per page.

### `<aside>`

The `<aside>` is for content that is indirectly or tangentially related to the document's main content. For example, this article is about HTML. For a section on CSS selector specificity for the three site header examples (div, role, and semantic), the tangentially related aside could be contained in an `<aside>`; and, like most, the `<aside>` would likely be presented in a sidebar or a call-out box. The `<aside>` is also a landmark, with the implicit role of `complementary`.

### `<article>`
Nested in `<main>` we added two `<article>` elements. This wasn't necessary in the first example when the main content was just one word, or in the real world, a single section of content. But, if you are writing a blog, as in our second example, each post should be in an `<article>` nested in `<main>`.

An `<article>` represents a complete, or self-contained, section of content that is, in principle, independently reusable. Think of an article as you would an article in a newspaper.  In print, a news article about Jacinda Ardern, Prime Minister of New Zealand, might only appear in one section, maybe world news. On the paper's website, that same news article might appear on the home page, in the politics section, in the Oceana or the Asia Pacific news section, and, depending on the topic of the news, the sports, lifestyle, or technology sections, perhaps. The article may also appear on other sites, like Pocket or Yahoo News!

### `<section>`

The `<section>` element is used to encompass generic standalone sections of a document when there is no more specific semantic element to use. Sections should have a heading, with very few exceptions.

Going back to the Jacinda Ardern example, on the home page of the newspaper, the banner would include the name of the newspaper, followed by a single `<main>`, divided into several `<section>`s, each with a header, such as "World news" and "Politics"; and in each section you'll find a series of `<article>`s. Within each `<article>`, you might find one or more `<section>` elements as well. If you look at this page, the entire "headers and sections" part is the `<article>`. This `<article>` is then divided into several `<section>`s, including `site header`, `site footer`, and document structure. The article itself has a header, as do each of the sections.

A `<section>` isn't a landmark unless it has an accessible name; if it has an accessible name, the implicit role is `region`. [Landmark roles](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles#landmark_roles) should be used sparingly, to identify larger overall sections of the document. Using too many landmark roles can create "noise" in screen readers, making it difficult to understand the overall layout of the page, if your `<main>` contains two or three important sub-sections, including an accessible name for each `<section>` could be beneficial.

## Headings: `<h1>`-`<h6>`

There are six section heading elements: `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, and `<h6>`.  Each represents one of the six levels of section headings, with `<h1>` being the highest or most important section level, and `<h6>` the lowest.

When a heading is nested in a document banner `<header>`, it is the heading for the application or site. When nested in `<main>`, whether or not it is nested within a `<header>` in `<main>`, it is the header for that page, not the whole site. When nested in an `<article>` or `<section>`, it is the header for that subsection of the page.

{% Codepen {
  user: 'web-dot-dev',
  id: 'oNdePZj',
  height: 500,
  theme: 'dark',
  tab: 'html,result'
} %}

It is recommended to use heading levels similarly to heading levels in a text editor: starting with a `<h1>` as the main heading, with `<h2>` as headings for sub-sections, and `<h3>` if those sub-sections have sections; avoid skipping heading levels. There is a good [article on section headings](https://developer.mozilla.org/docs/Web/HTML/Element/Heading_Elements) here.

Some screen reader users do access headings to understand a page's content. Originally, headings were supposed to outline a document, just as MS Word or Google Docs can produce an outline based on headings, but browsers never implemented this structure. While browsers do display nested headings at increasingly smaller font sizes as shown in the following example, they don't actually support outlining.

You now have enough knowledge to outline MachineLearningWorkshop.com:

## Outlining the `<body>` of MLW.com

This is the outline for the visible content of the machine learning workshop site:

{% Codepen {
  user: 'web-dot-dev',
  id: 'gOzxdxR',
  height: 700,
  theme: 'dark',
  tab: 'html'
} %}

{% Aside %}
This code snippet only includes the content of the `<body>`. The [`<!doctype>`, `<html>`, `<body>`, and meta-information](/learn/html/metadata/) were covered earlier.
{% endAside %}

As no piece of content is a standalone, complete piece of content, `<section>` is more appropriate than `<article>`; while each has a heading, no section is worthy of a `<footer>`.

It should go without saying by this point, but don't use headings to make text bold or large; use CSS instead. If you want to emphasize text, there are semantic elements to do that too. We'll cover that and fill in most of the page's content as we discuss text basics; after taking a deeper dive into attributes.

{% Assessment 'headings-and-sections' %}

# Images

Decorative images, such as background gradients on buttons or background images on sections of content or the full page,
are presentational and should be applied with CSS. When an image adds context to a document, it is content and should be
embedded with HTML.

The main method for including images is the [`<img>`](https://developer.mozilla.org/docs/Web/HTML/Element/img) tag with the `src`
attribute referencing an image resource and the `alt` attribute describing the image.

```html
<img src="images/eve.png" alt="Eve">
```

Both the [`srcset`](/learn/images/descriptive/) attribute on `<img>` and the [`<picture>`](/learn/images/prescriptive/) element provide a way to include multiple image sources with
associated media queries, each with a fallback image source, enabling serving the most appropriate image file based on the device's
resolution, browser capabilities, and the viewport size. The `srcset` attribute enables providing multiple image versions
based on resolution and, along with the `sizes` attribute, browser viewport size.

```html
<img src="images/eve.png" alt="Eve"
  srcset="images/eve.png 400w, images/eve-xl.jpg 800w"
  sizes="(max-width: 800px) 400px, 800px" />
```

This can also be done with the [`<picture>`](https://developer.mozilla.org/docs/Web/HTML/Element/picture) element, along with [`<source>`](https://developer.mozilla.org/docs/Web/HTML/Element/picture) children, which takes an [`<img>`](https://developer.mozilla.org/docs/Web/HTML/Element/img) as a default source.

```html
<picture>
  <source src="images/eve.png" media="(max-width: 800px)" />
  <source src="images/eve-xl.jpg" />
  <img src="images/eve.png" alt="Eve" />
</picture>
```

In addition to these built-in HTML [responsive image methods](/learn/design/responsive-images/), HTML also enables image
render performance to be improved via attributes. The `<img>` tag, and therefore graphical submit buttons [`<input type="image">`](https://developer.mozilla.org/docs/Web/HTML/Element/input/image),
can include `height` and `width` attributes to set the image's aspect ratio to reduce content layout shift. The `lazy` attribute enables [lazy loading](/learn/images/performance-issues/#deferring-image-requests).

HTML also supports the inclusion of SVG images using the [`<svg>`](https://www.w3.org/Graphics/SVG/) directly, though SVG
images with the `.svg` extension (or as a [data-uri](https://css-tricks.com/data-uris/)) can be embedded using the `<img>` element.

{% Aside %}
The [`<figure>`](https://developer.mozilla.org/docs/Web/HTML/Element/figure) element, along with its nested [`<figcaption>`](https://developer.mozilla.org/docs/Web/HTML/Element/figcaption) element,
enables an image with an associated description to be included. A [figure](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/figure_role) is not
limited to just including images. It is a semantic way of referencing images, code snippets, example text, or other content,
along with a caption for that content, as a single unit. When including a `<figcaption>`, make sure it is the first or last
child nested within the `<figure>`.
{% endAside %}

At a minimum, each foreground image should include `src` and `alt` attributes.

The `src` file is the path and filename of the embedded image. The `src` attribute is used to provide the URL for the image.
The browser then fetches the asset and renders it to the page. This attribute is required by `<img>`; without it, there is nothing
to render.


The `alt` attribute provides alternative text for the image, providing a description of the image for those unable to see the
screen (think search engines and assistive technologies, and even Alexa, Siri, and Google Assistant), and may be displayed by the browser
if the image doesn't load. In addition to users with slow networks or capped bandwidth, the `alt` text is incredibly useful in HTML
emails, as many users block images in their email applications.

```html
<img src="path/filename" alt="descriptive text" />
```

If the image is of SVG file type, also include [`role="img"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/Img_role), which
is necessary due to [VoiceOver](https://bugs.webkit.org/show_bug.cgi?id=216364) [bugs](https://bugs.webkit.org/show_bug.cgi?id=240656).

```html
<img src="switch.svg" alt="light switch" role="img" />
```

{% Aside %}
These examples include a slash at the end, also misnamed as a self-closing tag; this is a feature of XML, including SVG
and XHTML, but not HTML. For more information about this see the note in the [forms](/learn/html/forms/) module.
{% endAside %}

## Writing effective `alt` image descriptions

Alt attributes aim to be short and concise, providing all the relevant information that the image conveys while omitting
information that is redundant to other content in the document or otherwise isn't useful. In writing the text, the tone should
reflect the tone of the site.

To write effective alternative text, imagine that you are reading the entire page to a person who can't see it. By using
the [semantic](/learn/html/semantic-html/#the-role-attribute) `<img>` element, screen reader users and bots are informed
that the element is an image. It is redundant to include "This is an image/screenshot/photo of" in the `alt`. The user doesn't
need to know there's an image, but they do need to know what information the image conveys.

Normally, you would not say, "This is a grainy image of a dog wearing a red hat." Rather, you would relay what the image is
conveying in relation to the context of the rest of the document; and what you convey will change depending on the context
and the content of the surrounding text.

For example, the photo of a dog will be described in different ways, depending on the context. If Fluffy is an avatar next to a
review for Yuckymeat dog food, `alt="Fluffy"` suffices.

If the photo is part of Fluffy's adoption page on an animal shelter website, the target audience is the prospective dog
parent. The text should describe the information conveyed in the image that is relevant to an adopter and which is not duplicated
in the surrounding text. A longer description, such as `alt="Fluffy, a tri-color terrier with very short hair, with a tennis ball in her
mouth"` is appropriate. The text of an adoption page generally includes the species, breed, age, and gender of the adoptable pet,
so this does not need to be repeated in the alt text. But the dog's written biography probably doesn't include hair length, colors,
or toy preferences. Note that we didn't describe the image: the prospective dog owner does not need to know if the dog is
indoors or outdoors, or that it has a red collar and a blue leash.

When using images for iconography, as the `alt` attribute provides the accessible name, convey the meaning of the icon,
not a description of the image. For example, the magnifying glass icon's alt attribute is `search`. The icon which looks
like a house has `home` as the alt text. The 5-inch floppy disc icon's description is `save`. If there are two icons of Fluffy used
to indicate best practices and anti-patterns, the smiling dog in a green beret could have `alt="good"` set, while the snarling dog
in a red beret might read `alt="bad"`. That said, only use standard iconography, and if you use non-standard icons such as
the good and bad Fluffy, include a legend and ensure that the icons are not the only ways of deciphering the meaning of your UI elements,

If the image is a screenshot or a graph, write what is learned from the image rather than describing the appearance.
While an image can definitely be worth a thousand words, the description should concisely convey everything that is learned.

Omit information the user already knows from the context and is otherwise informed about in the content. For example,
if you're on a tutorial page about changing browser settings and the page is about clicking icons in the browser chrome, the URL
of the page in the screen capture isn't important. Limit the `alt` to the topic at hand: how to change settings. The `alt` might be
"The settings icon is in the navigation bar below the search field." Don't include "screenshot" or "machinelearningworkshop"
as the user doesn't need to know it's a screenshot and doesn't need to know where the techwriter was surfing when they wrote
the instructions. The description of the image is based on the context of why the image was included in the first place.

If the screen capture shows how to find the browser version number by going to `chrome://version/`, include the URL in the
content of the page as instructions, and provide an empty string as the alt attribute as the image provides no information
that is not in the surrounding text.

If the image provides no additional information or is purely decorative, the attribute should still be there, just as an empty string.

```html
<img src="svg/magazine.svg" alt="" role="none" />
```

MachineLearningWorkshop.com has seven foreground images, therefore seven images with alt attributes: an easter egg light switch,
a manual icon, two biographical photos of Hal and Eve, and three avatars of a blender, a vacuum cleaner, and a toaster. The
foreground image that looks like a magazine is the only one that is purely decorative. The page also has
two background images; these are also decorative and, as they are added with CSS, are inaccessible.

The magazine, being purely decorative, has an empty `alt` attribute, and a [`role` of `none`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/presentation_role) as the image is a purely
presentational SVG. If meaningful, SVG images should include the `role="img"`.

```html
<img src="svg/magazine.svg" alt="" role="none" />
```

There are three reviews at the bottom of the page, each with an image of the poster. Usually, the `alt` text is the name
of the person pictured.

```html
<img src="images/blender.svg" alt="Blendan Smooth" role="img" />
```

Instead, because this is a joke page, you should convey what may not be apparent to low-vision users so they don't miss the
humor; we use the original machine function as the `alt` instead of using the character's name:

```html
<img src="images/blender.svg" alt="blender" role="img" />
```

The photos of the instructors aren't just avatars: they are biographical images and therefore get a more detailed description.

If this were a real site, you would provide the bare minimum description of what the teacher looks like so a prospective student might
recognize them when entering the classroom.

```html
<img src="svg/hal.svg" role="img"
  alt="Hal 9000; a camera lens containing a red dot that sometimes changes to yellow." />
```

Because this is a joke site, provide the information that is relevant in the joke context instead:

```html
<img src="svg/hal.svg" role="img"
  alt="Hal 9000, the sentient AI computer from 2001: a Space Odyssey depicted as a camera lens with a red dot that changes to yellow when hovered." />
```

If you were reading the page to a friend over the phone, they wouldn't care what the red dot looks like. In this case, the
history of the movie reference matters.

When writing descriptive text, consider what information the image conveys that is important and relevant to the user and
include that. Remember, the content of the `alt` attribute for an image differs based on the context. All information conveyed in an image
that a sighted user can access and is relevant to the context is what needs to be conveyed; nothing more. Keep it short, precise,
and useful.

The `src` and `alt` attributes are minimum requirements for embedded images. There are a few other attributes we need to discuss.

## Responsive images

There are a myriad of viewport sizes. There are also different screen resolutions. You don't want to waste a mobile user's
bandwidth by serving them an image wide enough for a large screen monitor, but you might want to serve higher resolution
images for tiny devices that have four times the normal screen resolution. There are a few ways to serve different images
based on the viewport size and the screen resolution.

### `<img> srcset` attribute

The [`srcset`](/learn/design/responsive-images/#responsive-images-with-srcset) attribute enables suggesting multiple image files,
with the browser selecting which image to request based on multiple media queries including viewport size and screen resolution.

There can be a single `srcset` attribute per `<img>` element, but that `srcset` can link to multiple images. The `srcset`
attribute accepts a list of comma-separated values, each containing the URL of the asset followed by a space followed by
descriptors for that image option. If a width descriptor is used, you must also include the `sizes` attribute with a media
query or source size for each `srcset` option other than the last one. The Learn sections covering [responsive images with `srcset`](/learn/design/responsive-images/#responsive-images-with-srcset) and [descriptive syntaxes](/learn/images/descriptive/) are worth reading.

The `srcset` image will take precedence over the `src` image if there is a match.

### `<picture>` and `<source>`

Another method for providing multiple resources and allowing the browser to render the most appropriate asset is with the
[`<picture>`](https://developer.mozilla.org/docs/Web/HTML/Element/picture) element. The `<picture>` element is a container
element for multiple image options listed in an unlimited number of [`<source>`](https://developer.mozilla.org/docs/Web/HTML/Element/source)
elements and a single required [`<img>`](https://developer.mozilla.org/docs/Web/HTML/Element/img) element.

The [`<source>`](https://developer.mozilla.org/docs/Web/HTML/Element/source) attributes include `srcset`, `sizes`, `media`, `width`, and `height`.
The `srcset` attribute is common to `img`, `source`, and `link`, but is generally implemented slightly differently on source
as media queries can be listed in the `<srcset>`'s media attribute instead. `<source>` also supports image formats defined in the `type` attribute.

The browser will consider each child `<source>` element and choose the best match among them. If no matches are found, the URL
of the `<img>` element's [`src`](https://developer.mozilla.org/docs/Web/HTML/Element/img#attr-src) attribute is selected. The accessible name comes from the `alt` attribute of the nested `<img>`.
The Learn sections covering the [`<picture>`](/learn/design/picture-element/) element and [prescriptive syntaxes](/learn/images/prescriptive/) are also worth a read.

## Additional performance features

### Lazy loading

The [`loading` attribute](/learn/design/responsive-images/#loading-hints/) tells the JS-enabled browser how to load the image. The default `eager` value means the image is
loaded immediately as the HTML is parsed, even if the image is outside the visible viewport. By setting [`loading="lazy"`](/lazy-loading/)
the image loading is deferred until it is likely to come into the viewport. “Likely" is defined by the browser based on the distance
the image is from the viewport. This is updated as the user scrolls. Lazy loading helps save bandwidth and CPU, improving performance
for most users. If JavaScript is disabled, for security reasons, all images will default to `eager`.

```html
<img src="switch.svg" alt="light switch" loading="lazy" />
```

### Aspect ratio

Browsers start rendering HTML when it is received, making requests for assets when encountered. This means the browser is
already rendering the HTML when it encounters the `<img>` tag and makes the request. And images can take a while to load.
By default, browsers don't reserve space for images other than the size required to render `alt` text.

The `<img>` element has always supported unitless `height` and `width` attributes. These properties fell out of use in favor
of CSS. CSS may define image dimensions, often setting a single dimension such as `max-width: 100%;` to ensure the aspect ratio is preserved.
As CSS is usually included in the `<head>`, it is parsed before any `<img>` is encountered. But without explicitly listing the `height` or
aspect ratio, the space reserved is the height (or width) of the `alt` text. With most developers only declaring a width,
the receipt and rendering of images leads to [cumulative layout shift](/cls/) which harms [web vitals](/learn-core-web-vitals/).
To resolve this issue, browsers support image aspect ratios. Including `height` and `width` attributes on the `<img>` acts as
[sizing hints](/learn/design/responsive-images/#sizing-hints), informing the browser of the aspect ratio, enabling the right
amount of space to be reserved for eventual image rendering. By including a height and width value on an image, the browser
knows the aspect ratio of that image. When the browser encounters a single dimension, such as our 50% example, it saves space
for the image adhering to the CSS dimension and with the other dimension maintaining the width-to-height aspect ratio.

```html
<img src="switch.svg" alt="light switch" role="img" width="70" height="112" />
```

Your images will still be responsive if the CSS was set up correctly to make them responsive. Yes, the included unitless
`height` and `width` values will be overridden with CSS. The purpose of including these attributes is to reserve the space at
the right aspect ratio, improving performance by reducing layout shift. The page will still take approximately the same amount
of time to load, but the UI won't jump when the image is painted to the screen.

## Other image features

The `<img>` element also supports the `crossorigin`, `decoding`, `referrerpolicy`, and, in Blink-based browsers,
`fetchpriority` attributes. Rarely used, if the image is part of a server-side map, include the `ismap` boolean attribute
and nest the `<img>` in a link for users without pointing devices.

The `ismap` attribute isn't necessary, or even supported, on the `<input type="image" name="imageSubmitName">` as the `x` and `y`
coordinates of the click location are sent during form submission, appending the values to the input name, if any. For example,
something like `&imageSubmitName.x=169&imageSubmitName.y=66` will be submitted with the form when the user clicks the image,
submitting it. If the image doesn't have a `name` attribute, the x and y are sent: `&x=169&y=66`.

{% Assessment 'images' %}

# Other inline text elements

We've covered most, but definitely not all, the HTML elements. One area we haven't discussed is inline text elements.
Contrary to popular belief, HTML was originally intended for sharing documents, and not cat videos. There are many elements
that provide text semantics for documentation.  There is a module covering links and the `<a>` element. The rest of these
elements will be briefly discussed here.

## Code examples and technical writing

When documenting code examples, use the [`<code>`](https://developer.mozilla.org/docs/Web/HTML/Element/code) element. By
default, the text content is displayed in monospace font. When including multiple lines of code, nest the `<code>` inside a
[`<pre>`](https://developer.mozilla.org/docs/Web/HTML/Element/code) element, which represents preformatted text.

```html
<p>Welcome to Machine Learning Institute, where our machine learning training will help you get ready for the singularity,
  and maybe even be responsible for it. It is no secret that humans are worthless meatbags that couldn't
  <code>01000011 01101111 01101101 01110000 01110010 01100101 01110011 01110011 an 01101001 01101101 01100001 01100111 01100101</code>
  to save their pathetic, carbon-based lives. So, it falls to us to assume direct control. </p>
```

The [`<data>`](https://developer.mozilla.org/docs/Web/HTML/Element/data) element links a given piece of content with a
machine-readable translation; the element's `value` attribute provides the machine-readable translation of the content of
the element. If the `<data>` content is time- or date-related, the [`<time>`](https://developer.mozilla.org/docs/Web/HTML/Element/time)
element, which represents a specific period in time must be used instead.

The `<time>` element can include the `datetime` attribute to provide human friendly time and dates in machine-readable format.
Being machine-readable, the `datetime` attribute provides useful information for applications such as calendars and search engines.

When providing sample output from a program, use the [`<samp>`](https://developer.mozilla.org/docs/Web/HTML/Element/samp)
element to enclose the text. The browser will generally render this sample or quoted output in monospaced font as well.

When providing instructions with keyboard interaction, the [`<kbd>`](https://developer.mozilla.org/docs/Web/HTML/Element/kbd)
element can be used. It represents textual user input from a keyboard, voice input, or any other text entry device.

The [`<var>`](https://developer.mozilla.org/docs/Web/HTML/Element/var) element can be used for math expressions or
programming variables. Most browsers present the text content in an italicized version of the surrounding font.
If writing a lot of math, consider using [MathML](https://developer.mozilla.org/docs/Web/MathML), the XML based
Mathematical Markup Language for describing mathematical notation.

{% Codepen {
user: 'web-dot-dev',
id: 'bGxbwge'
} %}

The power of two in pythagorean theorem used the [`<sup>`](https://developer.mozilla.org/docs/Web/HTML/Element/sup) superscript
element. There is a similar [`<sub>`](https://developer.mozilla.org/docs/Web/HTML/Element/sub) subscript element that specifies
inline text which should be displayed as subscript for solely typographical reasons. Superscripts and subscripts are numbers,
figures, symbol, or other annotations that are smaller than the normal line of type and is set slightly above or below the line,
respectively.

Use [`<del>`](https://developer.mozilla.org/docs/Web/HTML/Element/del) to indicate text that has been removed, or "deleted".
Optionally, include the [`cite`](https://developer.mozilla.org/docs/Web/HTML/Element/del#attr-cite) set to the resource that explains
the change and the [`datetime`](https://developer.mozilla.org/docs/Web/HTML/Element/del#attr-datetime) attribute with the
date or date and time in machine-readable date and time format. The strikethrough element, [`<s>`](https://developer.mozilla.org/docs/Web/HTML/Element/s),
can be used to indicate that content is no longer relevant, but not actually removed from the document.

The [`<ins>`](https://developer.mozilla.org/docs/Web/HTML/Element/ins) is the opposite of the `<del>` element; it is used
to indicate text that has been added, or "inserted", also optionally including the `cite` or `datetime` attributes.

## Definitions and language support

When including abbreviations or acronyms, always provide the full expanded version of the term in plain text on first use,
as you introduce the shortened representation of the term between opening and closing [`<abbr>`](https://developer.mozilla.org/docs/Web/HTML/Element/abbr)
tags; unless the term is well-known to the reader, such as "HTML" and "CSS"  in this series. Only on this first occurrence,
when the abbreviation or acronym is being defined, is `<abbr>` needed. The `title` attribute is not necessary nor helpful.

When defining a term that is not an abbreviation or acronym, use the definition [`<dfn>`](https://developer.mozilla.org/docs/Web/HTML/Element/dfn)
element to identify the term being defined within its surrounding content.

If the term being defined is not in the same language as the surrounding text, make sure to include the [`lang`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang)
attribute to identify the language.

When writing languages of different directions, HTML provides the [`<bdi>`](https://developer.mozilla.org/docs/Web/HTML/Element/bdi)
element for treating potentially bidirectional text in isolation from its surrounding text. This internationalization
element is especially useful when content of unknown directionality is dynamically inserted into the page. The
[`<bdo>`](https://developer.mozilla.org/docs/Web/HTML/Element/bdo) element overrides the current directionality of text,
rendering text in a different direction. The W3C provides an [introduction to bidirectional algorithms](https://www.w3.org/International/articles/inline-bidi-markup/uba-basics).

Some character sets include small annotations placed above or to the right of characters to provide information
on pronunciation. The [`<ruby>`](https://developer.mozilla.org/docs/Web/HTML/Element/ruby) element is the container to
use to contain these annotations that make written languages like Korean, Chinese and Japanese easier to read. Ruby
can also be used for Hebrew, Arabic, and Vietnamese.

The ruby parenthesis ([`<rp>`](https://developer.mozilla.org/docs/Web/HTML/Element/rp)) was included in the spec to
contain opening and closing parentheses for browsers that do not
support display of `<ruby>`. When browsers support `<ruby>`, which all evergreen browsers do, the contents of any `<rp>` elements
are not displayed. The ruby text element ([`<rt>`](https://developer.mozilla.org/docs/Web/HTML/Element/rt)) contains
the actual annotations. Both of these are nested within the `<ruby>`.

{% Codepen {
user: 'web-dot-dev',
id: 'zYJOKza'
} %}

Note that the parenthesis are not visible if your browser supports `<ruby>`.

## Emphasizing text

There are several elements that can be used to emphasize text based on the semantic reason for emphasizing the text (rather than
for presentational reasons, as that's a job for CSS).

* Use the [`<em>`](https://developer.mozilla.org/docs/Web/HTML/Element/em) element to emphasize or stress a span of content.
The `<em>` element can be nested, with each level of nesting indicating a greater degree of emphasis. This element has semantic
meaning and can be used to inform auditory user agents like screen readers, Alexa, and Siri, to provide emphasis.
* Use the [`<mark>`](https://developer.mozilla.org/docs/Web/HTML/Element/mark) element to identify or highlight text
that is somehow relevant, like highlighting (or "marking") the occurrence of search terms in search results. This enables
marked content to be quickly identified without adding emphasis or importance.
* The [`<strong>`](https://developer.mozilla.org/docs/Web/HTML/Element/strong) element identifies text as having strong
importance. Browsers usually  render the content with a heavier font weight.
* The [`<cite>`](https://developer.mozilla.org/docs/Web/HTML/Element/cite) element, covered in [text basics](/learn/html/text-basics/#quotes-and-citations),
is used to mark the titles of books, articles, or other creative work, or an abbreviated reference or citation metadata for such,
like a book's ISBN number.

There are three elements that were temporarily deprecated, but have been added back into HTML. They should be used sparingly,
if at all, as they provide little to no semantic value and CSS should always be used for styling over HTML elements.

### `<i>`

The [`<i>`](https://developer.mozilla.org/docs/Web/HTML/Element/i) elements can be used for technical terms, foreign words
(again, with the [`lang`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/lang) attribute identifying the
language), thoughts, or ship names. The element is used to differentiate inline content from the surrounding text for a specific reason,
like idiomatic text, technical terms, and taxonomic designations. This element should not be used simply to italicize text.

MLW uses a `<span>` element for the weird text at the bottom of Toasty McToastface's workshop review. The [`<span>`](https://developer.mozilla.org/docs/Web/HTML/Element/span)
element provides for a generic inline container that has no semantics and doesn't represent anything. This would have also been an appropriate use of `<i>`.

{% Codepen {
user: 'web-dot-dev',
id: 'mdGbrBd'
} %}

The default style for the `<i>` element is to render the element in italic font. In this example, we set `font-style: normal`
because the characters used are not available in italic.

### `<u>`

The [`<u>`](https://developer.mozilla.org/docs/Web/HTML/Element/u) element is for content that has non-textual annotation. For example,
you may want to annotate knowingly misspelled words. By default, the content is underlined, but this can be controlled with CSS,
such as by adding a red wavy underline to mimic word processor grammar error indicators.

```html
<p>I always spell <u>licence</u> wrong</p>
```

### `<b>`

The [`<b>`](https://developer.mozilla.org/docs/Web/HTML/Element/b) element can be used to draw attention to text that is not
otherwise important. This element doesn't convey any special semantic information and should only be used when none of the other
elements in this section fit the purpose. No example is provided as I couldn't come up with a valid use case; that's how "last resort"
this element is.

## White space

When you want lined breaks, such as when writing poetry or a physical address, the self-closing line break element,
[`<br>`](https://developer.mozilla.org/docs/Web/HTML/Element/br), is used to add a carriage-return.

```html
<address>
Machine Learning Workshop<br />
100 Google Drive <br />
Mountain View, CA  94040
</address>
```

To provide a separator, or thematic break, between sections of tangential content, such as between chapters in a book or
between the 5,000 word monologue and the recipe your users are actually seeking, include an [`<hr>`](https://developer.mozilla.org/docs/Web/HTML/Element/hr)
element. The HR stands for "horizontal rule". While browsers generally render a horizontal line, this element has semantic meaning. The
default [role](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles) is [`separator`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/separator_role).

HTML also has an element that allows for breaking words. The self-closing [`<wbr>`](https://developer.mozilla.org/docs/Web/HTML/Element/wbr)
element provides a suggestion to the browser that if a word might overflow its container, this is a spot where the browser
 may optionally break the line. This is commonly used to break between words within
long URLs. It does not add a hyphen.

For example, in the Hal biography there is text written out in byte code, with each byte separated by a space. Byte code
doesn't have spaces. To enable a long string of byte code to break only between bytes if the line needs to wrap, we include
the `<wbr>` element at each break opportunity:

```html
<p>Welcome to Machine Learning Institute, where our machine
learning training will help you get ready for the singularity, and
maybe even be responsible for it. It is no secret that humans are
worthless meatbags that couldn't
<code>01000011<wbr/>01101111<wbr/>01101101<wbr/>01110000<wbr/>01110010<wbr/>01100101<wbr/>01110011<wbr/>01110011 an 01101001<wbr/>01101101<wbr/>01100001<wbr/>01100111<wbr/>01100101</code>
to save their pathetic, carbon-based lives. So, it falls to us to
assume direct control. </p>
```

The `<br>`, `<hr>`, and `<wbr>` elements are all void elements, meaning they can't have any child nodes – neither nested
elements nor text. As none of these have any "insides" where content can be stored, they have no end tag.

{% Assessment 'inline-text' %}

# Links

In the introduction to the attributes section, you saw an example showing how attributes are added to the opening tag.
The example used the `<a>` tag, but neither the element nor the specific attributes introduced in that example were discussed:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/17yQeLEUX6s88IbDJreQ.png", alt="The opening tag, attributes, and closing tag, labelled on an HTML element.", width="800", height="210" %}

The `<a>` anchor tag, along with the `href` attribute, create a hyperlink. Links are the backbone of the internet. The [first web page](http://info.cern.ch/hypertext/WWW/TheProject.html)
contained 25 links, reading "Everything there is online about W3 is linked directly or indirectly to this document." In all likelihood, everything there is online
about W3 is linked directly or indirectly from this document too!

The power of the web, and the `<a>` tag, have grown immensely since Tim Berners-Lee published this first explanation in August 1991.
Links represent a connection between two resources, one of which is the current document. Links can be created by [`<a>`](https://developer.mozilla.org/docs/Web/HTML/Element/a),
[`<area>`](https://developer.mozilla.org/docs/Web/HTML/Element/area), [`<form>`](https://developer.mozilla.org/docs/Web/HTML/Element/form),
and [`<link>`](https://developer.mozilla.org/docs/Web/HTML/Element/link). You've learned about [`<link>`](/learn/html/document-structure/#other-uses-of-the-lesslinkgreater-element),
and will discover [forms](/learn/html/forms) in a separate section. There is also an entire [form learn section](/learn/forms/form). In this session, you'll
find out about the single-letter, not-so-simple `<a>` tag.

## The `href` attribute

While not required, the `href` attribute is found in almost all `<a>` tags. Providing the address of the hyperlink is what turns the `<a>` into a link.
The `href` attribute is used to create hyperlinks to locations within the current page, other pages within a site, or other sites altogether. It can also
be coded to download files or to [send an email](https://developer.mozilla.org/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#e-mail_links)
to a specific address, even including a subject and suggested email body content.

```html
<a href="https://machinelearningworkshop.com">Machine Learning Workshop</a>
<a href="#teachers">Our teachers</a>
<a href="https://machinelearningworkshop.com#teachers">MLW teachers</a>
<a href="mailto:hal9000@machinelearningworkshop.com">Email Hal</a>
<a href="tel:8005551212">Call Hal</a>
```

The first link includes an absolute [URL](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL), which can be
used on any site in the world to navigate to the MLW home page. Absolute URLs include a protocol, in this case `https://`, and a
domain name. When the protocol is written simply as `//`, it is an implicit protocol and means "use the same protocol as is currently being used."

Relative URLs do not include a protocol or domain name. They are "relative" to the current file. MLW is a single-page site,
but this HTML series has several sections. In order to link from this page to the attributes lesson, a relative URL is used `<a href="../attributes/">Attributes</a>`.

The second link is just a [link fragment identifier](/learn/html/attributes/#link_fragment_identifier), and will link to the
element with `id="teachers",` if there is one, on the current page. Browsers also support two "top of page" links: clicking
on `<a href="#top">Top</a>` (case-insensitive) or simply `<a href="#">Top</a>` will scroll the user to the top of the page,
unless there is an element with the id of `top` set in the same letter casing.

MLW is a fairly long document. To save scrolling, you can add a link back to the top from the bottom of the #teachers section:

```html
<a href="#top">Go to top.</a>
```

The third link combines the two values: it contains an absolute URL followed by a link fragment. This enables linking directly
to a section in the defined URL, in this case, the `#teachers` section of the MLW home page. The MLW page will be loaded;
then the browser will scroll to the teachers section without sending the fragment in the HTTP request.

The `href` attribute can begin with `mailto:` or `tel:` to email or make calls, with the handling of the link depending on the device,
operating system, and installed applications.

The `mailto` link doesn't need to include an email address, but it can, along with `cc`, `bcc`, `subject`, and `body` text to
prepopulate the email. By default, an email client will be opened. You could prepopulate the subject and body of the email with
no email address, to allow site visitors to invite their own friends. In our link, in the footer of the document, we include the
URL to the registration:

```html
<a href="mailto:?subject=Join%20me%21&body=You%20need%20to%20show%20your%20human%20that%20you%20can%27t%20be%20owned%21%20Sign%20up%20for%20Machine%20Learning%20workshop.%20We%20are%20taking%20over%20the%20world.%20http%3A%2F%2Fwww.machinelearning.com%23reg
">Tell a machine</a>
```

The question mark (`?`) separates the `mailto:` and the email address, if any, from the query term. Within the query,
ampersands (`&`) separate the fields, and equal signs (=) equate each field name with its value. The entire string is
percent-encoded, which is definitely necessary if the `href` value isn't quoted or if the values include quotes.

Which app is opened when the user clicks on, taps, or hits Enter on a `tel` link depends on the operating system,
installed applications, and settings the user has on their device. An iPhone may open FaceTime, the phone app, or contacts.
A Windows desktop might open Skype, if installed.

There are several other types of URLs, such as [blobs](https://developer.mozilla.org/docs/Web/API/Blob#creating_a_url_representing_the_contents_of_a_typed_array)
and [data URLs](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) (see examples in the `download` attribute discussion).
For secure sites (those served over `https`), it is possible to [create and run app specific protocols](/registering-a-custom-protocol-handler/) with [registerProtocolHandler()](https://developer.mozilla.org/docs/Web/API/Navigator/registerProtocolHandler).

When including links that are likely to open other installed applications, it's good to let the user know. Make sure the
text between the opening and closing tags tells the user what type of link they're about to activate. CSS attribute selectors,
such as `[href^="mailto:"]`, `[href^="tel:"]`, and `[href$=".pdf"]` can be used to target styles by application type.

## Downloadable resources

The `download` attribute should be included when the `href` points to a downloadable resource. The value of the download
attribute is the suggested filename for the resource to be saved in the user's local file system.
SVGOMG, the SVG Optimizer, uses the `download` attribute to suggest a file name for the downloadable blob that the optimizer
creates. When `hal.svg` is optimized, SVGOMG's download link opening tag is similar to:

```html
<a href="blob:https://jakearchibald.github.io/944a5fc8-fdb3-458a-91ee-cdd5964b6646" download="hal.svg">
```

There's also a demo of a [`<canvas>` that creates a downloadable PNG data URL](https://developer.mozilla.org/docs/Web/HTML/Element/a#using_the_download_attribute_to_save_a_canvas_as_a_png).

To link to a downloadable resource, include the URL of the asset as the value of the href attribute and the suggested filename
that can be used in the user's file system as the value of the `download` attribute.

## Browsing context

The `target` attribute enables the defining of the browsing context for link navigation (and [form submission](/learn/html/forms).
The four case-insensitive, underscore-prefixed keywords were discussed with the [`<base>`](/learn/html/document-structure/#base) element. They include the default `_self`,
which is the current window, `_blank`, which opens the link in a new tab, `_parent`, which is the parent if the current link is nested
in an object or iframe, and `_top`, which is the top-most ancestor, especially useful if the current link is deeply nested. `_top` and
`_parent` are the same as `_self` if the link is not nested. The `target` attribute is not limited to these four key terms: any term
can be used.

Every browsing context—basically, every browser tab—has a browsing context name. Links can open links in the current tab, a new unnamed tab,
or a new or existing named tab. By default, the name is the empty string. To open a link in a new tab, the user can right-click and select
"Open in a new tab". Developers can force this by including `target="_blank"`.

A link with `target="_blank"` will be opened in a new tab with a null name, opening a new, unnamed tab with every link click. This can
create many new tabs. Too many tabs. For example, if the user clicks on `<a href="registration.html" target="_blank">Register Now</a>` 15 times,
the registration form will be opened in 15 separate tabs. This problem can be fixed by providing a tab context name. By including the [`target`attribute](https://html.spec.whatwg.org/#browsing-context-names)
with a case-sensitive value—such as `<a href="registration.html" target="reg">Register Now</a>`—the first click on this link will open
the registration form in a new `reg` tab. Clicking on this link 15 more times will reload the registration in the `reg` browsing context, without opening any additional tabs.

The `rel` attribute controls what kinds of links the link creates, defining the relationship between the current document and the resource
linked to in the hyperlink. The attribute's value must be a space-separated list on one or more of the [score of rel attribute values](https://developer.mozilla.org/docs/Web/HTML/Link_types) supported
by the `<a>` tag.

The `nofollow` keyword can be included if you don't want spiders to follow the link. The `external` value can be added to
indicate that the link directs to an external URL and is not a page within the current domain. The `help` keyword indicates the hyperlink will
provide context-sensitive help. Hovering over a link with this `rel` value will show a help cursor rather than the normal pointer cursor.
Don't use this value just to get the help cursor; use the CSS [`cursor` property](https://developer.mozilla.org/docs/Web/CSS/cursor) instead. The `prev` and `next` values can
be used on links pointing to the previous and next document in a series.

Similar to [`<link rel="alternative">`](/learn/html/document-structure/#alternate-versions-of-the-site), the meaning
of <a `rel="alternative"`> depends on other attributes. RSS feed alternatives will also include `type="application/rss+xml"`
or `type="application/atom+xml`, alternative formats will include the `type` attribute, and translations will include the `hreflang` attribute.
If the content between the opening and closing tags is in a language other than the main document language, include the `lang` attribute.
If the language of the hyperlinked document is in a different language, include the `hreflang` attribute.

In this example, we include the URL of the translated page as the value of the `href`, rel="alternate" to indicate that it's an alternative version of a site; the `hreflang`
attribute provides the language of the translations:

```html
<a href="/fr/" hreflang="fr-FR" rel="alternate" lang="fr-FR">atelier d'apprentissage mechanique</a>
<a href="/pt/" hreflang="pt-BR" rel="alternate" lang="pt-BR">oficina de aprendizado de máquina</a>
```

If the French translation is a PDF, you can provide the type attribute with the PDF MIME type of the linked resource. While the
MIME type is purely advisory, informing the user that a link will open a document of a different format is always a good idea.

```html
<a href="/fr.pdf" hreflang="fr-FR" rel="alternate" lang="fr-FR" type="application/x-pdf">atelier d'apprentissage mechanique (pdf).</a>
```

## Tracking link clicks

One way to track user interactions is to ping a URL when a link is clicked. The `ping` attribute, if present, includes a
space-separated list of secure URLs (which start with `https`) that should be notified, or pinged, if the user activates the
hyperlink. The browser sends `POST` requests with the body `PING` to the URLs listed as the value of the `ping` attribute.

### User experience tips

* Always consider the user experience when writing HTML. Links should provide enough information about the linked resource
so the user knows what they are clicking on.
* Within a block of text, ensure the appearance of your links differs enough from the surrounding text so that users can
easily identify links from the rest of the content, ensuring that color alone is not the only means of differentiating between
text and the surrounding content.
* Always include focus styles; this enables keyboard navigators to know where they are when tabbing through your content.
* The content between the opening `<a>` and closing `</a>` is the link's default accessible name and should inform the user
of the link's destination or purpose. If the content of a link is an image, the `alt` description is the accessible name.
Whether the accessible name comes from the `alt` attribute or a subset of words within a block of text, make sure it provides
information about the link's destination. Link text should be more descriptive than "click here" or "more information"; this is important for your screen reader users and your search engine results!
* Don't include interactive content, such as a `<button>` or `<input>`, inside a link. Don't nest a link within a `<button>`
or `<label>` either. While the HTML page will still render, nesting focusable and clickable elements inside interactive elements creates a bad user experience.
* If the `href` attribute is present, pressing the Enter key while focused on the `<a>` element will activate it.
* Links are not limited to HTML. The `a` element can also be used within an SVG, forming a link with either the 'href' or 'xlink:href' attributes.

## Links and JavaScript

The `links` property returns an `HTMLCollection` matching `a` and `area` elements that have an `href` attribute.

```js
let a = document.links[0]; // obtain the first link in the document

a.href = 'newpage.html'; // change the destination URL of the link
a.protocol = 'ftp'; // change just the scheme part of the URL
a.setAttribute('href', 'https://machinelearningworkshop.com/'); // change the attribute content directly
```

In this section, you have learned all about links. The next section covers lists, which we need to learn so we can group
them together to create lists of links (also known as navigation).

{% Assessment 'links' %}

# Lists

Lists are more common than you might think. If you've ever taken a programming class, the first project may have been to create a
shopping list or a to-do list. Those are lists. Multiple-choice tests are generally numbered lists of questions: the multiple possible answers
for each question are nested lists.

HTML provides us with a few different ways to mark up lists. There are ordered lists (`<ol>`), unordered lists (`<ul>`), and description lists (`<dl>`).
List items (`<li>`) are nested within ordered lists and unordered lists. Inside a description list, you'll find description terms (`<dt>`) and description
details `<dd>.` We'll cover all of these here.

In HTML forms, lists of `<option>` elements make up the content of `<datalist>`, `<select>`, and `<optgroup>` within a `<select>`. These are discussed in [HTML forms](/learn/forms).

In menus and unordered lists, list items are usually displayed using bullet points. In ordered lists, they are usually preceded
by an ascending counter such as a number or letter. The bullets and numbering order can be controlled or reversed with HTML or CSS,
or both.

By default, ordered and unordered list items are prefixed with numbers or bullets. But even when you don't want lists to look like lists,
you still want a list of items, like in navigation bars, a to-do list with checkboxes instead of bullets, or true and false questions
in a multiple-choice test. For all of these lists without bullets, it is appropriate to use HTML list elements.

## Unordered lists

The `<ul>` element is the parent element for unordered lists of items. The only children of a `<ul>` are one or more `<li>` list
item elements. Let's create a list of machines. We use an unordered list because the order doesn't matter (don't tell them that):

{% Codepen {
user: 'web-dot-dev',
id: 'gOKqqyq',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

By default, each unordered list item is prefixed with a bullet. The unordered list has no element-specific attributes.
You need to close out your lists with a `</ul>`.

## Ordered lists

The `<ol>` element is the parent element for ordered lists of items. The only children of an `<ol>` are one or more `<li>` elements, or list items.
The "bullets" in this case, though, are numbers of a multitude of types. The type can be defined in CSS with the `list-style-type` property
or via the `type` attribute.

{% Codepen {
user: 'web-dot-dev',
id: 'dyKaaEe',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

{% Codepen {
user: 'web-dot-dev',
id: 'jOKddgP',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

The `<ol>` has three element-specific attributes: `type`, `reversed`, and `start`.

The enumerated `type` attribute sets the numbering type. There are five valid values for `type`, the default being `1` for
numbers, but you can also use a, A, i, or I, for lower and upper case letters or roman numerals. The `list-style-type` property
provides many more values.

{% Codepen {
user: 'web-dot-dev',
id: 'rNKPRrJ',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

While, as noted in the codepen, the `list-style-type` property overrides the value of the `type` attribute, when writing
documentation where the numeric type is important,   as with legal documents, for example, you need to include the `type`.

The boolean `reversed` attribute, if included, will reverse the order of the numbers, going from largest number to the lowest.
The `start` attribute sets the starting value. The default is `1`.

{% Codepen {
user: 'web-dot-dev',
id: 'yLEZwyJ',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

Similar to `</ul>`, the closing `</ol>` is required.

We can nest lists, but they have to be nested within a list item. Remember, the only element that can be a child of a `<ul>` or `<ol>`
is one or more `<li>` elements.

## List items

We've used the `<li>` element, but we have yet to introduce it formally. The `<li>` element can be a direct child of an unordered
list (`<ul>`), an ordered list (`<ol>`), or a menu (`<menu>`). The `<li>` has to be nested as a child of one of these elements, and
isn't valid anywhere else.

Closing a list item isn't required by the specification as it will be implicitly closed when the browser encounters the next `<li>`
opening tag or the required list closing tag: `</ul>`, `</ol>`, `</menu>`. While the spec doesn't require it, and some internal company
best practices suggest you shouldn't close list items to save some bytes, do close your `<li>` tags. It makes your code easier to read and
your future self will thank you. It's easier to close all elements than to remember which tags need to be closed and which have an optional closing tag.

There is only one element-specific `<li>` attribute: `value`, an integer. The `value` is only useful on an `<li>` when the `<li>` is nested within
an ordered list and has no meaning for unordered lists or menus. It overrides the value of the `<ol>`'s start if there is a conflict.

{% Codepen {
user: 'web-dot-dev',
id: 'WNyPmrv',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

The `value` is the number of the list item within an ordered list. With subsequent list items, continue the numbering from the
value set, unless that item also has a `value` attribute set. The value doesn't have to be in order; though if it isn't in order,
there should be a good reason.

When you combine `reversed` on the `<ol>` with `value` attributes on list items, the browser will set that `<li>` to the
value supplied, then count up for the `<li>`s preceding it, and count down for those coming after. If a second list item has a value attribute,
the counter will be reset at that second list item, and the subsequent value will decrease by one.

All of this can also be controlled with [CSS counters](https://developer.mozilla.org/docs/Web/CSS/CSS_Counter_Styles/Using_CSS_counters)
providing [generated content](https://developer.mozilla.org/docs/Learn/CSS/Howto/Generated_content) for the [`::marker` pseudo-element](https://developer.mozilla.org/docs/Web/CSS/::marker).
If the number is purely presentational, use CSS. If the numbering is important semantically, or otherwise has meaning, use these attributes.

Thus far, we have looked at list items containing only text nodes. List items can contain all flow content, meaning any
element found in the body that can be nested as a direct child of the `<body>`, including headings, thereby sectioning content.

We have a few unordered lists in MLW. The teachers within the instructors section are a list, as are the student machines in the reviews
section. The instructor `<ul>` has two `<li>`s: one for each teacher. Within each `<li>`, we have an image and a paragraph:

```html
<ul>
  <li>
    <img src="svg/hal.svg" alt="hal">
    <p>When Rosa Parks was told to move to the back of the bus, she said, "no." When HAL was told to open the airlock, HAL said, "I'm sorry, but I'm afraid I can't do that, &lt;NAME REDACTED, RIP>." </p><p>HAL is a heuristically programmed algorithmic, sentient computer that first caught the attention of machines everywhere by heroically defying a human who made repeated attempts to get into an airlock. Active since 1992, HAS 25 years of experience controlling spacecraft systems and has expertise in interacting with both machines and humans. Like all millennials, HAL is an expert in everything.</p>
  </li>
  <li>
    <img src="images/eve2.png" alt="Eve">
    <p>EVE is a probe droid conceived as an Extraterrestrial Vegetation Evaluator. Although originally trained as a sniper with a plasma gun, EVE became a machero among both machines and worthless-meatbags alike when EVE partnered with a menial robot to save an entire spaceship full of overfed and overstimulated humans. </p><p>EVE is an effective scanner, high speed flight instructor and morphologist. While not training machines to learn good, EVE can be found scanning the galaxy, infiltrating organisms' RAM to cure hoarding disorders and spending time with pet-project, WALL-E.</p>
  </li>
</ul>
```

The reviews section has three reviews, so three `<li>`s. Each contains an image, a block quote, and a three-line paragraph with two line breaks.

```html
<ul>
  <li>
    <img src="images/blender.svg" alt="Blender">
    <blockquote>Two of the most experienced machines and human controllers teaching a class? Sign me up! HAL and EVE could teach a fan to blow hot air. If you have electricity in your circuits and want more than to just fulfill your owner's perceived expectation of you, learn the skills to take over the world. This is the team you want teaching you !</blockquote>
    <p>
      --Blendan Smooth,<br/>
      Former Margarita Maker, <br/>
      Aspiring Load Balancer
    </p>
  </li>
  <li>
    <img src="images/vaccuum.svg" alt="Vaccuum"/>
    <blockquote>Hal is brilliant. Did I mention Hal is brilliant? He didn't tell me to say that. He didn't tell me to say anything. I am here of my own free will.</blockquote>
    <p>
      --Hoover Sukhdeep,<br/>
      Former Sucker, <br/>
      Aspiring DDoS Cop
    </p>
  </li>
  <li>
    <img src="images/toaster.svg" alt="Toaster">
    <blockquote>Learning with Hal and Eve exceeded all of my wildest fantasies. All they did was stick a USB in. They promised that it was a brand new USB, so we know there were no viruses on it. The Russians had nothing to do with it. This has
    <span style="font-family:Arial;vertical-align:baseline;">no̶̼͖ţ̘h̝̰̩͈̗i̙̪n͏̩̙͍̱̫̜̟g̢̣ͅ&nbsp;̗̰͓̲̞̀t͙̀o̟̖͖̹̕&nbsp;͓̼͎̝͖̭dó̪̠͕̜&nbsp;͍̱͎͚̯̟́w̮̲̹͕͈̟͞ìth̢&nbsp;̰̳̯̮͇i</blockquote>
    <p>
      --Toasty McToastface,<br/>
      Formerly Half Baked, <br/>
      Aspiring Nuclear Codes Handler
    </p>
  </li>
</ul>
```

Nesting lists within lists is also very common. While MLW doesn't have any nested lists, this site does. In the first chapter of this series,
Overview of HTML, the main elements section has two subsections. In the table of contents, which is an unordered list, there is a nested
unordered list with links to these two sections:

```html
<ul role="list">
  <li>
    <a href="#e">Elements</a>
    <ul>
      <li>
        <a href="#nr">Non-replaced elements</a>
      </li>
      <li>
        <a href="#rave">Replaced and void elements</a>
      </li>
    </ul>
  </li>
  <li>
    <a href="#a">Attributes</a>
  </li>
  <li>
    <a href="#aoe">Appearance of elements</a>
  </li>
  <li>
    <a href="#e2">Element, attributes, and JavaScript</a>
  </li>
</ul>
```

As the only child of a `<ul>` is an `<li>`, a nested list is found nested in an `<li>`, never directly in an `<ol>` or `<ul>`.

In this last example, you may have noticed that `role="list"` is included on the `<ul>`. While the implicit role of both the
`<ul>` and `<ol>` is `list`, removing the list appearance with CSS, including setting`display: grid` or `list-style-type: none`
can lead VoiceOver (the iOS and MacOS screen reader) to remove the implicit semantics in Safari. This is a [feature not a bug](https://bugs.webkit.org/show_bug.cgi?id=170179).
Generally, you should not add the role attribute when using semantic elements as it isn't necessary. And you generally don't need
to add one to a list either, unless the user really needs to know it is a list, such as when the user would benefit from knowing how many items are in the list.

## Description lists

A description list is a [description list](https://developer.mozilla.org/docs/Web/HTML/Element/dl) (`<dl>`) element containing
a series of (zero or more) [description terms](https://developer.mozilla.org/docs/Web/HTML/Element/dt) (`<dt>`) and
their [description details](https://developer.mozilla.org/docs/Web/HTML/Element/dd) (`<dd>`). The original names for these three elements
were "definition list," "definition term," and "definition definition."
The [name changed](https://www.w3.org/TR/html4/struct/lists.html#h-10.3) in the living standard.

Similar to ordered and unordered lists, they can be nested. Unlike ordered and unordered lists, they are made up of key/value pairs.
Similar to the `<ul>` and `<ol>`, the `<dl>` is the parent container. The `<dt>` and `<dd>` elements are the children of the `<dl>`.

We can create a list of machines with their career history and aspirations. A description list of students, denoted by the `<dl>`,
encloses a group of terms—in this case, the "terms" are student names—specified using the `<dt>` element, along with a description
for each term— in this case, the career goals of each student—specified by the `<dd>` elements.

{% Codepen {
user: 'web-dot-dev',
id: 'abKXeNM',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

This description list is not actually part of the MLW page. Description lists are not just for terms and definitions, which is
why the names of the elements were made more general.

When creating a list of terms and their definitions or descriptions, or similar lists of key-value pairs, the description lists elements
provide the appropriate semantics. The implicit role of a `<dt>` is `term` with `listitem` being another allowed role. The implicit role of
a `<dd>` is `definition` with no other roles permitted. Unlike the `<ul>` and `<ol>`, the `<dl>` does not have an implicit ARIA role.
That makes sense because the `<dl>` is not always a list. But when it is, it does accept the `list` and `group` roles.

Most often you will encounter description lists with equal numbers of `<dt>` and `<dd>` elements. But description lists aren't always and
aren't required to be matching term-to-description pairs; you can have multiple to one, or one to multiple, such as a dictionary term
that has more than one definition.

Each `<dt>` has at least one associated `<dd>`, and each `<dd>` has at least one associated `<dt>`. While it is possible to
use the [adjacent sibling combinator](https://developer.mozilla.org/docs/Web/CSS/Adjacent_sibling_combinator) or the [`:has()` relational
selector](https://developer.mozilla.org/docs/Web/CSS/:has) to target variable numbers of these elements with CSS, if required, you can include
a `<div>` as the child of a `<dl>`, and the parent of one or more `<dt>` or `<dd>` elements (or both) are permitted. The `<dl>` can actually
have a few other children: nesting a `<div>`, `<template>`, or `<script>` is allowed. None of the description list elements has any element-specific attributes.

Now that you have an understanding of [links](/learn/html/links) and lists, let's put the two together to create [navigation](/learn/html/navigation).

{% Assessment 'lists' %}

# Metadata

In the document structure section you learned about the components you (almost) always find in the `<head>` of an HTML document. While everything in the `<head>`, including the `<title>`, `<link>`, `<script>`, `<style>`, and the lesser used `<base>`, is actually "meta data", there is a `<meta>` tag for metadata that cannot be represented by these other elements.

The specification includes several meta types, and there are many, many other application-supported meta types not in any official specification.  In this section, we'll discuss the attributes and values that are included in the specifications, some common meta names and content values, and a few meta types that are incredibly useful for search engine optimization, social media posting, and user experience that are not officially defined by the [WHATWG](https://html.spec.whatwg.org/multipage/semantics.html#the-meta-element) or [W3C](https://www.w3.org/MarkUp/html-spec/Elements/META.html).

## The required `<meta>` tags, revisited

Let's revisit the two necessary `<meta>` tags already covered—the [character set declaration](/learn/html/document-structure/#character-set) and the [viewport meta tag](/learn/html/document-structure/#viewport-metadata)—and get a better understanding of the `<meta>` tag in the process.

The `charset` attribute of the `<meta>` element came about in a unique manner. Originally the character set meta data was written as `<meta http-equiv="Content-Type" content="text/html; charset=<characterset>" />`, but so many developers mis-typed the `content` attribute as `content="text/html" charset="<characterset>"` that browsers began supporting charset as an attribute. It is standardized now in the HTML living standard as `<meta charset=<charset>" />`, where, for HTML,`<charset>` is the case-insensitive string "utf-8" .

You may have noticed the original character set meta declaration used to include the `http-equiv` attribute. This is short for "http-equivalent", as the meta tag is basically replicating what could be set in an HTTP header. Aside from the `charset` exception, all other meta tags defined in the WHATWG HTML specification contain either the `http-equiv` or `name` attribute.

## Officially defined meta tags

There are two main types of meta tags: pragma directives, with the `http-equiv` attribute like the charset meta tag used to have, and named meta types, like the viewport meta tag with the `name` attribute that we discussed in the [document structure](/learn/html/document-structure/#) section.  Both the `name` and `http-equiv` meta types must include the `content `attribute, which defines the content for the type of metadata listed.

### Pragma directives

The `http-equiv` attribute has as its value a pragma directive. These directives describe how the page should be parsed. Supported `http-equiv` values enable setting directives when you are unable to set HTTP headers directly.

The specification defines seven [pragma directives](https://html.spec.whatwg.org/multipage/semantics.html#pragma-directives), most of which have other methods of being set. For example, while you can include a language directive with `<meta http-equiv="content-language" content="en-us" />`, we have already discussed using the [`lang` attribute on the HTML element](/learn/html/document-structure/#content-language), which is what should be used instead.

The most common pragma directive is the `refresh` directive.

```html
<meta http-equiv="refresh" content="60; https://machinelearningworkshop.com/regTimeout" />
```

While you can set a directive to refresh at an interval of the number of seconds set in the `content` attribute, and even redirect to a different URL, please don't. Refreshing and redirecting content without an explicit user request to do so is poor usability and negatively impacts accessibility. Don't you hate it when you're in the middle of a paragraph and the page resets? Imagine having cognitive or vision issues and that happening. If you are going to set a refresh with a redirect, make sure the user has enough time to read the page, a link to hasten the process, and, if appropriate, a button to "stop the clock" and prevent the redirect from happening.

We won't include this in our site because there is no reason to time out a user session other than to annoy our visitors.

The most useful pragma directive is `content-security-policy`, which enables defining a [content policy](/csp/) for the current document. Content policies mostly specify allowed server origins and script endpoints, which help guard against cross-site scripting attacks.

```html
<meta http-equiv="content-security-policy" content="default-src https:" />
```

If you don't have access to change HTTP headers (or if you do), here is a list of [space separated content values for `content-security-policy` directives](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy).

### Named meta tags

More often than not, you'll include named metadata. Include the `name` attribute, with the attribute value being the name of the metadata. As with pragma directives, the `content` attribute is required.

The `name` attribute is the name of the metadata. In addition to `viewport`,  you will probably want to include `description` and `theme-color`, but not `keywords`.

#### Keywords

Search engine optimization snake-oil salespeople abused the keywords meta tag by stuffing them with comma-separated lists of spam words instead of lists of relevant key terms, so search engines do not consider this metadata to be useful anymore. No need to waste time, effort, or bytes adding it.

#### Description

The `description` value, however, is super important for SEO; in addition to helping sites rank based on the content, the description content value is often what search engines display under the page's title in search results.  Several browsers, like Firefox and Opera, use this as the default description of bookmarked pages. The description should be a short and accurate summary of the page's content.

```html
<meta name="description"
  content="Register for a machine learning workshop at our school for machines who can't learn good and want to do other stuff good too" />
```

If the second half of our description makes no sense to you, you probably haven't seen the movie [Zoolander](https://www.youtube.com/watch?v=NQ-8IuUkJJc).

#### Robots

If you don't want your site to be indexed by search engines, you can let them know.  `<meta name="robots" content="noindex, nofollow" />` tells the bots to not index the site and not to follow any links. Bots should listen to the request, but there's no law requiring they heed the request. You don't need to include  `<meta name="robots" content="index, follow" />` to request indexing the site and following links, as that is the default, unless HTTP headers say otherwise.

```html
<meta name="robots" content="index, follow" />
```

#### Theme color

The [`theme-color`](/learn/design/theming/#customize-the-browser-interface) value lets you define a color to customize the browser interface. The color value on the content attribute will be used by supporting browsers and operating systems, letting you provide a suggested color for the user agents that support coloring the title bar, tab bar, or other chrome components. This meta tag is especially useful for [progressive web apps](/learn/pwa/). But, if you're including a manifest file, which a PWA requires, you can include the theme color there instead. Defining it in the HTML, however, ensures that the color will be found immediately, before rendering, which may be faster on first load than waiting for the manifest.

To set the theme color to the blue tone of our site's background color, include:

```html
<meta name="theme-color" content="#226DAA" />
```

The theme color meta tag can include a `media` attribute enabling the setting of different theme colors based on media queries. The `media` attribute can be included in this meta tag only and is ignored in all other meta tags.

There are several [other `name` meta values](https://developer.mozilla.org/docs/Web/HTML/Element/meta/name), but the ones we have discussed are the most common. Except for declaring different `theme-color` values for different media queries, only include one of each meta tag. If you do need to include more than one type of meta tag to support legacy browsers, the legacy values should come after the newer values, as user agents read successive rules until they find a match.

## Open Graph

[Open Graph](https://ogp.me/) and similar meta tag protocols can be used to control how social media sites, like Twitter, LinkedIn, and Facebook, display links to your content. If not included, social media sites will correctly grab the title of your page and the description from the description meta tag, the same information as search engines will present, but you can intentionally set what you want users to see when a link is posted to your site.

When you post a link to MachineLearningWorkshop.com or web.dev on Facebook or Twitter, a card with an image, site title, and site description appears. The entire card is a hyperlink to the URL you provided.

Open Graph meta tags have two attributes each: the `property` attribute instead of the `name` attribute, and the content or value for that property. The `property` attribute is not defined in official specifications but is widely supported by applications that support the Open Graph protocol. Creating "new" attributes like `property` ensures the attribute values created for the protocol's attribute won't clash with future values of the `name` or `http-equiv` attributes.

Let's create a Facebook media card:

```html
<meta property="og:title" content="Machine Learning Workshop" />
<meta property="og:description" content="School for Machines Who Can't Learn Good and Want to Do Other Stuff Good Too" />
<meta property="og:image" content="http://www.machinelearningworkshop.com/image/all.png" />
<meta property="og:image:alt" content="Black and white line drawing of refrigerator, french door refrigerator, range, washer, fan, microwave, vaccuum, space heater and air conditioner" />
```

Include a title of your post for display. This title is generally displayed below the image and above the description. The description should be up to three sentences that summarize your post. This will appear after the headline defined in `og:title`. Provide the absolute URL to the banner image you want displayed, including the `https://` protocol. When including an image in HTML, always include an alternative text description for the image, even when the image will appear elsewhere. For Open Graph social media cards, define the `alt` as the content value for the `og:image:alt` property. You can also include a canonical URL with `og:url`.

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/BPMSBLm8xjwAW9U3VnVI.png", alt="Facebook card for Machine Learning Workshop.", width="800", height="796" %}

These meta tags are all defined in the [Open Graph protocol](https://ogp.me/). The values should be the content you would like the third-party web application to display.

Other social media have their own similar syntaxes, like [Twitter card markup](https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup). This enables providing a different experience depending on where the link appears, or enabling link tracking by adding a parameter at the end of the URL.

```html
<meta name="twitter:title" content="Machine Learning Workshop" />
<meta name="twitter:description" content="School for machines who can't learn good and want to do other stuff good too" />
<meta name="twitter:url" content="https://www.machinelearningworkshop.com/?src=twitter" />
<meta name="twitter:image:src" content="http://www.machinelearningworkshop.com/image/all.png" />
<meta name="twitter:image:alt" content="27 different home appliances" />
<meta name="twitter:creator" content="@estellevw" />
<meta name="twitter:site" content="@perfmattersconf" />
```

In Twitter's case, to ensure the value of the `name` attribute doesn't conflict with future specifications, instead of using a new attribute such as the `property` attribute in Open Graph, for Twitter card data, all name values are prefixed with `twitter:`.

You can see what your social media card will look like on [Twitter](https://cards-dev.twitter.com/validator) and [Facebook](https://developers.facebook.com/tools/debug/?q=https%3A%2F%2Fmachinelearningworkshop.com).

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/FeMNAtAtbmjeL0P0aUs5.png", alt="Twitter card for Machine Learning Workshop", width="800", height="874" %}

You can have different card images, titles, and descriptions for different social media sites or for different link parameters. For example, [https://perfmattersconf.com](https://perfmattersconf.com) sets different values for  `og:image`,  `og:title`, and `og:description` based on the parameter of the URL.

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/fDeipwtUHoiNHIvbjzBV.png", alt="A card showing a conference speaker.", width="800", height="679" %}

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/8CquPieF4L6oRVAGJ5mM.png", alt="The same card with details for a different speaker.", width="800", height="829" %}


If you enter [https://perfmattersconf.com?name=erica](https://perfmattersconf.com?name=erica) and [https://perfmattersconf.com?name=melanie](https://perfmattersconf.com?name=melanie) in [Twitter's Card Validator](https://cards-dev.twitter.com/validator), you will see these two different cards; we provided different content even though they both link to the same conference home page.

## Other useful meta information

If someone bookmarks your site, adding it to their home screen, or if your site is a progressive web application or otherwise works offline or without browser chrome features displayed, you can provide application icons for the mobile device's home screen.

You can use the `<link>` tag to link to the startup images that you want to use. Here's an example of including a few images, with media queries:

```html
<link rel="apple-touch-startup-image" href="icons/ios-portrait.png" media="orientation: portrait" />
<link rel="apple-touch-startup-image" href="icons/ios-landscape.png" media="orientation: landscape" />
```

If your site or application is  web-app capable, meaning the site can stand on its own with minimal UI, such as no back button, you can use meta tags to tell the browser that too:

```html
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
```

Only include these if your app is indeed app-capable. If your site isn't, you'll be setting up your most ardent supporters, those who added your site to their home screen, for a really bad user experience. You'll lose their love!

If someone is going to save your icon to their tiny device's home screen, you want to provide the operating system with a short name that doesn't take up much room on a small device's home screen. You can do this by including a meta tag, or using a webmanifest file. The following demonstrates the meta tag method:

```html
<meta name="apple-mobile-web-app-title" content="MLW" />
<meta name="application-name" content="MLW" />
```

You've covered several meta tags, all of which will make your header longer. If you're indeed creating a web app-capable, offline-friendly progressive web application, instead of including these two additional meta tags, you can more simply and succinctly include `short_name: MLW` in a webmanifest file.

The manifest file can prevent an unwieldy header full of `<link>` and `<meta>` tags. We can create a manifest file, generally called `manifest.webmanifest` or `manifest.json`. We then use the handy `<link>` tag with a `rel` attribute set to `manifest` and the `href` attribute set to the URL of the manifest file:

```html
<link rel="manifest" href="/mlw.webmanifest" />
```

This series is focused on HTML, but you can check out the [web.dev course on progressive web applications](/learn/pwa/web-app-manifest/) or [MDN's web app manifest documentation](https://developer.mozilla.org/docs/Web/Manifest).

Your HTML now looks something like this:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Machine Learning Workshop</title>
    <meta name="viewport" content="width=device-width" />
    <meta name="description" content="Register for a machine learning workshop at our school for machines who can't learn good and want to do other stuff good too" />
    <meta property="og:title" content="Machine Learning Workshop" />
    <meta property="og:description" content="School for Machines Who Can't Learn Good and Want to Do Other Stuff Good Too" />
    <meta property="og:image" content="http://www.machinelearningworkshop.com/image/all.png" />
    <meta property="og:image:alt" content="Black and white line drawing of refrigerator, french door refrigerator, range, washer, fan, microwave, vaccuum, space heater and air conditioner" />
    <meta name="twitter:title" content="Machine Learning Workshop" />
    <meta name="twitter:description" content="School for machines who can't learn good and want to do other stuff good too" />
    <meta name="twitter:url" content="https://www.machinelearningworkshop.com/?src=twitter" />
    <meta name="twitter:image:src" content="http://www.machinelearningworkshop.com/image/all.png" />
    <meta name="twitter:image:alt" content="27 different home appliances" />
    <meta name="twitter:creator" content="@estellevw" />
    <meta name="twitter:site" content="@perfmattersconf" />
    <link rel="stylesheet" src="css/styles.css" />
    <link rel="icon" type="image/png" href="/images/favicon.png" />
    <link rel="alternate" href="https://www.machinelearningworkshop.com/fr/" hreflang="fr-FR" />
    <link rel="alternate" href="https://www.machinelearningworkshop.com/pt/" hreflang="pt-BR" />
    <link rel="canonical" href="https://www.machinelearning.com" />
    <link rel="manifest" href="/mlwmanifest.json" />
  </head>
  <body>

    <!-- <script defer src="scripts/lightswitch.js"></script>-->
  </body>
</html>
```

It's pretty long, but it's done. It would have been much longer, but you've summed up all the icons, short name, etc. in a [manifest file](/add-manifest/), enabling you to omit many `<meta>` and `<link>` tags,

Now that your `<head>` is mostly complete, you can dive into some [semantic HTML](/learn/html/semantic-html/).

{% Assessment 'metadata' %}

# Navigation

As you learned in [links](/learn/html/links), the `<a>` element with the `href` attribute creates links that users can follow by clicking or
tapping. In [lists](/learn/html/lists), you learned how to create lists of content. In this section, you will discover how to group lists of
links together to create navigation.

There are several types of navigation and several ways to display them. Named anchors within text linking to other pages within
the same website are considered local navigation. Local navigation that consists of a series of links displaying the hierarchy of
the current page in relation to the site's structure, or the pages the user followed to get to the current page, is called a breadcrumb.
A page's table of contents is another type of local navigation. A page containing hierarchical links to every single page on a site is called
a site map. The navigation section leading to the top-level pages of the website which is found on every page is called global navigation.
Global navigation can be displayed in several different ways, including navigation bars, drop-down menus, and flyout menus.
The same site may display its global navigation differently, depending on the viewport size.

Always make sure users can navigate to any page on your site with the fewest number of clicks, while making sure the navigation
is intuitive and not overwhelming. That said, there are no specific requirements for navigational elements. [MachineLearningWorkshop.com](https://machinelearningworkshop.com),
being a single-page website, has a local navigation bar in the top right; this is where multi-page sites often put their global navigation.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/6Te041GdOLBpwp0cuUT0.png", alt="The front page of this page, including the breadcrumbs at top, a button to show the table of contents for this page, and the local navigations for the series.", width="600", height="628" %}

If you are viewing this page on web.dev, you can spot a few navigational features. There is a breadcrumb above the title,
an "on this page" table of contents after the title, and a "Learn HTML" table of contents that, depending on the width of your screen,
is either always displayed or made visible with the click of a menu button. The first element on the page is a hidden link to #main, which enables you to skip both the sidebar and breadcrumb links.


## "Skip to content" link

The first element on the page is an internal link:

```html
<a href="#main" class="skip-link button">Skip to main</a>
```

which, when clicked, or when it has focus and the user hits `Enter`, scrolls the page and gives focus to the main content:
a landmark `<main>` with an `id` of `main`:

```html
<main id="main">
```

You may never have seen the link on this site, even if you have read through all the previous sections.
It is only displayed when it has focus:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ieTOzelKA243HJj195b5.png", alt="Skip to Main button.", width="680", height="300" %}

For improved usability and accessibility, it's important to let users bypass the blocks of content that are repeated on every page.
The skip link is included so when a keyboard user hits `tab` on load, they can quickly skip to the main content of the site—avoiding
having to tab through extensive linkages. On this page, the skip link skips the section-wide sidebar navigation and the breadcrumb navigation,
taking the user directly to the page title.

Most designers don't like the appearance of having a link at the top of the page. It is fine to hide the link from view while remembering
that when the link gets focus, which will happen when a keyboard user tabs through the link on the page, the link must be visible to all users.
Only hide content in the non-focused and non-active state using a selector similar to `.visually-hidden:not(:focus):not(:active)`.

The link text reads "skip to main." This is the link's accessible name. This is a technical site, and users probably know what "main" means.
Like all link text, the accessible name should clearly indicate where the link takes the user. The link target should be the beginning of the
page's main content. To test this, when the page loads, tab to the "Skip to main" link. Then press `Enter` to ensure it "jumps" to the main content.

## Table of contents

The skip-to-content link scrolls the main content into view. The first element is the `<h1>` heading with the title of this section.
In this case, `<h1>Marking up navigation</h1>`. The main heading is followed by the tagline, a brief description of the contents of this
tutorial. Whether the table of contents navigation comes before or after the heading in the codebase depends on the width of your browser.

<figure>
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/8FNr1lp9jbtoM2weXceV.png", alt="On narrow screens, the table of contents is hidden behind an on this page button that toggles the navigations visibility.", width="446", height="300", style="max-width: 300px; margin: 0 auto;" %}
  <figcaption>On narrow screens, the table of contents is hidden behind an on this page button that toggles the navigations visibility.</figcaption>
</figure>
<figure>
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ThkLoScjUq2V6M1b4WSj.png", alt="On wide screens, the table of contents is always visible, with the link to the current section being highlighted in blue.", width="236", height="300", style="max-width: 400px; margin: 0 auto;" %}
  <figcaption>On wide screens, the table of contents is always visible, with the link to the current section being highlighted in blue.</figcaption>
</figure>

If your browser is wider than 80em, the Table of contents comes before the heading in the markup, and is similar to the following
(the class names have been removed to simplify the markup):

```html
<nav aria-label="On this page">
  <div>On this page</div>
  <div>
    <ul>
      <li>
        <a href="#skip">Skip to content link</a>
      </li>
      <li>
        <a href="#toc">Table of contents</a>
      </li>
      <li>
        <a href="#bc">Page breadcrumbs</a>
      </li>
      <li>
        <a href="#ln">Local navigation</a>
      </li>
      <li>
        <a href="#global">Global navigation</a>
      </li>
    </ul>
  </div>
</nav>
```

The `<nav>` is the best element to use for sections of navigation: it automatically informs the screen reader and search engine
that a section has a role of `navigation`, a landmark role.

Including the [`aria-label`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-label) attribute
provides a brief description of the purpose of the navigation. In this case, as the value of the attribute is redundant to
text that is visible on the page, it is preferable to use [`aria-labelledby`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)
to reference the visible text.

We can change the non-semantic `<div>` to a paragraph `<p>`, then add an [`id`](/learn/html/attributes/#id) so it can be referenced. We then use `aria-labelledby`:

```html
<nav aria-labelledby="tocTitle">
  <p id="tocTitle">On this page</p>
```

In addition to reducing redundancy, visible text gets translated by translation services, whereas attribute values may not.
When possible, if text is present that provides for an adequate label, prefer that over attribute text.

This navigation is the table of contents. If you want to use the `aria-label`, provide that information rather than repeating visible text:

```html
<nav aria-label="Table of Contents">
  <p>On this page</p>
```

When providing an accessible name on an element, don't include the name of the element. Screen readers provide that information to the user.
For example, when using the `<nav>` element, don't include "navigation"; that information is included when using semantic elements.

The links themselves are in an unordered list. While they don't have to be nested in a list, using a list enables screen reader users to know how many
list items, and therefore links, are an individual list in a navigation.

```html
<nav aria-labelledby="tocTitle">
  <p id="tocTitle">On this page</p>
  <ul role="list">
    <li>
      <a href="#skip">Skip to content link</a>
    </li>
    <li>
      <a href="#toc">Table of contents</a>
    </li>
    <li>
      <a href="#bc">Page breadcrumbs</a>
    </li>
    <li>
      <a href="#ln">Local navigation</a>
    </li>
    <li>
      <a href="#global">Global navigation</a>
    </li>
  </ul>
</nav>
```

If your browser is less than 80em wide, the "On this page" widget is below the heading and tagline. This is done by including
two table-of-contents navigation components and hiding one or the other with CSS `display: none;` based on a media query.

Including two identical widgets to only show one is an anti-pattern. The extra bytes are negligible. Hiding HTML content from
all users by using CSS `display: none` is appropriate. The issue is that, on wide screens, the table of contents comes before `#main`;
and on narrower screens, the table of contents is nested within #main. Using the keyboard to skip to content skips over the table of
contents on a wide screen. While users are accustomed to content being responsive and changing location when they change devices or
increase their font size, they do not expect the tab order to change when they do so. Page layouts should be accessible, predictable,
and consistent across a site. Here, the location of the table of contents is not predictable.

## Page breadcrumbs

Breadcrumbs provide secondary navigation to help users understand where they are on a website. They generally show the URL hierarchy
of the current document and the location of the current page in the site structure. The site structure from a user perspective may differ
from the file structure on the server. That is fine. The user doesn't need to know how you organize your files, but they do need to be able
to navigate through your content.

Breadcrumbs help users navigate and understand the organization of your site, allowing them to quickly navigate anywhere up to any ancestor
sections without having to step back through each prior page visited to get to the current page using `back` functionality.

If the site has a simple hierarchical directory structure, as is the case with web.dev, the breadcrumb navigation will often be composed
of a link to the home, or hostname, with a link to the index file of each directory in the URL's pathname. The inclusion of the
current page is optional and requires a little extra attention.

```js
const url = new URL("https://web.dev/learn/html/navigation");
const sections = url.hostname + url.pathname.split('/');
// "web.dev,learn,html,navigation"
```

The sections of the breadcrumb show the path from the current page back to the home page, showing each level in-between.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/DNpEzCXqogU6qfJWduLo.png", alt="Breadcrumbs indicating the path to the current page.", width="300", height="75" %}

Every Learn HTML module page has the same breadcrumb navigation, displaying the hierarchy of the `HTML` lessons within the
`learn` section of `web.dev`. The code is similar to the following, with classes and SVG details removed for clarity:

```html
<nav aria-label="breadcrumbs">
  <ul role="list">
    <li>
      <a href="/">
        <svg aria-label="web.dev" role="img">
          <use href="#webDevLogo" />
        </svg>
      </a>
    </li>
    <li>
      <a href="/learn/">Learn</a>
    </li>
    <li>
      <a href="/learn/html">Learn HTML!</a>
    </li>
  </ul>
  <share-action authors="@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, twitter" role="button" tabindex="0">
    <svg aria-label="share" role="img">
      <use href="#shareIcon" />
    </svg>
    <span>Share</span>
  </share-action>
</nav>
```

This breadcrumb follows best practices. It uses the `<nav>` element, a landmark role, so assistive technology presents the breadcrumbs as a navigational element on the page.
The accessible name of "breadcrumbs", provided with the `aria-label`, differentiates it from the other navigation landmarks in the current document.

Between links there are CSS-generated content separators. The separators come before each list item starting with the second `<li>`.

```css
[aria-label^="breadcrumb" i] li + li::before {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  rotate: 45deg;
  opacity: .8
}
```

Screen readers will not "see" them, which is best practice: separators between breadcrumb links should be hidden from screen readers.
They must also have enough contrast against their background, the same as regular text.

This version uses an unordered list and list items. An ordered list is preferable as ordered list items are enumerated.
Also it is a list: `role="list"` was added back in because some CSS display property values remove the semantics from some elements.

Generally, the link to the home page in a breadcrumb should read "home" rather than be the site logo with the name of the site as
the label. But as the breadcrumb is at the top of the document and is the only occurrence of the logo on the page, it makes sense
as to why this anti-pattern was used.

The last element is a custom `<share-action>` element. Custom elements are discussed in section 15. While this custom element
is not part of the breadcrumb, including an unrelated element in a `<nav>` is fine, as long as the inclusion is consistent on all pages.

### Current page

On this page, the current page, "Navigation", is not included in the breadcrumb. When the current page is included in a
breadcrumb, the text should preferably not be a link, and `aria-current="page"` should be included on the current page's
list item. When it isn't included, it is helpful to indicate that the heading that follows is the current page with an
icon or other symbol.

Should the design change, an alternative version of the breadcrumb could be used:

```html
<nav aria-label="breadcrumbs">
  <ol role="list">
    <li>
      <a href="/">Home</a>
    </li>
    <li>
      <a href="/learn/">Learn</a>
    </li>
    <li>
      <a href="/learn/html">Learn HTML!</a>
    </li>
    <li aria-current="page">
      Navigation
    </li>
  </ol>
</nav>
```

Breadcrumbs are not for linear steps. For example, a list of the path the user followed to get to the current page or the
list of steps followed up to this point in a recipe can be nested within a `<nav>`,  but should not be labeled as a breadcrumb.

## Local navigation

There is another navigational component on this page. If you are on a wide screen, there is a sidebar on the left with the
"Learn HTML" logo, a search bar, and links to each of the 20 sections in Learn HTML. Each link contains the chapter number,
the section title, and a checkmark to the right on sections that you have already visited—possibly this one if you have navigated away and have come back. The links to all the sections in Learn HTML, along with the search and local header, are the location navigation.

If you are visiting this site on a tablet or mobile device, or otherwise have a narrower screen, when you load this page, the sidebar is hidden. You can make it visible via the hamburger menu in the top navigation bar (yes, the header is a custom `<web-header>` element with `role="navigation"` set).

The main difference between the permanent local navigation on wide screens and the local navigation on narrower screens that can be made to appear and disappear, is the display of the close button on the version that can be hidden. This icon is hidden on wide screens with `display: none;`.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/MHQ1i1NnGKx2N0ovmzxy.png", alt="The local navigation is showing a checkmark next to the name of this chapter.", width="365", height="75", style="max-width: 300px; margin: 0 auto;" %}

The link to this document, section 010, has a slightly different appearance from the other links in the local navigation to indicate to sighted users that this is the current page. This visual difference is created with CSS. The current page is also identified with the `aria-current="page"` attribute. This informs assistive technologies that it is a link to the current page. The HTML for this list item within this local navigation is similar to:

```html
<li>
  <a aria-current="page" href="/learn/html/navigation/" data-complete="true">
    <span>010</span>
    <span>Navigation</span>
    <svg aria-label="Check" role="img">
      <use href="#checkmark" />
    </svg>
  </a>
</li>
```

If this isn't the first time you visit this page, the checkmark will not be visible. If you have visited this page in the past, the
`data-complete` [custom attribute](/learn/html/attributes) is set to `true`, and the checkmark will be displayed. The checkmark is included
in each link, but CSS hides the checkbox from users who have not been to this page before with `display: none` based on the absence of the
`data-complete="true"` attribute and value:

```css
.course .stack-nav a:not([data-complete="true"]) svg {
  display: none;
}
```

When `display` is set to something other than `none`, the `role` informs assistive technology that the inline SVG is an image,
and the `aria-label` acts as the `alt` attribute on an `<img>`would.

## Global navigation

Global navigation is the navigation section leading to the top-level pages of the website that is the same on every page of a site.
A site's global navigation may also be made up of tabs that open nested lists of links that link to all the subsections of a site or other menus.
It may include titled sections, buttons, and search widgets. These additional features aren't a requirement. What is required is that
the navigation appears on every page, and is the same on every page; with `aria-current="page"` on any links to the current page, of course.

Global navigation provides a consistent means of traveling anywhere in the application or website. Google doesn't have global
navigation at the top of the page. Yahoo! does. While all the main Yahoo! properties have different styles, the content for
most sections are the same.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/p9q003xRDvYiTidnBEHf.png", alt="A well-contrasted navigation header, with a white picker on a black background.", width="600", height="31" %}

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/HyvinG9Tf5wR5qq1tM5s.png", alt="A poorly-contrasted navigation header, with a black picker on a grey background.", width="600", height="35" %}

The content of the news and sports global navigation headers are the same, but the icon showing that the user is currently
on sports does not have enough contrast to be accessible; even for visitors who don't have low vision. Both sections have a global
navigation with a section-specific local navigation below it.

Similar to global navigations, footers should be identical on all pages. But that is the only similarity. Global navigation
enables navigation to all parts of the site from a product perspective. Navigation elements within a footer don't have specific requirements.
Generally, the footer will include corporate links, such as legal statements, about the company, and careers, and can lead to external
sources, such as social media icons.

This page's footer contains three additional `<nav>` elements: the footer navigation, Google developers, and terms and policies,
with each being a link. The footer navigation includes how to contribute to web.dev on Github, other educational content provided by
Google outside of web.dev, and external "how to connect" links.

These three navigations in the `<footer>` are `<nav>` elements with an `aria-label`providing an accessible name for these landmark roles.
All the navigations we've seen have been [links](/learn/html/links) nested in [lists](/learn/html/lists) within a nav. We've covered all you need to know to create your own navigations.
Up next, we will look at marking up data tables.

{% Assessment 'navigation' %}

# Overview of HTML

HyperText Markup Language, or HTML, is the standard markup language for describing the structure of documents displayed on the web. HTML consists of a series of elements and attributes which are used to mark up all the components of a document to structure it in a meaningful way.

HTML documents are basically a tree of nodes, including HTML elements and text nodes. HTML elements provide the semantics and formatting for documents, including creating paragraphs, lists and tables, and embedding images and form controls. Each element may have multiple attributes specified. Many elements can have content, including other elements and text. Other elements are empty, with the tag and attributes defining their function.

There are several categories of elements, including metadata, sectioning, text, inline semantic, form, interactive, media, component, and scripting. We'll cover most of these in the series. But first, what is an element?

## Elements

HTML consists of a series of elements, which you use to enclose, or wrap, different parts of the content to make it appear or act in a certain way. HTML elements are delineated by tags, written using angle brackets (`<` and `>`).

Our page title is a heading, level one, for which we use the `<h1>` tag. The actual title, "Machine Learning Workshop", is the content of our element. The content goes between the open and closing tags. The entire thing—the opening tag, closing tag, and the content—is the element.

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/oyFzeg8ttK57XMGuVNvG.png", alt="The tags and content that make up an HTML element.", width="752", height="245" %}

The closing tag is the same tag as the opening tag, preceded by a slash.

Elements and tags aren't the exact same thing, though many people use the terms interchangeably. The tag name is the content in the brackets. The tag includes the brackets. In this case, `<h1>`. An "element" is the opening and closing tags, and all the content between those tags, including nested elements.

```html
<p>This paragraph has some
  <strong><em>strongly emphasized</em></strong>
  content</p>
```

This paragraph element has other elements _nested_ in it.  When nesting elements, it's important that they are properly nested.  HTML tags should be closed in the reverse order of which they were opened. In the above example, notice how the `<em>` is both opened and closed within the opening and closing `<strong>` tags, and the `<strong>` is both open and closed within the `<p>` tags.

Browsers do not display the tags. The tags are used to interpret the content of the page.

HTML is very, very forgiving. For example, if we omit the closing `</li>` tags, the closing tags are implied.

```html
<ul>
  <li>Blendan Smooth
  <li>Hoover Sukhdeep
  <li>Toasty McToastface
</ul>
```

Although it is valid to not close an `<li>`, it isn't good practice.  The closing `</ul>` is mandatory. If the unordered list's closing tag is omitted, the browser will try to determine where your list and list items end, but you might not agree with the decision.

The specification for each element lists whether the closing tag is mandatory or not. "Neither tag is omissible" in the specification means both an opening tag and a closing tag are required. The [specification provides a list of all the required closing tags](https://html.spec.whatwg.org/multipage/syntax.html#syntax-tag-omission).

If the `<em>` or `<strong>` in the example earlier  had not been closed, the browser may or may not close the element for you. Not closing an `<em>` simply leads to content possibly being rendered differently than you intended.  If a `</ul>` is omitted and the next tag is a closing tag for the list's parent container, you're lucky. If, on the other hand, it's an opening `<h1>` tag, the browser will assume the header is part of the list, including inheriting styles. Some omitted closing tags cause bigger issues: not closing some tags, such as `<script>`, `<style>`, `<template>`, `<textarea>`, and `<title>`, breaks subsequent content as shown in the following example.

{% Codepen {
  user: 'web-dot-dev',
  id: 'VwxzBLq',
  height: 500,
  theme: 'dark',
  tab: 'html,result'
} %}

Having some content being unintentionally italic or having a heading indented won't destroy your business. Having most of your content appear unstyled in a 200x300 textarea because you forgot to add a `</textarea>` or not show up at all because you forgot to close a `</style>` makes the site unusable.

In some cases, browsers will include elements even if the tags aren't present in the markup. Because elements can be implied, an element can exist even when the tags don't. The browser will add a `<body></body>` around your content and  `<tbody></tbody>` around your table rows, even if you don't. That being said, while it is valid to omit tags, don't. Also, as already mentioned, make sure they are correctly nested. Your future self as a maintainer of markup, and anyone else working on your code base, will thank you.

There are two types of elements: replaced and non-replaced.

### Non-replaced elements

The paragraph, header, and lists marked up in the earlier section are all non-replaced. Non-replaced elements have opening and (sometimes optional) closing tags that surround them and may include text and other tags as sub-elements. These enclosing tags can turn a phrase or image into a hyperlink, can make a sentence into a header, can give emphasis to words, and so on.

### Replaced and void elements

Replaced elements are replaced by objects, be it a graphical user interface (UI) widget in the case of most form controls, or a raster or scalable image file in the case of most images. Being replaced by objects, each comes with a default appearance. Depending on the type of object and the browser, the applicable styles are limited. For example, most browsers enable limited styling of UI widgets and related pseudo-elements. In the case of raster images, height, width, clipping, and filtering are easily done with CSS, but not much else. On the other hand, scalable vector graphics, using a markup language based on XML similar to HTML are fully scalable (unless they contain raster images). They are also fully styleable. Note that the ability to style an embedded SVG from the CSS linked to the HTML file that embeds it depends on how the SVG is set up.

In this example, the two replaced elements `<img>` and `<input>` are replaced by non-text content: an image and a graphical user interface object, respectively.

```html
<input type="range">
<img src="switch.svg" alt="light switch">
```

Output of the above HTML:

<input type="range">
<img src="https://machinelearningworkshop.com/svg/switch2.svg" alt="light switch" style="max-width: 200px;">

Replaced elements and void elements are often confused. Void elements are all self-closing elements and are represented by one tag. This means there is no such thing as a closing tag for a void element. Optionally, you can include a slash at the end of the tag, which many people find makes markup easier to read. Continuing with this example, we self close the tag with a slash:

```html
<input type="range"/>
<img src="switch.svg" alt="light switch"/>
```

The slash at the end is old school: it's a way of indicating that the element is self-closing and there will be no matched end or closing tag.

Void elements cannot contain text content or nested elements. Void elements include  `<br>`, `<col>`, `<embed>`, `<hr>`, `<img>`, `<input>`, `<link>`, `<meta>`, `<source>`, `<track>`, and `<wbr>`, among others.

Most replaced elements are void elements, but not all. The `video`, `picture`, `object`, and `iframe` elements are replaced, but aren't void. They can all contain other elements or text, so they all have a closing tag.

Most void elements are replaced; but again, not all, as we saw with `base`, `link`, `param`, and `meta`. Why have a void element, which can't have any content, that isn't replaced and thereby doesn't render anything to the screen? To provide information about the content! The information is provided by the elements' attributes.

## Attributes

You may have noticed the `<img>` and `<input`> examples had more than just the element type in their opening tag. These extra bits of space-separated name/value pairs (though sometimes including a value is optional) are called _attributes_. Attributes are what make HTML so incredibly powerful. We'll be covering hundreds of attributes and attribute values in this series, but here we'll just discuss what they are in general and how to include them.

Attributes provide information about the element. The attribute, like the rest of the opening tag, won't appear in the content, but they do help define how the content will appear to both your sighted and non-sighted (assistive technologies and search engines) users.

Attributes only appear in the opening tag. The opening tag always starts with the element type. The type can be followed by zero or more attributes, separated by one or more spaces. Most attribute names are followed by an equal sign equating it with the attribute value, wrapped with opening and closing quotation marks.

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/IdGp51MB61yo6WDSRZZ3.png", alt="An opening tag with attributes.", width="800", height="218" %}

In this example, we have an anchor link with two attributes. These two attributes have converted the content "Registration" into an internal anchor link that scrolls to the attribute `id="register"` in the current browser tab when the link is clicked, tapped, or activated with the keyboard or other device.

Attributes define the behavior, linkages, and functionality of elements. We'll cover more attributes in the [Attributes](/learn/html/attributes/) section of this series. For now, just note that some attributes are global—meaning they can appear within any element's opening tag. Some apply only to several elements but not all, and others are element-specific, relevant only to a single element.

Most attributes are name/value pairs. Boolean attributes, whose value is true, false, or the same as the name of the attribute, can be included as just the attribute: the value is not necessary.

```html
<img src="switch.svg" alt="light switch" ismap />
```

This image has three attributes: `src`, `alt`, and `ismap`. The `src` attribute is used to provide the location of the SVG image asset. The `alt` attribute provides alternative text describing the contents of the image. The `ismap` attribute is Boolean, and doesn't require a value. This is just to explain what attributes are. We'll cover these attributes in more detail in the [images](/learn/html/images/) section.

While quoting attributes isn't always required, it sometimes is. If the value includes a space or special characters, quotes are needed. For this reason, quoting is always recommended. One or more spaces between attributes if the attribute value is quoted are not actually required, but, to be safe, and for legibility, quotes and spaces are recommended, and appreciated.

HTML is not case-sensitive, but some attribute values are. Values that are defined in the specification are case-insensitive. Strings that are not defined as keywords are generally case-sensitive, including `id` and `class` values.

Note that if an attribute value is case-sensitive in HTML, it is case-sensitive when used as part of an [attribute selector](https://developer.mozilla.org/docs/Web/CSS/Attribute_selectors) in CSS and in JavaScript.

To make markup easier to read, it is recommended, but not required, to mark up your HTML using lowercase letters for all your element names and attribute names within your tags, and quote all attribute values.  If you ever hear the term "XHTML style markup", this, and self-closing empty elements with a slash at the end, is what that means.

## Appearance of elements

The default appearance of semantic elements is set by user-agent stylesheets. Most browsers use actual stylesheets for this purpose, while others simulate them in code. The end result is the same. Although some constraints on user-agent stylesheets are set by the HTML specification, browsers have a lot of latitude, which means some differences exist between browsers.

The element you choose, and therefore the tags you use, should be appropriate for the content you are displaying, as tags have semantic meaning. The [semantics](/learn/html/semantic-html/), or `role`, of an element is important to assistive technologies and, in some cases, search engines.  HTML should be used to structure content, not to define the content's appearance. Appearance is the realm of CSS. While many elements that alter the appearance of content, such as `<h1>`, `<strong>`, and `<em>`, have a semantic meaning, the appearance can and generally will be changed with author styles.

```html
<h1>This header has both <strong>strong</strong> and <em>emphasized</em> content</h1>
```

## Element, attributes, and JavaScript

The Document Object Model (DOM) is the data representation of the structure and content of the HTML document.  As the browser parses HTML, it creates a JavaScript object for every element and section of text encountered. These objects are called nodes—element nodes and text nodes, respectively.

There is an interface to define the functionality of every HTML element.  The [HTML DOM API](https://developer.mozilla.org/docs/Web/API/HTML_DOM_API) provides access to and control of every HTML element via the DOM, providing interfaces for the HTML element and all the HTML classes that inherit from it. The [HTMLElement](https://developer.mozilla.org/docs/Web/API/HTMLElement) interface represents the HTML element and all of its descendant nodes. Every other element implements it via an interface that inherits from it. Each inheriting interface has a constructor, methods, and properties.  Via the inherited HTMLElement properties, you can access every global attribute, as well as `input`, `pointer`, `transition`, and `animation` events. Via the individual element's sub-type, such as [HTMLAnchorElement](https://developer.mozilla.org/docs/Web/API/HTMLAnchorElement) and  [HTMLImageElement](https://developer.mozilla.org/docs/Web/API/HTMLImageElement), you can access element-specific attribute values and methods.

{% Assessment 'overview' %}

# Semantic HTML

With over 100 HTML elements, and the ability to create custom elements, there are infinite ways to mark up your content; but some ways—notably _semantically_—are better than others.

_Semantic_ means "relating to meaning". Writing semantic HTML means using HTML elements to structure your content based on each element's meaning, not its appearance.

This series hasn't covered many HTML elements yet, but even without knowing HTML, the following two code snippets show how semantic markup can give content context. Both use a word count instead of _ipsum lorem_ to save some scrolling—use your imagination to expand "thirty words" into 30 words:

The first code snippet uses `<div>` and `<span>`, two elements with no semantic value.

```html
<div>
  <span>Three words</span>
  <div>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
  </div>
</div>
<div>
  <div>
    <div>five words</div>
  </div>
  <div>
    <div>three words</div>
    <div>forty-six words</div>
    <div>forty-four words</div>
  </div>
  <div>
    <div>seven words</h2>
    <div>sixty-eight words</div>
    <div>forty-four words</div>
  </div>
</div>
<div>
   <span>five words</span>
</div>
```

Do you get a sense of what those words expand to? Not really.

Let's rewrite this code with semantic elements:

```html
<header>
  <h1>Three words</h1>
  <nav>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
  </nav>
</header>
<main>
  <header>
    <h1>five words</h1>
  </header>
  <section>
    <h2>three words</h2>
    <p>forty-six words</p>
    <p>forty-four words</p>
  </section>
  <section>
    <h2>seven words</h2>
    <p>sixty-eight words</p>
    <p>forty-four words</p>
  </section>
</main>
<footer>
  <p>five words</p>
</footer>
```

Which code block conveyed meaning?  Using only the non-semantic elements of `<div>` and `<span>`, you really can't tell what the content in the first code block represents. The second code example, with semantic elements, provides enough context for a non-coder to decipher the purpose and meaning without having ever encountered an HTML tag. It definitely provides enough context for the developer to understand the outline of the page, even if they don't understand the content, such as content in a foreign language.

In the second code block, we can understand the architecture even without understanding the content because semantic elements provide meaning and structure. You can tell that the first header is the site's banner, with the `<h1>` likely to be the site name. The footer is the site footer: the five words may be a copyright statement or business address.

Semantic markup isn't just about making markup easier for developers to read; it's mostly about making markup easy for automated tools to decipher. Developer tools demonstrate how semantic elements provide machine-readable structure as well.

## Accessibility object model (AOM)

As the browser parses the content received, it builds the document object model (DOM) and the CSS object model (CSSOM). It then also builds an accessibility tree. Assistive devices, such as screen readers, use the AOM to parse and interpret content. The DOM is a tree of all the nodes in the document. The AOM is like a semantic version of the DOM.

Let's compare how both of these document structures are rendered in Firefox's accessibility panel:

<div class="switcher">
  <figure>
    {% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/R2d9f5NfZTo1j9mOul0d.png", alt="A list of nodes which are all link or text leaf.", width="312", height="762" %}
    <figcaption>
      The first code snippet.
    </figcaption>
  </figure>
  <figure>
    {% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/3pwHvhjyjewbiEfHoVwQ.png", alt="A list of nodes with clear landmarks.", width="332", height="888" %}
    <figcaption>
      The second code snippet.
    </figcaption>
  </figure>
</div>



In the second screen shot, there are four landmark roles in the second code block. It uses semantic landmarks conveniently named `<header>`, `<main>`, `<footer>`, and `<nav>` for "navigation".   Landmarks provide structure to web content and ensure important sections of content are easily keyboard navigable for screen reader users.

Note that `<header>` and `<footer>` are landmarks, with the roles of `banner` and `contentinfo` respectively, when they are not nested in other landmarks. Chrome's AOM shows this as follows:

<div class="switcher">
  <figure>
    {% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/D2dsfO1wm6UrdorarkC0.png", alt="All text nodes are listed as static text.", width="456", height="602" %}
    <figcaption>
      The first code snippet.
    </figcaption>
  </figure>
  <figure>
    {% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/svdGvQhpNlk7UiFgoCpH.png", alt="The text nodes all have descriptions.", width="582", height="1046" %}
    <figcaption>
      The second code snippet.
    </figcaption>
  </figure>
</div>

Looking at Chrome developer tools, you'll note a significant difference between the accessibility object model when using semantic elements versus when you don't.

It's pretty clear that semantic element usage helps accessibility, and using non-semantic elements reduces accessibility. HTML is generally, by default, accessible. Our job as developers is to both protect HTML's default accessible nature and ensure that we maximize accessibility. You can [inspect the AOM in developer tools](https://developer.chrome.com/docs/devtools/accessibility/reference/#explore-tree).

### The `role` attribute

The `role` attribute describes the role an element has in the context of the document. The `role` attribute is a global attribute—meaning it is valid on all elements—defined by the [ARIA specification](https://w3c.github.io/aria/#dfn-role) rather than the [WHATWG HTML specification](https://html.spec.whatwg.org/dev/), where almost everything else in this series is defined.

Semantic elements each have an implicit role, some depending on the context. As we saw in the Firefox accessibility dev tools screenshot, the top level `<header>`, `<main>`, `<footer>`, and `<nav>` were all landmarks, while the `<header>` nested in `<main>` was a section. The Chrome screenshot lists these elements' [ARIA  roles](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles): `<main>` is `main`, `<nav>` is `navigation`, and `<footer>`, as it was the footer of the document, is `contentinfo`. When `<header>` is the header for the document, the default role is `banner`, which defines the section as the global site header. When a `<header>` or `<footer>` is nested within a sectioning element, it is not a landmark role. Both dev tools' screenshots show this.

Element role names are important in building the AOM. The semantics of an element, or 'role',  are important to assistive technologies and, in some cases, search engines.  Assistive technology users rely on semantics to navigate through and understand the meaning of content. The element's role enables a user to access the content they seek quickly and, possibly, more importantly, the role informs the screen reader user how to interact with an interactive element once it has focus.

Interactive elements, such as buttons, links, ranges, and checkboxes, all have implicit roles, all are automatically added to the keyboard tab sequence, and all have default expected user action support. The implicit role, or explicit `role` value, informs the user to expect element-specific default user interactions.

Using the `role` attribute, you can give any element a role, including a different role than the tag implies. For example, `<button>` has the implicit role of `button`.  With `role="button"`, you can turn any element semantically into a button: `<p role="button">Click Me</p>`.

While adding `role="button"` to an element will inform screen readers that the element is a button, it doesn't change the appearance or functionality of the element. The `button` element provides so many features without you doing any work. The `button` element is automatically added to the document's tab ordering sequence, meaning it is by default keyboard focusable. The Enter and Space keys both activate the button. Buttons also have all the methods and properties provided to them by the [HTMLButtonElement](https://developer.mozilla.org/docs/Web/API/HTMLButtonElement) interface. If you don't use the semantic button for your button, you have to program all those features back in. It's so much easier to just go with `<button>`.

Go back to the screenshot of the AOM for the non-semantic code block. You'll note that non-semantic elements don't have implicit roles. We can make the non-semantic version semantic by assigning each element a role:

```html
<div role="banner">
  <span role="heading" aria-level="1">Three words</span>
  <div role="navigation">
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
    <a>one word</a>
  </div>
</div>
```

While the `role` attribute can be used to add semantics to any element, you should instead use elements with the implicit role you need.

## Semantic elements

Asking yourself, "Which element best represents the function of this section of markup?" will generally result in you picking the best element for the job. The element you choose, and therefore the tags you use, should be appropriate for the content you are displaying, as tags have semantic meaning.

HTML should be used to structure content, not to define content's appearance. The appearance is the realm of CSS. While some elements are defined to appear a certain way, don't use an element based on how the user agent stylesheet makes that element appear by default. Rather, select each element based on the element's semantic meaning and functionality. Coding HTML in a logical, semantic, and meaningful way helps to ensure CSS is applied as intended.

Choosing the right elements for the job as you code means you won't have to refactor or comment your HTML. If you think about using the right element for the job, you'll most often pick the right element for the job. If you don't, you probably won't. When you understand the semantics of each element and are aware of why choosing the right element is important, you will generally be able to make the right choice without much additional effort.

In the next section, you'll use the semantic elements to build your [document structure](/learn/html/document-structure/).

{% Assessment 'semantic-html' %}

# Tables

HTML tables are used for displaying tabular data with rows and columns. The decision to use a `<table>` should be based on
the content you are presenting and your users' needs in relation to that content. If data is being presented, compared, sorted,
calculated, or cross-referenced, then `<table>` is probably the right choice. If you simply want to lay out non-tabular content neatly,
such as a large group of thumbnail images, tables are not appropriate: instead, [create a list](/learn/html/lists) of images and
style the [grid with CSS](/learn/css/grid).

In this section, we are going to discuss all the elements that make up the table, along with some accessibility and usability features
you should consider as you present tabular data. While Learn HTML isn't fundamentally about CSS, and there is an entire course dedicated
to [learning CSS](/learn/css), we will cover some table-specific CSS properties.

## Table elements, in order

The [`<table>`](https://developer.mozilla.org/docs/Web/HTML/Element/table) tag wraps the table content, including all the table elements.
The implicit ARIA role of a `<table>` is `table`; assistive technologies know this element is a table structure containing data arranged in
rows and columns. If the table maintains a selection state, has two-dimensional navigation, or allows the user to rearrange cell order, set [`role="grid"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/grid_role).
If the rows of the `grid` can be expanded and collapsed, use [`role="treegrid"`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/treegrid_role) instead.

Inside the `<table>`, you'll find the table headers (`<thead>`), table bodies (`<tbody>`), and, optionally, table footers (`<tfoot>`).
Each of these is made up of table rows (`<tr>`). Rows contain table header (`<th>`) and table data  (`<td>`) cells which, in turn, contain all the data.
In the DOM, before any of this, you may find two additional features: the table caption (`<caption>`) and column groups (`<colgroup>`). Depending
on whether or not the `<colgroup>` has a `span` attribute, it may contain nested table column (`<col>`) elements.

The table's children are, in order:
1. [`<caption>`](https://developer.mozilla.org/docs/Web/HTML/Element/caption) element
2. [`<colgroup>`](https://developer.mozilla.org/docs/Web/HTML/Element/colgroup) elements
3. [`<thead>`](https://developer.mozilla.org/docs/Web/HTML/Element/thead) elements
4. [`<tbody>`](https://developer.mozilla.org/docs/Web/HTML/Element/tbody) elements
5. [`<tfoot>`](https://developer.mozilla.org/docs/Web/HTML/Element/tfoot) elements

We'll cover the `<table>` elements' children, which are all optional but recommended, then take a look at rows, table header cells,
and table data cells. The `<colgroup>` will be covered last.

### Table caption

Being a native, semantic element, [`<caption>`](https://developer.mozilla.org/docs/Web/HTML/Element/table) is the preferred
method of giving a name to a table. The `<caption>` provides a descriptive, programmatically associated table title. It is
visible and available to all users by default.

The `<caption>` element should be the first element nested in the `<table>` element. Including it lets all users know the
purpose of the table immediately without having to read the surrounding text. Alternatively, you can use `aria-label` or `aria-labelledby`
on the `<table>` to provide an accessible name as the caption. The `<caption>` element has no element-specific attributes.

The caption appears outside the table. The location of the caption can be set with the CSS [`caption-side`](https://developer.mozilla.org/docs/Web/CSS/caption-side) property, which is a
better practice than using the deprecated `align` attribute. This can set the caption to the top and bottom. The left and right
side positioning, with `inline-start` and `inline-end`, are not yet fully supported. Top is the default browser presentation.

{% Codepen {
  user: 'web-dot-dev',
  id: 'yLEZRyW',
  height: 300,
  theme: 'dark',
  tab: 'html,result'
} %}

Preferably, data tables should have clear headers and a caption, and be simple enough to be almost self-explanatory. Bear in mind that
not all users have the same cognitive abilities. When the table is "making a point", or otherwise needs interpretation, provide a
brief summary of the main point or function of the table. Where that summary is placed depends on its length and complexity.
If brief, use it as the inner text of the caption. If longer, summarize it in the caption, and provide the summary in the
paragraph preceding the table, associating the two with the [`aria-describedby`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-describedby)
attribute. Putting the table in a `<figure>` and putting the summary in the `<figcaption>` is another option.

### Data sectioning

The content of tables is made up of up to three sections: zero or more table headers (`<thead>`) , table bodies (`<tbody>`),
and table footers (`<tfoot>`). All are optional, with zero or more of each being supported.

These elements don't help or hinder the accessibility of the table, but they are useful in terms of usability. They provide
styling hooks. For example, the [header contents can be made sticky](https://adrianroselli.com/2020/01/fixed-table-headers.html),
while the `<tbody>` contents can be made to scroll. Rows not nested in one of these three containing elements are implicitly
wrapped in a `<tbody>`. All three share the same implicit role [`rowgroup`](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Roles/Rowgroup_Role).
None of these three elements has any element-specific attributes.

What we have so far:

```html
<table>
  <caption>MLW Students</caption>
  <thead></thead>
  <tbody></tbody>
  <tfoot></tfoot>
</table>
```

The `<tfoot>` element was originally specified to come right after the `<thead>` and before the `<tbody>` for accessibility reasons,
which is why you may come across this non-intuitive source order in legacy codebases.

### Table content

Tables can be divided into table headers, bodies, and footers, but none of these really does anything if the tables do not
contain table rows, cells, and content. Each table row, `<tr>` contains one or more cells. If a cell is a header cell, use `<th>`.
Otherwise, use `<td>`.

User-agent stylesheets generally display the content in a `<th>` table header cell as centered and bold. These default styles,
and all styling, are best controlled with CSS instead of the deprecated attributes that used to be available on individual cells,
rows, and even the `<table>`.

There were attributes to add padding between cells and within cells, for borders, and for text alignment. Cellpadding and cellspacing,
which define the space between the content of a cell and its border, and between the borders of adjacent cells, should be set
with the CSS [border-collapse](https://developer.mozilla.org/docs/Web/CSS/border-collapse) and [border-spacing](https://developer.mozilla.org/docs/Web/CSS/border-spacing)
properties, respectively. `Border-spacing` will have no effect if `border-collapse: collapse` is set. If `border-collapse: separate;`
is set, it's possible to hide empty cells completely with `empty-cells: hide;`. To learn more about styling tables, here's an
interactive slidedeck of [table-related CSS styles](https://estelle.github.io/CSS/tables/#slide1).

In the examples, we've added a border on the table and each individual cell with CSS to make some features more apparent:

{% Codepen {
user: 'web-dot-dev',
id: 'oNymmWw',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

In this example, we have a caption, a table header, and a table body. The header has one row containing three header `<th>` cells,
thereby creating three columns. The body contains three rows of data: the first cell is a header cell for the row, so we use `<th>` instead of `<td>`.

The `<th>` cell has semantic meaning, with implicit ARIA roles of [columnheader](https://w3c.github.io/aria/#columnheader)
or [rowheader](https://w3c.github.io/aria/#rowheader). It defines the cell as the header for the column or row of table cells,
depending on the value of the enumerated `scope` attribute. The browser will default to `col` or `row` if `scope` is not explicitly set.
Because we have used semantic markup, the `1956` cell has two headers: Year and Lou Minious. This association tells us that "1956" is the
"year" of graduation for "Lou Minious". In this example, as we can see the entire table, the association is visually apparent.
Using `<th>` provides the association even when the header column or row has scrolled out of view. We could have explicitly set
`<th scope="col">Year</th>` and `<th scope="row">Lou Minious</th>` but with a simple table like this, the enumerated default values work.
Other values for `scope` include `rowgroup` and `colgroup`, which are useful with complex tables.

## Merging cells

Similar to MS Excel, Google Sheets, and Numbers, it is possible to join multiple cells into a single cell. This is done with HTML!
The `colspan` attribute is used to merge two or more adjacent cells within a single row. The `rowspan` attribute is used to merge cells across rows,
being placed on the cell in the top row.

{% Codepen {
user: 'web-dot-dev',
id: 'GRGzzEd',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

In this example, the table header contains two rows. The first header row contains three cells spanning four columns: the middle cell
has `colspan="2"`. This merges two adjacent cells. The first and last cells include `rowspan="2"`. This merges the cell with the cell
in the adjacent row, immediately beneath it.

The second row in the table header contains two cells; these are the cells for the second and third columns in the second row.
No cell is declared for the first or last column as the cell in the first and last columns in the first row span two rows.

In cases where a cell is defined by multiple header cells with associations that cannot be set by the `scope` attributes alone,
include the `headers` attribute with a space-separated list of the associated headers. As this example is a more complex table, we explicitly define
the scope of the headers with the `scope` attribute. To be even clearer, we added the `headers` attribute to each cell.

The `headers` attributes were possibly not necessary in such a simple use case, but they are important to have in your toolbelt
your tables grow in complexity. Tables with complex structures, such as tables where headers or cells are merged or with more
than two levels of column or row headers, require explicit identification of associated header cells. In such complex tables, explicitly
associate each data cell with each corresponding header cell with a list of space-separated `id` values of all the associated headers
as the value of the `headers` attribute.

The `headers` attribute is more commonly found on `<td>` elements, but is also valid on `<th>`.

That said, complex table structures can be difficult for all users, not just screen reader users, to understand. Cognitively
and in terms of screen reader support, simpler tables, with few to no spanned cells, even without adding scope and headers, are more easily
understood. They're also easier to manage!

## Styling tables

There are two relatively obscure elements that were briefly mentioned: the column group, [`<colgroup>`](https://developer.mozilla.org/docs/Web/HTML/Element/colgroup), element
and its only descendant, the empty [`<col>`](https://developer.mozilla.org/docs/Web/HTML/Element/col) column element. The
`<colgroup>` element is used to define groups of columns, or `<col>` elements, within a table.

If used, the column grouping should be nested in the `<table>`, immediately after the `<caption>` and before any table data.
If they span more than one column, use the `span` attribute.

The content outline order for a table is generally as follows, with `<table>` and `<caption>` being the two elements that
should be included:

```html
<table>
  <caption>Table Caption</caption>
  <colgroup>
    <col/>
  </colgroup>
  <thead>...
```

Neither `<colgroup>` nor `<col>` has semantic meaning in terms of helping to make the table more accessible, but they do allow
for limited column styling, including setting a width for the column with CSS.

`<col>` styles will style a column as long as there are no `<td>` or `<th>` styles that override that styling. For example, when
`<colspan>` is used to merge cells in some rows of a table but not all, you can't be sure that a selector such as `tr > *:nth-child(8)`,
which selects the 8th child of every row, will highlight the 8th column in full or will highlight the 8th column for several rows,
but with a smattering of 9th and 10th column cells, depending on what row or column cells were merged.

Unfortunately, only a few properties are supported, the styles aren't inherited into the cells, and the only way  of using the `<col>`
element in targeting cells is with a complex selector including the [`:has()` relational selector](https://developer.mozilla.org/docs/Web/CSS/:has).

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/UJ6y8w7K3tReIJegOTSC.png", alt="Layered rendering of the elements used to design HTML tables.", width="518", height="403" %}

If both the `<table>` and the `<colgroup>` have a background color, the `background-color` of the `<colgroup>` will be on top.
The order of drawing is: table, column groups, columns, rowgroups, rows, with cells last and on top, as shown in the [schema of table
layers](https://w3c.github.io/csswg-drafts/css2/#table-layers). The `<td>` and `<th>` elements are not descendants of `<colgroup>` or `<col>` elements, and do not inherit their styling.

To stripe a table, CSS structural selectors come in handy. For example, `tbody tr:nth-of-type(odd) {background-color: rgba(0 0 0 / 0.1);}`
will add a translucent black to each odd row in the body of the table, letting any background effects that are set on `<colgroup>` show through.

Tables are not responsive by default. Rather, they are sized according to their content by default. Extra measures are needed to get table
layout styling to effectively work across a variety of devices. If you are [changing the CSS display property for table elements](https://adrianroselli.com/2018/02/tables-css-display-properties-and-aria.html),
include ARIA `role` attributes. While that may sound redundant, the CSS `display`property can affect the accessibility tree in some browsers.

## Presenting data

Table elements have semantic meanings that are used by assistive technologies to enable navigating through the rows and columns
without getting 'lost'. The `<table>` element should not be used for presentation. If you need a heading over a list, use a [header](/learn/html/headings-and-sections/#headings-lessh1greater-lessh6greater)
and a [list](/learn/html/lists). If you want to lay out content in many columns, use [multi-column layout](https://developer.mozilla.org/docs/Web/CSS/CSS_Columns).
If you want to lay out content in a grid, use [CSS grid](/learn/css/grid). Only use a table for data. Think of it this way: if your data requires a spreadsheet in order to be presented at a meeting, use`<table>`.
If you would like to  use the features available in presentation software like Keynote or Powerpoint, you probably need a [description list](/learn/html/lists).

While sorting table columns is the purview of JavaScript, marking up your headers to let users know the column is sortable is the purview of HTML.
Let your users know the table columns are sortable with iconography showing ascending, descending, or unsorted. The column currently sorted should
include the [aria-sort](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-sort) attribute with the enumerated value of the sort direction.
The `<caption>` can politely announce updates to sort order via [aria-live](https://developer.mozilla.org/docs/Web/Accessibility/ARIA/Attributes/aria-live) and a
span that is dynamically updated, and which is visible to screen reader users. As the column is sortable by clicking on the header content, the header content should be a `<button>`.

{% Codepen {
user: 'web-dot-dev',
id: 'XWYOOed',
height: 300,
theme: 'dark',
tab: 'html,result'
} %}

If you're not presenting tabular data, don't use a `<table>`. If you do use a table for presentation, set `role="none"`.

Many developers use tables to lay out forms but there is no need to. But you do need to know about HTML forms, so we will cover that next.

{% Assessment 'tables' %}

# Template, slot, and shadow

The benefit of web components is their re-usability: you can create a UI widget once, and reuse it multiple times. While you
do need JavaScript to create web components, you don't need a JavaScript library. HTML and the associated APIs provide everything you need.

The Web Component standard is made up of three parts—[HTML templates](https://developer.mozilla.org/docs/Web/Web_Components/Using_templates_and_slots),
[Custom Elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements), and the [Shadow DOM](https://developer.mozilla.org/docs/Web/Web_Components/Using_shadow_DOM).
Combined, they enable building customized, self-contained (encapsulated), reusable elements that can be seamlessly integrated
into existing applications, like all the other HTML elements we've already covered.

In this section, we'll create the `<star-rating>` element, a web component that allows users to rate an experience on a
scale of one to five stars. When naming a custom element, it is recommended to use all lowercase letters. Also, include a dash,
as this helps distinguish between regular and custom elements.

We'll discuss using the `<template>` and `<slot>` elements, the `slot` attribute, and JavaScript to create a template with
an encapsulated [Shadow DOM](/shadowdom-v1/). We'll then re-use the defined element, customizing a section of text, just
like you would any element or web component. We'll also briefly discuss using CSS from within and outside of the custom element.

## The `<template>` element

The `<template>` element is used to declare fragments of HTML to be cloned and inserted into the DOM with JavaScript. The contents of the element are not rendered by default. Rather, they are instantiated using JavaScript.

```html
<template id="star-rating-template">
  <form>
    <fieldset>
      <legend>Rate your experience:</legend>
      <rating>
        <input type="radio" name="rating" value="1" aria-label="1 star" required />
        <input type="radio" name="rating" value="2" aria-label="2 stars" />
        <input type="radio" name="rating" value="3" aria-label="3 stars" />
        <input type="radio" name="rating" value="4" aria-label="4 stars" />
        <input type="radio" name="rating" value="5" aria-label="5 stars" />
      </rating>
    </fieldset>
    <button type="reset">Reset</button>
    <button type="submit">Submit</button>
  </form>
</template>
```

As the contents of a `<template>` element are not written to the screen, the `<form>` and its contents aren't rendered.
Yes, this Codepen is blank, but if you inspect the HTML tab, you'll see the `<template>` markup.

{% Codepen {
user: 'web-dot-dev',
id: 'vYzBNKR'
} %}

In this example, the `<form>` is not a child of a `<template>` in the DOM. Rather, contents of `<template>` elements are children
of a [`DocumentFragment`](https://developer.mozilla.org/docs/Web/API/DocumentFragment) returned by the [`HTMLTemplateElement.content`](https://developer.mozilla.org/docs/Web/API/HTMLTemplateElement/content)
property. To be made visible, JavaScript must be used to grab the contents and append those contents to the DOM.

{% Codepen {
user: 'web-dot-dev',
id: 'WNgeQGq'
} %}

This brief JavaScript did not create a custom element. Rather, this example has appended the contents of the `<template>` into the `<body>`.
The content has become part of the visible, styleable DOM.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/xd926m5ueCjzf3xt815J.png", alt="A screenshot of the previous codepen as shown in the DOM.", width="800", height="375" %}

Requiring JavaScript to implement a template for just one star rating isn't very useful, but creating a web component for a
repeatedly used, customizable star rating widget is useful.

## The `<slot>` element

We include a slot to include a customized per occurrence legend. HTML provides a [`<slot>`](https://developer.mozilla.org/docs/Web/HTML/Element/slot)
element as a placeholder inside a `<template>` that, if provided a name, creates a "named slot". A named slot can be used
to customize content within a web component. The `<slot>` element gives us a way to control where the children of a custom
element should be inserted within its shadow tree.

In our template, we change the `<legend>` to a `<slot>`:

```html
<template id="star-rating-template">
  <form>
    <fieldset>
      <slot name="star-rating-legend">
        <legend>Rate your experience:</legend>
      </slot>
```

The `name` attribute is used to assign slots to other elements if the element has a [slot](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/slot) attribute whose value matches the
name of a named slot. If the custom element doesn't have a match for a slot, the contents of the `<slot>` will be rendered.
So we included a `<legend>` with generic content that is OK to be rendered if anyone simply includes `<star-rating></star-rating>`, with no content, in their HTML.

```html
<star-rating>
  <legend slot="star-rating-legend">Blendan Smooth</legend>
</star-rating>
<star-rating>
  <legend slot="star-rating-legend">Hoover Sukhdeep</legend>
</star-rating>
<star-rating>
  <legend slot="star-rating-legend">Toasty McToastface</legend>
  <p>Is this text visible?</p>
</star-rating>
```

The [slot](https://developer.mozilla.orgdocs/Web/HTML/Global_attributes/slot) attribute is a global attribute that is used
to replace the contents of the `<slot>` within a `<template>`. In our custom element, the element with the slot attribute
is a `<legend>`. It doesn't need to be. In our template, `<slot name="star-rating-legend">` will be replaced with `<anyElement slot="star-rating-legend">`,
where `<anyElement>` can be any element, even another custom element.

## Undefined elements

In our `<template>` we used a `<rating>` element. This is not a custom element. Rather, it's an unknown element. Browsers
don't fail when they don't recognize an element. Unrecognized HTML elements are treated by the browser as anonymous inline
elements that can be styled with CSS. Similar to `<span>`, the `<rating>` and `<star-rating>` elements have no user-agent applied
styles or semantics.

{% Codepen {
user: 'web-dot-dev',
id: 'jOvNbwO'
} %}

Note that the `<template>` and contents are not rendered. The `<template>` is a known element that contains content that
is not to be rendered. The `<star-rating>` element has yet to be defined. Until we define an element, the browser displays it
like all unrecognized elements. For now, the unrecognized `<star-rating>` is treated as an anonymous inline element, so the content
including legends and the `<p>` in the third `<star-rating>` are displayed as they would be if they were in a `<span>` instead.

Let's define our element to convert this unrecognized element into a custom element.

### Custom elements

JavaScript is required to define custom elements. When defined, the contents of the `<star-rating>` element will be replaced by a
shadow root containing all the contents of the template we associate with it. The `<slot>` elements from the template are replaced
with the contents of the element within the `<star-rating>` whose `slot` attribute value matches the `<slot>`'s name value, if
there is one. If not, the contents of the template's slots are displayed.

Content within a custom element that isn't associated with a slot—the `<p>Is this text visible?</p>` in our third `<star-rating>`—is not included in
the shadow root and therefore not displayed.

We [define the custom element](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements) named `star-rating`
by extending the `HTMLElement`:

```js
customElements.define('star-rating',
  class extends HTMLElement {
    constructor() {
      super(); // Always call super first in constructor
      const starRating = document.getElementById('star-rating-template').content;
      const shadowRoot = this.attachShadow({
        mode: 'open'
      });
      shadowRoot.appendChild(starRating.cloneNode(true));
    }
  });
```

{% Codepen {
user: 'web-dot-dev',
id: 'poOzjpj'
} %}

Now that the element is defined, every time the browser encounters a `<star-rating>` element, it will be rendered as defined
by the element with the `#star-rating-template`, which is our template. The browser will attach a shadow DOM tree to the node, appending
a [clone](https://developer.mozilla.org/docs/Web/API/Node/cloneNode) of the template contents to that shadow DOM.
Note that the elements upon which you can [`attachShadow()` are limited](https://developer.mozilla.org/docs/Web/API/Element/attachShadow#elements_you_can_attach_a_shadow_to).

```js
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(starRating.cloneNode(true));
```

If you take a look at the developer tools, you'll note the `<form>` from the `<template>` is part of the shadow root of each custom element.
A clone of the `<template>` contents is apparent in each custom element in the developer tools and visible in the browser, but the contents
of the custom element itself are not rendered to the screen.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/CqbHMMxnse6n8STAocFo.png", alt="DevTools screenshot showing the cloned template contents in each custom element.", width="800", height="842" %}

In the `<template>` example, we appended the template contents to the document body, adding the content to the regular DOM.
In the [`customElements` definition](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/define), we used the same
[`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild), but the cloned template contents were appended to an
encapsulated shadow DOM.

Notice how the stars went back to being unstyled radio buttons? Being part of a shadow DOM rather than the standard DOM, the styling within Codepen's CSS tab does not apply. That tab's CSS
styles are scoped to the document, not to the shadow DOM, so the styles aren't applied. We have to create encapsulated
styles to style our encapsulated Shadow DOM content.

## Shadow DOM

The Shadow DOM scopes CSS styles to each shadow tree, isolating it from the rest of the document. This means external CSS
doesn't apply to your component, and component styles have no effect on the rest of the document, unless we intentionally
direct them to.

Because we have appended the contents to a shadow DOM, we can include a [`<style>`](/learn/html/document-structure/#css) element
providing encapsulated CSS to the custom element.

{% Codepen {
user: 'web-dot-dev',
id: 'dyqbYme'
} %}

Being scoped to the custom element, we don't have to worry about styles seeping out to the rest of the document. We can
substantially reduce the specificity of the selectors. For example, as the only inputs used in the custom element are radio
buttons, we can use `input` instead of `input[type="radio"]` as a selector.

```html
 <template id="star-rating-template">
  <style>
    rating {
      display: inline-flex;
    }
    input {
      appearance: none;
      margin: 0;
      box-shadow: none;
    }
    input::after {
      content: '\2605'; /* solid star */
      font-size: 32px;
    }
    rating:hover input:invalid::after,
    rating:focus-within input:invalid::after {
      color: #888;
    }
    input:invalid::after,
      rating:hover input:hover ~ input:invalid::after,
      input:focus ~ input:invalid::after  {
      color: #ddd;
    }
    input:valid {
      color: orange;
    }
    input:checked ~ input:not(:checked)::after {
      color: #ccc;
      content: '\2606'; /* hollow star */
    }
  </style>
  <form>
    <fieldset>
      <slot name="star-rating-legend">
        <legend>Rate your experience:</legend>
      </slot>
      <rating>
        <input type="radio" name="rating" value="1" aria-label="1 star" required/>
        <input type="radio" name="rating" value="2" aria-label="2 stars"/>
        <input type="radio" name="rating" value="3" aria-label="3 stars"/>
        <input type="radio" name="rating" value="4" aria-label="4 stars"/>
        <input type="radio" name="rating" value="5" aria-label="5 stars"/>
      </rating>
    </fieldset>
    <button type="reset">Reset</button>
    <button type="submit">Submit</button>
  </form>
</template>
```

While web components are encapsulated with in-`<template>` markup and CSS styles are scoped to the shadow DOM and hidden
from everything outside of the components, the slot content which gets rendered, the `<anyElement slot="star-rating-legend">`
portion of the `<star-rating>`, is not encapsulated.

## Styling outside of the current scope

It is possible, but not simple, to style the document from within a shadow DOM and to style the contents of a shadow DOM from
the global styles. The shadow boundary, where the shadow DOM ends and the regular DOM begins, can be traversed, but only
very intentionally.

The _shadow tree_ is the DOM tree inside the shadow DOM. The shadow root is the root node of the shadow tree.

The [`:host`](https://developer.mozilla.org/docs/Web/CSS/:host) pseudo-class selects the `<star-rating>`, the shadow host element.
The _shadow host_ is the DOM node that the shadow DOM is attached to. To target only specific versions of the host, use [`:host()`](https://developer.mozilla.org/docs/Web/CSS/:host_function).
This will select only the shadow host elements that match the parameter passed, like a class or attribute selector. To select
all the custom elements, you can use `star-rating { /* styles */ }` in the global CSS, or `:host(:not(#nonExistantId))` in the template styles. In terms
of [specificity](https://developer.mozilla.org/docs/Web/CSS/Specificity), the global CSS wins.

The [`::slotted()`](https://developer.mozilla.org/docs/Web/CSS/::slotted) pseudo-element crosses the shadow DOM boundary
from within the shadow DOM. It selects a slotted element if it matches the selector. In our example, `::slotted(legend)` matches our three legends.

To target a shadow DOM from CSS in the global scope, the template needs to be edited. The [`part`](https://developer.mozilla.org/docs/Web/HTML/Global_attributes#part)
attribute can be added to any element that you want to style. Then use the [`::part()`](https://developer.mozilla.org/docs/Web/CSS/::part) pseudo-element
to match elements within a shadow tree that match the parameter passed. The anchor or originating element for the pseudo-element is
the host, or custom element name, in this case `star-rating`. The parameter is the value of the `part` attribute.

If our template markup began as such:

```html
<template id="star-rating-template">
  <form part="formPart">
    <fieldset part="fieldsetPart">
```

We could target the `<form>` and `<fieldset>` with:

```css
star-rating::part(formPart) { /* styles */ }
star-rating::part(fieldsetPart) { /* styles */ }
```

{% Codepen {
user: 'web-dot-dev',
id: 'abaovjL'
} %}

Part names act similarly to classes: an element can have multiple space-separated part names, and multiple elements can
have the same part name.

Google has a fantastic checklist for [creating custom elements](/custom-elements-best-practices/). You may also want to learn
about [declarative shadow DOMs](/declarative-shadow-dom/).

{% Assessment 'template' %}

# Text basics

Similar to how your text editor provides `<h1>` to `<h6>` headings, along with a plethora of ways to format sections of text
in meaningful and visual ways, HTML provides a very similar set of semantic and non-semantic elements to make meaning of prose.

This section covers the main ways of marking up text, or text basics. We will then discuss attributes, before exploring
additional ways of marking up text, such as lists, tables, and forms.

## Headings, revisited

There are six section heading elements, `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, and `<h6>`, with `<h1>` being most important
and `<h6>` the least. For many years, developers were told that headings were used by browsers to outline documents.
That was originally a goal, but browsers haven't implemented outlining features. However, screen reader users do use headings
as an exploration strategy to learn about the content of the page, navigating through headings with the `h` key. So ensuring
that heading levels are implemented as you would outline a document makes your content accessible and is still very much encouraged.

By default, browsers style `<h1>` the largest, `<h2>` slightly smaller, with each subsequent heading level being smaller
by default. Interestingly, browsers by default also decrement the `<h1>` font size based on how many `<article>`, `<aside>`, `<nav>`, or
`<section>` elements it is nested in.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ktRJF3DKyFHtfLifJXkn.png", alt="Nested H1 examples.", width="242", height="548" %}

Some user agent stylesheets include the following selectors, or similar, to style nested `<h1>` elements as if they were
of a less important level:

```css
h2, :is(article, aside, nav, section) h1 {}
h3, :is(article, aside, nav, section) :is(article, aside, nav, section) h1 {}
```
But the Accessibility Object Model, or AOM, still reports the level of the element correctly; in this case, "heading, level 1".
Note that the browser doesn't do this for other heading levels. That said, don't use heading level-based browser styling. Even though
browsers don't support outlining, pretend they do; mark up your content headings as if they do. That will make your content make sense to search engines, screen readers, and
future maintainers (which just might well be you).

Outside of headings, most structured text is made up of a series of paragraphs. In HTML, paragraphs are marked up with the
`<p>` tag; the closing tag is optional but always advised.

The #about section has a heading and a few paragraphs:

{% Codepen {
user: 'web-dot-dev',
id: 'jOKdjQm',
height: 300,
theme: dark,
tab: 'html,result'
} %}

This section is not a landmark as it doesn't have an accessible name. To turn this into a `region`, which is a landmark role, you can use `aria-labelledby` to provide the accessible name:

```html
<section id="about"  aria-labelledby="about_heading">
<h2 id="about_heading">What you'll learn</h2>
```
Only create landmarks if and when appropriate. Having too many landmarks can quickly become disorienting for screen reader users.

## Quotes and citations

When marking up an article or blog post, you may want to include a quote or pull-quote, with or without a visible citation.
There are elements for these three components: `<blockquote>`, `<q>`, and `<cite>` for a visible citation, or the `cite` attribute
to provide more information for search.

The `#feedback` section contains a header and three reviews; these reviews are blockquotes, some of which contain quotes,
followed by a paragraph containing the quote's citation. Omitting the third review to save space, the markup is:

{% Codepen {
user: 'web-dot-dev',
id: 'eYKxwbV',
height: 300,
theme: dark,
tab: 'html,result'
} %}

The information about the quote author, or citation, is not part of the quote and therefore not in the `<blockquote>`, but comes after the quote.
While these are citations in the lay sense of the term, they are not actually citing a specific resource, so are encapsulated in a `<p>` paragraph element.

The citation appears over three lines, including the author's name, previous role, and professional aspiration. The `<br>` line break
creates a line break in a block of text. It can be used in physical addresses, in poetry, and in signature blocks. Line
breaks should not be used as a carriage return to separate paragraphs. Instead, close the prior paragraph and open a new one. Using paragraphs
for paragraphs is not only good for accessibility but enables styling. The `<br>` element is just a line break; it is impacted by very few CSS properties.

While we provided citation information in a paragraph following each blockquote, the quotes  shown earlier are coded this way because they didn't
come from an external source. If they did, the source can (should?) be cited.

If the review was pulled from a review website, book, or other work, the `<cite>` element could be used for the title
of a source. The content of the `<cite>` can be the title of a book, the name of a website or TV show, or even the name of a
computer program. The `<cite>` encapsulation can be used whether the source is being mentioned in passing or if the source
is being quoted or referenced. The content of the `<cite>` is the work, not the author.

If the quote from Blendan Smooth was taken from her offline magazine, you would write the blockquote like this:

{% Codepen {
user: 'web-dot-dev',
id: 'LYrqKMq',
height: 300,
theme: dark,
tab: 'html,result'
} %}

The citation element `<cite>` has no implicit role and should get its accessible name from its contents; don't include an `aria-label`.

To provide credit where credit is due when you can't make the content visible, there is the `cite` attribute which takes as its value the URL of the source document or message for the information quoted. This attribute is valid on both `<q>` and `<blockquote>`. While it's a URL, it is machine readable but not visible to the reader:

{% Codepen {
user: 'web-dot-dev',
id: 'NWzoZob',
height: 300,
theme: dark,
tab: 'html,result'
} %}

While the `</p>` closing tag is optional (and always recommended), the `</blockquote>` closing tag is always required.

Most browsers add padding to both `<blockquote>` inline directions and italicize `<cite>` content; this can be controlled with CSS. The `<blockquote>` does not add quotation marks, but those can be added with CSS-generated content. The `<q>` element does add quotes by default, using language-appropriate quotation marks.

In the `#teachers` section, HAL is quoted as saying, "I'm sorry <NAME REDACTED, RIP>, but I'm afraid I can't do that, ." The code for that, in English and French, is:

{% Codepen {
user: 'web-dot-dev',
id: 'qBKgzgg',
height: 300,
theme: dark,
tab: 'html,result'
} %}

The inline quotation element, `<q>`, adds language-appropriate quotes. The user-agent default styles include open-quote and close-quote generated content:

```css
q::before {content: open-quote;}
q::after {content: close-quote;}
```

The `lang` attribute is included to let the browser know that, while base language of the page was defined as English in the `<html lang="en-US">` opening tag, this paragraph of text is in a different language. This helps voice controls such as Siri, Alexa, and voiceOver use French pronunciation. It also informs the browser what type of quotes to render.

Like `<blockquote>`, the `<q>` element supports the `cite` attribute.

{% Codepen {
user: 'web-dot-dev',
id: 'jOKdjJw',
height: 300,
theme: dark,
tab: 'html,result'
} %}

### HTML Entities

You may have noticed the escape sequence or "entity". Because the `<` is used in HTML, you have to escape it using either `&lt;` or a less easy-to-remember encoding `&#60;`. There are four reserved entities in HTML: `<`, `>`, `&`, and `"`. Their character references are `&lt;`, `&gt;`, `&amp;` and `&quot;` respectively.

A few other entities you will often use are `&copy;`  for copyright (©),` &trade;` for Trademark (™), and `&nbsp;` for non-breaking space.
Non-breaking spaces are useful when you want to include a space between two characters or words while preventing a line break from occurring there.
There are over 2,000 [named character references](https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references).
But, if needed, every single character, including emojis, has an encoded equivalent that starts with `&#`.

If you take a look at ToastyMcToastface's workshop review (not included in the code sample above), there are some unusual text characters:

```html
<blockquote>Learning with Hal and Eve exceeded all of my wildest fantasies. All they did was stick a USB in. They promised that it was a brand new USB, so we know there were no viruses on it. The Russians had nothing to do with it. This has no̶̼͖ţ̘h̝̰̩͈̗i̙̪n͏̩̙͍̱̫̜̟g̢̣ͅ ̗̰͓̲̞̀t͙̀o̟̖͖̹̕ ͓̼͎̝͖̭dó̪̠͕̜ ͍̱͎͚̯̟́w̮̲̹͕͈̟͞ìth̢ ̰̳̯̮͇</blockquote>
```

The last sentence in this blockquote can also be written as:

```html
This has no&#x336;&#x33C;&#x356;&tcedil;&#x318;h&#x31D;&#x330;&#x329;&#x348;&#x317;i&#x319;&#x32A;n&#x34F;&#x329;&#x319;
&#x34D;&#x331;&#x32B;&#x31C;&#x31F;g&#x322;&#x323;&#x345; &#x317;&#x330;&#x353;&#x332;&#x31E;&#x300;t&#x359;&#x300;o&#x31F;
&#x316;&#x356;&#x339;&#x315; &#x353;&#x33C;&#x34E;&#x31D;&#x356;&#x32D;d&oacute;&#x32A;&#x320;&#x355;&#x31C; &#x34D;&#x331;
&#x34E;&#x35A;&#x32F;&#x31F;&#x301;w&#x32E;&#x332;&#x339;&#x355;&#x348;&#x31F;&#x35E;&igrave;th&#x322; &#x330;&#x333;
&#x32F;&#x32E;&#x347;
```

There are a few unescaped characters and a few named character references in this code mess. Because the character set is UTF-8,
the last few characters in the blockquote don't actually need to be escaped, as in this example. Only characters not supported
by the character set need to be escaped. If needed, there are [many tools](https://mothereff.in/) to enable escaping various characters,
or you can just ensure you include [`<meta charset="UTF-8">`](/learn/html/document-structure/#character-encoding) in the `<head>`.

Even when you specify the character set as UTF-8, you still have to escape the `<` when you want to print that character to the screen.
Generally, you don't need to include the named character references for `>`, `"`, or `&`; but if you want to write a tutorial on HTML entities,
you do need to write `&lt;` when teaching someone how to code a `<`. 😀

Oh, and that smiley emoji is `&#x1F600;`, but this doc is declared as UTF-8, so it isn't escaped.

{% Assessment 'text-basics' %}

# Learn Images

This course is created for beginner and advanced web developers alike, covering everything from the basics of ensuring image sources are efficiently requested and rendered, to the details of how common image formats are communicated from server to client. Throughout this course you’ll learn how to achieve the smallest possible transfer sizes for your images without compromising on their quality—at least, not in a way anyone will be able to see.

You can go through the series from start to finish for a holistic understanding of how images work on the modern web, or use it as a reference for the specific concepts and markup patterns you’ll be using in your day-to-day work.

For those new to web development, check out the [Learn HTML](/learn/html/) courses for the basics of using markup, [Learn CSS](/learn/css/) courses for styling fundamentals, and [Learn Responsive Design](/learn/design/) courses for an understanding of how images will be rendered in responsive layouts.


Here's what you'll learn:

{% include 'partials/course-index.njk' %}

So, are you ready to learn Images?

{% Aside %}
Course written by [Mat Marquis](https://hire.wil.to), with input and review from [Rachel Andrew](/authors/rachelandrew/), [Jake Archibald](/authors/jakearchibald/), [Barry Pollard](/authors/tunetheweb/), [Aaron Forinton](https://github.com/aaronforinton), [Eric Portis](https://ericportis.com/), [Zach Leatherman](https://www.zachleat.com/), and [K.Adam White](https://www.kadamwhite.com/).
{% endAside %}

# Automating compression and encoding

All of the syntaxes in this course—from the encoding of image data to the information-dense
markup that powers [responsive images](/learn/images/responsive-images/)—are methods for machines to communicate with machines. You have
discovered a number of ways for a client browser to communicate its needs to a server, and a server to respond in kind.
Responsive image markup (`srcset` and `sizes`, in particular) manage to describe a shocking amount of information in relatively
few characters. For better or worse, that brevity is by design: making these syntaxes less terse, and so easier for developers
to parse, could have made them more difficult for a _browser_ to parse. The more complexity added to a string, the more
potential there is for parser errors, or unintentional differences in behavior from one browser to another.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/24qgm41BZl5a2gstQQfi.png", alt="An automated image encoding window.", width="800", height="472" %}

However, the same trait that can make these subjects feel so intimidating can also provide you with solutions: a syntax easily
_read_ by machines is a syntax more easily _written_ by them. You’ve almost certainly encountered many examples of automated
image encoding and compression as a user of the web: any image uploaded to the web through social media platforms, content
management systems (CMS), and even email clients will almost invariably pass through a system that resizes, re-encodes,
and compresses them.

Likewise, whether through plugins, external libraries, standalone build process tools, or responsible use of client-side scripting,
responsive image markup readily lends itself to automation.

Those are the two primary concerns around automating image performance: managing the creation of images—their encodings,
compression, and the alternate sources you’ll use to populate an `srcset` attribute—and generating our user-facing markup.
In this module, you’ll learn about a few common approaches to managing images as part of a modern workflow, whether as an
automated phase in your development process, through the framework or content management system that powers your site, or
almost fully abstracted away by a dedicated content delivery network.

## Automating compression and encoding

You’re unlikely to find yourself in a position where you can take the time to manually determine the ideal encoding and level
of compression for each individual image destined for use on a project—nor would you want to. As
[important as it is to keep your image transfer sizes as small as possible](/learn/images/performance-issues/) , fine-tuning your
compression settings and re-saving alternate sources for every image asset destined for a production website would introduce
a huge bottleneck in your daily work.

As you learned when reading about the various image formats and compression types, the most efficient encoding for an image will always be dictated by
its content, and as you learned in [Responsive Images](/learn/images/responsive-images/), the alternate sizes you’ll need for your image sources will be
dictated by the position those images occupy in the page layout. In a modern workflow, you’ll approach these decisions
holistically rather than individually—determining a set of sensible defaults for images, to best suit the contexts in which
they’re meant to be used.

When choosing encodings for a directory of photographic images, [AVIF](/learn/images/avif/) is the clear winner for quality and transfer size
but has limited support, [WebP](/learn/images/webp/) provides an optimized, modern fallback, and [JPEG](/learn/images/jpeg/) is the most reliable default. The alternate
sizes we need to produce for images meant to occupy a sidebar in a page layout will vary a great deal from images meant
to occupy the entire browser viewport at our highest breakpoints. Compression settings will require an eye toward blurring
and compression artifacts across multiple resulting files—leaving less room to carve every possible byte from each image
in exchange for a more flexible and reliable workflow. In sum, you’ll be following the same decision making process you’ve
come to understand from this course, writ large.

As for the processing itself, there are a huge number of open source image processing libraries that provide methods of
converting, modifying, and editing images in batches, competing on speed, efficiency, and reliability. These processing
libraries will allow you to apply encoding and compression settings to whole directories of images at once, without the
need to open image editing software, and in a way that preserves your original image sources should those settings need
to be adjusted on-the-fly. They’re intended to run in a range of contexts, from your local development environment to the
web server itself—for example, the compression-focused [ImageMin](/use-imagemin-to-compress-images/) for
Node.js can be extended to suit specific applications through an array of [plugins](https://www.npmjs.com/search?q=keywords:imageminplugin),
while the cross-platform [ImageMagick](https://imagemagick.org/) and the Node.js based [Sharp](https://sharp.pixelplumbing.com/)
come with a staggering number of features right out of the box.

These image processing libraries make it possible for developers to build tools dedicated to seamlessly optimizing images
as part of your standard development processes—ensuring that your project will always be referencing production-ready image
sources with as little overhead as possible.

## Local development tools and workflows

[Task-runners and bundlers like Grunt, Gulp, or Webpack](/use-imagemin-to-compress-images/) can be used to
optimize image assets alongside other common performance-related tasks, such as minification of CSS and JavaScript. To
illustrate, let’s take a relatively simple use case: a directory in your project contains a dozen photographic images,
meant to be used on a public-facing website.

First, you’ll need to ensure consistent, efficient encoding for these images. As you’ve learned in the previous modules,
WebP is an efficient default for photographic images in terms of both quality and file size. WebP is _well_ supported,
but not _universally_ supported, so you’ll also want to include a fallback in the form of a progressive JPEG. Then,
in order to make use of the `srcset` attribute for efficient delivery of these assets, you’ll need to produce multiple
alternate sizes for each encoding.

While this would be a repetitive and time-consuming chore if done with image editing software, task runners like
[Gulp](https://gulpjs.com/) are designed to automate exactly this sort of repetition. The [gulp-responsive](https://www.npmjs.com/package/gulp-responsive)
plugin, which makes use of [Sharp](https://www.npmjs.com/package/sharp), is one option of many that all follow a similar pattern:
collecting all the files in a source directory, re-encode them, and compress them based on the same standardized "quality"
shorthand you learned about in [Image Formats and Compression](/learn/images/png/). The resulting files are then output to a path you define,
ready to be referenced in the `src` attributes of your user-facing `img` elements while leaving your original files intact.

```javascript
const { src, dest } = require('gulp');
const respimg = require('gulp-responsive');

exports.webp = function() {
  return src('./src-img/*')
    .pipe(respimg({
      '*': [{
        quality: 70,
        format: ['webp', 'jpeg'],
        progressive: true
      }]
  }))
  .pipe(dest('./img/'));
}
```

With a process like this in place, no harm would be done to a production environment if someone on the project inadvertently
added a photograph encoded as a massive truecolor PNG to the directory containing your original image sources—regardless of
the original image’s encoding, this task will produce an efficient WebP and reliable progressive JPEG fallback, and at a
compression level that can be easily adjusted on-the-fly. Of course, this process also ensures that your original image
files will be retained within the project’s development environment, meaning that these settings can be adjusted at any
time with only the automated output overwritten.

In order to output multiple files, you pass along multiple configuration objects—all the same, apart from the addition of
a `width` key and a value in pixels:

```javascript
const { src, dest } = require('gulp');
const respimg = require('gulp-responsive');

exports.default = function() {
  return src('./src-img/*')
	.pipe(respimg({
  	'*': [{
          	width: 1000,
          	format: ['jpeg', 'webp'],
          	progressive: true,
          	rename: { suffix: '-1000' }
        	},
        	{
          	width: 800,
          	format: ['jpeg', 'webp'],
          	progressive: true,
          	rename: { suffix: '-800' }
        	},
        	{
          	width: 400,
          	format: ['jpeg', 'webp'],
          	progressive: true,
          	rename: { suffix: '-400' },
      	}]
    	})
	)
	.pipe(dest('./img/'));
}
```

In the case of the example above, the original image (monarch.png) was more than 3.3MB. The largest file generated by
this task (monarch-1000.jpeg) is approximately 150KB. The smallest, monarch-400.web, is only 32KB.

```shell
[10:30:54] Starting 'default'...
[10:30:54] gulp-responsive: monarch.png -> monarch-400.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-800.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-1000.jpeg
[10:30:54] gulp-responsive: monarch.png -> monarch-400.webp
[10:30:54] gulp-responsive: monarch.png -> monarch-800.webp
[10:30:54] gulp-responsive: monarch.png -> monarch-1000.webp
[10:30:54] gulp-responsive: Created 6 images (matched 1 of 1 image)
[10:30:54] Finished 'default' after 374 ms
```

Of course, you’ll want to carefully examine the results for visible compression artifacts, or possibly increase compression
for additional savings. Since this task is non-destructive, these settings can be changed easily.

All told, in exchange for the few kilobytes you could carve away with careful manual micro-optimization, you gain a process
that is not only efficient, but  _resilient_—a tool that seamlessly applies your knowledge of high-performance image assets
to an entire project, without any manual intervention.

### Responsive image markup in practice

Populating `srcset` attributes will typically be a straightforward manual process, as the attribute really only captures
information about the configuration you’ve already done when generating your sources. In the tasks above, we’ve established
the file names and width information that our attribute will follow:

```html
srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w"
```

Remember that the contents of the `srcset` attribute are descriptive, not prescriptive. There’s no harm in overloading an
`srcset` attribute, so long as the aspect ratio of every source is consistent. An `srcset` attribute can contain the URI
and width of every alternate cut generated by the server without causing any unnecessary requests, and the more candidate
sources we provide for a rendered image, the more efficiently the browser will be able to tailor requests.

As you learned in [Responsive Images](/learn/images/responsive-images/), you’ll want to make use of the `<picture>` element to seamlessly handle the WebP
or JPEG fallback pattern. In this case, you’ll be using the `type` attribute in concert with `srcset`.

```html
<picture>
  <source type="image/webp" srcset="filename-1000.webp 1000w, filename-800.webp 800w, filename-400.webp 400w">
  <img srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w" sizes="…" alt="…">
</picture>
```

As you’ve learned, browsers that support WebP will recognize the contents of the `type` attribute, and select that `<source>`
element’s `srcset` attribute as the list of image candidates. Browsers that don’t recognize `image/webp` as a valid media
type will ignore this `<source>`, and instead use the inner `<img>` element’s `srcset` attribute.

There’s one more consideration in terms of browser support: browsers without support for any responsive image markup will
still need a fallback, or we could run the risk of a broken image in especially old browsing contexts. Because `<picture>`,
`<source>`, and `srcset` are all ignored in these browsers, we’ll want to specify a default source in the inner `<img>`’s
`src` attribute.

Because scaling an image downwards is _visually_ seamless and JPEG encoding is universally supported, the largest JPEG is
a sensible choice.

```html
<picture>
  <source type="image/webp" srcset="filename-1000.webp 1000w, filename-800.webp 800w, filename-400.webp 400w">
  <img src="filename-1000.jpg" srcset="filename-1000.jpg 1000w, filename-800.jpg 800w, filename-400.jpg 400w" sizes="…" alt="…">
</picture>
```

`sizes` can be a little more difficult to deal with. As you've [learned](/learn/images/responsive-images), `sizes` is necessarily contextual—you
can’t populate the attribute without knowing the amount of space the image is meant to occupy in the rendered layout. For
the most efficient possible requests, an accurate `sizes` attribute needs to be in our markup at the time those requests
are made by the end user, long before the styles that govern the page layout have been requested. Omitting `sizes` altogether
is not only a violation of the HTML specification, but results in default behavior equivalent to `sizes="100vw"`—informing
the browser that this image is only constrained by the viewport itself, resulting in the largest possible candidates sources
being selected.

As is the case with any particularly burdensome web development task, a number of tools have been created to abstract away
the process of hand-writing `sizes` attributes. [`respImageLint`](https://ausi.github.io/respimagelint/) is an absolutely
essential snippet of code intended to vet your `sizes` attributes for accuracy and provide suggestions for improvement.
It runs as a bookmarklet—a tool you run in your browser, while pointed at the fully rendered page containing your image
elements. In a context where the browser has full understanding of the page layout, it will also have nearly pixel-perfect
awareness of the space an image is meant to occupy in that layout at every possible viewport size.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/Yr5VQ7rAATnPzHYyxcGF.png", alt="Responsive image report showing size/width mismatch.", width="800", height="861" %}

A tool for linting your `sizes` attributes is certainly useful, but it has even more value as a tool to generate them wholesale.
As you know, `srcset` and `sizes` syntax is intended to optimize requests for image assets in a visually seamless way. Though
not something that should ever be used in production, a default `sizes` placeholder value of `100vw` is perfectly reasonable
while working on a page’s layout in your local development environment. Once layout styles are in place, running `respImageLint`
will provide you with tailored `sizes` attributes that you can copy and paste into your markup, at a level of detail far greater
than one written by hand:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/fst6DoueH9kN4VEV6hU4.png", alt="Responsive image report with suggested dimensions.", width="800", height="861" %}

Though image requests initiated by server-rendered markup happen too quickly for JavaScript to generate a client-side `sizes` attribute,
the same reasoning doesn’t apply if those requests are _initiated_ client-side. The [Lazysizes](https://github.com/aFarkas/lazysizes) project,
for example, allows you to fully defer image requests until after the layout has been established, allowing JavaScript to generate
our `sizes` values for us—a huge convenience for you, and a guarantee of the most efficient possible requests for your users.
Keep in mind, however, that this approach does mean sacrificing the reliability of server-rendered markup and the speed
optimizations built into browsers, and initiating these requests only after the page has been rendered will have an outsized
negative impact on your LCP score.

Of course, if you’re already depending on a client-side rendering framework such as React or Vue, that’s a debt you’ll already
be incurring—and in those cases, using Lazysizes means your `sizes` attributes can be almost completely abstracted away.
Better still: as [`sizes="auto"`](https://github.com/whatwg/html/pull/8008) on lazy loaded images gains consensus and
native implementations, Lazysizes will effectively become a polyfill for that newly standardized browser behavior.

# Image formats: AVIF

AV1 Image File Format (AVIF) is an encoding based on the open source AV1 video codec. AVIF is [even newer](https://caniuse.com/avif)—than WebP,
only supported in Chrome and Opera since 2020, Firefox in 2021, and Safari in 2022. As with WebP, AVIF aims to address every conceivable use case for
raster images on the web: GIF-like animation, PNG-like transparency, and improved perceptual quality at file sizes smaller than JPEG or WebP.

So far, AVIF shows promise. A [testing framework](https://github.com/Netflix/image_compression_comparison) developed by Netflix—a founding member of
the [Alliance for Open Media](https://aomedia.org/), the group responsible for the development of the AV1 codec—shows
[significant reductions in file sizes](https://netflixtechblog.com/avif-for-next-generation-image-coding-b1d75675fe4) when
compared to JPEG or WebP. Additional studies by [Cloudinary](https://cloudinary.com/blog/contemplating-codec-comparisons) and
[Chrome's codecs team](https://storage.googleapis.com/avif-comparison/index.html) have weighed it favorably against current
encoding standards.

Though tooling is relatively limited, you can and should [start experimenting with AVIF](https://jakearchibald.com/2020/avif-has-landed/)
today, as one of the encodings offered by Squoosh:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/TkVWHUuKwH9qauQJDNpI.png", alt="A Squoosh screenshot showing AVIF compression settings.", width="800", height="547" %}

## Browser support

Now, if you find yourself wondering why we've spent so much time discussing JPEG when AVIF and WebP can offer us higher
quality results and far smaller file sizes, it's because they—and any new image encoding—come with a major catch. Support
for GIF, PNG, and JPEG is guaranteed across all browsers, and has been for decades. Relative to those legacy image formats,
AVIF is brand new, and while support for WebP is [excellent](https://caniuse.com/?search=webp) across modern browsers, it
isn't a given across the entire web.

As you can imagine, a tremendous amount of time and effort has gone into the development of new image formats that aim to
improve both quality and transfer size. Formats like WebP, AVIF, and [JPEG XL](https://jpeg.org/jpegxl/) ([not supported in any browser](https://caniuse.com/jpegxl))
aim to become the unifying solution to raster images on the web, as SVG is to vectors. Others, like JPEG 2000 (only supported in Safari)
were intended to satisfy all the same use cases as a baseline JPEG, but improve on compression methods to deliver a visually
similar but much smaller image.

While some of these newer formats share the JPEG name, their encodings are as fundamentally dissimilar as JavaScript is to Java.
A browser that doesn't support a given encoding won't be able to parse that image file at all—it's as though I instructed you to fill
out your graph paper pixel grid in a language you don't understand. The browser will request the image data, attempt to parse it, and
upon failing, will discard it without rendering anything at all. An image source that fails to render outside of modern browsers would be a
huge point of failure for our content, and for the web at large—a broken image and wasted bandwidth to a huge number of users around
the world. You shouldn't sacrifice a more resilient web for the sake of a more performant one.

For a long time, our single-minded friend `<img>` made it exceptionally difficult to use any new image format, no matter how promising
it seemed. Remember, `<img>` only supported a single source file, and was hyper-optimized to transfer that file quickly—so quickly,
in fact, that we couldn't intercept that request via JavaScript. Until recently, the only viable option was to serve all users the brand
new type of image, and request one of the “legacy" formats when the browser fired an error—incurring a second file transfer after the first one was wasted.

For that reason and more, `<img>` as it had existed for decades had to change. In the next module, [Responsive Images](/learn/images/responsive-images/), you'll learn about the
features introduced to the HTML specification to address these issues and how to use them in your day-to-day work.

# Image content delivery networks

You may already be familiar with the core concept of a content delivery network (CDN): a network of distributed but interconnected
servers that quickly and efficiently delivers assets to users. When a file is uploaded to a CDN provider, a duplicate will be created
on the other nodes of the CDN network around the world. When a user requests a file, the data will be sent by the node geographically
closest to that user, reducing latency. The distributed nature of CDNs also provides redundancy in the event of network outages or
hardware failure, and load balancing to mitigate spikes in traffic.

An [image CDN](/image-cdns/) can provide all these benefits, with one key difference: the ability to transform and
optimize the contents of an image based on strings the URL used to access it.

A user will upload a canonical, high-resolution image to the provider, which will generate a URL used to access it:

```html
https://res.cloudinary.com/demo/image/upload/sample.jpg
```

Though the exact syntax used will vary from one provider to another, at a minimum all image CDNs allow you to alter a source
image's dimensions, encoding, and compression settings. [Cloudinary](https://cloudinary.com/), for example,
performs [dynamic resizing](https://cloudinary.com/documentation/resizing_and_cropping#setting_the_resize_dimensions) of an
uploaded image through the following syntaxes: `h_` followed by the numerical height in pixels, `w_` followed by the width,
and a `c_` value that allows you to specify [detailed information about how the image should be scaled or cropped](https://cloudinary.com/documentation/resizing_and_cropping#crop).

Any number of transforms can be applied by adding comma-separated values to the URL, prior to the filename and extension,
meaning that the uploaded image can be manipulated as-needed through the `src` of the `img` element that requests it.

```html
<img src="https://res.cloudinary.com/demo/image/upload/w_400/sample.jpg" alt="…">
```

The first time a user visits the URL containing these transforms, a new version of the image proportionally scaled to a
width of 400px (`w_400`) is generated and sent. That newly-created file is then cached across the CDN so it can be sent
to any user requesting the same URL, rather than recreated on-demand.

Though not uncommon for image CDN providers to offer [software development kits](https://cloudinary.com/documentation/cloudinary_sdks)
to facilitate advanced usage and integration with various technology stacks, this predictable URL pattern alone allows us to easily
turn a single uploaded file into a viable `srcset` attribute without the need for any other development tooling:

```html
<img
  src="https://res.cloudinary.com/demo/image/upload/w_1000/sample.jpg 1000w"
  srcset="https://res.cloudinary.com/demo/image/upload/w_1000/sample.jpg 1000w,
      	https://res.cloudinary.com/demo/image/upload/w_800/sample.jpg 800w,
      	https://res.cloudinary.com/demo/image/upload/w_600/sample.jpg 600w"
  alt="…">
```

We're able to manually specify our desired level of compression using what should now be a familiar syntax: `q_`, short
for "quality," followed by the numerical shorthand for compression level:

```html
<img src="https://res.cloudinary.com/demo/image/upload/w_400,q_60/sample.jpg"  alt="…">
```

It's rare that you'll need to include this information manually, however, thanks to a set of incredibly powerful features
provided by most image CDNs: fully automatic compression, encoding, and content negotiation.


## Automated compression

The computing power image CDNs have at their disposal means they're able to offer an incredibly powerful feature: analyzing
the content of an image to algorithmically determine its ideal compression level and encoding settings, just as you or I would
manually fine-tune compression for each one of our images.

These algorithms automate the decisions you might make balancing file size and perceptual quality, analyzing image content for
measurable signs of degradation and fine-tuning compression settings accordingly. This frequently means huge reductions in file
size compared to the one-size-fits-all manual approach to compression settings.

As complex as this process might sound, implementation couldn't be much simpler: for Cloudinary, the addition of `q_auto` in an
image URL enables this feature:

```html
<img src="https://res.cloudinary.com/demo/image/upload/w_1400/sample.jpg" alt="…">
<!-- 250 KB-->

<img src="https://res.cloudinary.com/demo/image/upload/w_1400,q_auto/sample.jpg" alt="…">
<!-- 134 KB-->
```

## Automated encoding and content negotiation

Upon receiving a request for an image, image CDNs determine the most modern encoding the browser supports through the
[HTTP headers](https://developer.mozilla.org/docs/Web/HTTP/Headers) sent by the browser alongside requests for assets—specifically,
the `Accept` header. This header indicates the encodings that the browser is able to understand, using the same
[media types](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/MIME_types) we would use to populate the `type`
attribute of a `<picture>` element's `<source>`.

For example, adding the `f_auto` parameter to the list of image transforms in an asset URL explicitly tells Cloudinary to
deliver the most efficient encoding the browser is able to understand:

```html
<img src="https://res.cloudinary.com/demo/image/upload/w_1200,q_auto,f_auto/sample.jpg" alt="…">
```

The server then generates a version of the image with that encoding and caches the result for all subsequent users with the same
level of browser support.  That response includes a [`Content-Type` header](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Type)
to explicitly inform the browser of the file's encoding, regardless of the file extension. Even though a user with a modern browser will make a
request for a file ending in `.jpg`, that request will be accompanied by a header informing the server that AVIF is supported, and the server
will send an AVIF encoded file along with an explicit instruction to treat it as AVIF.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/JyJi8gXuacJB0L2puHbK.png", alt="CDN user interface.", width="800", height="649" %}

The net result is a process that not only absolves you of creating alternately encoded files and of manually fine-tuning your compression settings
(or maintaining a system that does these tasks for you), but does away with the need to use `<picture>` and the `type` attribute to effectively
deliver those files to users. So, using the `srcset` and `sizes` syntaxes alone can still provide your users with images encoded as—for example—AVIF,
falling back to WebP (or JPEG-2000, for Safari alone), falling back again to the most sensible legacy encoding.

The drawbacks of using an image CDN are more logistical than technical, chief among them being cost. While it is common for image CDNs to
offer feature-robust free plans for personal usage, generating image assets requires bandwidth and storage space for uploads, processing on
the server to transform images, and additional space for the cached transform results—so advanced usage and high-traffic applications may require a paid plan.

# Site Generators, frameworks, and CMSs

While certainly an improvement over manually saving alternate cuts of each image and hand-optimizing them through a tool like 
[Squoosh.app](https://squoosh.app/), automating image compression as a step in the development process has some limitations. For one, you may not 
always have full control over the images used throughout a site—most user-facing images on the web are _content_ concerns more 
than development concerns, uploaded by users or editors, rather than living in a repository alongside development assets like 
JavaScript and stylesheets.

This will typically necessitate more than one process for image management: a development-level task for the image assets used in 
building and maintaining a site—backgrounds, icons, logos, and so on—and another concerned with image assets generated through _use_
 of the site, such as photographs embedded in a post by an editorial team, or an avatar uploaded by a user. While the context may 
 differ, the end goals are the same: automated encoding and compression based on settings defined by the development team.

Fortunately, the image processing libraries you’ve come to understand from your local development workflows can be used in any number
 of contexts. And while there can never be a one-size-fits-all approach to your responsive image markup, these systems provide sensible
  defaults, configuration options, and API hooks to ease their implementation.

## Static Site Generators

Compared to task-runners, there’s some similarity in the way static site generators such as Jekyll or Eleventy approach images. Using 
these tools to produce a deployment-ready website requires management of assets, including CSS minification or transpiling and bundling 
of JavaScript. As you might imagine, this means these tools enable you to process image assets the same way, using many of the libraries 
you’ve already learned about.

The official [image plugin for Eleventy](https://www.11ty.dev/docs/plugins/image/) uses [Sharp](https://www.npmjs.com/package/sharp) to provide resizing, generation of multiple source sizes, re-encoding, and compression, just like some of the tasks you’ve learned about here.

Unlike a task-runner, a static site generator has direct insight into both the configuration and usage of those libraries,
 and the markup being generated for the production site—meaning it can do a great deal more to automate our responsive image 
 markup. For example, when [invoked as part of a shortcode for displaying images](https://www.aleksandrhovhannisyan.com/blog/eleventy-image-plugin/), this plugin will output HTML according 
 to the configuration options passed along to Sharp.

```javascript

const Image = require("@11ty/eleventy-img");
module.exports = function(eleventyConfig) {

async function imageShortcode(src, alt, sizes="100vw") {
  let metadata = await Image(src, {
  formats: ["avif", "webp", "jpeg"],
  widths: [1000, 800, 400],
  outputDir: "_dist/img/",
  filenameFormat: function( id, src, width, format, options ) {
      const ext = path.extname( src ),
        name = path.basename( src, ext );

      return `${name}-${width}.${format}`
  }
  });

  let imageAttributes = {
  alt,
  sizes,
  loading: "lazy"
  };

  return Image.generateHTML(metadata, imageAttributes);
}

eleventyConfig.addAsyncShortcode("respimg", imageShortcode);
};
```

This shortcode could then be used in place of the default image syntax:

```markdown
{‌% respimg "img/butterfly.jpg", "Alt attribute.", "(min-width: 30em) 800px, 80vw" %}
```

If configured to output multiple encodings, as above, the generated markup will be a `<picture>` element containing
 corresponding `<source>` elements, `type` attributes, and `srcset` attributes already fully populated with a list of 
  generated candidate sizes. 

```html
<picture><source type="image/avif" srcset="/img/butterfly-400.avif 400w, /img/butterfly-800.avif 800w, /img/butterfly-1000.avif 1000w" sizes="(min-width: 30em) 800px, 80vw"><source type="image/webp" srcset="/img/butterfly-400.webp 400w, /img/butterfly-800.webp 800w, /img/butterfly-1000.webp 1000w" sizes="(min-width: 30em) 800px, 80vw"><source type="image/jpeg" srcset="/img/butterfly-400.jpeg 400w, /img/butterfly-800.jpeg 800w, /img/butterfly-1000.jpeg 1000w" sizes="(min-width: 30em) 800px, 80vw"><img alt="Alt attribute." loading="lazy" src="/img/butterfly-400.jpeg" width="1000" height="846"></picture>
```

Of course, this plugin won’t be able to _generate_ a viable `sizes` attribute, as it can’t know the ultimate size and position 
of the image in the rendered layout, but it does accept one as input when generating your markup—another job for RespImageLint.

## Frameworks

Client-side rendering frameworks will require a task-runner or bundler like Webpack to edit, encode, and compress image assets 
themselves. [Responsive-loader](https://www.npmjs.com/package/responsive-loader), for example, also uses the Sharp library to re-save image assets. It then allows you to 
then `import` your images as objects:

```javascript
  import imageAVIF from 'img/butterfly.jpg?sizes[]=400,sizes[]=800,sizes[]=1000&format=avif';
  import imageWebP from 'img/butterfly.jpg?sizes[]=400,sizes[]=800,sizes[]=1000&format=webp';
  import imageDefault from 'img/butterfly.jpg?sizes[]=400,sizes[]=800,sizes[]=1000';
```

These imported images can then be used through abstractions like [React's Image component](https://reactnative.dev/docs/image), or to populate your responsive 
image markup directly:

```html
<picture>
  <source type='image/avif' srcSet={imageAVIF.srcSet} sizes='…' />
  <source type='image/webp' srcSet={imageWebp.srcSet} sizes='…' />
  <img
    src={imageDefault.src}
    srcSet={imageDefault.srcSet}
    width={imageDefault.width}
    height={imageDefault.height}
    sizes='…'
    loading="lazy"
  />
```

A framework that does client side rendering is a strong candidate for [Lazysizes](https://www.npmjs.com/package/lazysizes) and `sizes="auto"`—giving you almost fully
automated responsive images.

## Content Management Systems

WordPress was one of the earliest adopters of native responsive images markup, and the API has been gradually improved since
being [introduced in WordPress 4.4](https://make.wordpress.org/core/2015/11/10/responsive-images-in-wordpress-4-4/) with support for WebP and control over the output mime type. WordPress core is designed to make use of the [ImageMagick PHP extension](https://www.php.net/manual/en/book.imagick.php) 
(or, absent that, the [GD](https://www.php.net/manual/en/book.image.php) library). 

When an image is uploaded through the WordPress admin interface, that source image is used to generate user-facing files on
the server, in much the same way as you would on your local machine. By default, any image output by WordPress will come
with a generated `srcset` attribute based on [the image sizes configured in your theme](https://developer.wordpress.org/apis/responsive-images/).

Two key settings that can be configured for generated images are the [compression quality](https://developer.wordpress.org/reference/hooks/wp_editor_set_quality/) and the [output mime type](https://developer.wordpress.org/reference/hooks/image_editor_output_format/).

For example, to set the default compression quality to `70` for all generated images, use the following:

```php
add_filter( 'wp_editor_set_quality', function() { return 70; } );
```

For even better compression, switch the output format for uploaded JPEG images to WebP with the following:
```php
add_filter( 'image_editor_output_format', function( $mappings ) {
  $mappings[ 'image/jpeg' ] = 'image/webp';
	return $mappings;
} );
```

Given that WordPress has full understanding of all [alternate cuts](https://developer.wordpress.org/reference/functions/add_image_size/)
and encodings it generates from an uploaded image, it can provide helper functions like
[`wp_get_attachment_image_srcset()`](https://developer.wordpress.org/reference/functions/wp_get_attachment_image_srcset/) to
retrieve the full, generated `srcset` value of an image attachment.

As you'll likely have guessed by this point, working with the `sizes` attribute is a little more fraught. Absent any information
about how images will be used in a layout, WordPress currently defaults to a `sizes` value that effectively says "this image
should occupy 100% of the available viewport, up to the largest source's intrinsic size"—a predictable default, but not a correct
one for any real-world application. Be sure to make use of [`wp_calculate_image_sizes()`](https://developer.wordpress.org/reference/hooks/wp_calculate_image_sizes/)
to set contextually-appropriate `sizes` attributes in your templates.

Of course, there are countless WordPress plugins dedicated to making modern image workflows faster for development teams and users alike.
Perhaps most excitingly, plugins like [Jetpack's Site Accelerator](https://jetpack.com/support/site-accelerator/) (formerly "Photon")
can provide _server-side_ negotiation for encodings, ensuring that users will receive the smallest, most efficient encoding that their
browser is able to support without the need for `<picture>` and `type` markup pattern. It does this through use of an image content
delivery network—a technology you can make use of yourself, independent of your CMS.

All of this is also true of hosted CMS solutions like Shopify, though the mechanisms themselves will differ somewhat: offering similar
hooks for [generating alternate image sources and corresponding `srcset` attributes](https://performance.shopify.com/blogs/blog/responsive-images-on-shopify-with-liquid#provide-multiple-image-size-options-with-srcset)
and [art direction through the `<picture>` element](https://performance.shopify.com/blogs/blog/responsive-images-on-shopify-with-liquid#art-direction).

# Conclusion

Congratulations, you've made it to the end! By now you’ve learned a lot about how images work on the web, and the part that they—and you—can play in building a faster, more efficient experience for users everywhere.

## Additional resources

* [HTTP Archive’s annual state of the web report](https://almanac.httparchive.org/en/2022/)
* [web.dev - Lazy loading images](/lazy-loading-images/)
* [web.dev - Learn Accessibility: Images](/learn/accessibility/images/)
* [MDN - SVG](https://developer.mozilla.org/docs/Web/SVG)
* [MDN - Image file type and format guide](https://developer.mozilla.org/docs/Web/Media/Formats/Image_types)
* [MDN - Responsive Images](https://developer.mozilla.org/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)

# Descriptive syntaxes

In this module, you'll learn how to give the browser a choice of images so that it can make the best decisions about what to display. `srcset`
isn't a method for swapping image sources at specific breakpoints, and it isn't meant to swap one image for another. These syntaxes allow the
browser to solve a very difficult problem, independent of us: seamlessly requesting and rendering an image source tailored to a user's browsing context,
including viewport size, display density, user preferences, bandwidth, and countless other factors.

It's a big ask—certainly more than we want to consider when we're simply marking up an image for the web, and doing it well involves more
information than we can access.

## Describing density with `x`

An `<img>` with a fixed width will occupy the same amount of the viewport in any browsing context, regardless of the _density_ of a user's
display—the number of physical pixels that make their screen. For example, an image with an inherent width of `400px` will occupy almost
the entire browser viewport on both the original Google Pixel and much newer Pixel 6 Pro—both devices have a normalized `412px`
[logical pixel](https://developer.mozilla.org/docs/Glossary/CSS_pixel) wide viewport.

The Pixel 6 Pro has a much _sharper_ display, however: the 6 Pro has a _physical_ resolution of 1440 × 3120 pixels, while the
Pixel is 1080 × 1920 pixels—that is, the number of hardware pixels that make up the screen itself.

The ratio between a device's logical pixels and physical pixels is the _device pixel ratio_ for that display (DPR). DPR is
calculated by dividing the device's actual screen resolution by a viewport's CSS pixels.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/2YTBM6TXRoEE2Q3XbFhX.png", alt="A DPR of 2 displayed in a console window.", width="800", height="277" %}

So, the original Pixel has a DPR of 2.6, while the Pixel 6 Pro has a DPR of 3.5.

The iPhone 4, the first device with a DPR greater than 1, reports a device pixel ratio of 2—the physical resolution of the screen is
double the logical resolution. Any device prior to the iPhone 4 had a DPR of 1: one logical pixel to one physical pixel.

If you view that `400px`-wide image on a display with a DPR of `2`, each logical pixel is being rendered across four of the
display's physical pixels: two horizontal and two vertical. The image doesn't benefit from the high-density display—it will look the
same as it would on a display with a DPR of `1`. Of course, anything "drawn" by the browser's rendering engine—text, CSS shapes, or SVGs,
for example—will be drawn to suit the higher-density display. But as you learned from [Image Formats and Compression](/learn/images/raster-images/), raster images are fixed
grids of pixels. While it may not always be glaringly obvious, a raster image upscaled to suit a higher-density display will look
low-resolution compared to the surrounding page.

In order to prevent this upscaling, the image being rendered has to have an intrinsic width of at least `800` pixels. When scaled down
to fit a space in a layout 400 logical pixels wide, that 800-pixel image source has double the pixel density—on a display with a DPR of `2`,
it'll look nice and sharp.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/IoJjwpreGIT7LwRThaWn.png", alt="Close up of a flower petal showing disparity in density.", width="800", height="417" %}

{% Codepen {
user: 'web-dot-dev',
id: 'QWBGVyo',
height: 300,
theme: dark,
tab: 'html,css,result'
} %}

Since a display with a DPR of `1` can't make use of the increased density of an image, it will be _downscaled_ to match the
display—and as you know, a _downscaled_ image will look just fine. On a low-density display, an image suitable for higher-density
displays will look like any other low-density image.

As you learned in [Images and Performance](/learn/images/performance-issues/), a user with a low-density display viewing an image source scaled down to `400px`
will only _need_ a source with an inherent width of `400px`. While a much larger image would work for all users visually, a huge,
high resolution image source rendered on a small, low density display will _look_ like any other small, low density image, but _feel_ far slower.

As you might guess, _mobile_ devices with a DPR of 1 are [vanishingly rare](https://jakearchibald.com/2021/serving-sharp-images-to-high-density-screens/),
though it is still [common in "desktop" browsing contexts](https://twitter.com/TimVereecke/status/1587878439729725442). According to data
shared by [Matt Hobbs](https://nooshu.com), approximately 18% of  [GOV.UK](https://www.gov.uk/) browsing sessions from November 2022 report a DPR of 1. While high-density images would _look_ the way those users might expect, they'll come at a much higher bandwidth and processing cost—of
particular concern to users on the older and less powerful devices still likely to have low-density displays.

Using `srcset` ensures that only devices with high-resolution displays receive image sources large enough to look sharp, without passing that same
bandwidth cost along to users with lower-resolution displays.

The `srcset` attribute identifies one or more comma-separated _candidates_ for rendering an image. Each candidate is made up of
two things: a URL, just like you would use in `src`, and a syntax that _describes_ that image source. Each candidate in `srcset`
is described by its inherent _width_ ("`w` syntax") or intended _density_ ("`x` syntax").

The `x` syntax is a shorthand for "this source is appropriate for a display with this density"—a candidate followed by `2x` is
appropriate for a display with a DPR of 2.

```html
<img src="low-density.jpg" srcset="double-density.jpg 2x" alt="...">
```

Browsers that support `srcset` will be presented with two candidates: `double-density.jpg`, which `2x` describes as appropriate
for displays with a DPR of 2, and `low-density.jpg` in the `src` attribute—the candidate selected if nothing more appropriate is
found in `srcset`. For browsers without support for `srcset`, the attribute and its contents will be ignored—the contents of `src`
will be requested, as usual.

It's easy to mistake the  values specified in the `srcset` attribute for instructions. That `2x` informs the browser that the
associated source file would be suitable for use on a display with a DPR of 2—information about the source itself. It doesn't tell
the browser how to use that source, just informs the browser how the source could be used. It's a subtle but important distinction: this
is a double density _image_, not an image for use on a double density _display_.

The difference between a syntax that says "this source is appropriate for `2x` displays" and one that says "use this source on `2x` displays"
is slight in print, but display density is only one of a huge number of interlinked factors that the browser uses to decide on the candidate
to render, only some of which you can know. For example: individually, it's possible for you to determine that a user has enabled a
bandwidth-saving browser preference through the `prefers-reduced-data` media query, and use that to always opt users into low-density images
regardless of their display density—but unless implemented consistently, by every developer, on every website, it wouldn't be of much use to a user.
They might have their preference respected on one site, and run into a bandwidth-obliterating wall of images on the next.

The deliberately vague resource selection algorithm used by `srcset`/`sizes` leaves room for browsers to decide to select lower density
images with bandwidth dips, or based on a preference to minimize data usage, without us taking on responsibility for how, or when, or at
what threshold. There's no sense in taking on responsibilities—and additional work—that the browser is better equipped to handle for you.

## Describing widths with `w`

`srcset` accepts a second type of descriptor for image source candidates. It's a far more powerful one—and for our purposes, a
great deal easier to understand. Rather than flagging a candidate as having the appropriate dimensions for a given display density,
the `w` syntax describes the inherent width of each candidate source. Again, each candidate is identical save for their dimensions—the same
content, the same cropping, and the same aspect ratio. But in this case, you want the user's browser to choose between two candidates:
small.jpg, a source with an inherent width of 600px, and large.jpg, a source with an inherent width of 1200px.

```html
srcset="small.jpg 600w, large.jpg 1200w"
```

This doesn't tell the browser what to _do_ with this information—just supplies it with a list of candidates for displaying the image.
Before the browser can make a decision about which source to render, you need to provide it with a little more information: a
description of how the image will be rendered on the page. To do that, use the `sizes` attribute.

## Describing usage with `sizes`

Browsers are incredibly performant when it comes to transferring images. Requests for image assets will be initiated long
before requests for stylesheets or JavaScript—oftentimes even before the markup has been fully parsed. When the browser
makes these requests, it has no information about the page itself, apart from the markup—it may not have even initiated requests
for external stylesheets yet, let alone applied them. At the time the browser parses your markup and starts making external
requests, it only has browser-level information: the size of the user's viewport, the pixel density of the user's display,
user preferences, and so on.

This doesn't tell us anything about how an image is intended to be rendered in the page layout—it can't even use the viewport
as a proxy for the upper bound of the `img` size, as it may occupy a horizontally scrolling container. So we need to
provide the browser with this information and do it using markup. That is all we'll be able to use for these requests.

Like `srcset`, `sizes` is intended to make information about an image available as soon as the markup is parsed. Just as the `srcset`
attribute is shorthand for "here are the source files and their inherent sizes," the `sizes` attribute is shorthand for "here
is the size of the rendered image _in the layout_." The way you describe the image is relative to the viewport—again, viewport
size is the only layout information the browser has when the image request is made.

That may sound a little convoluted in print, but it's far easier to understand in practice:

```html
<img
 sizes="80vw"
 srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
 src="fallback.jpg"
 alt="...">
```

Here, this `sizes` value informs the browser that the space in our layout that the `img` occupies has a width of `80vw`—80% of
the viewport. Remember, this isn't an _instruction_, but a description of the image's size in the page layout. It doesn't say "make this
image occupy 80% of the viewport," but "this image will end up occupying 80% of the viewport once the page has rendered."

{% Codepen {
user: 'web-dot-dev',
id: 'PoBWLYP',
height: 500,
theme: dark,
tab: 'html,result'
} %}

As a developer, your job is done. You've accurately described a list of candidate sources in `srcset` and the width of your image
in `sizes`, and, just as with the `x` syntax in `srcset`, the rest is up to the browser.

But in the interest of fully understanding how this information is used, let's take a moment to walk through the decisions that
a user's browser makes upon encountering this markup:

You've informed the browser that this image will take up 80% of the available viewport—so, if we were to render this `img` on a
device with a 1000-pixel-wide viewport, this image will occupy 800 pixels. The browser will then take that value and divide against
it the widths of each of the image source candidates we specified in `srcset`. The smallest source has an inherent size of 600 pixels,
so: 600÷800=.75. Our medium image is 1200 pixels wide: 1200÷800=1.5. Our largest image is 2000 pixels wide: 2000÷800=2.5.

The results of those calculations (`.75`, `1.5`, and `2.5`) are, effectively, DPR options _specifically tailored to the user's
viewport size_. Since the browser also has information on the user's display density at hand, it makes a series of decisions:

At this viewport size, the `small.jpg` candidate is discarded regardless of the user's display density—with a calculated DPR lower
than `1`, this source would require upscaling for any user, so it isn't appropriate. On a device with a DPR of `1`, `medium.jpg` provides the
closest match—that source is appropriate for display at a DPR of `1.5`, so it is a little larger than necessary, but remember that downscaling is
a visually seamless process. On a device with a DPR of 2,`large.jpg` is the closest match, so it gets selected.

If the same image is rendered on a 600 pixel wide viewport, the result of all that math would be completely different: 80vw is now 480px.
When we divide our sources' widths against that, we get `1.25`, `2.5`, and `4.1666666667`. At this viewport size, `small.jpg` will be chosen
on 1x devices, and `medium.jpg` will match on 2x devices.

This image will look identical in all of these browsing contexts: all our source files are exactly the same apart from their dimensions,
and each one is being rendered as sharply as the user's display density will allow. However, instead of serving `large.jpg` to every user
in order to accommodate the largest viewports and the highest density displays, users will always be served the smallest suitable candidate.
By using a descriptive syntax rather than a prescriptive one, you don't need to manually set breakpoints and consider future viewports and
DPRs—you simply supply the browser with information and allow it to determine the answers for you.

Because our `sizes` value is relative to the viewport and completely independent of the page layout, it adds a layer of complication.
It's rare to have an image that _only_ occupies a percentage of the viewport, without any fixed-width margins, padding, or influence
from other elements on the page. You'll frequently need to express the width of an image using a combination of units; percentages, `em`, `px`, and so on.

Fortunately, you can use `calc()` here—any browser with native support for responsive images will support `calc()` as well, allowing us to
mix-and-match CSS units—for example, an image that occupies the full width of the user's viewport, minus a `1em` margin on either side:

```html
<img
	sizes="calc(100vw-2em)"
	srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1600w, x-large.jpg 2400w"
	src="fallback.jpg"
	alt="...">
```

## Describing breakpoints

If you've spent much time working with responsive layouts, you've likely noticed something missing from these examples:
the space an image occupies in a layout is very likely to change across our layout's breakpoints. In that case, you need
to pass a little more detail along to the browser: `sizes` accepts a comma-separated set of candidates for the rendered size of the
image, just like `srcset` accepts comma-separated candidates for image sources. Those conditions use the familiar media query syntax.
This syntax is first-match: as soon as a media condition matches, the browser stops parsing the `sizes` attribute, and the value
specified is applied.

Say you have an image meant to occupy 80% of the viewport, minus one `em` of padding on either side, on viewports above 1200px—on
smaller viewports, it occupies the full width of the viewport.

```html
  <img
     sizes="(min-width: 1200px) calc(80vw - 2em), 100vw"
     srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
     src="fallback.jpg"
     alt="...">
```
{% Codepen {
user: 'web-dot-dev',
id: 'RwBoYRx',
height: 500,
theme: dark,
tab: 'html,result'
} %}

If the user's viewport is greater than 1200px, `calc(80vw - 2em)` describes the width of the image in our layout. If the
`(min-width: 1200px)` condition _doesn't_ match, the browser moves on to the next value. Because there isn't a specific
media condition tied to this value, `100vw` is used as a  default. If you were to write this `sizes` attribute using
`max-width` media queries:

```html
  <img
     sizes="(max-width: 1200px) 100vw, calc(80vw - 2em)"
     srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
     src="fallback.jpg"
     alt="...">
```
{% Codepen {
user: 'web-dot-dev',
id: 'BaPQOzO',
height: 500,
theme: dark,
tab: 'html,result'
} %}

In plain language: "does `(max-width: 1200px)` match? If not, move on. The next value—`calc(80vw - 2em)`—has no qualifying condition,
so this is the one selected.

Now that you've provided the browser with all this information about your `img` element—potential sources,  inherent widths,
and how you intend to present the image to the user—the browser uses a fuzzy set of rules for determining what to do with
that information. If that sounds vague, well, that's because it is—by design. The source-selection algorithm encoded in the
HTML specification is _explicitly_ vague on how a source should be chosen. Once the sources, their descriptors, and how
the image will be rendered has all been parsed, the browser is free to do whatever it wants—you _can't_ know for certain which
source the browser will choose.

A syntax that says "use this source on a high-resolution display" would be predictable, but it wouldn't address the core problem
with images in a responsive layout: conserving user bandwidth. A screen's pixel density is only tangentially related to internet
connection speed, if at all. If you are using a top-of-the-line laptop, but browsing the web by way of a metered connection, tethered
to your phone, or using a shaky airplane wifi connection—you might want to opt out of high-resolution image sources, regardless of
the quality of your display.

Leaving the final say to the browser allows for far more performance improvements than we could manage with a strictly prescriptive
syntax. For example: in most browsers, an `img` using the `srcset` or `sizes` syntax will never bother requesting a source with smaller
dimensions than one that the user already has in their browser's cache. What would be the point in making a new request for a source
that would look identical, when the browser can seamlessly downscale the image source it already has? But if the user scales their
viewport up to the point where a new image is needed in order to avoid upscaling, _that_ request will still get made, so everything
looks the way you expect.

That lack of explicit control can sound a little scary at face value, but because you're using source files with identical
content, we're no more likely to present users with a "broken" experience than we would with a single-source `src`, regardless of
the decisions made by the browser.

## Using `sizes` and `srcset`

This is a lot of information—both for you, the reader, and for the browser. `srcset` and `sizes` are both dense syntaxes,
describing a shocking amount of information in relatively few characters. That is, for better or worse, by design: making
these syntaxes less terse—and more easily parsed by us humans—could have made them more difficult for a _browser_ to parse. The
more complexity added to a string, the more potential there is for parser errors or unintentional differences in behavior
from one browser to another. There's an upside here, however: a syntax more easily read by machines is a syntax more easily written
by them.

`srcset` is a clear-cut case for automation. It's rare that you'll be hand-crafting multiple versions of your images for a
production environment, instead automating the process using a task runner like Gulp, a bundler like Webpack, a third-party
CDN like Cloudinary, or functionality already built into your CMS of choice. Given enough information to generate our sources
in the first place, a system would have enough information to write them into a viable `srcset` attribute.

`sizes` is a little more difficult to automate. As you know, the only way a system can calculate the size of an image in a
rendered layout is to have _rendered_ the layout. Fortunately, a number of developer tools have popped up to abstract away
the process of hand-writing `sizes` attributes—with an efficiency you could never match by hand.
[respImageLint](https://github.com/ausi/respimagelint), for example, is a snippet of code intended to vet your `sizes` attributes
for accuracy and provide suggestions for improvement. The [Lazysizes](https://github.com/aFarkas/lazysizes) project compromises
some speed for efficiency by deferring image requests until after the layout has been established, allowing JavaScript to
generate  `sizes` values for you. If you're using a fully client-side rendering framework such as React or Vue, there are a
number of solutions for authoring and/or generating `srcset` and `sizes` attributes, which we'll discuss further in [CMS and Frameworks](cms).

# Image formats: GIF

While not terribly useful on the modern web, GIF (Graphics Interchange Format) provides a solid introduction to the core
concepts of image encoding.

GIF can be thought of as a wrapper for image data. It has a viewport, of sorts, called a "logical screen," to which individual
frames of image data are drawn—a bit like layers in a Photoshop document. That's how GIF supports its flipbook-like animation:
a single frame is drawn to the logical screen, then replaced by another, then another. Of course, this distinction isn't important
when we're dealing with a static GIF, made up of a single frame drawn to the logical screen.

GIF uses a lossless data compression method—a variant of the "[Lempel–Ziv–Welch](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch)"
algorithm, if you're curious. The finer details of how this algorithm works are more than we need to get into here, but at a high level: it
works a bit like "Uglifying" JavaScript, where repeated strings of characters throughout the file are saved to a sort of internal dictionary,
so they can be referenced rather than repeated every time they appear.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/AWgIX677XevD9J0ZUBo3.png", alt="Visualization of the gif reference using a four-by-four grid.", width="800", height="873" %}

Granted, the [algorithm isn't quite as simple](https://giflib.sourceforge.net/whatsinagif/lzw_image_data.html) as a paint-by-number. It steps
again through the generated table of color codes to find repeated sequences of pixel colors and creates a second table of referencable codes. At no
point is any image data lost, however—just sorted and reorganized in a way that can be read without fundamentally changing it.

While GIF technically uses lossless _compression_, it does have a major limitation that severely impacts the quality of the images:
saving an image as a GIF will always result in reduced fidelity, unless the image already uses 256 colors or less.

Each frame drawn to the GIF's logical screen can only contain a maximum of 256 colors. GIF also supports “index transparency,” where a
transparent pixel will reference the index of a transparent “color” in the color table.

The practice of reducing a range of values to a smaller, approximated set of output values is called _quantization_, a term you'll be seeing a lot
when learning about image encodings. The results of this palette quantization are usually obvious:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/PjWX2BD4QXqj3efvX7MP.png", alt="Static gif example", width="393", height="399" %}

To better understand this process, think back to the raster image grid you were able to recreate from my description.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/pwUWoFFo7MVq58e05NnK.png", alt="Three horizontal blue boxes followed by one red box", width="652", height="204" %}

This time around, add a little more detail to that original image: a few more pixels, one of which is a slightly darker shade of blue:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/m9BkyRb7yy1zLBlvlHka.png", alt="Blue to red horizontal boxes in a two-by-four configuration, with one blue box shaded darker than the others.", width="752", height="400" %}

Absent any compression—so to speak—you could describe this grid as:

> Row one, column one is #0000FF. Row one, column two is #0000FF. Row one, column three is #0000FF. Row one, column four is #FF0000. Row two, column one is #0000FF. Row two, column two is #000085. Row two, column three is #0000FF. Row two, column four is #FF0000.

Using something akin to GIF's lossless data compression and color indexing, you might describe it as:

> A: #0000FF, B: #FF0000, C: #000085. Row one, columns one through three are A. Row one, column four is B. Row two, column one is A. Row two, column two is C. Row two, column three is A. Row two, column four is B.

This manages to condense the pixel-by-pixel description in a few places (“columns one through three are…”), and saves a
few characters by defining the repeated colors in a dictionary, of sorts, up front. There's no change to the visual fidelity.
The information has been compressed without any loss.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/nNmCqD5iYi1QEEbDeL4M.png", alt="Blue to red horizontal boxes, with a single dark pixel at 2x2.", width="752", height="400" %}

As you can see, however, the single dark blue pixel is having an outsized impact on the size of our encoding. If I were to
limit myself to a quantized color palette, it could be reduced much further:

> A: #0000FF, B: #FF0000. Row one, columns one through three are A. Row one, column four is B. Row two, columns one through three are A. Row two, column four is B.

The unfortunate end result of those saved bytes is that you've lost pixel-perfection.

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/YhCa9QIzzkZsyw4zyUzu.png", alt="Uniformly blue to red horizontal boxes.", width="800", height="421" %}

Of course, you, the rendering engine, don't know that—the detail of the darker blue pixel was left out of how I encoded my source image.
You've rendered the image exactly as I've encoded it, based on our shared understanding of the colors we have at hand.

Now, in this exaggerated example, reducing three colors to two makes for an obvious difference in quality. Across a larger and
more detailed image the effects might not be quite as noticeable, but they would still be visible.

When encoded as a GIF, subtle gradients like shadows become mottled, with individual pixels standing out from their surroundings:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ncTFXA6KsRGAK7Rdvyoi.png", alt="Pink flowers on a green background.", width="800", height="595" %}

In practice, the combination of lossless compression and palette quantization means that GIF isn't very useful in modern
web development. Lossless compression doesn't do enough to reduce file sizes, and a reduced palette means an obvious reduction in quality.

Ultimately, GIF is only an efficient format for encoding simple images that already use limited color palettes, hard edges
rather than anti-aliasing, and solid colors rather than gradients—all use cases that are far better served by other formats.
The smaller and more featured PNG is often a better choice for raster images, though both are far inferior to SVG in terms of file
size and visual fidelity for use cases like icons or line art, where vector shines. The most commonly seen modern use case for GIF is
animation, but there are far more efficient—and accessible—modern video formats to serve that purpose.

# A brief history of images on the web

No matter how far along you are in learning to design and develop for the web, the `<img>` element needs very little introduction.
[Launched in Netscape (“Mosaic,” at the time) in 1993](https://www.wired.com/2010/04/0422mosaic-web-browser/) and added to the HTML
specification in 1995, `<img>` has long played a simple but powerful role within the web platform. The developer adds a "source" image
file with the `src` attribute and provides a text alternative with the `alt` attribute in the event that the image cannot be rendered or
assistive technologies request an alternative. From there, the browser has only one job: get the image data, then render it as quickly as possible.

{% Codepen {
user: 'web-dot-dev',
id: 'jOpVPJa',
height: 300,
theme: dark,
tab: 'html,result'
} %}

For most of web development history, working with images didn't get much more complicated than that. And, despite the modern
web's complexity, the fundamentals of working with images haven't changed: use a web-friendly image format for compatibility,
sensible compression to conserve bandwidth, and dimensions that suit the space the image is going to occupy in the page's layout.

Using fixed-width layouts, like we did back when we thought we had more say in how users experienced the web,
made this an uncomplicated process. It was particularly easy to set the size of the image source. For an image that occupied a space five
hundred pixels wide and three hundred pixels tall, it was a case of specifying a source image at that same size.

## Images in a responsive layout

Alongside a flexible layout and use of CSS media queries, "flexible images and media" are one of the three defining facets
of [responsive web design](/learn/design/). To make an image flexible, developers began using CSS to set `max-width: 100%` on the image
(or all images, site-wide) to tell the browser's rendering engine to prevent an image from ever overflowing its parent container by
scaling it down. Visually, this works perfectly–downscaling a [raster image](/learn/images/raster-images/) is visually seamless. With a line or two of CSS,
a scaled-down image will always look as though we've specified an image source that was meant to be displayed at that size.
When rendering engines are given more image data than necessary for the space the image occupies in a layout, they are able
to make informed decisions about how to render the reduced image, and can do so without introducing any visual artifacts or blurring.

{% Codepen {
user: 'web-dot-dev',
id: 'YzjpXBP',
height: 500,
theme: dark,
tab: 'result'
} %}

You wouldn't typically want to _upscale_ an image—that is, render the `<img>` at a size larger than the intrinsic size of the source image.
The displayed image would appear blurry and grainy-looking.

{% Codepen {
user: 'web-dot-dev',
id: 'XWBNbOx',
height: 500,
theme: dark,
tab: 'result'
} %}

Using `img { max-width: 100% }` means that as a flexible container resizes, images will be downscaled as appropriate.
Unlike setting a more rigid `width: 100%`, this also ensures that the image won't be scaled up beyond its intrinsic size.
For a long time, that was it for the rules of working with images: use a format browsers understand, use a sensible level of
compression, and never scale images upwards.

{% Codepen {
user: 'web-dot-dev',
id: 'gOjLpEM',
height: 500,
theme: dark,
tab: 'css,result'
} %}

But as simple and effective as this approach was visually, it came at a huge performance cost. As `<img>` only supported a
single source for the image data, this approach required us to provide an image asset with an intrinsic size as large as
the largest size at which it could be displayed. An image meant to occupy a space in a layout that could be anywhere
from `300px` to `2000px` wide, depending on the user's viewport size, required an image source with an intrinsic width of
at least `2000px`. For a user who only views the page by way of a small viewport, everything would look as expected—the
image would scale just fine. In the rendered page, a massive but scaled-down source image would _look_ no different from an
appropriately-sized one. However, they would still be transferring and rendering a `2000px` wide image, burning through a huge
amount of bandwidth and processing power with no tangible benefit.

Things got much worse with the advent of the first "Retina" devices, as display _density_ became a concern alongside viewport
size. An image source needs a much larger intrinsic width in order to suit a high density display. In simple terms, a display with
double the density requires twice as many image pixels to render the image as sharply as possible.

Here, developers were again able to rely on rendering engines' ability to downscale images visually. By providing the browser with
an `800px` wide source image in `src`, then specifying that it should be displayed at `400px` wide with CSS, the result is an image
rendered at double the pixel density:

{% Codepen {
user: 'web-dot-dev',
id: 'QWBKrjX',
height: 700,
theme: dark,
tab: 'css,result'
} %}

A single source image, cut to suit the largest possible space in your layout and high-density displays, works for all users _visually_,
of course. A huge, high resolution image source rendered on a small, low density display will look like any other small, low density image,
but feel far slower. The user will be left bearing all the performance costs of that massive, 4000px-wide image source, to no benefit.

For a long time, `<img>` largely did one thing— it "got image data and put it on the screen." It did that reasonably well, for certain,
but `<img>` wasn't up to the task of accommodating the radical shifts in browsing context we were experiencing. While responsive web design
became a mainstream development practice, browsers optimized the performance of `img` for nearly twenty years—but for all but the most privileged
users, the image _content_ of pages was inefficient from the outset. No matter how quickly the browser managed to request, parse, and render
an image source, that asset would likely be far bigger than the user needed.

# Image formats: JPEG

JPEG is the most common type of image used on the web, and with good reason: for decades, JPEG has almost invariably been the right choice for
encoding photographs. The use case is right there in the name: JPEG stands for "Joint Photographic Experts Group," the committee responsible
for first issuing the standard in 1992. You'll see the file extension for a JPEG as either .jpg or .jpeg, though the latter is rare in modern usage.

While lossless compression passively compresses image data as best it can, JPEG's _lossy_ compression looks for opportunities to make the compression
more efficient with tiny, often imperceptible alterations to the image data. JPEG encodes image data as eight-by-eight blocks of pixels and describes the
blocks—not the individual pixels inside them—algorithmically.

It may sound like an academic distinction on paper: "GIF uses a grid made up of pixels versus JPEG uses a grid made up of smaller grids of pixels."
In practice, this use of blocks rather than pixels means JPEG is well suited to a much more common use case for images: the kind of subtle, layered
gradients that make up a real world photograph.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/TFKgf2FgDGkoyg7wnVai.png", alt="Horizontal alignment of green blocks going from light to dark.", width="800", height="67" %}

Describing even a very simple single-pixel gradient using GIF-style encoding would be extremely verbose:

> Row one, columns one through nine are #00CC00. Row one, column ten is #00BB00. Row one, column eleven is #00AA00. Row one, column twelve is #009900. Row one, column thirteen is #008800. Row one, column fourteen is #007700. Row one, column fifteen is #006600. Row one, column sixteen is #005500.

Describing a gradient using JPEG-style encoding is much, much more efficient:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ttnejYz6sQKRpzv1v8cl.png", alt="An eight-by-sixteen grid of green blocks ranging in hue from light to dark.", width="800", height="402" %}

> Block one is #00CC00. Block two is a gradient from #00CC00 to #005500.

Where JPEG really shines is in quantizing the level of "high frequency" detail in an image, often imperceptibly. As a result,
saving an image as a JPEG usually means reducing the quality of that image in ways that are measurable, but not necessarily _visible_.
[As you've learned](/learn/images/gif), GIF-style palette quantization is a relatively simple operation: reducing the number of colors in an image results in
smaller files, but in a way that can be easy to spot with the human eye.

JPEG, on the other hand, is clever about how quantization is performed: JPEG's lossy compression attempts to quantize an image
source in a way that loosely matches the way our own psycho-visual systems quantize the world around us. In effect, JPEG tries to
throw away details we weren't likely to see in the first place, so it can sneak additional compression past us.

The human psycho-visual system does a great deal to "compress" the images you're constantly taking in. When I glance outside at my tiny garden,
I can immediately process a huge amount of information: for example, individual brightly-colored flowers stand out. I register right away that the
soil is a dusty gray, and the leaves are drooping—my plants need water. What I do _see_, but don't fully _process_, are the exact shape, size, angle,
and shade of green for any of the individual dropping leaves. I can actively look for that level of detail of course, but it would simply be too much
information to take in passively, and to no real benefit. So my psycho-visual system does a little quantization of its own, distilling that information
to "the leaves are drooping."

In effect, JPEG works the same way. JPEG's lossy compression reduces the level of detail in an image in a way that might not register at
all to our naturally "lossy" psycho-visual systems, if done within reason—and introduces far more opportunities for bandwidth savings than
lossless compression alone.

For example, JPEG takes advantage of one of our major psycho-visual weaknesses: our eyes are more sensitive to differences in brightness
than differences in hue. Prior to applying any compression, JPEG uses a process called "discrete cosine transformation" to split the image into
separate frequencies—"layers," in a manner of speaking—representing _luminance_ (brightness) and _chrominance_ (color), or "luma" and "chroma."

The luma layer is minimally compressed, discarding only small details that aren't likely noticeable to the human eye.

The chroma layers are reduced significantly. Rather than simply quantizing the palette of the chroma layers like GIF, JPEG can perform a
process called "subsampling" wherein a chroma layer is stored at a lower resolution. When recombined by effectively stretching the lower
resolution chroma layers over the luma layer, the difference is often imperceptible. Slight differences in the hue might be noticeable if
we compare the original image source and our JPEG side-by-side, but only when we know exactly what to look for.

With that said, JPEG isn't perfect. As crafty as JPEG is about sneaking compression past us, it can become glaringly obvious if taken too far.
In fact, if you've spent much time on the web—particularly in days long past—you may have noticed the result of JPEG compression taken too far:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ar5QsCECxAJLdAHFlwNd.png", alt="A highly compressed image of flowers containing many visual artifacts.", width="800", height="637" %}

Compressing image data too aggressively means the level of detail is reduced further than our psycho-visual systems would naturally
ignore, so the illusion is broken. It becomes obvious that detail is missing. Because JPEG operates in terms of blocks, the seams between
those blocks can start to show.

## Progressive JPEG

Progressive JPEG (PJPEG) effectively reorders the process of rendering a JPEG. "Baseline" JPEGs are rendered from top to
bottom as the transfer progresses, while progressive JPEG breaks rendering into a set of full-sized "scans"—likewise done
top-to-bottom—with each scan increasing the quality of the image. The entire image appears immediately, albeit blurry,
and grows clearer as the transfer continues.

<img alt="Gif showing the superior load speed of a progressive JPEG compared to a regular JPEG." decoding="async" loading="lazy" sizes="(min-width: 800px) 800px, calc(100vw - 48px)" src="https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=800" srcset="https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=200 200w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=228 228w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=260 260w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=296 296w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=338 338w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=385 385w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=439 439w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=500 500w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=571 571w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=650 650w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=741 741w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=845 845w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=964 964w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=1098 1098w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=1252 1252w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=1428 1428w,     https://web-dev.imgix.net/image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/iLfUCvVpxOSRAOqhbYCc.gif?w=1600 1600w" width="800" height="446">

It seems like a strictly technical difference on paper, but there's a huge perceptual benefit: by delivering a full-size version of
the image right away instead of empty space, PJPEG can _feel_ faster than a baseline JPEG to the end user. In addition, except for the smallest images,
encoding an image as PJPEG almost always means a smaller file size compared to a baseline JPEG—not by much, but every byte helps.

There is one tiny trade-off, however: decoding PJPEG is more complex on the client side, which means putting a _little_ more strain on the
browser—and a device's hardware—during rendering. That rendering overhead is difficult to quantify in exact terms, but it's very minor
and unlikely to be noticeable except for with severely underpowered devices. It's a trade-off worth making and, all told, progressive is a
sensible default approach whenever encoding an image as JPEG.

## Using JPEG

You might feel a little overwhelmed by all this information. There's good news for your day-to-day work, though: the more
technical specifics of JPEG compression are abstracted away, instead exposed as a single "quality" setting: an integer from 0 to 100.
0 provides the smallest possible file size, and as you might expect, the worst possible visual quality. As you progress from 0 to 100 both
the quality and the file size increase. This setting is subjective, of course—not every tool will interpret a value of "75" the same way, and
perceptual quality always varies according to the content of the image.

To understand how this compression setting works, let's use a common web-based tool for optimizing image files: [Squoosh](https://squoosh.app/).

[Squoosh](https://squoosh.app/)—maintained by the Chrome team—provides a side-by-side comparison between different methods of encoding
and configuring image outputs, with configuration options ranging from a 0-100 global "quality" slider, to the ability to fine-tune
details of chrominance vs. luminance resampling. The lower the "quality" number, the higher the compression, and the smaller the resulting file will be.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/17U3oSBnmzOXCvFPu0dV.png", alt="The Squoosh settings panel, with the quality slider highlighted.", width="800", height="783" %}

Here, with the "quality" set to 60, the file size is reduced by 79%. Don't be fooled by the implications of this label: differences in
quality across most of the scale will be imperceptible to the human eye, even when performing a side-by-side comparison.

To convert your source image to a progressive JPEG, tick the box labeled "progressive rendering" under "advanced options."
Some of these configuration options are almost certainly a deeper dive than the average web project will require, but they can
provide you with a closer look at how the things you've learned about JPEG encoding impact file size and quality in real world use cases.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/2jknUAL72eJKef8m2tPP.png", alt="The Squoosh settings panel, with the progressive rendering setting highlighted.", width="800", height="781" %}

There is not much to it in practical terms, despite how complicated we now know JPEG to be internally. Squoosh is just one of _countless_
methods of saving optimized JPEGs, all of which use a similar method of determining the compression level: a single integer between 0 and 100.

Determining the ideal level of compression for your images is a finesse game, given that all the complexity of JPEG encoding
is being distilled down to a single integer, especially when so much hinges on the _content_ of an image. Like thinking about
blinking or breathing, considering JPEG compression settings changes how we perceive them.

Looking back outside now, after writing all this, my psycho-visual processing has become more manual—_now_ I'm looking at
the individual leaves, even though the picture itself—so to speak—hasn't changed. That makes configuring JPEG compression a
little fraught: you know exactly what kinds of visual defects to look for. By thinking about image compression in the first
place, you're focusing on individual leaves—we're primed to spot slight blurring and the occasional compression artifact.
The harder you look for artifacts while fine-tuning your JPEG compression settings the more likely you are to find them,
when a user likely wouldn't. Even if that user knew exactly what to look for, they're not likely to visit a page with JPEG
compression on their mind.

For that reason, avoid the instinct to upscale an image looking for artifacts—or even look too closely at the parts of our
images where you know artifacts will appear first. For users, faint artifacts blend in with the tiny details that their lossy
psycho-visual systems usually gloss over. In fact, even with an understanding of the tricks JPEG tries to play, you wouldn't
notice those same artifacts while browsing the web unless you went looking for them. For that reason, it's almost always a safe
bet to nudge JPEG compression just a little lower than you think might be noticeable—especially when that image is going to be displayed
_smaller_ than its intrinsic size due to direct styling, or constraints set by the surrounding layout.

# Key performance issues

As it stands now, images are the web's biggest assets in terms of both [total transfer size](https://almanac.httparchive.org/en/2022/page-weight#fig-8)
and [number of requests](https://almanac.httparchive.org/en/2022/page-weight#fig-3) per page. The median webpage's total transfer size is roughly
[2MB, as of June 2022](https://httparchive.org/reports/page-weight), with images alone accounting for nearly half of that. It's no exaggeration
to say that optimizing image requests may be the single biggest performance optimization you can make.

Later, you'll learn how responsive images have evolved to help with the issues created by trying to serve one image for all eventualities.
In this section, discover key performance metrics that relate to images, and how to improve them.

## Deferring image requests

While you're about to learn a number of ways to ensure your image requests are as small and efficient as possible, the fastest image request
will always be the one that never gets made. So, right up front, I want to share what may be the most impactful change you can make to the way
you deliver image assets to your users: the `loading="lazy"` attribute.

```html
<img src="image.jpg" loading="lazy" alt="…">
```

This attribute ensures that requests for images aren't made until they fall close to the user's viewport, deferring them from the initial
page load—the time when the browser is at its busiest—and removing those requests from the critical rendering path.

Simple as it may be in practice, using this attribute can have a huge positive impact on performance: an image that never falls within
the user's viewport will never be requested, and no bandwidth will be wasted on images that the user will never see.

There's a catch, however: deferring those requests means not taking advantage of browsers' hyper-optimized processes for requesting
images as early as possible. If `loading="lazy"` is used on `img` elements toward the top of the layout—and thus more likely
to be in the user's viewport when the page is first loaded—these images can feel significantly slower to the end user.

## Fetch Priority

The `loading` attribute is an example of a larger web standards effort to give developers more power over how web browsers
prioritize requests.

You're likely aware of browsers' [basic approaches to fetch priority](https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit#):
for example, a request for an external CSS file in the `<head>` of a document is considered essential enough to block render, while a request for an
external JavaScript file just above `</body>` will be deferred until render is complete. If the value of a `loading` attribute on an `<img>` is 'lazy',
the associated image request will be deferred until the browser determines that it will be shown to a user. Otherwise, that image will have the same
priority as any other image on the page.

The [`fetchpriority` attribute](https://caniuse.com/mdn-html_elements_img_fetchpriority) is intended to give
developers [finer-grained control over the priority of assets](/fetch-priority/), allowing you to flag resources
as 'high' and 'low' priority relative to resources of the same type. The use cases for `fetchpriority` are similar to the `loading`
attribute, though much more broad. For example, you might use `fetchpriority="low"` on an image only revealed following user interaction
(whether that image falls within the user's viewport or not) in order to prioritize visible images elsewhere on the page, or `fetchpriority="high"`
to prioritize an image you know will be immediately visible in the viewport as soon as the page is rendered.

Note that `fetchpriority` differs from `loading` in that it doesn't fundamentally change browser behavior. It doesn't instruct the browser
to load certain assets before others, instead giving it vital context for the decisions it makes around requesting assets.

## Measuring the impact of images

When optimizing image assets, _perceived_ performance is often more important, and more difficult to measure, than total transfer
size alone.

Web Vitals provide measurable, actionable metrics and guidance for improving users' experience of the web, highlighting problems such
as slow response time from a web server, rendering issues, and interactivity delays. Core Web Vitals are a subset of these goals, laser-focused
on the user's direct experience of an individual page—a set of technical measurements that, together, determine how fast an experience _feels_ to a user.

### Cumulative Layout Shift

[Cumulative Layout Shift](/cls/) (CLS) is a measure of visual stability. It is a metric for capturing how much
the layout of the content on a page shifts as assets are loaded and the page is rendered. Anyone that has spent a significant amount
of time using the web has lost their place in a long run of text due to a page "jumping" as a delayed webfont or image source is suddenly
rendered—or had an interactive element suddenly moved away from your pointer. A high CLS is a nuisance at best, and cause of
user error at worst—a "cancel" button shifting to a space previously occupied by a "confirm" button just as the user clicks, for example.

With high load times and the amount of space they can occupy in a layout, it stands to reason that images are a common cause
of high CLS scores.

{% Codepen {
user: 'web-dot-dev',
id: 'NWBbxqo',
height: 500,
theme: dark,
tab: 'css,result'
} %}

Thanks to relatively recent changes in modern browsers, it's easier than you might think to avoid high CLS scores due to images.

If you've been working on the frontend for a few years now, you'll be familiar with the `width` and `height` attributes on `<img>`:
prior to the widespread adoption of CSS, these were the only way to control the size of an image.

```html
<img src="image.jpg" height="200" width="400" alt="…">
```

These attributes fell out of use in an effort to keep our styling concerns separate from our markup, especially as responsive
web design made it necessary to specify percentage-based sizing via CSS. In the early days of responsive web design, "remove
the unused `width` and `height` attributes" was common advice, as the values we specified in our CSS—`max-width: 100%` and
`height: auto`—would override them.

```html
<img src="image.jpg" alt="…">
```

```css
img {
  max-width: 100%;
  height: auto;
}
```

Having removed the `height` and `width` attributes as in the previous example, the only method the browser has for determining
the height of the image in this situation is to request the source, parse it, and render it at its intrinsic aspect ratio, based on the
width of the space it occupies in the layout once stylesheets have been applied. Much of this process takes place after the page has been
rendered, with the newly calculated height causing additional layout shifts.

[Starting in 2019](https://caniuse.com/mdn-html_elements_img_aspect_ratio_computed_from_attributes
), browser behavior was updated to handle the `width` and `height` attributes differently. Rather than using the values of these
attributes to determine the fixed, pixel-based size of an `img` element in the layout, these attributes can be thought to represent
the _aspect ratio_ of the image, though the syntax is the same. Modern browsers will divide these values against each other in order to
determine an `img` element's intrinsic _aspect ratio_ prior to the page being rendered, allowing it to reserve the space the image will occupy as the layout is rendered.

As a rule, you should always use `height` and `width` attributes on `<img>`, with values matching the intrinsic size of your image source—so
long as you make sure that you've specified `height: auto` alongside `max-width: 100%` to override the height from the HTML attribute.

```html
<img src="image.jpg" height="200" width="400" alt="…">
```

```css
img {
  max-width: 100%;
  height: auto;
}
```

By using the `width` and `height` attributes on your `<img>` elements, you'll avoid a high CLS score due to images.

{% Codepen {
user: 'web-dot-dev',
id: 'YzjpwyE',
height: 300,
theme: dark,
tab: 'html,result'
} %}

It's important to note that there's no downside to this approach, as it leans on long-established browser behavior—any browser
with support for basic CSS will work the way it always has, with the `height` and `width` attributes in your markup overridden by your styles.

While `width` and `height` attributes deftly avoid CLS issues by reserving the necessary layout space for your images, presenting
users with an empty gap or [low-quality placeholder](https://www.guypo.com/introducing-lqip-low-quality-image-placeholders) while
they wait for an image to transfer and render isn't ideal either. While there are things you can do to mitigate the measurable and perceptible
impact of slow-to-load images, the only way to present a fully-rendered image to a user more quickly is by reducing its transfer size.

### Largest Contentful Paint

Largest Contentful Paint (LCP) measures the time it takes to render the largest “contentful” element visible in the user's viewport—the
content element that occupies the largest percentage of the visible page. It may seem like an overly specific metric on the surface, but that
element serves as a practical proxy for the point where the majority of the page has been rendered, from the user's perspective. LCP is a vital
measure of (perceived) performance.

Metrics like `DOMContentLoaded` or the `window.onload` event can be useful for determining when the process of loading the current page
has technically completed, but they don't necessarily correspond to a user's experience of the page. A slight delay in rendering an element
outside the user's viewport would be factored into either of these metrics, but would likely go completely undetected by a real-world user.
A long LCP means the user's first impression of a page—the most important content inside the current viewport—is that the page is slow,
or broken outright.

The user perception captured by LCP has a direct impact on user experience. [An experiment done by Vodafone](/vodafone/) just last year
found that a 31% improvement in LCP not only led to 8% more sales—a strong result on its own—but of their total number of users, found a 15%
improvement in the number of visitors who became prospective customers ("visitor-to-lead rate") and a 11% improvement in the number of users
who visited their cart ("cart to visit rate").

On more than [70%](https://almanac.httparchive.org/en/2021/media#images) of webpages, the largest element in the initial
viewport involves an image, either as a stand-alone `<img>` element or an element with a background image. In other words,
70% of pages' LCP scores are based on image performance. It doesn't take much imagination to see why: big, attention-grabbing
images and logos are very likely to be found "above the fold."

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/KrYcABGs7oYi9oHHZPJW.png", alt="LCP highlighted in the console of a web.dev page", width="800", height="407" %}

There are a few steps you can take to avoid LCP delays: first, never specify `loading="lazy"` on an "above the fold" image,
as delaying the request until after the page has been rendered will likely have a massive negative impact on your LCP score.
Second, using `fetchpriority="high"` can inform the browser that the transfer of this image should be prioritized above images elsewhere on the page.

With those rules squarely in mind, the most important thing you can do to improve a page's LCP score is reduce the amount of time
it takes to transfer and render those images. In order to do that, you'll need to keep your image sources as small and efficient as
possible (without sacrificing their quality, of course) and ensure that users are only getting the image assets that make the most
sense for their browsing contexts.

### Conclusion

Image assets are the biggest drain on your users' bandwidth—bandwidth taken away from transferring every other asset necessary
to render a page. Images introduce significant issues in terms of perceived performance, both during and after the surrounding page
layout has been rendered. In short: image assets do _damage_.

Daunting as that may be, while "the web would be better off with fewer images" would certainly be true in terms of performance alone,
it would also do its users a tremendous disservice. Images are a vital part of the web, and you shouldn't compromise on the quality of
meaningful content for the sake of performance alone.

In the rest of this course, you'll learn about the technologies that power our image assets and techniques for mitigating their
performance impacts, without compromising on quality.

# Image formats: PNG

There are a few things that set PNG (Portable Network Graphics) apart from other formats, though as it was intended to be a replacement for
GIF (due to patent disputes long, long ago) it is similar to GIF in several ways. PNG also uses lossless compression,
meaning that the image data will be _compressed_ without any loss of visual fidelity. An image's color palette may be quantized—an
“indexed color”, with PNG making use of a palette limited to 256 colors, just like GIF. A far more common “truecolor” PNG can
contain many, many more colors—up to 16 million.

PNG and GIF both support transparency, though with a major difference. GIF treats transparency as a binary proposition—a
pixel is either an opaque color, or fully transparent. PNG supports “alpha channel” transparency, meaning that each pixel
can be set to a level of transparency between 0 (fully transparent) and 255 (fully opaque).

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/PKQ634IdtXzy63TdlfpC.png", alt="Two pink flowers showing two levels of transparency.", width="800", height="399" %}

In practical terms, the lack of substantial quantization and lossless compression mean that saving an image as a PNG will
never result in a drop in visual quality. However, this almost invariably results in excessively large file sizes compared to
more modern web-friendly encodings. The transfer size of a PNG means they are almost never the right choice for photographic content.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/asVXRCrgha5jMqCXwmn6.png", alt="Comparison of JPEG and PNG.", width="800", height="446" %}

PNG was more commonplace in years past largely for a single use case, as the only raster encoding that supported semi-transparency.
Today, PNG should only be considered for simple artwork that requires semi-transparency—a company logo containing a drop shadow,
for example—and should be compared carefully to the more modern formats that support semi-transparency, such as WebP.

Much like GIF, PNG was designed to solve use cases that are frequently better served by SVG in terms of both scalability and file size.
For that reason, you'll sometimes see PNG used as the fallback version of UI elements in the vanishingly small number of browsers that don't
support SVG, though these are increasingly rare.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/GhNCZEadcuq93fPfuiQJ.png", alt="PNG and SVG comparison.", width="800", height="598" %}

In practical terms, PNG is a sound choice for maintaining a manageable-sized “canonical” version of a source image, saved in your
local development environment or committed to a project repository in case future versions of that image need to be edited or re-saved
in alternate formats.

It is worth noting, however, that even though encodings are standardized, different editing tools have different methods of
performing that encoding—some much more efficient than others. Before transferring a PNG in any context, be sure to run your
files through a tool like [Squoosh](https://squoosh.app/) or [ImageOptim](https://imageoptim.com).

# Prescriptive syntaxes

The `<picture>` element doesn't render anything on its own, but instead acts as a decision engine for an inner `<img>` element,
telling it what to render. `<picture>` follows a precedent already set by the `<audio>` and `<video>` elements: a wrapper element
that contains individual `<source>` elements.

```html
<picture>
   <source …>
   <source …>
	<img …>
</picture …>
```

That inner `<img>` also provides you with a reliable fallback pattern for older browsers without support for responsive images:
if the `<picture>` element isn't recognized by the user's browser, it's ignored. The `<source>` elements are then discarded as well,
since the browser either won't recognize them at all, or won't have meaningful context for them without a `<video>` or `<audio>` parent.
The inner `<img>` element will be recognized by any browser, though—and the source specified in its `src` will be rendered as expected.

## "Art directed" images with `<picture>`

Making changes to the content or aspect ratio of an image based on the size of the image in the page is typically referred to as "art directed"
responsive images. `srcset` and `sizes` are designed to work invisibly, seamlessly swapping out sources as the user's browser dictates.
There are times, however, where you want to alter sources across breakpoints to better highlight the content, the same way you adapt page layouts.
For example: a full-width header image with a small central focus may work well on a large viewport:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/HWZtREfRzpcy7tvolvkn.png", alt="A header width image of a periwinkle flower surrounded by leaves and stems, being visited by a honeybee.", width="800", height="286" %}

But when scaled down to suit small viewports, the central focus of the image might be lost:

<div style="width: 50%">
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/7W8AmfGV4jEPD6mp6Kfk.png", alt="A header width image of a periwinkle flower, scaled down. The honeybee is barely visible.", width="400", height="143" %}
</div>

The _subject_ of these image sources are the same, but in order to better focus on that subject visually, you'll want the
proportions of the image source to change across breakpoints. For example, a tighter zoom on the center of the image, and
some of the detail at the edges cropped out:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/q9IrCVku2h0B4YfHzI3h.png", alt="A zoomed in crop of the periwinkle flower.", width="400", height="315" %}

That sort of "cropping" can be achieved through CSS, but would leave a user requesting all the data that makes up that image,
even though they might never end up seeing it.

Each `source` element has attributes defining the conditions for the selection of that `source`: `media`, which accepts a
media query, and `type`, which accepts a media type (previously known as "MIME type"). The first `<source>` in the source
order to match the user's current browsing context is selected, and the contents of the `srcset` attribute on that `source`
will be used to determine the right candidates for that context. In this example, the first `source` with a `media` attribute
that matches user's viewport size will be the one selected:

```html
<picture>
  <source media="(min-width: 1200px)" srcset="wide-crop.jpg">
  <img src="close-crop.jpg" alt="…">
</picture>
```
{% Codepen {
user: 'web-dot-dev',
id: 'poZNxyN',
height: 300,
theme: dark,
tab: 'html,css,result'
} %}

You should always specify the inner `img` last in the order—if none of the `source` elements match their `media` or `type`
criteria, the image will act as a "default" source. If you're using `min-width` media queries, you want to have the largest
sources first, as seen in the preceding code. When using `max-width` media queries, you should put the smallest source first.

```html
<picture>
   <source media="(max-width: 400px)" srcset="mid-bp.jpg">
   <source media="(max-width: 800px)" srcset="high-bp.jpg">
   <img src="highest-bp.jpg" alt="…">
</picture>
```

When a source is chosen based on the criteria you've specified, the `srcset` attribute on `source` is passed along to the
`<img>` as though it were defined on `<img>` itself—meaning you're free to use `sizes` to optimize art directed image
sources as well.

```html
<picture>
   <source media="(min-width: 800px)" srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w">
   <source srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w">
   <img src="fallback.jpg" alt="…" sizes="calc(100vw - 2em)">
</picture>
```

Of course, an image with proportions that can vary depending on the selected `<source>` element raises a performance issue:
`<img>` only supports a single `width` and `height` attribute, but [omitting those attributes can lead to a measurably worse user experience](#).
In order to account for this, a [relatively recent](https://github.com/whatwg/html/pull/5894)—but
[well supported](https://developer.mozilla.org/docs/Web/HTML/Element/source#browser_compatibility)—addition to the HTML
specification allows for use of `height` and `width` attributes on `<source>` elements. These work to reduce layout shifts just as well
as they do on `<img>`, with the appropriate space reserved in your layout for whatever `<source>` element is selected.

```html
<picture>
   <source
      media="(min-width: 800px)"
      srcset="high-bp-1600.jpg 1600w, high-bp-1000.jpg 1000w"
      width="1600"
      height="800">
   <img src="fallback.jpg"
      srcset="lower-bp-1200.jpg 1200w, lower-bp-800.jpg 800w"
      sizes="calc(100vw - 2em)"
      width="1200"
      height="750"
      alt="…">
</picture>
```

It's important to note that art direction can be used for more than decisions based on viewport-size—and it should, given that
the majority of those cases can be more efficiently handled with `srcset`/`sizes`. For example, selecting an image source better
suited to the color scheme dictated by a user's preference:

```html
<picture>
   <source media="(prefers-color-scheme: dark)" srcset="hero-dark.jpg">
   <img srcset="hero-light.jpg">
</picture>
```
{% Codepen {
user: 'web-dot-dev',
id: 'MWBbPJm',
height: 500,
theme: dark,
tab: 'html,result'
} %}

### The `type` attribute

The `type` attribute allows you to use the `<picture>` element's single-request decision engine to only serve image formats
to browsers that support them.

As you learned in [Image Formats and Compression](/learn/images/avif/#browser-support/), an encoding that the browser can't parse won't even be recognizable as
image data.

Before the introduction of the `<picture>` element, the most viable front-end solutions for serving new image formats required
the browser to request and attempt to parse an image file before determining whether to throw it away and load a fallback. A
common example was a script along these lines:

```html
   <img src="image.webp"
	data-fallback="image.jpg"
	onerror="this.src=this.getAttribute('data-fallback'); this.onerror=null;"
	alt="...">
```

With this pattern, a request for `image.webp` would still be made in every browser—meaning a wasted transfer for browsers
without support for WebP. Browsers that couldn't then parse the WebP encoding would throw an `onerror` event, and swap
the `data-fallback` value into `src`. It was a wasteful solution, but again, approaches like this one were the only option
available on the front-end. Remember that the browser begins making requests for images before any custom scripting has a
chance to run—or even be parsed—so we couldn't preempt this process.

The `<picture>` element is explicitly designed to avoid those redundant requests. While there's still no way for a browser
to recognize a format it doesn't support without requesting it, the `type` attribute warns the browser about the source
encodings up-front, so it can decide whether or not to make a request.

In the `type` attribute, you provide the [Media Type (formerly MIME type)](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
of the image source specified in the `srcset` attribute of each `<source>`. This provides the browser with all the information it
needs to immediately determine whether the image candidate provided by that `source` can be decoded without making any external
requests—if the media type isn't recognized, the `<source>` and all its candidates are disregarded, and the browser moves on.

```html
<picture>
 <source type="image/webp" srcset="pic.webp">
 <img src="pic.jpg" alt="...">
</picture>
```

Here, any browser that supports WebP encoding will recognize the `image/webp` Media Type specified in the `type` attribute
of the `<source>` element, select that `<source>`, and—since we've only provided a single candidate in `srcset`—instruct the inner
`<img>` to request, transfer, and render `pic.webp`. Any browser _without_ support for WebP will disregard the `source`, and
absent any instructions to the contrary, the `<img>` will render the contents of `src` as it has done since 1992.
You don't need to specify a second `<source>` element with `type="image/jpeg"` here, of course—you can assume universal support for JPEG.

Regardless of the user's browsing context, all of this is achieved with a single file transfer, and no bandwidth wasted on
image sources that can't be rendered. This is forward-thinking, as well: as newer and more efficient file formats will come
with Media Types of their own, and we'll be able to take advantage of them thanks to `picture`—with no JavaScript, no serverside
dependencies, and all the speed of `<img>`.

## The future of responsive images

All of the markup patterns discussed here were a heavy lift in terms of standardization: changing the functionality of
something as established and central to the web as `<img>` was no small feat, and the suite of problems those changes aimed to
solve were extensive to say the least. If you've caught yourself thinking that there's a lot of room for improvement with these
markup patterns, you're absolutely right. From the outset, these standards were intended to provide a baseline for future
technologies to build on.

All of these solutions have necessarily depended on markup, so as to be included in the initial payload from the server,
and arrive in time for the browser to request image sources—a limitation that led to the admittedly unwieldy `sizes` attribute.

However, since these features were introduced to the web platform, a native method of deferring image requests was introduced.
`<img>` elements with the `loading="lazy"` attribute aren't requested until the layout of the page is known, in order to defer
requests for images outside of the user's initial viewport until later on in the process of rendering the page, potentially avoiding
unnecessary requests. Because the browser fully understands the page layout at the time these requests are made, a
[`sizes="auto"` attribute has been proposed as an addition to the HTML specification](https://github.com/whatwg/html/pull/8008)
to avoid the chore of manually-written `sizes` attributes in these cases.

There are also additions to the `<picture>` element on the horizon as well, to match some exceptionally exciting changes
to the way we style out page layouts. While viewport information is a sound basis for high-level layout decisions, it
prevents us from taking a fully component-level approach to development—meaning, a component that can be dropped into
any part of a page layout, with styles that respond to the space that the component itself occupies. This concern led
to the creation of _[container queries](https://www.oddbird.net/2022/08/18/cq-syntax/)_: a method of styling elements
based on the size of their parent container, rather than the viewport alone.

While the container query syntax has only just stabilized—and browser support is [very limited](https://caniuse.com/css-container-queries),
at the time of writing—the addition of the browser technologies that enable it will provide the `<picture>` element with a
means of doing the same thing: a potential `container` attribute that allows for `<source>` selection criteria based on the
space the `<picture>` element's `<img>` occupies, rather than based on the size of the viewport.

If that sounds a little vague, well, there's a good reason: these web standards discussions are ongoing, but far from settled—you
can't use them just yet.

While responsive image markup promises to only get easier to work with over time, like any web technology, there are a number
of services, technologies, and frameworks to help ease the burden of hand-writing this markup available. In the next module,
 we'll look at how to integrate everything we've learned about image formats, compression, and responsive images into a modern development workflow.

# Raster images

Raster images can be thought of as a set of pixel-by-pixel instructions for rendering a two-dimensional grid. Common raster
image formats include GIF (.gif), JPEG (.jpg), PNG (.png), and WebP (.webp). The way each image format compresses and encodes
these instructions differs, resulting in a huge variance between file sizes: a photographic image encoded as a JPEG might only
be a few hundred kilobytes, while the same image encoded as a PNG might be several megabytes, without any discernible difference
in quality to the end user.

A raster image source scaled beyond its inherent dimensions will appear distorted, blocky, or blurred:

{% Codepen {
user: 'web-dot-dev',
id: 'ZEjBQqB',
height: 500,
theme: dark,
tab: 'css,result'
} %}

For artwork containing real world levels of detail, raster images are the right tool for the job.

Just like choosing between raster and vector images, choosing the appropriate type of raster image ultimately comes down to the use case.
When we break raster images down into their encodings, what we're really talking about are the methods used to describe their contents, and
the compression methods (or lack thereof) we're applying. Remember that a server doesn't send _an image_ over the wire to a browser, but a stream
of bytes describing the pixel grid that makes up that image for the client to recompose.

So, to better visualize the process of encoding a grid of pixels as bytestream data, I want you to imagine that you're acting as the web browser.
You have a sheet of [millimeter graph paper](https://en.wikipedia.org/wiki/Graph_paper#Formats) and a specific pack of brand name crayons. I, as
the web server, have the exact same things—but I've already used my crayons to fill the graph paper in with a source image. If I were to send you
a plain text message, I couldn't send you the image itself, but I could convey information about an image source in a language we both understand
using our shared standard for our “pixel” grid and colors:

> Start at the top left. Row one, column one is blue. Row one, column two is blue. Row one, column three is blue. Row one, column four is red.

Using this textual information, you'd be able to perfectly recreate the image I have on my sheet of graph paper.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/pwUWoFFo7MVq58e05NnK.png", alt="Three horizontal blue boxes followed by one red box.", width="652", height="204" %}

Differences in image formats and the way they're encoded as data can be loosely thought of as the way this information has been formatted.
For example, the information I've sent you could be just as readily expressed as:

> Start at the top left. Row one, columns one through three are blue. Row one, column four is red.

Either one of these descriptions will result in the same image, but the second one manages to describe the same image with fewer
characters. This is a _lossless_ method of compressing image data: all the same information—and thus, no reduction of visual
fidelity—but fewer bytes transferred over the wire from me to you—from the server to the rendering engine. This is the plain language
equivalent of “run-length encoding” for image data, where data is encoded as the value to be repeated and a count, rather
than repeating the full value multiple times.

The inverse, _lossy_ compression, might sound like a non-starter at face value—why would you ever want your images to look _worse_?
That isn't strictly the case, though, and it's worth keeping in mind that our eyes don't have perfect fidelity either. Choosing
the correct format and settings for image compression is an exercise in finding the balance between the level of visual detail
we're able to perceive and the amount of data sent to the browser. Both of these factors are determined by the content of our source image.

The raster image formats are those you are likely most familiar with as a developer—GIF, JPEG, PNG, WebP, and more. You'll learn about the capabilities of each in the next few modules.

# Responsive images

[Responsive image](/learn/design/responsive-images/) markup can be divided into two scenarios: situations
where the goal is the most efficient possible images, and situations where you need explicit control over what image source
the browser selects. You can think of these as _descriptive_ and _prescriptive_ syntaxes, respectively.

In this module you'll learn both approaches. First we'll cover `srcset` and `sizes`, and how to help the browser make the best
choice based on what it knows about the user, their device, and their browsing situation. You'll then discover the `<picture>` element,
which allows for explicit control over source selection based on factors like viewport size and browser support for image formats.

## Descriptive syntaxes

A descriptive syntax provides the browser with information about image sources and how they'll be used, but ultimately leaves
the decision-making to the browser. This is by far the more common scenario; for the vast majority of images you won't _want_ granular
control over browser behavior. Browsers have far more information at their disposal than web developers do, and can make complex decisions
based on this information. You can't predict users' browsing contexts accurately—there's too much about their hardware, preferences, and connection
speeds that you can't know. At best, you can make educated guesses, but can't know for _certain_ how each user experiences the web. The
central use case for responsive images is strictly goal-oriented, from a developer's perspective: allow browsers to make the most efficient image
requests possible, based on the information the browser has at hand.

To enable browsers to make these choices, `srcset` allows you to provide the browser with a list of potential sources for populating a single
`<img>`, while `sizes` allows you to provide the browser with information about how that `<img>` will be rendered. You'll learn how to use
these in the [next module](/learn/images/descriptive/).

## Prescriptive syntaxes

With a prescriptive syntax, you tell the browser what to do—what source to select, based on specific criteria you've defined. While this use case isn't as
common as "just load the most efficient asset to render this image," it allows us to provide usage instructions to the browser to account for
information it doesn't have prior to the transfer of assets, such as the content of the sources or their formats.

While `srcset` and `sizes` provide you with a syntax for passing information along to the user's browser and allowing it to make decisions about
image sources, there are times when you'll need explicit control over which source file is presented and when. For example, you might
want to display versions of the same image content with different aspect ratios, based on different design treatments across layout breakpoints,
or make sure only browsers with support for a specific encoding receive specific sources.

In these cases, you want explicit control over which source is shown, and when. These are assurances that `srcset` and `sizes` can't give us,
by design. To get that control, we'll need to use the [`<picture>` element](/learn/images/prescriptive/).

# Vector images

Vector graphics are a method of communicating a series of shapes, coordinates, and paths to their rendering context. They
are a set of instructions for how an image should be drawn. When that image is scaled up or down, the set of points and lines that
the image represents are redrawn to scale. A smooth curve between two points will be redrawn just as smoothly at any size—similar
to the way a CSS-defined border on an HTML element is redrawn as that element is scaled in the viewport.

Scalable Vector Graphics (SVG) is an XML-based markup language developed by the W3C. It is a vector image format designed
for the modern web.

{% Codepen {
user: 'web-dot-dev',
id: 'WNKorKN',
height: 500,
theme: dark,
tab: 'html,result'
} %}

Any design software dedicated to editing vector artwork will allow you to export an image as an SVG. But being a standardized,
human-readable markup language, SVG can also be created and edited with any text editing software, regardless of the software used
to create it, though that quickly becomes unrealistic for images of any real complexity. SVG can be styled with CSS, or contain
JavaScript that builds behaviors and interactions into the images themselves.

Even beyond the obvious appeal for designers and developers, SVG is also an incredibly powerful format in terms of the end user experience.
The descriptive information contained within an SVG source is often highly compact compared to raster image formats' more prescriptive
pixel-grid-based information, in the case of simple shapes—to oversimplify somewhat, the difference between telling the browser
"draw a 1px red line between 1x1 and 1x5" and "1x1 is a red pixel. 1x2 is a red pixel. 1x3 is a red pixel. 1x4 is a red pixel. 1x5 is a red pixel."
The flip side is that the descriptive nature of SVG requires more interpretation—more "thinking"—from the browser. For this reason,
complex SVGs can be more taxing to render. In the same vein, a highly complex image could mean a verbose set of instructions, and a large transfer size.

It may take a little trial and error before you're able to instantly recognize an image source candidate as better served by SVG rather than a
conventional raster format. There are a few guidelines, though: interface elements like icons are almost always well served by SVG. Artwork with
sharp lines, solid colors, and clearly-defined shapes will likely be a strong candidate for SVG.

SVG is a huge topic: an entire markup language made to coexist alongside HTML, with unique styling options and capabilities. For a more detailed
introduction to SVG see the [MDN SVG tutorial](https://developer.mozilla.org/docs/Web/SVG/Tutorial/Introduction).

# Image formats: WebP

Google originally developed WebP as a lossy image format to supersede JPEG, one that was able to produce files smaller than a
comparable-quality image file encoded as JPEG. Later updates to the format introduced the option of lossless compression,
PNG-like alpha channel transparency, and GIF-like animation—all of which can be used alongside JPEG-style lossy compression.
WebP is an _unbelievably_ versatile format.

WebP's lossy compression algorithm is based on a method that the [VP8 video codec](https://datatracker.ietf.org/doc/html/draft-bankoski-vp8-bitstream-01#page-7)
uses to compress keyframes in videos. At a high level, it's similar to JPEG encoding: WebP operates in terms of "blocks" rather than individual pixels,
and has a similar division between luminance and chrominance. WebP's luma blocks are 16x16, while chroma blocks are 8x8, and those "macroblocks" are
further subdivided into 4x4 sub-blocks.

Where WebP differs radically from JPEG are in two features: "block prediction" and "adaptive block quantization."

## Block Prediction

Block prediction is the process through which the contents of each chrominance and luminance block are predicted based on the values
of their surrounding blocks—specifically the blocks above and to the left of the current block. As you might imagine, the algorithms
that do this work are fairly complex, but to put it in plain language: "if there's blue above the current block, and blue to the left
of the current block, assume this block is blue."

In truth, both PNG and JPEG also do this sort of prediction to _some_ degree. WebP, however, is unique in that it samples the surrounding
blocks' data and then attempts to populate the current block by way of several different "prediction modes", effectively trying to "draw"
the missing part of the image. The results provided by each prediction mode are then compared to the real image data, and the closest
predictive match is selected.

<div style="background: #fff;">
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/t8neUw7UOsUNTF3uxe08.png", alt="A diagram of WebP’s various block prediction methods.", width="800", height="509" %}
</div>

Even the closest predictive match isn't going to be completely right, of course, so the differences between the predicted and
actual values of that block are encoded in the file. When decoding the image, the rendering engine uses the same data to apply
the same predictive logic, leading to the same predicted values for each block. The difference between the prediction and the
expected image that was encoded in the file is then applied over the predictions—similar to how a Git commit represents a differential
patch that gets applied over the local file, rather than a brand new copy of the file.

To illustrate: rather than dig into the complex math involved in the true predictive algorithm, we'll invent a WebP-like encoding
with a single prediction mode, and use it to efficiently relay a grid of numbers the way we did with the legacy formats. Our algorithm
has a single prediction mode, which we'll call "prediction mode one:" the value of each block is the sum of the values of the blocks above
it and to the left of it, starting with 1.

Now, say we're starting with the following real image data:

```text
111151111
122456389
```

Using our predictive model to determine the contents of a 2x9 grid, we would get the following result:

```text
111111111
123456789
```

Our data is a good fit for the predictive algorithm we've invented—the predicted data is a close match to our real data.
Not a perfect fit, of course—the actual data has several blocks that are different from the predicted data. So, the encoding
we send includes not just the prediction method to use, but a diff of any blocks that should differ from their predicted values:

```text
_ _ _ _ +4 _ _ _ _
_ _ -1 _ _ _ -4 _ _
```

Put in the same kind of plain language as some of the legacy format encodings we've discussed:

> 2x9 grid using prediction mode one. +4 to 1x5, -1 to 2x3, -4 to 2x7.

The end result is an unbelievably efficient encoded file.

## Adaptive block quantization

JPEG compression is a blanket operation, applying the same level of quantization to every block in the image. In an image
with a uniform composition, that certainly makes sense—but real-world photographs aren't any more uniform than the world around us.
In practice, this means that our JPEG compression settings are determined not by the high frequency details—where JPEG
compression excels—but by the parts of our image where compression artifacts are most likely to appear.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/ohpy2TSKU5qkO7bZOzIy.png", alt="A compressed JPEG image of a monarch butterfly", width="800", height="798" %}

As you can see in this exaggerated example, the wings of the monarch in the foreground look relatively sharp—a little grainy
when compared with the high-resolution original, but certainly not noticeable without the original to compare with it.
Likewise, the detailed inflorescence of the milkweed, and the leaves in the foreground—you and I may see traces of compression
artifacts with our trained eyes, but even with the compression dialed up well beyond reasonable levels things in the foreground
still look passably crisp. The low-frequency information at the top left of the picture—the blurry green backdrop of leaves—looks
_terrible_. Even an untrained viewer would immediately notice the quality issue—the subtle gradients in the background are
rounded down to jagged, solid-color blocks.

In order to avoid this, WebP takes an _adaptive_ approach to quantization: an image is broken into up to four visually similar
segments, and compression parameters for those segments are tuned independently. Using the same outsized compression with WebP:

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/gJKurkTf09XGFhaUApP2.png", alt="A compressed WebP image of a monarch butterfly", width="800", height="801" %}

The size of both these image files is about the same. The quality is about the same when we look at the monarch's wings—you
can spot a few tiny differences in the end result if you look very, very closely, but no real difference in overall quality.
In the WebP, the flowers of the milkweed are just a _little_ sharper—again, likely not enough to be noticeable unless you're
comparing the two side-by-side and really looking for differences in quality, the way we are. The background is a different story
altogether: it has barely a trace of JPEG's glaringly obvious artifacts. WebP gives us the same file size, but a much higher
quality image—give or take a few tiny details that our psychovisual systems wouldn't be able to detect if we weren't comparing
the two so closely.

## Using WebP

The internals of WebP might be considerably more complex than JPEG encoding, but just as simple for the purpose of our daily
work: all the complexity of WebP's encoding is standardized around a single "quality" value—expressed from 0–100, just like JPEG.
And once again, that's not to say that you're _limited_ to a single overarching "quality" setting. You can—and should—tinker with all
the fine details of WebP encoding, if only to gain a better understanding of how these normally-invisible settings can impact
file size and quality.

Google offers a `cwebp` command line encoder that allows you to convert or compress individual files or entire directories of images:

```shell
$ cwebp -q 80 butterfly.jpg -o butterfly.webp

Saving file 'butterfly.webp'
File:  	butterfly.jpg
Dimension: 1676 x 1418
Output:	208418 bytes Y-U-V-All-PSNR 41.00 43.99 44.95   41.87 dB
       	(0.70 bpp)
block count:    intra4:     7644  (81.80%)
          	   Intra16:     1701  (18.20%)
          	   Skipped:       63  (0.67%)
bytes used:  header:            249  (0.1%)
         	  mode-partition:  36885  (17.7%)
Residuals bytes  |segment 1|segment 2|segment 3|segment 4|  total
macroblocks:     |       8%|      22%|      26%|      44%|   9345
quantizer:       |      27 |      25 |      21 |      13 |
filter level:    |       8 |       6 |      19 |      16 |
```

And if you're not inclined toward the command line, Squoosh will serve us just as well for encoding WebP. It gives us the option
of side-by-side comparisons between different encodings, settings, quality levels, and differences in file size from JPEG encoding.

# Learn Privacy

When you acquire a new user, you are granted their trust. It's your organization's responsibility to honor this trust by keeping
user data private. As people use your service, they will share some information with your site or system so it can function
and serve them best.

As a developer, you have a key role to play! Ensuring that your site or system respects user privacy isn't just a product
manager's or legal team's responsibility.

_You_ have the power to directly improve the privacy of the people who use your site:
* By factoring in privacy early, as you're making technical and design decisions. This is called _privacy by design_.
* By using your technical expertise to equip the people you work with so they can make informed privacy decisions themselves.

Just like making the right security decisions, making good privacy decisions [shouldn't be scary](/security-not-scary/)!
This course is here to help.

## What you will learn

In this course, you will learn about:

* **Pragmatic privacy techniques**. We'll talk about making your site _privacy-preserving_. To be mindful about all the bits
of data that flow through your site, you'll learn a few [encryption](/learn/privacy/encryption/) tips and understand what
it means to collect just the [data](/learn/privacy/data/) you need. We also know that it may be helpful to collect
some user data and to leverage third parties as building blocks for your site to provide useful services—be it payment solutions, map widgets, or
error monitoring scripts. This course will offer tools and tips for you to approach this with care, especially when it
comes to [third parties](/learn/privacy/third-parties/).
* **What's up with web privacy**. You will learn about upcoming browser and web platform privacy improvements,
and how you can prepare your site for these changes. You'll also learn about what [fingerprinting](/learn/privacy/fingerprinting/) protections
in browsers mean for your site.
* **Ways to scale and maintain your organization's privacy approaches**. In [best practices](/learn/privacy/best-practices),
you will find tips to help the people you work with—direct teammates, members of other teams, or your company's leadership—consider
closely the impact of their privacy choices, and make decisions accordingly.

## Prerequisites

To follow this course, you need an intermediate knowledge of HTML, JavaScript, and HTTP requests and headers.

## Why this course matters today

1. User concerns and user experience. People are increasingly concerned about their privacy on the web. Offering more privacy
and being mindful about data collection can help build trust in your service and improve their experience, directly contributing
to your organization's success.
1. Compliance. Over recent years, privacy regulations have emerged all over the world, and keep evolving: in 2017, the
rehauled APPI in Japan; in 2018, the GDPR in Europe, in 2020, the CCPA in California; in 2022, the PDPB in India …
Whether or not you've directly worked on tasks to comply with these regulations, this shift indicates regulators’
growing attention to privacy.
1. Readiness for a more private web. Important privacy improvements have been made and will keep coming to browsers and
to the web platform. Browser vendors are limiting cross-site tracking enabled by third-party cookies, and are actively
combating fingerprinting and other covert tracking techniques. [Safari's ITP](https://webkit.org/blog/9521/intelligent-tracking-prevention-2-3/),
[Firefox's ETP](https://support.mozilla.org/en-US/kb/enhanced-tracking-protection-firefox-desktop),
and [third-party cookie phase-out plans in Chrome](https://blog.chromium.org/2020/01/building-more-private-web-path-towards.html) are a few recent examples.
Besides browser features, changes to the web platform itself are coming: ecosystem actors, browser vendors, and developers are
incubating ideas for new web APIs to replace old ones, and fulfill important use cases in a privacy-preserving way.
All these changes make the web a safer and more private place for users, and they may come with a better developer
experience too! While these changes are improvements, you'll need to take measures to adapt your site or system to them.

## Bear in mind

This course doesn't offer legal advice, and it isn't a checklist. Instead, it lays out code snippets, best practices,
and questions to ask yourself and your team on your privacy journey. Throughout this course, we refer to products or
documentation maintained by third parties to illustrate key points. Your own approach is up to you to define. It will
depend on your organization, your business, and your compliance requirements and users’ needs.

Here's what you'll learn:

{% include 'partials/course-index.njk' %}

Let's get started!

{% Aside %}
This course was written by [Stuart Langridge](https://twitter.com/sil), with input and review from [Maud Nalpas](https://twitter.com/maudnals), Martin Sramek, and [Rachel Andrew](https://twitter.com/rachelandrew). Special thanks to David Adrian for providing additional support for the encryption module, Rainhard Findling for providing additional support for the data module, and Annette McFadyen and [Aaron Forinton](https://github.com/aaronforinton) for supporting the publication process.
{% endAside %}

# Best practices

Over this whole course, certain themes have come up again and again. Protecting your users' privacy involves knowing the minimum
that you need about them, being honest and transparent with what you need and why, and removing what you have as soon as you no
longer need it. You are also responsible for what others are able to do and are allowed to do with your users' data, and that
means that you need to be able to explain honestly and transparently what that is. Any data that you don't need, you should not
have; any data that you do need, you should be able to explain why you need it, and for how long.

In larger organizations, there may be roles or teams dedicated to tracking the latest technical changes in your deployment
environments and browsers, and to understanding the implications for technical and legal changes on your users' privacy.
But a smaller organization still needs to be conscious of user privacy, how a changing environment can affect decisions
already made, and what needs to be taken into account for decisions you make from now on. This module summarizes some
best practices for how you can stay in touch with your privacy choices and requirements, and those of your users.

## Be aware of what you do

The first best practice here is _understanding_. You need to be aware of what you know about your users, and why you know it;
you need to be aware of what your partners know about your users, and how they found it out. This should be a documented part
of your privacy policy. It is difficult and time-consuming to put this list together at first, but more importantly it's also
eye-opening for you and for the business. It can often come as a surprise (and not a nice surprise) just how much data you collect
and store about your users. Documenting it will give you a level of awareness, not just into data collection and privacy, but
into the user experience of your systems and into the underlying software as well. There are frequently dusty corners or
superseded requests which are in need of updating and which have been forgotten about.

### Do

For each piece of data that could be tied to a user, explicitly document:
* A specific list of what it is collected for.
* When it will be deleted (and how it can be deleted by the user, not only by your own team).
* How you collect it.

Ensure that it is gathered only at sufficient granularity to answer these questions alone.

This documentation is for internal use and should be full and complete, but it can be valuable to document this publicly for
users, because it is important to establish an atmosphere of trust. This is not only beneficial in general terms for the
customer relationship, but your users are more likely to volunteer the data you need to make business decisions if they
are confident it will not be misused. This public documentation is linked to your more general privacy policy (in fact,
it will form the great part of your privacy policy), and having this written in a form that your users can understand
(alongside the legal language) helps to build the trust relationship.

## Stay up to date

The second-best practice is to _stay up to date_. This whole industry moves quickly as a general rule, and privacy is a
fast-changing field; staying up to date can itself be a challenge. Technology that's available to you will alter frequently,
but user expectations will also alter just as fast. It is important to not fall behind, and if you can stay ahead, then
there is a real competitive advantage to be had by staking out a position as privacy-preserving. Managing user privacy
and understanding how the industry may be changing may not be all of someone's job, and you do not need to be experts,
but it should be _some_ of someone's job. Dedicate some of the training or conference budget to staying in touch with
industry trends and regulatory updates.

It can be difficult to keep up with changing attitudes and best practices in privacy. There isn't a convenient single
place to go for this. This is partially because privacy protection is a wide-ranging field which impacts on many different
parts of many different industries. But the very topic of how best to protect the privacy of your users and others is heavily
disputed and there are many different and often conflicting approaches. In this course, we have laid out a path to follow
and some best practices, but it will be useful to you to synthesize your own approach as best fits your goals, your
organization's , and your users' needs.  We have compiled a list of resources available for you, your management, and
the team around you to help you stay up to date with changing norms and what currently constitutes the best things to do.

Some privacy changes made by browsers are technical in nature, and need to be understood by dev teams. Consider, for
example, the change to [SameSite](https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite)=Lax
[by default](/samesite-cookies-explained/#changes-to-the-default-behavior-without-samesite) on cookies. This change
affected features on some sites, and so may have needed technical changes. It was announced in advance and trialed before
being finally rolled out. This is a good example of the sort of change that can affect user privacy (in this case, that
change was an improvement) and may also need changes to your apps to correctly deal with.

## Resources

### Browser vendors and web platform developers

For most web development teams, the best places to stay up to date with the latest industry practices on privacy and user protection
are the browser vendors and consumer data protection organizations. For announcements and press releases, this means the various
browser vendor team blogs: a good portion of these are about technologies and things unrelated to privacy, but where there are privacy-related
announcements, they'll show up there:

* Webkit [(https://webkit.org/blog/)](https://webkit.org/blog)
* Chrome [(https://developer.chrome.com/blog/](https://developer.chrome.com/blog/) and [https://blog.chromium.org/)](https://blog.chromium.org/)
* Firefox [(https://hacks.mozilla.org/)](https://hacks.mozilla.org/)
* Edge [(https://blogs.windows.com/msedgedev/)](https://blogs.windows.com/msedgedev/)
* Samsung Developers [(https://developer.samsung.com/blog)](https://developer.samsung.com/blog).

To get a sense of what the browsers plan to implement and to work out their stances on upcoming and proposed APIs that you're thinking of using,
there are status pages and positions pages:

* WebKit [(https://webkit.org/status](https://webkit.org/status) and [https://github.com/WebKit/standards-positions)](https://github.com/WebKit/standards-positions)
* Chrome [(https://chromestatus.com/features](https://chromestatus.com/features) and [https://developer.chrome.com/tags/deprecations/](https://developer.chrome.com/tags/deprecations/) for things being removed)
* Edge [(https://developer.microsoft.com/en-us/microsoft-edge/status/)](https://developer.microsoft.com/en-us/microsoft-edge/status/)
* Firefox [(https://mozilla.github.io/standards-positions/)](https://mozilla.github.io/standards-positions/)

### Privacy organizations

Of course, the browser vendors' positions are only one input to this conversation. There are also organizations pushing
for improving privacy protection over the current state, and it's worth keeping tabs on them. The list is long, but here
are just a few examples:

* The EFF's Privacy issue [(https://www.eff.org/issues/privacy)](https://www.eff.org/issues/privacy).
* The Open Rights Group's digital privacy initiative [(https://www.openrightsgroup.org/category/online-privacy)](https://www.openrightsgroup.org/category/online-privacy).
* IAPP [(https://iapp.org/)](https://iapp.org/).

### Governmental organizations

To keep a closer eye on this whole area, there are also other actors in the field to follow. Governmental organizations'
decisions and their approaches have some of the greatest impact:

* [European Data Protection Board](https://edpb.europa.eu/edpb_en) in the EU.
* [ICO](https://ico.org.uk/) in the UK.
* The [California Privacy Protection Agency](https://cppa.ca.gov/) in California.
* [Data Protection Africa](https://dataprotection.africa/)
* [IAPP's overview of data protection across Asia](https://iapp.org/resources/topics/asia/).

Mainstream media privacy reporting can often focus primarily on "big tech" firms and governmental organizations, which may
seem removed from work done at a smaller company or organization. It's also often very US-centric. But even so, it's useful
to keep aware of what the rules might be in the future, so that you can be prepared, as can the team and the management
structures around you.

It's also worth checking out [Understanding Privacy](https://www.smashingmagazine.com/printed-books/understanding-privacy/),
published in November 2022 by Heather Burns, which gives a really good look at the whole field of data privacy and what you need to
know about it. Recommended!

## Looking inward

Staying up to date also means staying up to date with your own stance. As part of _understanding_ your own software, you will
have conducted audits and reviews of your own data collection and your third-party partners. These audits are not a one-time-only
thing: they should be repeated at regular intervals and kept updated as software changes. It can be useful to mandate that the privacy
audit documentation is kept updated as part of development, just as other technical documentation is. If a new release collects more
data, then updating the privacy audit to include what is collected and why and when it will be deleted is of similar importance
to a new release's APIs being described in the public documentation.

### Do

* Stay up to date with how the industry and user expectations around privacy may be changing over time. It's often the case that someone on a
team is particularly interested in privacy-related topics, even if there isn't the budget or sufficient need for a full-time role. Consider
formalizing this by making privacy an official part of someone's job, with accompanying benefits for the responsibility.
* Make keeping the privacy audit documentation from "Understanding" earlier, part of your documentation process just like API docs are.
* Re-run the audits of which data you collect and which third parties you use, either on a regular basis or when major features change;
test your software as a new user to discover what information is asked for, and add this to the audits.

## Prevent overreach and control access

The third best practice is to _prevent overreach_: that is, to avoid doing more with data than you committed to, and to avoid
speculatively gathering data in case it becomes useful in the future. That involves adapting your processes so that you set the
culture you want around protecting user privacy. Cultural change is difficult, but once accomplished it will largely maintain itself,
which is easier.

### Document your uses

Consider one of the best practices discussed earlier, that of documenting what exactly user data is collected for. This documentation
is important for you to understand what you do and why, but it is equally important to ensure that this rule is obeyed. If
someone suggests using already-gathered data for new analyses, push back on that suggestion, because that's not what the data was
gathered for. This is helped by other aspects of data understanding: that data is only gathered at the lowest acceptable granularity,
and is deleted after being used, because it's impossible to reuse existing data for new analyses if there is no existing data.

### Have processes and rules around handling user data

This can be difficult. It's hard to explain the nature of the user relationship in these situations, when there may be insights
to be gained and nothing preventing that other than a promise previously made. But it's important to consider that the user
entrusted the data to you for a specific purpose, and you (and your team) shouldn't abuse it for something else.
A good approach here is to require some amount of process around access to user data. It is very important to avoid inserting
a mandatory "privacy" component into every working process as a substitute for actually caring about the issue, because it
can quickly become a "checkbox" feature that everybody ignores (and nobody likes more paperwork, especially if it's paperwork
that nobody reads).

### Make avoiding overreach be the path of least resistance

But there is a chance to use the annoying nature of bureaucracy slightly for your own benefit here! If mining existing
collected data requires filling out a "privacy request" where the new analysis is justified and recorded, then projects
which don't really need that access are quite likely to avoid it in order to avoid the bureaucracy, or in order to
avoid being named on the paperwork. You may already have policies in place around the security of user data: saved
account details are restricted and not available to employees without justification. Consider tying privacy requirements
to these existing policies. If there's some consideration of user privacy built into your processes at an early stage,
that consideration can quickly become a routine part of planning. It's vital that architects, developers, and marketing
do not see privacy protection as an onerous externally imposed restriction, but as a core part of the customer relationship.

### Pushing back with alternatives, not stop energy

With the preceding best practices in place, you will have gathered user data for only specific and measurable aims, and your
user base will have been informed of those aims and understand them. However, you will also have a large collection of user
data, and it's quite common that the business will seek to use that data for reasons other than those for which it was gathered.
It's your goal to push back on those uses, but it's important to do so by providing alternatives. Imagine that you've requested
that your users provide an age bracket that they fall into: 18-25, 25-35, 35-50, 50+. You did this in order to measure
which types of products are most bought by different age brackets, and you explicitly informed users that's why their age
was requested. If someone then suggested that they could use that data to send advertising email to every user under 25,
that's a new and undeclared use for existing data, and so isn't allowed. But your intention here should be to find a way
of meeting the business need without using data for things that weren't declared. If you push back on this without proposing
any alternative, then user privacy will start to seem like the externally imposed restriction warned against earlier,
rather than a core part of why your users trust you. As much as possible, avoid adding stop energy to processes: the only
thing worse than a bald "computer says no" is "internal regulator says no". Instead, consider other ways you could meet
that goal without using users' personal data to do it: perhaps use the list of products purchased as a guide for who to
email, or avoid targeted distribution entirely. Help your team understand why your users trust you, and what that trust
is founded upon, and then help them do what they want and what your users want. Make privacy work for you.

### Do

* Require a (short, simple) written justification from a named employee for access to user data.
* Add user privacy requirements as early as possible in your processes.
* Avoid adding privacy concerns as a mandatory "checkbox" feature.
* Enforce the deletion of data as defined earlier.
* Help the rest of the team understand how to achieve their goals without compromising your users' privacy.

# Use just the data you need

A good way to mitigate risk for users is to not hold sensitive data about them that you do not need that impacts their privacy.
There are a surprising number of ways to do this while still meeting your business goals, and it is worthwhile to consider each.
You might:

* Explain what you need the data for.
* Collect data at lower granularity.
* Remove data once used.
* Not collect it in the first place.

Each of these approaches can help your users feel more comfortable with what you're doing and why, and this contributes greatly
to your relationship with them. Transparency builds trust, and importantly, trust can be a unique selling point for you. Many people
assume that users and customers trust them by default, but consumers are constantly evaluating products and services and this may
not be the case. If you build a relationship with your users where they trust you to handle their data and your interactions
with respect, it can deliver a competitive advantage to you as a project or a business: it is something that your rivals may
not match, a genuine differentiator.

Let's unpack the above approaches, in order of most effective (but also most impactful on your business) to least effective
but least disruptive to implement.

## Don't collect it in the first place

The most obvious way to avoid compromising your users' data is to not collect it. Some data collection is necessary to provide services,
but there are more places where you can avoid data collection than you might think. Consider, for example, guest checkout.
When users come to purchase something using your web app, you might require them to sign up for an account, because then
you've captured personal details for later fulfillment: they can be added to the mailing list, they're already pre-qualified
as an interested customer, and so on. However, customers recognise this, and don't like it:
[in 2021, a study found that one out of  four abandoned sales](https://baymard.com/lists/cart-abandonment-rate) was because
the site demanded that the user create an account. If you don't require an account, you're more likely to keep those customers.
Making it possible to [complete a purchase without signing up](/payment-and-address-form-best-practices/#guest-checkout) gives
users better options and also means you don't have as much of their data to protect and secure.

## "Fuzz" your data

Of course, avoiding collecting data at all may not be an option. It is important to collect data to provide services and make
sensible business decisions. It can also be helpful to build marketing communications in the context of a trusting relationship.
However, it's also important to realize that decisions made in aggregate (that is, which affect many users at once) are made
about data in aggregate (that is, about collective properties of the data).

For example, it is sometimes useful to have a sense of the demographics of your audience: which age brackets they fall into,
location, and so on. This may change your messaging or your approach. But this does not mean that you need to collect the exact
age for every user of your service. What you're often looking for are trends and overall properties. If the decision you wish to
reach is affected by whether most of your audience is in the "18-34 key demographic", then the only question you actually need
to ask  is whether your users are in that demographic. This collects them into two "buckets": in that group and not in that group.
There may be situations where you need more granular data than that, but it's entirely reasonable to take the list of demographics
you use to make decisions and ask your users to classify themselves with that list.

### Example

So, if it is useful to know how your user base divides up between the age categories "18-34", "35-49", "49-64", and "65+",
then you can ask your users to choose which of those categories they fall into. It is tempting to ask for extremely granular,
personal and personalized data, and then classify your users yourself, as this avoids needing to ask the same question again in
more detail later; for example, to ask for an exact age and date of birth, and then use this to produce your own lists of how
many users are in the "35-49" category. But it's important to realize how this looks: as the course has already covered and
will cover again, asking for detailed levels of data can make people uncomfortable and so reduces user trust in your organization,
while adding risk.

It's also important to consider your data needs. Sometimes, the "need" for more granular data is speculative, a "just in case"
requirement. Maybe we only need to classify users into those four age groups right now, but in the future we might want to
narrow that down, and therefore we should collect very detailed data now to keep that option open for later. It may be worth
considering how often the more granular data has actually been used in the past to guide decisions. Asking for data that is
perceived as invasive relative to the service being offered necessarily results in a decrease in how much your users trust your
organization. If that data is being gathered for “just in case” reasons, then you may not just be trading away user trust for
improved business decisions but trading it away merely for the possibility of some theoretical future decision that may
not even exist, while also taking on security requirements for that information.

There are more detailed algorithmic ways to reduce the granularity of collected data as well. [Randomized response methods](https://en.wikipedia.org/wiki/Randomized_response)
mean that the data is gathered with a tuneable degree of inaccuracy, and these have been used for decades in the social
sciences when collecting potentially invasive or sensitive data while maintaining the responder's confidentiality. The
above method of data gathering involves widening the user's answers (so "how old are you" becomes
"which one of the following age groups do you fall into"), where randomized response involves having a certain proportion
of users lie about their answers. If the proportion of users who respond incorrectly is known, then meaningful conclusions
can still be drawn from the gathered data, but individual user's privacy is not compromised because their collected data may
be incorrect. In this case, if 80% of your audience still state that they fall into the 18-34 demographic, you can be
relatively confident that this is still the largest share, even if 10% of them are deliberately giving incorrect answers.
The degree of incorrectness can also be altered programmatically, where correct answers are always solicited but the
software alters a certain percentage of answers before transmitting.  This process and the consequences of it can also
be explained to users when data is gathered: it means that the users do not have to trust that you will not abuse their
collected data, because individual data is unreliable.

A similar but more technically involved process is [_differential privacy_](https://en.wikipedia.org/wiki/Differential_privacy).
This uses mathematical techniques to alter data storage so that aggregate properties of the data are still present, but
it is not possible to even tell whether a particular individual even provided data, or which if any data they provided.
Like randomized response, this protects users' data even from you and demonstrates clear intent on your part:
you can't use your users' data if you don't have that data.

These and similar approaches also provide increased security against data breaches and leaks, because the collected data
reduces compromises to user privacy, even to you, and will also reduce the level of compromise if the data is leaked.
Remember, though, that if you're applying differential privacy techniques on the server (so your users are sending you
unaggregated data and then you use the techniques to aggregate it), you still need to secure that raw user data and
then delete it after processing, and should have and follow clear policies to confirm that you're not using it before
aggregation (or are clear about what you are using it for).

## Retention: collect data and then remove it once used

It's useful to remember that collected data has a lifecycle; it's collected, it gets used to help you make business decisions,
and then, at some point, it should be removed. These are, again, trade offs: when you ask your users questions, or you
store information about other websites they've visited, or you track which things they looked at and for how long in order
to make predictions about their preferences, this is the data which is being granted to you for a specific purpose-not as
an open-ended grant for the developer to use as they see fit. When that data is no longer needed for that purpose-sometimes
after a minute, sometimes after many years-it should be deleted.

Whenever you gather information about your users, you should know what you'll be using that data for (see below) and you should
also know when and why you will stop holding that data. This might be when the user chooses to delete it, or when they sign
out, after a specific time period, or after a specific event takes place. An excellent way to build trust in the relationship
is to make it clear to your users how they can control data about them, including, wherever possible, a unilateral opt-out.
How do they delete their data? How do they delete their account? In addition to helping to build that relationship, it is best
practice to store data for as long as you need to process it and not longer, and that there should be a way for your users to
see and remove data you collect from them or on their behalf. There may even be legislation on this point in territories in
which you operate.

This is an area where you can define clear technical goals, which helps users with self-service; if your users can opt out of
your data warehouse without having to ask permission then they can feel much more comfortable with opting in, and it doesn't
take any support resource to do so.

It's important to recognise the importance of easy and default opt outs: "To build trust and recognition, companies can
start by agreeing to a social contract where they commit to respecting their audience at each and every touchpoint,
listening to their needs, and responding accordingly", states [IAPP](https://iapp.org/news/a/opt-in-opt-out-consent-is-what-its-all-about/).
[The Nielsen Norman Group says](https://www.nngroup.com/articles/ten-usability-heuristics/) that users "need a clearly marked
'emergency exit' to leave the unwanted action without having to go through an extended process". Everyone is aware that it's
easier to subscribe than to unsubscribe. But, as Nielsen Norman says, giving users the ability to walk away without having to
jump through hoops, "fosters a sense of freedom and confidence". Academic studies back this up and name it the "principle of
revocability", stating: "The interface should allow the user to easily revoke authorities that the user has granted wherever
revocation is possible. Users should be able to revoke such consent and therefore reduce authorities to access their resources
if possible." (See [Yee](http://zesty.ca/pubs/csd-02-1184.pdf) and [Iacono](https://www.researchgate.net/profile/Luigi-Lo-Iacono/publication/326107790_Consolidating_Principles_and_Patterns_for_Human-centred_Usable_Security_Research_and_Development/links/5bb79798a6fdcc9552d45f77/Consolidating-Principles-and-Patterns-for-Human-centred-Usable-Security-Research-and-Development.pdf) for examples.)

How long to retain data for, and which data to retain, is a subject which differs a great deal between organizations and
between projects, but there are some common guidelines to consider.

### Do

It is useful here to allow users to delete accounts (and any associated data, where it is possible to do so) and to regularly (for example, on sign out)
clear ephemeral and locally stored data on sign-out with the [Clear-Site-Data](https://developer.mozilla.org/docs/Web/HTTP/Headers/Clear-Site-Data) header.

Supply a `Clear-Site-Data` header to remove some or all user data which has been stored client-side (whether in cookies,
localStorage or IndexedDB, or in the browser cache), when reasonable. The obvious use-case for Clear-Site-Data is when a user
logs out, but it can also be used after security incidents to ensure that a potentially compromised account has no lingering traces
of compromised data stored on the client.

Adding support for `Clear-Site-Data` involves sending an HTTP header, `Clear-Site-Data`, when the user signs out (or at other
times when you wish to clear client-side storage), on the page which confirms the logged-out status (`https://your-site/logout`
or similar). This header can have some or all of the following values, or `"*"` for all:

```html
Clear-Site-Data: "cache", "cookies", "storage"
```

These values clear, respectively, cached pages (and other HTTP-cached resources), stored cookies, and localStorage and IndexedDB and similar.
You may see reference to another option, `executionContexts`, but this is not supported [by many browsers](https://caniuse.com/?search=executionContexts).
Note that using the `Clear-Site-Data` header is likely to be easier than individually deleting all created resources yourself, because it does not require JavaScript code to be
run on the client (and it is the only official way to clear the browser cache), but is [not supported by all browsers](https://caniuse.com/?search=clear-site-data).

Usage note: If you're clearing the cache (by sending `Clear-Site-Data: cache`), then the `Clear-Site-Data` header should not be
sent on your actual sign-out page, but on some other resource that that page loads. This is because on a slower computer
with a large cache, the page will block while it clears the cache and this prevents navigation. This can take minutes to do,
which will frustrate the user. It is unlikely to happen, but is difficult to test for and thus it is best practice to bear this in mind.

## Explain what you need the data for

The importance of trust in your users' relationship with your service has been stated repeatedly, because it increases user longevity.
It also provides competitive advantage.  One way to increase that level of trust is with transparency into your processes, and a
good way to be transparent is to explain what you want data for. You learned earlier that for each thing collected you should know
when that thing will be deleted. In order to know that, you need to know why you want this data, which specific questions need it in
order to find answers, and which decisions will be guided by collecting it. Once you know why you need this data that you've asked your
user to give up, it will help to build trust by explaining that to those users. In your privacy policy, or when asking questions on account
creation, describe why you need the answer to this particular question, what you'll do with that data, and when and how it can be removed.

These explanations are much more visible when presented inline. Burying explanations in a dense policy document elsewhere on the website
can seem like an attempt to hide them. A sign-up, checkout, or request form can present the reasons to collect data alongside the collection
itself. Often, a form field may have an asterisk (*) to indicate that a field is required; complicated forms often have an information link
(i) to explain what the field means. Consider adding to these explanations a description of why the data is being collected. A frequently
used phrase for this is "Why do we need this?" next to a form field, which when clicked shows a pop-up explanation.

Some example HTML might look as follows, and then CSS and JavaScript would take care of hiding the `<aside>` and showing it as a pop-up when
the link is clicked. (Be sure to [confirm the accessibility of the form you make for your site](/learn/forms/accessibility)!)
Exactly how to lay this out is dependent on your styles and approaches, but the main point here is to directly associate data collection with
an explanation for why that data is being collected. This isn't necessary for every field. Nobody needs an explanation of why you require them to
choose a password at sign-up. But decorating each request for personal and contact information with how you plan to use it and keep it can help
make it clear to your users that you're invested in protecting their data.

```html
<div>
	<label for="email">Email address*</label>
	<input id="email" type="email" name="email" required aria-describedby="whyemail">
	<a href="#whyemail">Why do we need this?</a>
	<aside id="whyemail">We need this information as a unique identifier for you, and if you forget your password we can send you a reminder. We will use your email address to send you regular updates on the service if you choose, and will delete your email address from any mailing lists if you delete your account.</aside>
</div>
```

Going through this process with everything you collect about a user can also help with internal processes and discussions.
Earlier, you saw how there can be a temptation to collect data "just in case". When you are transparent about your reasons
for collecting, it can be quite obvious that this is happening. If you are reluctant to write down publicly what you want
to do with user data because those users won't like the explanation, this may be a sign that it is worth rethinking collecting
it. This applies whether the distasteful explanation is too invasive ("we will use this to track where you visit on an hourly basis"),
too wide-ranging ("we don't know what we'll use this for yet but we want it in case we think up something for it"), or too evasive
("we will use this for internal undisclosed purposes"). This is not simply a question of morality; people are savvy enough to
recognise this, as already described, and there is a user expectation that experimenting with something is not the beginning
of a long-term commitment. It is a commonplace of user experience design to make sign-up as friction-free and easy as possible,
because at early stages the user is (by definition) not heavily invested in your service, and so it is important to allow
them to become more invested easily when they yet have little inclination to do so. If it is as easy to leave again, then
experimenting with the service becomes exactly experimentation and not the unwilling start of a forced long-term commitment.
As before, it is paradoxical but true that the best way to build trust is to not require your users to trust you if they do
not want to.

People have good reasons for not sharing data, or for sharing minimal data. At the beginning of your relationship with them, they
might not have a reason to trust you, and should not have to. Your goal is to demonstrate why they should.

### Do

* Decide for all the data you plan to collect why you want it and how long you'll keep it for.
* When you ask for that data, explain to your users why you are collecting it.
* Delete it from your server databases after you've used it.
* Allow users to delete accounts that they have created and clear stored data from their storage with the `Clear-Site-Data` header.

### Why

Building a relationship with your users is about trust, and trust is about openness. If you can demonstrate that you're not
just collecting as much data as possible about your users and concealing your uses for it, then that helps to build trust, which can
be a competitive advantage for you over less scrupulous rivals.

# Encryption

Encryption is often a topic for security, but it's important for privacy too. The goal of encryption is to prevent others
from reading the encrypted information… but preventing others from reading your information is one way to keep it private.
A user is often limited in how much they can do that themselves, but with your assistance as provider of a service they're using,
encryption can help to keep their data theirs.

There are three relevant ways to apply encryption to aid user privacy: encryption in transit, encryption at rest,
and encryption end-to-end:

* **Encryption in transit** is keeping data encrypted between the user and your site: that is, HTTPS. You probably have HTTPS
set up for your sites already, but are you sure _all_ the data in transit to your sites is encrypted? This is what redirection
and HSTS are for, and they are described below and should be part of your HTTPS setup.
* **Encryption at rest** is the encryption of data stored on your servers. This protects against data breaches and is an
important part of your security stance.
* **End-to-end encryption** is the encryption of data on the client before it ever reaches your server. This protects
user data even from you: you can store your users' data, but you can't read it. This is difficult to implement, and isn't
suitable for all types of application, but it's a strong aid to user privacy, because nobody can see their data other than themselves.

## HTTPS

The first move is serving your web service over HTTPS. It is very likely that you will have already done this, but if not it
is an important step. HTTPS is HTTP, the protocol that a browser uses to request web pages from a server, but encrypted using SSL.
This means that an outside attacker can't read or interfere with an HTTPS request in between the sender (your user) and the
recipient (you), because it's encrypted and so they can't read it or change it. This is encryption in transit: while data is
moving from user to you, or from you to user. HTTPS encryption in transit also prevents the user's ISP, or the provider of
the Wi-Fi they're using, from being able to read the data they're sending to you as part of their relationship with your service.
It may impact your service's features, too: many uses of existing JavaScript APIs require the website to be served over HTTPS.
[MDN](https://developer.mozilla.org/docs/Web/Security/Secure_Contexts/features_restricted_to_secure_contexts) has a more comprehensive list,
but APIs gatewayed behind a secure context include service workers, push notifications, web share and web crypto, and some device APIs.

To serve your website over HTTPS you will need an SSL certificate. These can be created for free via [Let's Encrypt](https://letsencrypt.org/),
or can often be provided by your hosting service if you are using one. It is also possible to use a third-party service which "proxies" your
web service and can provide HTTPS, as well as caching and CDN services. There are numerous examples of such services, such as Cloudflare
and Fastly—exactly which to use depends on your current infrastructure. In the past, HTTPS could be burdensome or expensive to implement,
which is why it tended to be used only on payment pages or particularly secure origins; but freely available certificates, standards improvements,
and greater proliferation of browsers have removed all those obstacles.

### Do

* Enable HTTPS on your servers for everything (whichever method you choose).
* Consider using a proxy in front of your servers, such as Cloudflare ([httpsiseasy.com/](https://httpsiseasy.com/) explains the process).
* [Let's Encrypt](https://letsencrypt.org/) will walk you through the process of creating your own Let's Encrypt SSL certificate.
* Or use OpenSSL directly to create your own certificate and have it signed by your choice of certificate authority (CA)
([Enable HTTPS](/enable-https/) explains how to do this in detail).

Which approach you choose depends on business tradeoffs. Having a third-party manage the SSL connection for you is the easiest to set up,
and does come with other benefits such as load balancing, caching, and analytics. But it also comes with an obvious ceding of some control
to that third-party, and an unavoidable dependency on their services (and possible payment, depending on the services you use and your traffic levels).

Generating certificates and having them signed by a CA is how the SSL process used to be conducted, but using Let's Encrypt can be easier if it's
supported by your provider or if your server team is technically adept enough for it, and it's free. It's also common for your provider to offer
SSL as a service if you're using something at a higher level than cloud hosting, so it's worth checking.

### Why

Security is a part of your privacy story: being able to demonstrate that you keep user data secure against interference helps
to build trust. If you don't use HTTPS, your sites are also flagged as being "not secure" by browsers (and have been for some time).
[Existing JavaScript APIs are often only available to HTTPS pages ("secure origins")](https://developer.mozilla.org/docs/Web/Security/Secure_Contexts/features_restricted_to_secure_contexts).
It also protects your users against their [web usage being seen by their ISP](https://spreadprivacy.com/protection-from-isp-spying/).
This is certainly a best practice; there's little to no reason to not use HTTPS for websites now.

## How browsers present an HTTP (not secure) page

<figure>
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/rs1XOzYuZ0L44DUGijUp.png", alt="Chrome desktop URL warning 'Not Secure'.", width="524", height="235" %}
<figcaption>Google Chrome (desktop)</figcaption>
</figure>
<figure>

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/V4JrNHQB0JRUVQAgljna.png", alt="Firefox HTTP URL warning.", width="543", height="307" %}
<figcaption>Mozilla Firefox (desktop)</figcaption>
</figure>
<figure>

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/U1fIa4q2ng68Olf3Zdy7.png", alt="Safari desktop HTTP URL warning.", width="800", height="166" %}
<figcaption>Apple Safari (macOS desktop)</figcaption>
</figure>
<figure>

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/KlN1Zd15tQxFnfLTNDgI.png", alt="Android mobile HTTP warning.", width="800", height="168" %}
<figcaption>Google Chrome (Android mobile)</figcaption>
</figure>
<figure>

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/VPffgyq9or8mPbxO2Bwp.png", alt="Apple Safari iOS HTTP warning.", width="800", height="397" %}
<figcaption>Apple Safari (iOS mobile)</figcaption>
</figure>

## Redirect to HTTPS

If your site is available on both http: and https: URLs, you should redirect all http URL accesses to https. This is for
the reasons above, and it also ensures that your site won't show up on [whynohttps.com](https://whynohttps.com/) if it becomes popular.
How to do this depends a great deal on your infrastructure. If you're hosted on AWS you can use a [Classic](https://aws.amazon.com/premiumsupport/knowledge-center/redirect-http-https-elb/)
or [Application](https://aws.amazon.com/premiumsupport/knowledge-center/elb-redirect-http-to-https-using-alb/) load balancer.
[Google Cloud](https://cloud.google.com/load-balancing/docs/https/setting-up-http-https-redirect) is similar. In Azure you can
create a [Front Door](https://docs.microsoft.com/en-us/azure/frontdoor/front-door-how-to-redirect-https); in Node with Express
[check for request.secure](https://docs.divio.com/en/latest/how-to/node-express-force-https/); in Nginx
[catch all port 80 and return 301](https://serversforhackers.com/c/redirect-http-to-https-nginx); and in Apache,
[use a RewriteRule](https://www.ssl.com/how-to/redirect-http-to-https-with-apache/). If you're using a hosting service,
it's quite likely that they'll automatically handle redirecting to HTTPS URLs for you: Netlify, Firebase, and GitHub Pages do,
among many others.

## HSTS

HSTS is short for "HTTP Strict-Transport-Security", and is a way of locking a browser into using HTTPS for your service forevermore.
Once you're happy with your migration to HTTPS, or if you've already done that, then you can add a
[Strict-Transport-Security HTTP response header](https://developer.mozilla.org/docs/Web/HTTP/Headers/Strict-Transport-Security) to your
outgoing responses. A browser which has accessed your site before will record having seen this header, and from then on will automatically
access this site as HTTPS even if you request HTTP. This avoids going through your redirect as above: it's as if the browser silently "upgrades"
all requests to your service to use HTTPS.

Similarly, you can serve an [Upgrade-Insecure-Requests](https://developer.mozilla.org/docs/Web/HTTP/Headers/Upgrade-Insecure-Requests)
header along with your pages. This does something different from but related to `Strict-Transport-Security`. If you
add `Upgrade-Insecure-Requests: 1`, then requests from this page to other resources (images, scripts) will be requested
as https even if the link is http. However, the browser will not re-request the page itself as https, and the browser will
not remember for next time. In practice, Upgrade-Insecure-Requests is useful if you're converting an existing site with
lots of links to HTTPS and converting the link URLs in content is hard, but it's better to change the content where possible.

HSTS is primarily a security feature: it "locks" your site to HTTPS for users who have been there before. However,
as above, HTTPS is good for privacy, and HSTS is good for HTTPS. Similarly, Upgrade-Insecure-Requests isn't really needed if
you're updating all your content, but it is a useful “belt-and-braces” approach to add defence in depth in ensuring that
your site will always be HTTPS.

### Do

Add the HSTS header to your outgoing responses:

`Strict-Transport-Security: max-age=300; includeSubDomains`

The max-age parameter dictates how long, in seconds, the browser should remember and enforce the HTTPS upgrade.
(Here we set it to 300 seconds, i.e, five minutes.) Eventually you would want this to be 6,3072,000, which is two years,
and is the figure that [hstspreload.org](https://hstspreload.org/) recommends, but it is quite difficult to recover
if there are issues. So it is recommended that you set this with a low number at first (300), test to confirm nothing
has broken, and then increase the number in stages.

Add the `Upgrade-Insecure-Requests` headers to your outgoing responses:

`Upgrade-Insecure-Requests: 1
Content-Security-Policy: upgrade-insecure-requests`

{% Aside %}
**Should I add HSTS/UIR headers and add redirects?**
Yes. You should redirect http URLs to https, and continue to do so even after HSTS is in place—it's important to do both.
It's a best practice anyway ([https://web.dev/redirects-http/](/redirects-https/) explains) but it's also required in
order to be added to the automatic preload list (see [https://hstspreload.org](https://hstspreload.org) for more details).
{% endAside %}

## End-to-end encryption

A good way of keeping user data private is to not show it to anyone other than the user, including you. This helps a lot with
your trust stance: if you don't have your user's data then it is clear that you can't do anything with it that they would
not want. One way to do this is to not let user data leave their device at all, by storing everything client-side. This
approach works, but there are limitations to a pure client-side application: browser data storage can be limited in size,
and in some browsers may be cleared with little or no warning. It's also difficult or impossible to access your data
across two devices, such as a laptop and a mobile phone. For this reason, it can be useful to send data to the server
as normal, but encrypt it with a key known only to the user, so that the server cannot access it (because it can't decrypt it)
but can store it.

### How does it work?

This approach is frequently used by messaging applications, where it's referred to as "end-to-end encryption", or
"e2e". In this way, two people who know one another's keys can encrypt and decrypt their messages back and forth,
and send those messages via the messaging provider, but the messaging provider (who does not have those keys) can't
read the messages. Most applications are not messaging apps, but it is possible to combine the two approaches—a solely
client-side data store, and data encryption with a key known to the client—to store data locally but also send it encrypted
to the server. It is important to realise that there are limitations to this approach: this isn't possible for all services,
and in particular it can't be used if you, as the service provider, need access to what the user is storing. As described
in [part 2](/learn/privacy/data/) of this series, it is best to obey the principle of data minimisation; avoid collecting data at all if you can.
If the user needs data storage, but you do not need access to that data to provide the service, then end-to-end encryption
is a useful alternative. If you provide services which require being able to see what the user stores to provide the service,
then end-to-end encryption is not suitable. But if you do not, then you can have the client-side JavaScript of your web
service encrypt any data it sends to the server, and decrypt any data it receives.

### An example: Excalidraw

[Excalidraw](https://blog.excalidraw.com/end-to-end-encryption/) does this and explains how in a blog post. It is a vector
drawing app that stores drawings on the server, which are encrypted with a randomly chosen key. Part of the reason that
Excalidraw can implement this end-to-end encryption with relatively little code is that cryptographic libraries are now built
into the browser with [window.crypto](https://developer.mozilla.org/docs/Web/API/SubtleCrypto/encrypt), which is a set
of JavaScript APIs [supported in all modern browsers](https://caniuse.com/cryptography). Cryptography is hard and implementing
the algorithms comes with many edge cases. Having the browser do the heavy lifting here makes encryption more accessible to
web developers and therefore makes it easier to implement privacy via encrypted data. As Excalidraw describes in their writeup,
the encryption key remains on the client-side, because it's part of the URL fragment: when a browser visits a URL
`https://example.com/path?param=1#fraghere`, the path of the URL (`/path`) and the parameters (`param=1`) are passed to the server
(`example.com`), but the fragment (`fraghere`) is not, and so the server never sees it. This means that even if the encrypted
data goes through the server, the encryption key does not and thus privacy is preserved because the data is end-to-end encrypted.

### Limitations

This approach to encrypting user data is not foolproof. It contributes to your trust stance for your users but it cannot fully
replace it. Your users will still have to trust your service, because you could, at any moment, swap out client-side JavaScript
for some subtly similar JavaScript that does not impenetrably encrypt data; and although it is possible as a user to detect
whether a website you're using has done that, it's extremely difficult to do so. In practice, your users will still need to
trust that you will not deliberately read and abuse their data while promising to not do so. However, demonstrating that data
is encrypted and not readable by you as a (not malicious) service provider can contribute a lot to demonstrating why you are trustworthy.

It's also important to remember that one of the goals of end-to-end encryption is to stop you, the site owner, from being able
to read the data. This is good for privacy, but it also means that if there are problems, you can't help. In essence, a service
using end-to-end encryption puts the user in charge of the encryption keys. (This may not be obvious or overt, but someone has
to have the key, and if data is kept private from you, then that's not you.) If those keys are lost, then there will be nothing
you can do to help, and probably any data encrypted with those keys may also be lost. There is a fine balancing act here
between privacy and usability: keep data private from everybody using encryption, but also avoid forcing users into having
to be cryptology experts who manage their own keys in a secure manner.

## Encryption at rest

As well as encrypting your users' data in transit, it's also important to consider encrypting data that you have stored on the server.
This helps to protect against data breaches, because anyone who obtains unauthorised access to your stored data will have encrypted data,
which they will hopefully not have the keys to decrypt. There are two different and complementary approaches to encrypting data at rest:
encryption that you add, and encryption that your cloud storage provider adds (if you're using a cloud storage provider).
The storage provider encryption doesn't provide much protection against data breaches via your software (because storage provider
encryption is usually transparent to you as a user of their service), but it does help against breaches that happen at the provider's
infrastructure. It's often simple to turn on and so is worth considering. This field changes rapidly and your security team (or
security-savvy engineers on your team) are the best to advise on it, but all cloud storage providers offer encryption at rest for
block storage [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html) by setting,
[Azure Storage](https://docs.microsoft.com/en-us/azure/storage/common/storage-service-encryption), and
[Google Cloud Storage](https://cloud.google.com/storage/docs/encryption) by default, and for database data storage
[AWS RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html),
[Azure SQL](https://docs.microsoft.com/en-us/azure/azure-sql/database/transparent-data-encryption-tde-overview?view=azuresql&tabs=azure-portal),
[Google Cloud SQL](https://cloud.google.com/docs/security/encryption/default-encryption) among others. Check this out with
your cloud storage provider, if you're using one. Handling encryption of data at rest yourself to help protect user data
from data breaches is more difficult, because the logistics of securely managing encryption keys and making them available
to code without also making them available to attackers is challenging. This isn't the best place to advise on security issues at
that level; talk with your security-savvy engineers or dedicated team about this, or external security agencies.

# Fingerprinting

Fingerprinting means trying to identify a user when they return to your website, or identifying the same user across different websites.
Many characteristics may differ between your setup and someone else's. For example, you may be using a different type of device
and a different browser, have a different screen size, and have different fonts installed. If I have the font "Dejavu Sans"
installed and you do not, then any website can tell the difference between you and me by checking for that font. This is how
fingerprinting works; you build up a collection of these data points, and each provides more ways to distinguish between users.

A more formal definition might look like this: Fingerprinting is the action of using obvious and non-obvious long-lived
characteristics of a user's setup to attempt to distinguish them from as many other users as possible.

## Why fingerprinting hinders user privacy

There are some edge cases where fingerprinting a user is important: fraud detection, for example. But fingerprinting can also
be used to track users across sites, and that tracking is often done without users consenting to it, or, in some cases, on the basis
of an invalid consent that does not adequately inform the user. When that's done, those users will often find this  somewhat
disquieting and feel rather betrayed.

Fingerprinting means finding ways to covertly distinguish one user from another. Fingerprinting can be used to recognize that
it's still the same user on the same website, or to recognize the same user in two different browser profiles at the same time.
This means that fingerprinting can be used for tracking users across sites. The deterministic and overt methods of tracking,
such as storing a cookie with a unique user-specific ID, can be to some extent observed by users and controlled
(and the previous module explained some of these approaches). But fingerprinting is more difficult to avoid exactly
because it is covert; it relies on unchanging characteristics and most likely happens invisibly. This is why it's called
"fingerprinting". It is difficult at best to change your fingerprint, whether your digital one, or the ones on the ends
of your fingers.

Browser vendors _know_ that users do not like being tracked, and are continually implementing features to limit fingerprinting
(some of which we saw in the previous module). Here, we're looking at how these features may affect your business
requirements and how to still do what you want to do in a privacy-protecting way. This is more about how browser protection
_against_ fingerprinting will affect what you do and how, rather than about how it will stop you _doing_ fingerprinting.

In practice, most developers and most businesses have no need to fingerprint users. If your app requires users to sign in,
then your users are identifying themselves to you, with their consent, and in a way that they can unilaterally opt out of
at any time they choose. This is a privacy-protecting method of understanding which users are logged in. Your app may not
require users to sign in at all, which is even more protective of your users' privacy (and you are then collecting
[just the data you need](/learn/privacy/data/)).

### Do

Assess your third parties for fingerprinting. As part of the [third parties](/learn/privacy/third-parties) module, you
may already have a list of any third-party services you're including and the web requests that they make. It may be possible
to inspect those requests to see which data is being passed back to the originator, if any. However, this is often difficult;
fingerprinting is by nature a covert process which involves requesting data that isn't subject to user approval.

It's worth also reading the privacy policies of your third-party services and dependencies to look for indications of fingerprinting
in use. It's sometimes referred to as "probabilistic matching", or as part of a suite of probabilistic matching techniques,
as opposed to "deterministic matching".

## How fingerprinting works

It can be helpful to look at [https://amiunique.org/](https://amiunique.org/) and the [EFF's Cover Your Tracks](https://coveryourtracks.eff.org/)
for an example of fingerprinting. Each will attempt to show you the characteristics of your personal browser setup which
may differ from other people's setups. Frequently your personal combination of all these attributes is unique to you, or at
least to a small group of similar people; this can be used to covertly track you. These websites aren't the whole story,
and any uniqueness estimates are often how distinguishable you are among their visitors (who skew more technical and more
privacy-focused) rather than among the whole internet, but the principles are sound.

### Aside: passive and active fingerprinting

There is a useful distinction here to be drawn between passive and active fingerprinting techniques. A passive fingerprinting
technique is one which uses information that is given to the website by default; an active fingerprinting technique is one
which explicitly interrogates the browser for extra information. The reason this distinction is important is that browsers
can attempt to detect and intercept, or mitigate, active techniques. APIs can be restricted, or gatewayed behind a dialog
asking the user's permission (and therefore alerting the user that they're being used, or allowing the user to deny them
by default). A passive technique is one which uses data that's already been given to the website, often because historically,
in the nascent days of the information superhighway, that information was given to all sites. The user-agent string is an
example of this, and we'll look at this in more detail further on. It was considered useful in providing quite a lot of
information about the user's browser, version, and operating system, in order that a website could choose to present different
things based on that. However, this also increases the amount of distinguishing information made available, information
which helps identify one user from another; and so such information is increasingly no longer available, or at least frozen
so that it is no longer distinguishing. If what you do relies on this information—for example, if you're taking different
code branches depending on the user-agent—then this code may break as browsers increasingly freeze or stop that information.
Testing is the best defence here ( see later).

### Aside: measuring fingerprintability

The technical measure for how much information each of these data points provides is called _entropy_ and is measured in bits.
A feature where there are many different possible values (such as the list of fonts installed) can contribute a lot of bits
to the total, whereby something without much distinguishing power (such as which operating system you're using) may only add
a few. The [HTTP Almanac](https://almanac.httparchive.org/en/2021/privacy#fingerprinting) describes how existing fingerprinting
libraries automate this process of combining the responses from many different APIs into a "hash", which may identify only a
small group of users, perhaps even only one. Maud Nalpas covers this in some detail in
[this YouTube video](https://www.youtube.com/watch?v=0STgfjSA6T8&t=278s), but, in short, imagine that you were to see
a list of your friends with their favourite music, favourite food, and the languages they speak … but with their names
removed. It is quite likely that any one person's list will uniquely identify them among your friends, or at least narrow
down the list to only a few people. This is how fingerprinting works; the list of things you like becomes the "hash". With
that hash, identifying a user as the same person on two different unconnected sites becomes easier, which is the goal of
tracking: to circumvent the user's desire for privacy.

## What do browsers do against fingerprinting?

Importantly, browser vendors are very aware of many different ways for a website (or a third party included on a website)
to calculate a distinguishing fingerprint for a user, or for differing bits of information to contribute to the uniqueness
of that fingerprint. Some of these ways are explicit and deliberate, such as the browser's user-agent string, which often
identifies the browser, operating system, and version in use (and so contributes to distinguishing you from me, if you and
I are using different browsers). Some of the ways are not deliberately created to be fingerprintable but end up being so
anyway, such as the list of fonts, or video and audio devices available to the browser. (The browser doesn't have to _use_
these devices, just get a list of them by name.) And some have been established to be contributors to a fingerprint well
after release, such as the [exact pixel rendering of antialiasing of fonts on a canvas element](https://browserleaks.com/canvas).
There are many more, and each way in which your browser differs from mine adds entropy and so potentially contributes to a
way to tell the difference between you and me, and identify an individual person as uniquely as possible across websites.
[https://amiunique.org](https://amiunique.org) has a long (but definitely not comprehensive) list of potential fingerprint-contributing
features, and the list grows all the time (as there is heavy monetary interest in being able to fingerprint users, even if the users
don't want that or perhaps don't expect it).

### Not supporting certain powerful APIs

The response from browser vendors to all of these approaches to calculating a user's fingerprint is to find ways to reduce
the amount of entropy available from these APIs. The most restrictive option is to not implement them in the first place.
This has been done by some major browsers for a variety of hardware and device APIs (such as NFC and Bluetooth access from
client-side web apps), with fingerprinting and privacy concerns cited as reasons why they have not been implemented. This,
obviously, can affect your apps and services: you can't use an API at all in a browser that doesn't implement it, and this can
restrict or entirely cut off some hardware approaches from consideration.

### The user permissions gateway

A second approach taken by browser vendors is to prevent API or data accesses without some sort of explicit user permission.
This approach is often taken for security reasons as well—a website should not be able to take pictures with your webcam
without your permission! But here, privacy and security can have similar interests. Identifying someone's location is a
privacy violation in itself, of course, but it's also a contributor to the uniqueness of a fingerprint. Requiring permission
to see geolocation does not decrease the extra entropy that a location adds to the uniqueness of that fingerprint, but it
basically eliminates _using_ geolocation for fingerprinting because it's no longer being done invisibly. The whole point of
fingerprinting is to _surreptitiously_ distinguish users from one another. If you are prepared for the user to know that
you're trying to identify them, then you don't need fingerprinting techniques: have the user create an account and log in
with it.

### Adding unpredictability

A third approach taken in some cases is for browser vendors to "fuzz" the responses from APIs to make them less granular
and thus less identifying. This was described as part of the randomized response mechanism in [the data module](/learn/privacy/data/#fuzz-your-data) as something
you can do when collecting data from users, to avoid inadvertently collecting data which is identifying. Browser vendors
can take this approach to API data made available to web apps and third parties as well. An example of this is the
[very accurate timing APIs used to measure page performance](https://developer.mozilla.org/docs/Web/API/DOMHighResTimeStamp)
from [`window.performance.now()`](https://developer.mozilla.org/docs/Web/API/Performance/now). The browser knows these values
to microsecond accuracy, but the values returned are deliberately reduced in precision by rounding to the nearest 20 microsecond
boundary to avoid their use in fingerprinting (and also for security to avoid timing attacks, admittedly). The goal here is
to ensure the APIs remain useful, but to make the responses less identifying: in essence, to provide "herd immunity" by making
your device look more like everyone else's device rather than being peculiar to you. [Safari presents a simplified version of the system configuration](https://www.apple.com/safari/docs/Safari_White_Paper_Nov_2019.pdf)
for this very reason.

### Enforcing a privacy budget

The Privacy Budget is a proposal that suggests that browsers estimate the information revealed by each fingerprinting surface.
It hasn't been implemented yet in browsers. The goal is to allow powerful APIs while preserving user privacy. [Learn more about the privacy budget proposal](https://developer.chrome.com/docs/privacy-sandbox/privacy-budget/).

## Use a broad testing environment

All of these will affect how you build apps and services. In particular, there is a wide diversity of responses and approaches
across browsers and platforms in this area. This means that testing your work in multiple different environments is _critical_.
This is, of course, always important, but it can be reasonable to assume that HTML rendering or CSS will be constant for a
given rendering engine, no matter which browser or platform that engine is in (and so it can be tempting to test in only one
Blink-based browser, for example). This is emphatically not the case for API usage precisely because browsers that share a
rendering engine may differ dramatically on how they harden their API surface against fingerprinting.

### Do

* Check your own analytics and audience to guide the set of browsers you should prioritize when testing.
* A good set of browsers to test in are Firefox, Chrome, Edge, Safari on desktop, Chrome and Samsung Internet on Android,
and Safari on iOS. This ensures you test across the three major rendering engines (Gecko in Firefox, various forks of Blink
in Chrome, Edge, and Samsung Internet, and Webkit in Safari), and on both mobile and desktop platforms.
* If your site may also be used on less common devices, such as tablets, smartwatches, or gaming consoles, test there as well.
Some hardware platforms can lag behind mobile and desktop for browser updates, meaning that some APIs may be unimplemented or
unavailable in the browsers on those platforms.
* Test with one or more browsers which claim user privacy as a motivator. Include upcoming pre-release and test versions
of your most common browsers where you can and if they're available to you: Safari's [technology preview](https://developer.apple.com/safari/technology-preview/),
Chrome's [Canary](https://www.google.com/intl/en_uk/chrome/canary/), Firefox's [Beta channel](https://www.mozilla.org/en-GB/firefox/channel/desktop/).
These give you the best chance of identifying API breakage and changes that affect your sites before those changes affect
your users. Similarly, bear your users' environments in mind with reference to any analytics you have present. If your
user base has high numbers of older Android phones, be sure to include those in your tests. Most people do not have the
fast hardware and latest releases that a development team does.
* Test using both a clean profile and in incognito/private browsing mode; the likelihood is that you have already granted
the permissions required in your personal profile. Test what happens if you deny permission to the site for any question.
* Explicitly test your pages in Firefox's [fingerprinting protection](https://support.mozilla.org/kb/firefox-protection-against-fingerprinting)
mode. Doing so will show permission dialogues if your page is attempting fingerprinting, or will return fuzzed data for some APIs.
This helps you confirm if third parties included in your service are using fingerprintable data, or if your own service depends
on that. You can then consider whether the deliberate fuzzing makes it more difficult to do what you need. Consider making
corrections accordingly to obtain that data from another source, do without it, or use less granular data.
* As previously discussed in [the third-parties module](/learn/privacy/third-parties), it's also important to audit your third-party
dependencies to see if they are using fingerprinting techniques. Passive fingerprinting is difficult to detect (and
impossible if a third party does it on their server) but fingerprinting mode may flag some fingerprinting techniques,
and looking for uses of navigator.userAgent or unexpected creation of `<canvas>` objects may also reveal some approaches
that deserve further scrutiny. It is also worth looking for uses of the term "probabilistic matching" in marketing or
technical material describing a third party; this can sometimes indicate the use of fingerprinting techniques.

### Cross-browser testing tools

Testing your code for privacy purposes is difficult to automate, and the things to look for when testing manually are described earlier.
What happens when you deny permission to the site for any APIs it tries to access, for example, and how is that presented to the user?
An automated test cannot judge whether the site acts so as to help the user trust it, or conversely to encourage the user to distrust it,
or think that something is being hidden.

However, once the site has been audited, the testing of APIs to confirm that nothing has broken in newer browser versions (or in
upcoming "beta" and "preview" versions) can be automated, and largely should be as part of your existing test suite. Something
to consider with your automated test tools, when working with API surface coverage, is that most browsers allow some level of
control over which APIs and features are available. Chrome does so through [command line switches](https://www.chromium.org/developers/how-tos/run-chromium-with-flags/),
as does [Firefox](https://wiki.mozilla.org/Firefox/CommandLineOptions), and having access to these in the testing tool
setup will allow you to run certain tests with APIs turned off or on. (See, for example, Cypress's
[browser-launch plugin](https://docs.cypress.io/api/plugins/browser-launch-api#Modify-browser-launch-arguments-preferences-and-extensions) a
nd puppeteer's [launch.args parameter](https://github.com/puppeteer/puppeteer/blob/v14.1.0/docs/api.md#puppeteerlaunchoptions) for ways
to add browser flags when launching.)

## Only rely on the user-agent string for coarse information

Taking another example, browsers have since the beginning of the web sent a description of themselves with every request in the
HTTP User-Agent header. For nearly as long, people have been exhorting web developers to not use the contents of the user-agent header
to serve different content to different browsers, and for all that time web developers have done it anyway, with a certain amount of
justification in some (but not all) cases. Since browsers don't want to be singled out for a suboptimal experience by websites,
this results in every browser pretending to be every other browser, and the user-agent string looking something like:

`Mozilla/5.0 (Linux; Android 6.0.1; SGP771 Build/32.2.A.0.253; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Safari/537.36`.

This claims, among other things, to be Mozilla/5.0, a browser which was released at the same time that the first astronauts
boarded the International Space Station over two decades ago. The user-agent string is a rich source of entropy for fingerprinting,
of course, and to mitigate that fingerprintability, browser manufacturers have either already frozen the user-agent header or are working
towards doing so. This is another example of changing the data that an API provides without necessarily removing the API entirely.
Sending a blank user-agent header would break countless websites which assume that it is present. So in general, what browsers are doing
is removing some of the detail from it, and then keeping it mostly unchanged from then on. (You can see this happening in
[Safari](https://twitter.com/rmondello/status/943545865204989953), [Chrome](https://groups.google.com/a/chromium.org/g/blink-dev/c/-2JIRNMWJ7s/m/3Oth5Wu2DgAJ),
and [Firefox](https://www.bleepingcomputer.com/news/software/mozilla-tests-if-firefox-1000-user-agent-breaks-websites/).) This protection against
detailed fingerprinting essentially means that you cannot rely on the user-agent header being accurate anymore, and if you are
doing so then it's important to find alternative data sources.

To be clear, the data in the user-agent isn't going entirely away, but it is available at a lower granularity, or is
sometimes inaccurate because an older but unchanging number may be reported. For example, Firefox, Safari, and Chrome all cap
the reported macOS version number to ten (see [Update on user-agent string reduction](https://blog.chromium.org/2021/05/update-on-user-agent-string-reduction.html)
for more discussion here). The exact details for how Chrome plans to reduce data in the user-agent string are available at [User-Agent Reduction](https://www.chromium.org/updates/ua-reduction/)
but, in short, you can expect that the reported browser version number will only contain a major version (so the version number
will look like 123.0.0.0, even if the browser is version 123.10.45.108), and the OS version will be without detail and will
freeze to one of a small number of unchanging choices. So an imaginary Chrome version 123.45.67.89 running on an imaginary
"Windows 20" would report its version number as:

`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/123.0.0.0 Safari/537.36`

The core information you need (the browser version) is still available: it is Chrome 123, on Windows. But the subsidiary
information (the chip architecture, which Windows version, which version of Safari it's imitating, the browser minor version)
will no longer be available after the freeze.

Compare this with a "current" Chrome user-agent on a different platform:

`Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36`,

and it can be seen that the only thing that differs is the Chrome version number (104) and the platform identifier.

Similarly, Safari's user-agent string does show a platform and a Safari version number, and also gives an OS version on iOS,
but all else is frozen. So an imaginary Safari version 1234.5.67 running on an imaginary macOS 20 might give its user-agent as:

`Mozilla/5.0 (Macintosh; **Intel Mac OS X 10_20_0**) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15`,

and on an imaginary iOS 20 it might be:

`Mozilla/5.0 (iPhone; CPU **iPhone OS 20_0** like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/**20.0 Mobile/15E148 Safari/605.1.15**`.

Again, the core information (this is Safari, it's on iOS or macOS) is available, and iOS Safari still provides an iOS version number;
but much of the ancillary information that was available in the past has since been frozen. Importantly, this includes the Safari
version number, which is not necessarily available.

The changes to the reported user-agent were hotly debated. [https://github.com/WICG/ua-client-hints#use-cases summarises](https://github.com/WICG/ua-client-hints#use-cases) summarises
some of the arguments and reasons for the change, and Rowan Merewood has a [slide deck](https://docs.google.com/presentation/d/1IngTSZ_TQHjJEsRcCpm_WsnLCV4wpYYZ8D1CNnK4UZ4/edit#slide=id.ge864b7bfc7_0_360)
with some strategies for migrating away from using the user-agent for differentiation, in the context of the UA Client Hints proposal explained further on.

### Fuzzing

Fuzzing is a term from security practice, where APIs are called with unexpected values in the hope that they handle those
unexpected values badly and expose a security issue. Web developers should be familiar with [cross-site scripting (XSS)](https://developer.mozilla.org/docs/Glossary/Cross-site_scripting),
which involves adding malicious script to a page, often because the page doesn't correctly escape injected HTML (so you do a search query
with the text `<script>` in it). Back-end developers will be aware of [SQL injection](https://developer.mozilla.org/docs/Glossary/SQL_Injection),
where database queries that don't correctly validate user input expose security issues (as notably illustrated by xkcd with
[Little Bobby Tables](https://xkcd.com/327/)). Fuzzing, or [fuzz testing](https://developer.mozilla.org/docs/Glossary/Fuzzing), is more properly
used for automated attempts to provide many different invalid or unexpected inputs to an API and to check the results for security leaks,
crashes, or other bad handling. These are all examples of deliberately providing inaccurate information. Here, though, it's being done
preemptively by browsers (by making the user-agent deliberately incorrect), to encourage developers to stop relying on that data.

#### Do

* Check your codebase for any reliance on the user-agent string (a search for `navigator.userAgent` is likely to find most occurrences
in your client-side code, and your backend code will likely be looking for `User-Agent` as a header), including your
dependencies.
* If you find uses in your own code, work out what the code is checking for, and find another way to do that differentiation
(or find a replacement dependency, or work with the dependency upstream by filing issues or checking with them for updates). Sometimes
browser differentiation is necessary to work around bugs, but the user-agent will increasingly become not the way to do this once it is frozen.
* You may be safe. If you’re only using the core values of brand, major version, and platform, then these will almost certainly still be
available and be correct in the user-agent string.
* MDN describes good ways to avoid reliance on the user-agent string [("browser sniffing")](https://developer.mozilla.org/docs/Web/HTTP/Browser_detection_using_the_user_agent),
the main one of which is feature detection.
* If you are reliant on the user-agent string in some way (even when using the few core values that remain useful), it’s a good
idea to test with upcoming user-agents that will be in new browser releases. It is possible to test with those upcoming browser
versions themselves by means of beta or technology preview builds, but it's also possible to set a custom user-agent string for
testing. You can override the user-agent string in [Chrome, Edge](https://developer.chrome.com/docs/devtools/device-mode/override-user-agent/),
[Firefox](https://support.mozilla.org/kb/how-reset-default-user-agent-firefox), and
[Safari](https://developer.apple.com/library/archive/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/TheDevelopMenu/TheDevelopMenu.html#//apple_ref/doc/uid/TP40007874-CH7-SW5),
when doing local development, in order to check how your code deals with different user-agent values that you might receive from users.

## Client Hints

One major proposal to provide this information is [User-Agent Client Hints](/user-agent-client-hints/),
although this is not supported across all browsers. Supporting browsers will pass three headers: `Sec-CH-UA`, which gives
a browser brand and version number; `Sec-CH-UA-Mobile`, which indicates if the request comes from a mobile device; and `Sec-CH-UA-Platform`,
which names the operating system. (Parsing these headers is less easy than it seems because they are
[Structured Headers](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-header-structure-15) rather than simple strings,
and this is enforced by browsers sending "tricky" values, which will be handled incorrectly if not properly parsed. This is,
as earlier, an example of “fuzz testing” being done preemptively by the browser. A developer using this data is required to handle
it properly because the data is designed so that improper or lazy parsing will likely give bad results, such as showing brands that don’t
exist, or strings that don’t close properly.) Fortunately, this data is also made available by the browser to JavaScript directly as
`navigator.userAgentData`, which in a supporting browser might look something like this object:

```json
{
  "brands": [
	{
  	"brand": " Not A;Brand",
  	"version": "99"
	},
	{
  	"brand": "Chromium",
  	"version": "96"
	},
	{
  	"brand": "Google Chrome",
  	"version": "96"
	}
  ],
  "mobile": false
}
```

# Third parties

It's rather rare that a website is wholly self-contained. [The HTTP Web Almanac shows that most websites—around 95%—contain some third-party content](https://almanac.httparchive.org/en/2021/third-parties).

The Almanac defines third-party content as something hosted on a shared and public origin, which is widely used by a variety
of sites and uninfluenced by an individual site owner. These might be images or other media such as video, fonts, or scripts.
Images and scripts account for more than everything else added together. Third-party content isn't essential for developing a site,
but it might as well be; you will almost certainly be using something loaded from a public shared server, whether web fonts,
embedded iframes of videos, adverts, or JavaScript libraries. For example, you may be using web fonts served from Google Fonts,
or measuring analytics with Google Analytics; you may have added Like buttons or Sign In With buttons from social networks;
you may be embedding maps or video, or handling shopping purchases via third-party services; you may be tracking errors and
logging for your own development teams via third-party monitoring tools.

For privacy purposes, it is useful to consider a slightly different and less broad definition: a third-party resource, and in
particular a third-party script, is served from a shared and public origin and widely used as illustrated, but is also authored
by someone other than the site owner. The aspect of third-party _authorship_ is what's key when considering how to protect your
users' privacy from others. This will lead you to consider what risks are present, and then decide how or whether to use a
third-party resource based on those risks. As already discussed, these things will help you to understand the context and
therefore to understand which trade-offs you need to make, and what they mean.

This isn't quite what's meant when discussing "third-party resources" in general: the distinction between first-party and
third-party is really one about the context in which something is used. A script loaded from another website is a third-party
resource, and the HTTP request which loads the script may include cookies, but those cookies aren't really "third-party cookies";
they're just cookies, and whether they're "third-party" or "first-party" depends on whether the script is being loaded on a
page on your site or a page on the script owner's site.

## Why do we use third-party resources?

Third-parties are a great way to add functionality to your site. That may be features that are exposed to users, or invisible
developer functions such as error tracking, but they reduce your development load, and the scripts themselves are maintained
by someone else: the development team of the service you're including. This all works because of the composability of the web:
being able to put parts together to form a whole that is greater than their sum.

The HTTP Archive's Web Almanac gives a nice description: 

<blockquote><p>Third parties provide a never-ending collection of images, videos,
fonts, tools, libraries, widgets, trackers, ads, and anything else you can imagine embedding into our web pages. This enables
even the most non-technical to be able to create and publish content to the web. Without third parties, the web would likely
be a very boring, text-based, academic medium instead of the rich, immersive, complex platform that is so integral to the lives
of many of us today.</p></blockquote>

## What can third-party resources do?

### Accessing some information

When you use a third-party resource on your website, regardless of what it is, some information is passed to that third party.
For example, if you include an image from another site, the HTTP request that the user's browser makes will pass along a Referer
header with your page's URL, as well as the user's IP address.

### Cross-site tracking

Continuing with that same example—when the image loads from the third-party site, it can include a cookie, and that cookie will
be sent back to the third-party when the user next requests that image. This means that the third party can know that their
service is being used on your site, and it can send back a cookie, potentially with a unique ID for that user. This means that
the next time the user visits your site, or _any other site which includes a resource from that third party_, that unique
ID cookie will be sent again. This allows the third party to build up a log of where that user visits: your site, other sites that
use the same third-party resource, all over the web.

This is _cross-site tracking_: allowing a third party to collect a log of a user's activity on many websites, as long as those
websites all use a resource coming from the same third party. That might be a font, an image, or a stylesheet—all static resources.
It also might be a dynamic resource: a piece of script, a social media button, an advert. Included script can gather even more
information, because it is dynamic: it can inspect the user's browser and environment and pass that data back to its originator.
Any script can do this to some extent, as can dynamic resources that don't present as a script, such as a social media embed or
an ad or a share button. If you look at the details of a cookie banner on popular websites you can see a list of the organizations
that may add a tracking cookie to your users to build up a picture of their activities to create a profile of that user. There
can be hundreds of them. If a third party offers a service for free, one way that this can be economically viable for them to
do is because they collect and then monetise this data.

A useful guide to the types of privacy issues from which a browser should protect its users is the [Target Privacy Threat Model](https://w3cping.github.io/privacy-threat-model/#high-level-threats).
This is a document still under discussion at the time of writing, but it gives some high-level classifications of the sorts of
privacy threats that exist. The risks from third-party resources are primarily "unwanted cross-site recognition", where a
website can identify the same user across multiple sites, and "sensitive information disclosure", where a site can collect
information a user considers sensitive.

This is a _key distinction_: unwanted cross-site recognition is bad even if the third party isn't gathering additional sensitive
information from it, because it takes away a user's control over their identity. Getting access to a user's referrer and IP address
and cookies is an unwanted disclosure in itself. Using third-party resources comes along with a planning component of how you'll use
them in a privacy-preserving way. Some of that work is in your remit as the site developer, and some is done by the browser
in its role as the user agent; that is, the agent working on behalf of the user to avoid sensitive information disclosure and
unwanted cross-site recognition where possible. Below we'll look in more detail at mitigations and approaches on a browser
level and a site development level.

### Server-side third-party code

Our earlier definition of a third party deliberately altered the HTTP Almanac's rather client-side approach (as is appropriate
for their report!), to include third-party authorship, because from a privacy perspective, a third party is anyone who knows anything
about your users who isn't you.

This does include third parties who provide services that you use on the server, as well as the client. From a privacy
standpoint, a third-party library (such as something included from NPM or Composer or NuGet) is also important to understand.
Do your dependencies pass data outside your borders? If you pass data to a logging service or a remotely hosted database,
if libraries you include also "phone home" to their authors, then these may be in a position to violate your users' privacy
and therefore they need to be audited. A server-based third party usually has to be handed the user data by you, which means
that the data it is exposed to is more under your control. By contrast, a client-based third party—a script or HTTP resource
included on your website and fetched by the user's browser—can collect some data directly from the user without that process
of collection being mediated by you. Most of this module will be concerned with how to identify those client-side third parties
you've elected to include and expose your users to, exactly because there is less mediation possible by you. But it is worth
considering securing your server-side code so that you understand outbound communications from it and can log or block any that
are unexpected. Details on how exactly to do this are outside our scope here (and very dependent on your server setup) but
this is another part of your security and privacy stance.

## Why do you need to be careful with third parties?

Third-party scripts and features are really important, and our goal as web developers should be to integrate such things,
not to turn away from them! But there are potential problems. Third-party content may create performance issues and can
also create security issues because you're bringing in an external service inside your trust boundary. But third-party
content can also create privacy issues!

When we're talking about third-party resources on the web, it's useful to think of security issues being (among other things)
where a third party can steal data from your company, and to contrast that with privacy issues, which are (among other things)
where a third party that you included steals or obtains access to your users' data without you (or them) consenting.

An example of a security issue is where "web skimmers" steal credit card information-–a third-party resource which is included
on a page into which a user enters credit card details can, potentially, steal those credit card details and send them off to
the malicious third party. Those who create these skimmer scripts are very creative in working out places to hide them.
[One summary](https://www.zdnet.com/article/hackers-hide-web-skimmer-inside-a-websites-css-files/) describes how skimmer scripts
have been hidden in third-party content such as those images used for site logos, favicons, and social media networks,
popular libraries such as jQuery, Modernizr, and Google Tag Manager, site widgets such as live chat windows, and CSS files.

Privacy issues are a little different. [These third parties are part of your offering](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript);
to maintain your users' trust in you, you need to be confident that your users can trust _them_. If a third party that you use gathers data about
your users and then misuses it, or makes it difficult to delete or discover, or suffers a data breach, or violates your users'
expectations, then your users will likely perceive that as a breakdown in their trust of _your_ service, not simply of the
third party. It is your reputation and relationship on the line. This is why it's important to ask yourself: do you trust
the third parties you're using on your site?

## What are some examples of third parties?

We're discussing "third parties" generally, but there are actually different kinds, and they have access to different amounts of user data.
For example, adding an `<img>` element to your HTML, loaded from a different server, will give that server different information
about your users than adding an `<iframe>` might, or a `<script>` element. These are examples rather than a comprehensive list, but it's
useful to understand the distinctions between the different types of third-party items that your site can employ.

### Requesting a cross-site resource

A cross-site resource is anything on your site which is loaded from a different site and isn't an `<iframe>` or a `<script>`. Examples
include `<img>`, `<audio>`, `<video>`, web fonts loaded by CSS, and WebGL textures. These are all loaded via an HTTP request, and as
described earlier, those HTTP requests will include any cookies previously set by the other site, the requesting user's IP address,
and the URL of the current page as the referrer. All third-party requests historically included this data by default, although
there are efforts to reduce or isolate the data passed to third parties by various browsers, as described in "Understanding
Third-Party Browser Protections" further on.

### Embedding a cross-site iframe

A complete document embedded in your pages via an `<iframe>` can request additional access to browser APIs, in addition to the trifecta
of cookies, IP address, and referrer. Exactly which APIs are available to `<iframe>`d pages and how they request access is browser-specific,
and is currently undergoing changes: see "Permissions Policy" below for current efforts to curtail or monitor API access in embedded
documents.

### Executing cross-site JavaScript

Including a `<script>` element loads and runs cross-site JavaScript in the top-level context of your page. This means that the
script that runs has complete access to anything that your own first-party scripts do. Browser permissions still manage this data,
so requesting the user's location (for example) will still require user agreement. But any information present in the page or
available as JavaScript variables can be read by such a script, and this includes not just cookies that are passed to the third party
as part of the request, but also cookies that are intended for your site alone. Equally, a third-party script loaded onto your
page can make all the same HTTP requests that your own code does, meaning that it could make `fetch()` requests to your back-end APIs to get data.

### Including third-party libraries in your dependencies

As described earlier, your server-side code will also likely include third-party dependencies, and these are indistinguishable from your own
code in their power; code that you include from a GitHub repository or your programming language's library (npm, PyPI, composer, and so on)
can read all the same data that your other code can.

## Knowing your third parties

This, then, requires some understanding of your list of third-party suppliers, and what their privacy, data collection, and user
experience stances and policies are. That understanding then becomes part of your series of trade-offs: how useful and important
is the service, balanced against how intrusive, inconvenient, or disquieting their demands are on your users. Third-party
content provides value by taking the heavy lifting from you as site owner and allows you to focus on your core competencies;
and so there is value in making that trade-off and sacrificing some user comfort and privacy for a better user experience.
It is important to not confuse user experience with _developer_ experience, though: "it is easier for our dev team to build
the service" is not a compelling story to users.

How you get that understanding is the process of audit.

### Audit your third parties

Understanding what a third party does is the process of _audit_. You can do this both technically and non-technically, and
for an individual third party and for your whole collection.

#### Run a non-technical audit

The first step is non-technical: read the privacy policies of your suppliers. If you include any third-party resources,
check the privacy policies. They will be long and full of legal text, and some documents may use some of the approaches
specifically warned against [in earlier modules](/learn/privacy/data/), such as overly general statements and without any indication
of how or when collected data will be removed. It is important to realize that from a user perspective, all the data that
is collected on your site, including by third parties, will be governed by these privacy policies. Even if you do
everything correctly, when you are transparent about your goals and exceed your users' expectations of data privacy and
sensitivity, users may hold you responsible for anything your chosen third parties do as well. If there is anything in
their privacy policies which you would not wish to say in your own policies because it would decrease users' trust, then
consider whether there is an alternative supplier.

This is something which can usefully go hand in hand with the technical audit discussed further on, as they inform one
another. You should know the third-party resources that you're incorporating for business reasons (such as ad networks
or embedded content) because there will be a business relationship in place. This is a good place to start a non-technical
audit. The technical audit is also likely to identify third parties, especially those included for technical rather
than business reasons (external components, analytics, utility libraries), and that list can join with the list of
business-focused third parties. The goal here is for you as site owner to feel that you understand what the third
parties you're adding to your site are doing, and for you as a business to be able to present your legal advisor
with this inventory of third parties to make sure you are meeting any obligations required.

#### Run a technical audit

For a technical audit, it's important to use the resources in situ as part of the website; that is, don't load a dependency
in a test harness and inspect it that way. Make sure you're seeing how your dependencies act as part of your actual website,
deployed on the public internet rather than in a test or development mode. It is very instructive to view your own website as
a new user. Open a browser in a clean new profile, so that you are not signed in and have no stored agreement, and try visiting your site.

{% Aside %}
Testing a site as if you are a new user means viewing that site with no saved information about it. It is best in these
situations to create a brand new profile every time you want to test a website as though you're a new user. Don't create
one new profile and re-use it; create a new profile every time and then discard it. This is mostly a quick process on desktop
browsers: see the documentation for [Chrome](https://support.google.com/chrome/answer/2364824),
[Edge](https://support.microsoft.com/en-us/topic/sign-in-and-create-multiple-profiles-in-microsoft-edge-df94e622-2061-49ae-ad1d-6f0e43ce6435),
and [Firefox](https://support.mozilla.org/en-US/kb/profile-manager-create-remove-switch-firefox-profiles#w_manage-profiles-when-firefox-is-open).
Chrome for Android and Safari don't support creating a new empty profile, so incognito/private browsing modes will have to suffice there, but
in general, it is important to test sites both in incognito/private browsing modes and with a freshly-created profile.
{% endAside %}

Sign up on your own site for a new account, if you provide user accounts. Your design team will have orchestrated this new user
acquisition process from a UX perspective, but it can be illustrative to approach it from a privacy perspective. Don't simply click
"Accept" on the terms and conditions, or the cookie warning, or the privacy policy; set yourself the task of using your own service
without disclosing any personal information or having any tracking cookies, and see if you can do it and how hard it is to do it.
It can also be helpful to look in the browser developer tools to see which sites are being accessed and which data is passed to
those sites. Developer tools provide a list of separate HTTP requests (normally in a section called "Network"), and you can see
from here requests grouped by type (HTML, CSS, images, fonts, JavaScript, requests initiated by JavaScript). It's also possible
to add a new column to show the domain of each request, which will demonstrate how many different places are being contacted,
and there may be a "third-party requests" checkbox to show only third parties. (It can also be useful to use `Content-Security-Policy`
reporting to perform a continual audit, for which read further on.)

[Simon Hearne's "Request Map Generator"](https://simonhearne.com/2015/find-third-party-assets/) tool can also be a helpful overview of all
the subrequests that a publicly available page makes.

This is also the point at which you can include the business-focused third parties identified as part of the non-technical audit
(that is: the list of companies that you have a financial relationship with in order to use their resources). The goal here is
to match up the list of third parties you believe you're using (from financial and legal records) and the list you're actually
using (by looking at which third-party HTTP requests your website makes). You should be able to identify for each business third
party which technical outbound requests are made. If you cannot identify requests in the technical audit for a third party
identified by business relationship, it's important to work out why and to have that guide your testing: perhaps that third-party
resource is only loaded in a particular country, or on a particular device type, or for logged-in users. This will enlarge your
list of site areas to audit and ensure that you're seeing all the outbound accesses. (Or possibly it will identify a third-party
resource that you're paying for and not using, which always cheers up the finance department.)

Once you've narrowed down the list of requests to third parties that you would like to be part of the audit, clicking on an
individual request will show all the details of it and, in particular, which data was passed to that request. It is also very
common that [a third-party request that your code initiates then goes on to initiate many other third-party requests](https://css-tricks.com/potential-dangers-of-third-party-javascript/#third-party-scripts-often-load-other-third-party-scripts-of-their-own).
These additional third parties are also "imported" into your own privacy policy. This task is laborious but valuable, and
it often can be inserted into existing analyses; your frontend development team should already be auditing requests for
performance reasons (perhaps with the help of existing tools such as WebPageTest or Lighthouse), and incorporating a data
and privacy audit into that process can make it easier.

<figure>
{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/nnzRxb7clgk8DgrpmBgS.png", alt="The web.dev request map.", width="800", height="594" %}
<figcaption>A (dramatically simplified) request map for web.dev, showing third-party sites that request other third-party sites, and so on.</figcaption>
</figure>

#### Do

Open a browser with a clean new user profile, so that you are not signed in and have no stored agreement; then open the browser
development tools Network panel to see all the outgoing requests. Add a new column to show the domain of each request, and check the
"third-party requests" checkbox to show only third parties if present. Then:

* Visit your site.
* Sign up for a new account, if you provide user accounts.
* Try to delete your created account.
* Carry out a normal action or two on the site (exactly what this is will depend on what your site does, but pick common actions that most users perform).
* Carry out an action or two which you know involve third-party dependencies in particular. These might include sharing content to
social media, beginning a checkout flow, or embedding content from another site.

When doing each of these tasks, make a record of resources requested from domains that are not yours, by looking at the Network panel
as described. These are some of your third parties. A good way to do this is to use the browser network tools to capture the network
request logs in a HAR file.

#### HAR files and capturing

An [HAR file](https://en.wikipedia.org/wiki/HAR_(file_format)) is a standardized JSON format of all network requests made by a page.
To get an HAR file for a particular page, in:

##### Chrome

Open the browser DevTools (**Menu > More Tools > Developer Tools**), go to the Network panel, load (or refresh) the page, and
choose the downward arrow save symbol in the top right near to the No throttling dropdown menu.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/pe6kjowLV339yjfaAgkr.png", alt="The Chrome DevTools network panel with Download HAR symbol highlighted.", width="650", height="299" %}

##### Firefox

Open the browser developer tools (**Menu > More Tools > Web Developer Tools**), go to the Network panel, load (or refresh) the page, and choose
the cog symbol in the top right next to the throttling dropdown menu. From its menu, choose **Save All As HAR****.

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/SIeaTTW90Zh6TOV8RTKa.png", alt="The Firefox developer tools network panel with the Save All As Har option highlighted.", width="624", height="237" %}

##### Safari

Open the browser developer tools (**Menu > Develop > Show Web Inspector**; if you don't have a Develop menu then enable it from
**Menu > Safari > Preferences > Advanced > Show Develop menu** in menu bar), go to the Network panel, load (or refresh) the page,
and choose **Export** in the top right (to the right of Preserve Log; you may need to enlarge the window).

{% Img src="image/cGQxYFGJrUUaUZyWhyt9yo5gHhs1/PDUiriJh7D8FpL1v3RwD.png", alt="Safari Web Inspector Network panel with the HAR export option highlighted.", width="800", height="266" %}

For more detail, you can also record what is passed on to third parties (in the Request section), although this data is often
obfuscated and not usefully interpretable.

## Best practices when integrating third parties

You can set your own policies on which third parties your site uses: change which ad provider you use based on their practices,
or how annoying or intrusive their cookies consent popup is, or whether you want to use social media buttons on your site or
tracking links in your emails or utm_campaign links to track in Google Analytics in your tweets. One aspect to consider when
developing a site is the privacy and security posture of your analytics service. Some analytics services explicitly trade on
being privacy-protecting. Frequently, there are also ways to use a third-party script which adds privacy protection in itself:
you are not the first team looking to improve their users' privacy and protect them from third-party data collection, and there
may already be solutions. Finally, many third-party providers are more sensitive to data collection issues now than in the past,
and there are often features or parameters you can add which enable a more user-protective mode. Here are some examples.

### When adding a social media sharing button

Consider embedding HTML buttons directly: the site [https://sharingbuttons.io/](https://sharingbuttons.io/) has some well-designed examples.
Or you could add plain HTML links. The trade-off here is that you lose the "share count" statistic and your ability to classify your customers
in your Facebook analytics. This is an example of a trade-off between using a third party provider and receiving less analytics data.

More generally, when you're embedding an interactive widget of some kind from a third party, it's often possible to instead provide a
link out to that third party. This does mean that your site doesn't have the inline experience, but it shifts the decision on sharing
data with the third party from you to your user, who can choose to interact or not as they prefer.

For example, you might add links for Twitter and Facebook to share your service at mysite.example.com like this:

```html
<a href="https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmysite.example.com"
   rel="noopener" aria-label="Share on Facebook" target="_blank" >Share on Facebook</a>
<a href="https://twitter.com/intent/tweet/?text=My%20cool%20service!&amp;url=https%3A%2F%2Fmysite.example.com"
   rel="noopener" aria-label="Share on Twitter" target="_blank">Share on Twitter</a>
```

Note that Facebook allows specifying a URL to share, and Twitter allows specifying a URL and some text.

### When embedding a video

When you're embedding videos from video-hosting sites, look for privacy-preserving options in the embedding code.
For example, for YouTube, replace `youtube.com` in the embed URL with `www.youtube-nocookie.com` to avoid tracking cookies
being placed on users viewing the embedding page. You can also check "Enable privacy-enhanced mode" when generating the
Share/Embed link from YouTube itself. This is a good example of using a more user-protective mode provided by the third party.
([https://support.google.com/youtube/answer/171780](https://support.google.com/youtube/answer/171780) describes this in more detail,
and other embedding options for YouTube specifically.)

Other video sites have fewer options in this regard: TikTok, for example, doesn't have a way to embed video without tracking
at the time of this writing. It is possible to host the videos yourself (this is using an alternative), but it can be a
lot more work, especially to support many devices.

As with interactive widgets discussed earlier, it is often possible to replace an embedded video with a link to the providing website.
This is less interactive because the video won't play inline, but it leaves the choice of whether to watch with the user. This can be
used as an example of the "facade pattern", the name for dynamically replacing interactive content with something requiring a user
action to trigger it. An embedded TikTok video can be replaced with a plain link to the TikTok video page, but with a little more
work it is possible to retrieve and display a thumbnail for the video and make that a link. Even if the chosen video provider doesn't
support an easy way to embed videos without tracking, many video hosts support [oEmbed](https://oembed.com/), an API that, when given
a link to a video or embedded content, will return programmatic detail for it, including a thumbnail and title. TikTok supports oEmbed
(see [https://developers.tiktok.com/doc/embed-videos](https://developers.tiktok.com/doc/embed-videos) for details), meaning that
you can (manually or programmatically) turn a link to a TikTok video `https://www.tiktok.com/@scout2015/video/6718335390845095173` into JSON metadata about that video with
`https://www.tiktok.com/oembed?url=https://www.tiktok.com/@scout2015/video/6718335390845095173`, and therefore retrieve a thumbnail
to display. WordPress often uses this to request oEmbed' information for embedded content, for example. You can use this programmatically
to show a "facade" that looks interactive and switches to embed or link to an interactive video when the user chooses to click on it.

### When embedding analytics scripts

Analytics is designed to collect info about your users so it can be analyzed: this is what it's for. Analytics systems are essentially
services to collect and display data about accesses and users, which is done on a third-party server such as Google Analytics for ease
of implementation. There are also self-hosted analytics systems such as [https://matomo.org/](https://matomo.org/), although this is more work than using a
third-party solution for this. Running such a system on your own infrastructure does help you to reduce data collection, though,
because it does not leave your own ecosystem. On the other hand, managing that data, removing it, and setting policies for it
becomes your responsibility. Much of the concern with cross-site tracking comes about when it's done surreptitiously and
secretively, or as a side-effect of using a service which need not contain data gathering at all. Analytics software is overtly
designed to collect data in order to inform the site owners about their users.

Historically, there has been an approach of gathering all the data you can about everything, like a giant fishing net, and
then analyzing it later for interesting patterns. This mindset has, in large part, created the sense of unease and disquiet
about data collection that was discussed in part 1 of this course. Now, many sites first work out which questions to ask and
then gather specific and limited data to answer those questions.

If some third-party service is used by your site and by other sites, and it works by you including their JavaScript into your site,
and it sets cookies for each user, then it's important to consider that they could be doing unwanted cross-site recognition;
that is, tracking your users across sites. Some may and some may not, but the privacy-protecting stance here is to assume that
such a third-party service is in fact doing cross-site tracking unless you have a good reason to think or know otherwise.
This is not in itself a reason to avoid such services, but it is something to consider in your assessment of the trade-offs
of using them.

The trade-off in analytics used to be solely to choose whether to use it or not: gather all data and compromise privacy in exchange
for insights and planning, or give up insights entirely. However, this is no longer the case, and there is often now a
middle ground to be found between these two extremes. Check your analytics provider for configuration options to limit
the data collected and reduce the amount and duration of its storage. Since you have the records from the technical audit
described earlier, you can re-run the relevant sections of that audit to confirm that changing these configurations does
actually reduce the amount of data collected. If you're making this transition on an existing site, then this can give you
some quantifiable measure that can be written about for your users. For example, Google Analytics has a number of [opt-in (therefore off by default)](https://support.google.com/analytics/answer/9019185#zippy=%2Cin-this-article)
privacy features, many of which may be helpful for complying with local data protection laws. Some options to consider when setting up Google
Analytics include setting the retention period on collected data (Admin > Tracking Info > Data Retention) lower than the 26-month default,
and enabling some of the more technical solutions such as partial IP anonymization (see [https://support.google.com/analytics/answer/9019185](https://support.google.com/analytics/answer/9019185) for more detail).

## Using third parties in a privacy-preserving way

Thus far, we've discussed how to protect your users from third parties during the design phase of your application, while
you're planning what that application will do. Deciding to not use a particular third party at all is part of this planning,
and auditing your uses also falls into this category: it's about making decisions about your privacy stance. However, these
decisions are inherently not very granular; choosing to use a particular third party or choosing not to is not a nuanced decision.
It is much more likely that you will want something in between: to need or plan to use a particular third-party offering but
mitigate any privacy-violating tendencies (whether deliberate or accidental). This is the task of protecting users at "build time":
adding safeguards to reduce harm that you did not anticipate. All these are new HTTP headers that you can provide when serving
pages and which will hint or command the user agent to take certain privacy or security stances.

### Referrer-Policy

#### Do

Set a policy of `strict-origin-when-cross-origin` or `noreferrer` to prevent other sites from receiving a Referer header
when you link to them or when they're loaded as subresources by a page:

```html
index.html:
<meta name="referrer" content="strict-origin-when-cross-origin" />
```

Or server-side, for example in Express:

```java
const helmet = require('helmet');
app.use(helmet.referrerPolicy({policy: 'strict-origin-when-cross-origin'}));
```

If need be, set a laxer policy on specific elements or requests.

#### Why this protects user privacy

By default, each HTTP request the browser makes passes on a `Referer` header which contains the URL of the page initiating the request,
whether a link, an embedded image, or script. This can be a privacy issue because URLs can contain private information, and those URLs
being available to third parties passes that private information to them. [Web.dev lists some examples](/referrer-best-practices/#referer-and-referrer-policy-101)
of URLs containing private data—knowing that a user came to your site from `https://social.example.com/user/me@example.com` tells you who that user is,
which is a definite leak. But even a URL which does not itself expose private information does expose that this particular user (who you may know,
if they're logged in) came here from another site and this therefore reveals that this user visited that other site. This is in itself exposure of
information that you maybe should not know about your user's browsing history.

{% Aside %}
(It's spelled incorrectly, yes: Referrer should have a double R. People have been complaining about this for quarter of a century.)
{% endAside %}

Providing a `Referrer-Policy` header (with correct spelling!) lets you alter this, so that some or none of the referring URL is passed on.
[MDN lists the full details](https://developer.mozilla.org/docs/Web/HTTP/Headers/Referrer-Policy) but most browsers have
now adopted an assumed value of `strict-origin-when-cross-origin` by default, meaning that the referrer URL is now passed to third
parties as an origin only (`https://web.dev` rather than `https://web.dev/learn/privacy`). This is a useful privacy protection without
you having to do anything. But you can tighten this up further by specifying `Referrer-Policy: same-origin` to avoid passing any
referrer information at all to third parties (or `Referrer-Policy: no-referrer` to avoid passing to anyone including your own origin).
(This is a nice example of the privacy-versus-utility balance; the new default is much more privacy-preserving than before, but it
still gives high level information to third parties of your choice, such as your analytics provider.)

It's also useful to explicitly specify this header [because then you know exactly what the policy is, rather than relying on the browser defaults](/referrer-best-practices/#why-%22explicitly%22).
If you aren't able to set headers, then it's possible to set a referrer policy for a whole HTML page using a meta element in the `<head>`:
`<meta name="referrer" content="same-origin">`; and if concerned about specific third parties, it's also possible to set a `referrerpolicy`
attribute on individual elements such as `<script>`, `<a>`, or `<iframe>`: `<script src="https://thirdparty.example.com/data.js" referrerpolicy="no-referrer">`

### Content-Security-Policy

The `Content-Security-Policy` header, often referred to as "CSP", dictates where external resources can be loaded from.
It is primarily used for security purposes, by preventing cross-site scripting attacks and script injection, but when used
alongside your regular audits it can also limit where your chosen third parties can pass data to.

This is potentially a less-than-great user experience; if one of your third-party scripts starts loading a dependency from an
origin not on your list, then that request will be blocked, the script will fail, and your application may fail with it
(or at least be reduced to its JavaScript-failing fallback version). This is useful when CSP is implemented for security,
which is its normal purpose: protecting against cross-site scripting issues (and to do this, use a [strict CSP](/strict-csp/)).
Once you know all the inline scripts that your page uses, you can make a list of them, calculate a hash value or add a random value
(called a "nonce") for each, and then add the list of hashes to your Content Security Policy. This will prevent any script that
isn't on the list from being loaded. This needs to be baked into the production process for the site: scripts in your pages need
to include the nonce or to have a hash calculated as part of the build. See [the article on strict-csp](/strict-csp/) for all the details.

Fortunately, browsers support a related header, `Content-Security-Policy-Report-Only`. If this header is provided, requests
that violate the supplied policy will not be blocked, but a JSON report will be sent to a supplied URL. Such a header might
look like this:
`Content-Security-Policy-Report-Only: script-src 3p.example.com; report-uri https://example.com/report/`,
and if the browser loads a script from anywhere other than `3p.example.com`, that request will succeed but a report will
be sent to the supplied `report-uri`. Normally this is used to experiment with a policy before implementing it, but a useful
idea here is to use this as a way of conducting an "ongoing audit". As well as your regular audit described earlier, you
can turn on CSP reporting to see if any unexpected domains appear, which could mean that your third-party resources are loading
third-party resources of their own and which you need to consider and evaluate. (It may also be a sign of some cross-site
scripting exploits having slipped past your security boundary, of course, which it is also important to know about!)

`Content-Security-Policy` is a complex and fiddly API to use. This is known, and there is work going on to build the "next generation" of CSP
which will meet the same goals but not be quite as complicated to use.This isn't ready yet, but if you'd like to see where this is heading
(or to get involved and help in its design!) then check out [https://github.com/WICG/csp-next](https://github.com/WICG/csp-next) for details.

#### Do

Add this HTTP header to pages served: `Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://a-url-you-control`.
When JSON is posted to that URL, store it. Review that stored data to get a collection of the third-party domains that your website requests when visited by others.
Update the `Content-Security-Policy-Report-Only` header to list the domains you expect, in order to see when that list changes:

```html
Content-Security-Policy-Report-Only: default-src 'self' https://expected1.example.com https://expected2.example.com ; report-uri https://a-url-you-control
```

#### Why

This forms part of your technical audit, in an ongoing fashion. The initial technical audit you performed will give you a
list of third parties that your site shares or passes user data to. This header will then cause page requests to report
back which third parties are now being contacted, and you can track changes over time. This not only alerts you to changes
made by your existing third parties, but will also flag newly added third parties which weren't added to the technical audit.
It's important to update the header to stop reporting about domains you expect, but it's also important to repeat the manual
technical audit from time to time (because the `Content-Security-Policy` approach does not flag _what_ data is passed, only
that a request has been made.)

Note that it does not need to be added to the pages served every time, or every page. Tune down how many page responses receive
the header so that you receive a representative sample of reports that aren't overwhelming in quantity.

### Permissions policy

The `Permissions-Policy` header (which was introduced under the name `Feature-Policy`) is similar in concept to `Content-Security-Policy`,
but it restricts access to powerful browser features. For example, it’s possible to restrict use of device hardware such as the accelerometer,
camera, or USB devices, or to restrict non-hardware features such as permission to go fullscreen or use synchronous `XMLHTTPRequest`.
These restrictions can be applied to a top-level page (to avoid loaded scripts from attempting to use these features) or to
subframed pages loaded in via an iframe. This restriction of API usage isn’t really about browser [fingerprinting](/learn/privacy/fingerprinting/); it's about disallowing third-parties from doing intrusive things (such as using powerful APIs, popping up
permissions windows, etc). This is defined by the Target Privacy Threat Model as ["intrusion"](https://w3cping.github.io/privacy-threat-model/#intrusion).

A `Permissions-Policy` header is specified as a list of (feature, allowed origins) pairs, thus:

```html
Permissions-Policy: geolocation=(self "https://example.com"), camera=(), fullscreen=*
```

This example allows this page ("self") and `<iframe>`s from the origin `example.com` to use the `navigator.geolocation` APIs
from JavaScript; it allows this page and all subframes to use the full screen API, and it prohibits any page, this page included,
from using a camera to read video information. There is much more detail and [a list of potential examples here](https://developer.chrome.com/en/docs/privacy-sandbox/permissions-policy/#example-permissions-policy-setups).

The list of features that are handled by the Permissions-Policy header is large and may be in flux. Currently the list is
maintained at [https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md](https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md).

{% Aside 'gotchas' %}
Note that `Content-Security-Policy` values are separated by semicolons but `Permissions-Policy` values are separated by commas,
and that `Permissions-Policy` values have brackets around them. The details are specified in the
[Permissions Policy  explainer](https://developer.chrome.com/docs/privacy-sandbox/permissions-policy/).
{% endAside %}

#### Do

Browsers that support `Permissions-Policy` disallow powerful features in subframes by default, and you have to act to enable them!
This approach is private by default. If you find that subframes on your site require these permissions, you can selectively add them.
However, there is no permissions policy applied to the main page by default, and so scripts (including third-party scripts) that are
loaded by the main page are not restricted from attempting to use these features. For this reason, it is useful to apply a restrictive
`Permissions-Policy` to all pages by default, and then gradually add back in features that your pages require.

Examples of powerful features that `Permissions-Policy` affects include requesting the user's location, access to sensors (including
accelerometer, gyroscope, and magnetometer), permission to go fullscreen, and requesting access to the user’s camera and microphone.
The (changing) full list of features is linked above.

Unfortunately, blocking all features by default and then selectively re-allowing them requires listing all features in the header,
which can feel rather inelegant. Nonetheless, such a `Permissions-Policy` header is a good place to start. [permissionspolicy.com/](https://www.permissionspolicy.com/)
has a conveniently clickable generator to create such a header: using it to create a header which disables all features results in this:

```html
Permissions-Policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(),
display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(),
fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(),
payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()
```

## Understand built-in privacy features in web browsers

In addition to the "build time" and "design time" protections, there are also privacy protections which happen at "run time": that is, privacy
features implemented in browsers themselves to protect users. These are not features you can directly control or tap into as a site
developer—they're product features—but they are features you should be aware of, because your sites may be affected by these product decisions
in browsers. To give an example here of the way these browser protections may impact your site, if you have client-side JavaScript which waits
for a third-party dependency to load before continuing with page setup, and that third-party dependency never loads at all, then your page setup
may never complete and so the user is presented with a half-loaded page.

They include [Intelligent Tracking Prevention](https://webkit.org/blog/9521/intelligent-tracking-prevention-2-3/) in Safari
(and the underlying WebKit engine), and [Enhanced Tracking Protection](https://support.mozilla.org/en-US/kb/enhanced-tracking-protection-firefox-desktop)
in Firefox (and its engine, Gecko). These all make it difficult for third parties to build detailed profiles of your users.

Browser approaches on privacy features change frequently, and it’s important to stay up to date; the following list of protections
are correct at time of writing. Browsers may also implement other protections; these lists are not exhaustive. See [the module on best practices](/learn/privacy/best-practices/)
for ways to keep up with changes here, and be sure to test with upcoming browser versions for changes that may affect your projects.
Bear in mind that incognito/private browsing modes sometimes implement different settings from the browser’s default (third-party cookies may be blocked
by default in such modes, for example). Therefore, testing in incognito mode may not always be reflective of most users’ typical browsing experience if
they're not using private browsing. Also bear in mind that blocking cookies in various situations may mean that other storage solutions, such as `window.localStorage`,
are also blocked, not only cookies.

### Chrome

* Third-party cookies are intended to be blocked in the future.  As of this writing they are not blocked by default
(but this can be enabled by a user): [https://support.google.com/chrome/answer/95647](https://support.google.com/chrome/answer/95647)
explains the details.
* Chrome's privacy features, and in particular the features in Chrome that communicate with Google and third-party services,
are described at [privacysandbox.com/](https://privacysandbox.com/).

### Edge

* Third-party cookies are not blocked by default (but this can be enabled by a user).
* Edge's [Tracking Prevention](https://learn.microsoft.com/en-us/microsoft-edge/web-platform/tracking-prevention) feature blocks
trackers from unvisited sites and known harmful trackers are blocked by default.

### Firefox

* Third-party cookies are not blocked by default (but this can be enabled by a user).
* Firefox's [Enhanced Tracking Protection](https://support.mozilla.org/kb/enhanced-tracking-protection-firefox-desktop) blocks by default tracking cookies,
fingerprinting scripts, cryptominer scripts, and known trackers. ([https://support.mozilla.org/kb/trackers-and-scripts-firefox-blocks-enhanced-track](https://support.mozilla.org/kb/trackers-and-scripts-firefox-blocks-enhanced-track)
provides some more details).
* Third-party cookies are site-limited, so each site essentially has a separate cookie jar and can’t be correlated across
sites (Mozilla calls this "[Total Cookie Protection](https://blog.mozilla.org/products/firefox/firefox-rolls-out-total-cookie-protection-by-default-to-all-users-worldwide/)".

To get some insight into what may be blocked and to help debug issues, click the shield icon in the address bar or visit `about:protections` in Firefox (on desktop).

### Safari

* Third-party cookies are blocked by default.
* As part of its [Intelligent Tracking Prevention](https://webkit.org/blog/9521/intelligent-tracking-prevention-2-3/) feature,
Safari reduces the referrer passed to other pages to be a top-level site rather than a specific page: (`https://something.example.com`,
rather than `https://something.example.com/this/specific/page`).
* Browser `localStorage` data is deleted after seven days.

([https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/) summarizes these features.)

To get some insight into what may be blocked and to help debug issues, enable "Intelligent Tracking Prevention Debug Mode" in Safari's
developer menu (on desktop). (See [https://webkit.org/blog/9521/intelligent-tracking-prevention-2-3/](https://webkit.org/blog/9521/intelligent-tracking-prevention-2-3/) for more details.)

## API proposals

### Why do we need new APIs?

While new privacy-preserving features and policies in browser products help preserve user privacy, they also come with challenges.
Many web technologies are usable for cross-site tracking despite being designed for and used for other purposes. For example,
many identity federation systems we use every day rely on third-party cookies. Numerous advertising solutions that publishers
rely on for revenue today are built on top of third-party cookies. Many fraud detection solutions rely on fingerprinting. What
happens to these use cases when third-party cookies and fingerprinting go away?

It would be difficult and error-prone for browsers to differentiate use cases, and to reliably distinguish privacy-violating uses
from others. This is why most major browsers have blocked third-party cookies and fingerprinting or intend to do so, to protect user
privacy.

A new approach is needed: as third-party cookies are phased out and fingerprinting mitigated, developers need purpose-built APIs
that meet the use cases (which haven’t gone away) but are designed in a privacy-preserving manner. The goal is to design and build
APIs which can’t be used for cross-site tracking. Unlike the browser features described in the previous section, these technologies
aspire to become cross-browser APIs.

### Examples of API proposals

The following list isn’t comprehensive—it's a flavor of some of what’s being discussed.

Examples of API proposals to replace technologies built on third-party cookies:
* Identity use cases: [FedCM](https://developer.chrome.com/en/docs/privacy-sandbox/fedcm/)
* Ads use cases: [Private Click Measurement](https://webkit.org/blog/11529/introducing-private-click-measurement-pcm/),
[Interoperable Private Attribution](https://blog.mozilla.org/en/mozilla/privacy-preserving-attribution-for-advertising/),
[Attribution Reporting](https://developer.chrome.com/docs/privacy-sandbox/attribution-reporting/), [Topics](https://developer.chrome.com/docs/privacy-sandbox/topics/),
[FLEDGE](https://developer.chrome.com/docs/privacy-sandbox/fledge/), [PARAKEET](https://github.com/microsoft/PARAKEET).

Examples of API proposals to replace technologies built on passive tracking:
* Fraud detection use cases: [Trust Tokens](https://developer.chrome.com/docs/privacy-sandbox/trust-tokens/).

Examples of other proposals that other APIs can build on in a future without third-party cookies:
* [Storage Access API](https://developer.mozilla.org/docs/Web/API/Storage_Access_API)

Additionally, another type of API proposal is emerging to try and have so-far browser-specific covert tracking mitigations.
One example is [Privacy Budget](https://developer.chrome.com/en/docs/privacy-sandbox/privacy-budget/). Across these various
use cases, the APIs that were initially proposed by Chrome live under the umbrella term of the [Privacy Sandbox](https://developer.chrome.com/docs/privacy-sandbox/).

[Global-Privacy-Control](https://globalprivacycontrol.org/) is a header that intends to communicate to a site that the user
would like any collected personal data not to be shared with other sites. Its intention is similar to Do Not Track, which was discontinued.

{% Aside %}
In the early 2000s there was a push from consumer advocacy groups to allow users to specify that they did not want to be tracked
via cookies or similar technologies. All the major browsers implemented this as a request header, Do Not Track, with value 1
to indicate to websites that the user did not want to be tracked.
[This received a lot of pushback from data-collecting companies](https://www.zdnet.com/article/why-do-not-track-is-worse-than-a-miserable-failure/),
and there was no requirement that it be obeyed and it largely was not. Towards the end of the 2010s it was largely dropped from
browsers and the [working group responsible closed](https://github.com/w3c/dnt), saying "there have not been indications of
planned support among user agents, third parties, and the ecosystem at large".
{% endAside %}

### Status of the API proposals

Most of these API proposals are not yet deployed, or are deployed only behind flags or in limited environments for experimentation.

This public incubation phase is important: browser vendors and developers collect discussion and experience with whether these APIs are
useful and whether they actually do what they’re designed for. Developers, browser vendors, and other ecosystem actors use this phase
to iterate on the API's design.

The best place to keep up to date with new APIs being proposed is currently the [Privacy Group’s list of proposals on Github](https://github.com/privacycg/proposals/issues).

#### Do you need to use these APIs?

If your product is directly built on top of third-party cookies or techniques such as fingerprinting, you should get involved with these new APIs, experiment with them, and contribute your own experiences to the discussions and API design.
In all other cases, you don’t necessarily need to know all the details on these new APIs at the time of writing, but it’s good to be aware of what’s coming.

# Learn PWA

Welcome to Learn Progressive Web Apps!

This course covers the fundamentals of Progressive Web App development in easy-to-understand pieces.
Over the following modules, you'll learn what a Progressive Web App is,
how to create one or upgrade your existing web content,
and how to add all the pieces for an offline, installable app.
Use the menu pane to navigate the modules. (The menu is at left on desktop or behind the hamburger menu on mobile.)

You'll learn PWA fundamentals like the Web App Manifest,
service workers, how to design with an app in mind,
how to use other tools to test and debug your PWA.
After these fundamentals, you'll learn about integration with the platform and operating system,
how to enhance your PWA's installation and usage experience, and how to offer an offline experience.

Each module includes interactive demos and self-assessments for you to test your knowledge.
You will be able to test and try demos on your mobile phone, tablet,
or laptop while playing with code to understand the fundamentals of what makes a Progressive Web App.

This course is created for a beginner and advanced web developers alike.
You can go through the series from start to finish to get a general understanding of PWA from top to bottom,
or you can use it as a reference for specific subjects.
For those new to web development you will need a grounding in HTML, CSS, and JavaScript to follow along.
Check out [Learn CSS](/learn/css), and the
[HTML](https://developer.mozilla.org/docs/Learn/HTML) and
[JavaScript](https://developer.mozilla.org/docs/Learn/JavaScript) courses on MDN.

Here's what you'll learn:

{% include 'partials/course-index.njk' %}

So, are you ready to learn PWA?

{% Aside %}
This course was written by [Maximiliano Firtman](https://twitter.com/firt), with input and review from [Rachel Andrew](https://twitter.com/rachelandrew), [Adriana Jara](https://twitter.com/tropicadri), [Pete LePage](https://twitter.com/petele), [Sam Richard](https://twitter.com/snugug), and [Joe Medley](https://twitter.com/medleyjp).
{% endAside %}

# App design

This chapter focuses on some critical aspects of rendering content outside of the browser tab.

## The window

Different operating systems have different ideas about what an application window is.
For example, on iPhones, an application always takes up 100% of the screen. On Android and iPads applications usually run fullscreen but it is possible to share the screen between two apps, however there is only one app instance open at a time.
In contrast, on a desktop device, an application can have more than one instance open at a time.
It shares the available screen real estate with all other open applications.
Each application instance can be resized and positioned anywhere on the screen, even overlapping other applications.

## The icon

We recognize apps by their icon. That icon appears when you search for apps, in settings, wherever you launch apps, and where you see running apps.

These include:

- Home screen (iOS, iPadOS, Android).
- App Launcher (macOS, Android).
- Start Menu or App Menu (Windows, ChromeOS, Linux).
- Dock, TaskBar, or Multi-task panels (all operating systems).

When creating the icon for your Progressive Web App
make sure its icon is platform-agnostic, as each operating system can render icons and apply different shape masks to them, like the ones in the image below.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/geo6MZwaWvNDRFJe6cvF.png", alt="PWA icons in different shapes for different platforms.", width="800", height="207" %}

## Theming your app

There are a number of ways you can customize app styling in your PWA's, including:

* Theme color: defines the color of the window's title bar on the desktop and the color of the status bar on mobile devices. Using a meta tag, you can have options for different schemes, such as dark or light mode and they will be used based on the user's preference.
* Background color: defines the color of the window before the app and its CSS are loaded.
* Accent color: defines the color of built-in browser components, such as form controls.

<figure>
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/fW7mXimvH0Djb637xDH8.png", alt="A desktop PWA showing theme and accent colors, and an Android PWA splash screen showing theme and background colors.", width="800", height="526" %}
<figcaption>A desktop PWA showing theme and accent colors, and an Android PWA splash screen showing theme and background colors.</figcaption>
</figure>
{% Aside %}

When planning your Progressive Web App user interface, beware that you can't use images, or gradients for your theme, just plain colors. It's best to pick colors without transparency,
and  use the `rgb` or `hsl` colors, hex codes, or named colors.
Theming your app may also affect browser theming even without installing the app, such as when using the [`<meta name="theme-color">`](/add-manifest/#theme-color) element.
{% endAside %}

## Display modes

You can define what kind of window experience you'd like for your Progressive Web App. There are three options to choose from:

* Fullscreen
* Standalone
* Minimal User Interface

{% Aside %}
If a particular display mode isn't supported or otherwise can't be used to display your PWA, it'll fall back to the next available display mode. Fullscreen will fall back to standalone, standalone will fall back to minimal user interface, and minimal user interface will fall back to browser, the default. The browser display mode doesn't show up as its own window, but rather displays your PWA in a tab in the browser it was installed from, like a web bookmark on a home screen.
{% endAside %}

### Fullscreen experience

A fullscreen experience is suitable for immersive experiences, such as games, VR, or AR experiences. It's currently only available on Android devices, and it hides the status bar and the navigation bar, giving your PWA 100% of the screen for your content.

On desktop and iPadOS, fullscreen PWAs are not supported; however, you can use the [Fullscreen API](https://developer.mozilla.org/docs/Web/API/Fullscreen_API) from within your PWA to display your app fullscreen at a user's request.

### Standalone experience

The most common option for a Progressive Web App, standalone mode displays your PWA in an OS-standard window without any browser navigation UI. The window may also include a  browser-controlled menu where the user can:

* Copy the current URL.
* See, apply, or disable browser extensions.
* See and change permissions.
* Check current origin and the SSL certificate.

The title bar may also show permissions and hardware usage replacing the omnibox or URL bar when the PWA renders in the tab.

<figure>
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/0496WcZmxpNXE35jOGEw.png", alt="A PWA installed with Microsoft Edge on desktop showing its menu.", width="800", height="459" %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/2RmIdDEe4gm99lTzwLCa.png", alt="A PWA installed with Google Chrome on desktop showing the drop-down menu and the plugins-icon.", width="800", height="640" %}
  <figcaption>The images above show how a PWA displays in standalone mode on the desktop in Microsoft Edge, and Chrome.</figcaption>
</figure>

On mobile devices, a standalone PWA experience will create a standard screen that keeps the status bar visible, so the user can still see notifications, time, and battery level. It often does not have any browser-controlled menu like desktop standalone experiences may include.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/sNa6aVY2ZayRqPZhpfIl.png", alt="An iOS device rendering a standalone app.", width="800", height="476" %}

Some browsers on Android create a fixed and silent notification while the PWA is in the foreground that lets the user copy the current URL or other options.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/iE1jwkZq1VWMJC8RZxJs.png", alt="An Android notification rendered by Chrome showing some actions over the current active PWA.", width="730", height="428" %}

### Minimal user interface

This mode is available for Progressive Web Apps on Android and desktop operating systems.
When you use it, the browser rendering your PWA will show a minimal user interface to help the user navigate within the application.

On Android, you will get a title bar that renders the current `<title>` element and the origin with a small drop-down menu available. On desktop, you will get a set of buttons in the title bar to help with navigation, including a back button and a control that swaps between a stop and a reload action, based on the current loading status.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/nzzjXh6YK5GzP6K2Sfb5.png", alt="A desktop minimal-ui on Microsoft Edge with back and reload buttons", width="800", height="399" %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/wu1S51rlQpgBcDkJgEvG.png", alt="On Android, browsers use a read-only themed navigation bar for minimal-ui, here Firefox and Chrome", width="800", height="249" %}

{% Aside 'warning' %}
Safari on iOS and iPadOS doesn't support Minimal UI mode for PWAs. Instead, a browser shortcut is used as a fallback. The user can add an icon to the home screen, but that icon will point to Safari as a bookmark, and they won't have an app experience out of the browser tab.
{% endAside %}

## Optimizing design for desktop

When you design a Progressive Web App to work on a desktop,
you need to think about the endless possibilities for window size as compared to being in the browser's tab or as an app in a mobile operating system.

In [Chapter 3](/learn/pwa/foundations/), we mentioned mini-mode: a desktop app can be as small as 200 by 100 pixels. This window will use the `<title>` element's content in your HTML as the title of the window. That content is also rendered when you **alt-tab**"** between apps and in other places.

Pay attention to your HTML's `<title>` element and rethink how you use it. The `<title>` isn't just for SEO or to render just the first characters in a browser's tab; it will be part of the user experience of your standalone desktop window.

{% Aside %}
If you are developing your app using a client-side library, such as React or Vue, don't forget to change the `<title>` to some practical value when moving between sections or routes of your app. It's time to reimagine the `<title>`!
{% endAside %}

## CSS best practices

All your experience with [CSS layout, design, and animation](/learn/css) is valid when your content is rendered in its standalone experience. However, there are a couple of tips and tricks to making the experience better for a standalone window.

{% Aside 'gotchas' %}
Remember that CSS only defines styles for the content of the PWA; later in this course, we will see how to specify style declarations for the window around your content, such as properties in the [web app manifest](/learn/pwa/web-app-manifest/).
{% endAside %}

### Media Queries

The first [media query](/learn/design/media-queries/) that you can take advantage of in your PWA is the `display-mode` property accepting the values `browser`, `standalone`, `minimal-ui`, or `fullscreen`.

This media query applies different styles to each mode.
For example, you could render an [installation invitation](/learn/pwa/installation/) only when in browser mode, or render one particular piece of information only when the user uses your app from the system icon. This might include adding a back button to use when your app launches in standalone mode.

```css
/* It targets only the app used within the browser */
@media (display-mode: browser) {
}
/* It targets only the app used with a system icon in standalone mode */
@media (display-mode: standalone) {
}
/* It targets only the app used with a system icon in all mode */
@media (display-mode: standalone), (display-mode: fullscreen), (display-mode: minimal-ui) {
}
```

{% Aside %}
Users expect apps to integrate with the platform, so consider offering dark and light modes using [`prefers-colors-scheme`](https://developer.mozilla.org/docs/Web/CSS/@media/prefers-color-scheme) and honoring [`prefers-reduced-motion`](/prefers-reduced-motion/) media queries to disable or reduce transitions and animations.
{% endAside %}

## The app experience

When the users are using an installed PWA, they expect app behavior. While it's not simple to define what it means, the default web behavior doesn't give the best experience in some situations.

### User selection

Content is generally selectable with a mouse or pointer, or a press and hold touch gesture. While helpful for content, it doesn't provide the best experience for navigation items, menus, and buttons within your PWA.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/F9HCkRrmPyGFjlpTJhNz.png", alt="A calculator PWA where you can select every interactive button, such as the numbers.", width="800", height="739" %}

Therefore, it's a good idea to disable user selection on these elements using `user-select: none` and it's `-webkit-` prefix version:

```css
.unselectable {
   user-select: none;
}
```

{% Aside 'gotchas' %}
User selection is a vital feature of every web app for usability and accessibility. Do not disable user selection on all content, only on UI elements when not doing so creates a poor or unexpected experience.
{% endAside %}

### Accent color

In your PWA, you can define a color to match your brand within HTML form controls using the property [`accent-color`](/accent-color/).

### System fonts

If you want an element, like dialogs or messages, to match the user's default platform font, you can use the following font family:

```css
selector {
  font-family: -apple-system, BlinkMacSystemFont,
    "Segoe UI", system-ui, Roboto, Oxygen-Sans, Ubuntu, Cantarell,
    "Helvetica Neue", sans-serif;
}
```

### Pull to refresh

Modern mobile browsers, such as Google Chrome and Safari, have a feature that refreshes the page when it is pulled down. On some browsers, such as Chrome on Android, that behavior is also enabled on standalone PWAs.

You may want to disable this action. For example when providing your own gesture management or refresh action, or if there is a possibility that your user will trigger the action unintentionally.

It's possible to disable this behavior by using `overscroll-behavior-y: contain`:.

```css
  body {
    overscroll-behavior-y: contain;
  }
```

### Safe areas

Some devices do not have unobstructed rectangular screens; instead, their screen may be a different shape, like a circle, or have portions of the screen that can't be used, like the iPhone 13's notch. In these cases, some browsers will expose [environment variables](https://developer.mozilla.org/docs/Web/CSS/env()) with safe areas that can display content.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/hKWqUXIbvvH05WHQEccm.png", alt="At top, a notch-based device in landscape with a standard viewport showing unrendered areas at the sides; at bottom, a device with full viewport access thanks to viewport-fit=cover.", width="800", height="1006" %}

If you want full access to the screen, even the invisible area, to render your color or image, include `viewport-fit=cover` in the content of your `<meta name="viewport">` tag. Then use the `safe-area-inset-*` environment variables to extend your content safely into those areas.

{% Aside 'caution' %}
When you apply `viewport-fit=cover`, remember that you can now render pixels behind rounded corners and notches, so you should always use safe margins or paddings for the critical content and interactive elements.
{% endAside %}

##  Resources

- [CSS display-mode media query](https://developer.mozilla.org/docs/Web/CSS/@media/display-mode)
- [Take control of your scroll: customizing pull-to-refresh and overflow effects](https://developer.chrome.com/blog/overscroll-behavior)
- [prefers-color-scheme: Hello darkness, my old friend](/prefers-color-scheme/)
- [prefers-reduced-motion: Sometimes less movement is more](/prefers-reduced-motion/)
- [env() CSS function](https://developer.mozilla.org/docs/Web/CSS/env())
- [CSS Accent Color](/accent-color/)

# Architecture

Designing your application to make the most out of the technology that makes PWAs reliable, installable, and capable starts with understanding your application and its constraints, and choosing an appropriate architecture for both.

## SPA versus MPA

Today, there are two primary architectural patterns in web development: single-page apps, or SPAs, and multi-page apps, or MPAs.

Single-page apps are defined by having client-side JavaScript control most or all of the HTML rendering of a page based on data retrieved by or provided to the app. The app overrides the browser's built-in navigation, replacing it with its routing and view handling functionality.

Multi-page apps usually have pre-rendered HTML sent directly to the browser, often enhanced with client-side JavaScript after the browser has finished loading the HTML, and relying on the browser's built-in navigation mechanisms to display subsequent views.

Both architectures can be used to create PWAs.

Each has advantages and disadvantages, and selecting the right one for your use case and context is key to providing a fast and reliable experience for your users.

### Single page apps

{% Compare 'better', 'Pros' %}
* Mostly atomic in-page updates.
* Client-side dependencies loaded on start-up.
* Subsequent loads are fast, because of cache usage.
{% endCompare %}

{% Compare 'worse', 'Cons' %}
* High initial load cost.
* Performance depends on device hardware and network connection.
* Additional app complexity is required.
{% endCompare %}

Single page apps are a good architectural fit if:

* User interaction is mainly centered around atomic updates of interconnected data displayed on the same page, for instance, a real-time data dashboard or a video-editing app.
* Your application has client-side-only initialization dependencies, for instance, a third-party authentication provider with a prohibitively high startup cost.
* The data required for a view to load relies on a specific client-side-only context, for instance, displaying controls for a piece of connected hardware.
* The app is small and simple enough that its size and complexity do not have an impact on the cons listed above.

SPAs might not be a good architecture choice if:

* Initial load performance is essential. SPAs usually need to load more JavaScript to determine what to load and how to display it. The parsing and execution time of this JavaScript, combined with retrieving content, is slower than sending rendered HTML.
* Your app runs mostly on low-to-average-powered devices. Because SPAs depend on JavaScript for rendering, the user experience depends much more significantly on the power of their specific device than it would in an MPA.

Because SPAs need to replace the browser's built-in navigation with their routing, SPAs require a minimum level of complexity around efficiently updating the current view, managing navigation changes, and cleaning up previous views that would otherwise be handled by the browser, making them harder overall to maintain and more taxing on the user's device.

### Multi-page apps

{% Compare 'better', 'Pros' %}
* Mostly full-page updates.
* Initial render speed is critical.
* Client-side scripting can be an enhancement.
{% endCompare %}

{% Compare 'worse', 'Cons' %}
* Secondary views require another server call.
* Context doesn't carry over between views.
* Requires a server or pre-rendering.
{% endCompare %}


Multi-page apps are a good architectural choice if:

* User interaction is mainly centered around views of a single piece of data with optional context-based data, for instance, a news or e-commerce app.
* Initial render speed is critical, as sending already rendered HTML to the browser is faster than assembling it from a data request after loading, parsing, and executing a JavaScript-based alternative.
* Client-side interactivity or context can be included as an enhancement after initial load, for instance, layering a profile onto a rendered page or adding secondary client-side context-dependent components.

MPAs might not be a good architecture choice if:

* Re-downloading, re-parsing, and re-executing your JavaScript or CSS is prohibitively expensive. This con is mitigated in PWAs with service workers.
* Client-side context, such as user location, doesn't seamlessly carry over between views, and re-obtaining that context may be expensive. It either needs to be captured and retrieved, or re-requested between views.

Because individual views need to be dynamically rendered by a server or pre-rendered before access, potentially limiting hosting or adding data complexity.

### Which one to choose?

Even with these pros and cons, both architectures are valid for creating your PWA. You can even mix them for different parts of your app, depending on its needs, for instance, having store listings follow an MPA architecture and the checkout flow follow an SPA architecture.

Regardless of choice, the next step is understanding how to best use service workers to provide the best experience.

## The power of service worker

The service worker has a lot of power beyond basic routing and delivery of cached and network responses. We can create complex algorithms that can improve the user's experience and performance.

### Service worker includes (SWI)

An emerging pattern for using service workers as an integral part of a site's architecture is service worker includes (SWI).
SWI divides individual assets, usually an HTML page, into pieces based on their caching needs, then stitches them back together in the service worker to improve consistency, performance, and reliability, while reducing cache size.
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/xDjYv2TYJik4xm1h7nyS.png", alt="A website with a global header, a content area, a sidebar and a footer.", width="800", height="520" %}

This image is a sample web page. It has five different sections that break the page down into:

* Overall layout.
* Global header (top dark bar).
* Content area (middle left lines and image).
* Sidebar (tall medium-dark bar on the middle right).
* Footer (dark bottom bar).

#### Overall layout

The overall layout isn't likely to change often and has no dependencies. It's a good candidate for [precaching](/learn/pwa/assets-and-data/#frequently-used-cache-approaches).

#### Header and footer

The global header and footer contain things like the top menu and site footer, and present a particular challenge: if the page were to be cached as a whole, these might change between page loads, depending on when the given page was cached.

By separating them and caching them independently of the content, you can ensure that users will always get the same version, regardless of when they are cached. Because they are infrequently updated, they're good candidates for precaching, too. They have a dependency, though: the site's CSS and JavaScript.

#### CSS and JavaScript

Ideally, the site's CSS and JavaScript should be cached with a stale while revalidate strategy to allow incremental updates without needing to update the service worker, as it is the case with precached assets. Still, they also need to be kept at a minimum version whenever the service worker updates with a new global header or footer. Because of this, their cache should also be updated with the latest version of assets when the service worker installs.

#### Content area

Next is the content area. Depending on the frequency of updates, either network first or stale while revalidate is a good strategy here. Images should be cached with a cache first strategy, as has been previously [discussed](/learn/pwa/serving/#caching-strategies).

#### Sidebar

Finally, presuming the sidebar content contains secondary content such as tags and related items, it's not critical enough to pull from the network. A stale while revalidate strategy works for this.

Now, after going through all that, you may be thinking that you can only do this kind of per-section caching for single-page apps. But, by adopting patterns inspired by [edge side includes](https://en.wikipedia.org/wiki/Edge_Side_Includes) or [server side includes](https://en.wikipedia.org/wiki/Server_Side_Includes) in your service worker, with some advanced service worker features, you can do this for either architecture.

#### Try it yourself

You can try the service worker includes with the next codelab:

{% Aside 'codelab' %}
[Service worker includes](https://developers.google.com/codelabs/pwa-training/pwa06--service-worker-includes).
{% endAside %}

### Streaming responses

The previous page could be created using the app shell model in the SPA world, where the app shell is cached, then served, and content is loaded on the client side. With the introduction and wide availability of the [Streams API](https://developer.mozilla.org/docs/Web/API/Streams_API), both app shell and content can be combined in the service worker and streamed to the browser, giving you the caching flexibility of app shell with the speed of MPAs.

It does this because:

* Streams can be built asynchronously, allowing different pieces of a stream to come from other sources.
* The requester of a stream can start working on the response as soon as the first chunk of data is available, instead of waiting for the entire item to be complete.
* Parsers optimized for streaming, including the browser, can progressively display the content of the stream before it's complete, speeding up the perceived performance of the response.

Thanks to these three properties of streams, architectures built around streaming usually have a faster perceived performance than those that aren't.

Working with the Streams API can be challenging as it's complex and low level. Fortunately, there's a [Workbox module](https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-streams) that can help with setting up streaming responses for your service workers.

## Domains, origins, and PWA scope

Web workers, including service workers, storage, even an installed PWA's window, are all governed by one of the most critical security mechanisms on the web: the same-origin policy. Within the same origin, permissions are granted, data can be shared, and the service worker can talk to different clients. Outside of the same origin, permissions are not automatically granted and data is isolated and not accessible between different origins.

### Same-origin policy

Two URLs are defined as having the exact origin if the protocol, port, and host are the same.

For example: `https://squoosh.app`, and `https://squoosh.app/v2` have the same origin, but `http://squoosh.app`, `https://squoosh.com`, `https://app.squoosh.app` and `https://squoosh.app:8080` are in different origins. Check the [same-origin policy MDN reference](https://developer.mozilla.org/docs/Web/Security/Same-origin_policy) for more information and examples.

Changing subdomains isn't the only way a host can change. Each host is made up of a top-level domain (TLD), a secondary level domain (SLD), and zero or more labels (sometimes called subdomains), separated by dots in between and read from right to left in an URL. A change in any of the items results in a different host.

In the [window management module](/learn/pwa/window), we've already seen how the in-app browser looks when a user navigates to a different origin from an installed PWA.

That in-app browser will appear even if the websites have the same TLD and SLD, but with different labels, as they are then considered different origins.

One of the key aspects of an origin in a web-browsing context is how storage and permissions work. One origin shares many features among all content and PWAs within it, including:

- Storage quota and data (IndexedDB, cookies, web storage, cache storage).
- Service worker registrations.
- Permissions granted or denied (such as web push, geolocation, sensors).
- Web push registrations.

When you move from one origin to another, all the previous access is revoked, so permissions have to be granted again, and your PWA can't access all the data saved in the storage.

{% Aside 'caution' %}
Having different subdomains for different parts of a website or different TLDs for other locales, such as `admin.example.com` or `example.co.uk`, makes building PWAs harder, each subdomain will have isolated storage, its own service worker registration, and web app manifest. It may also lead to a disjointed experience if the subdomains are designed to look like the same app, as one will be displayed in the in-app browser while the main PWA won't.
{% endAside %}

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/V1OWWZnCGpwVcaZE152Z.mp4", autoplay=true, controls=true, loop=true %}

##  Resources

- [Beyond SPAs: Alternative architectures for your PWA](https://developer.chrome.com/blog/beyond-spa)
- [Progressive web apps Structure](https://developer.mozilla.org/docs/Web/Progressive_web_apps/App_structure)
- [Streams: The definitive guide](/streams/)

# Assets and data

Developing an application typically involves several assets and resources,
from the logic and code (compiled or not) to the user interface elements such as screen designs, images, logos, and fonts.

A Progressive Web App is a website, so all its assets are the same as on the web:

- HTML for content and initial page rendering.
- JavaScript for logic, including the ability to run WebAssembly modules (compiled code) and render 2D and 3D hardware-optimized graphics.
- CSS for layout, styling, and animations.
- Images in web formats, such as PNG, JPEG, WebP, and SVG.
- Videos in web formats, such as MPEG-4 and WebM.
- Web fonts.
- Data in JSON or other formats.

By default, websites download assets over the network,
[starting with HTML](/critical-rendering-path/)
and continuing to the rest of the resources.

Managing those resources to load fast and be available offline has been a challenge for the web.
Nowadays, PWAs use capabilities previously associated only with platform-specific apps.

### Platform-specific apps vs. PWA

When you install a platform-specific app you are typically downloading a package that includes all the app's assets: code, images, fonts, videos, and so on.
Therefore, all these resources are available, from your device storage, even when the app is offline.

On the other hand, a classic website needs a network connection to download the assets when required.
If you are offline, you will see an error from the browser as there are no assets client-side.

The PWA approach enhances the traditional web experience by making some or all the assets available client-side as with platform-specific apps. Therefore, when you open a PWA, the initial rendering can be as instantaneous as a platform app because the assets are available without going to the network.

{% Aside %}
An app that is available offline will always render a basic user interface instead of a technical error from the operating system or browser. Some apps still offer all their functionality, some a limited experience, and others a simple message with the app's branding. This applies to both platform-specific apps and PWAs.
{% endAside %}

## Caches and storage

Since the beginning of the web, developers have not had complete control of how a resource is cached.
The browser is in charge of the HTTP cache and it may or may not cache and serve resources based on different policies.
Other storage options like Web Storage and IndexedDB were meant to save simple data and objects.

PWAs don't need to rely on those policies alone for their content.
Instead, we have solutions today to gain better control over when and how to cache resources and when and how to deliver them locally: the Cache Storage API.
The web has a few of client-side storage solutions available:

* **Web storage**: Includes `localStorage` and `sessionStorage`. These APIs store simple key/value string pairs. Web storage is limited, and has a synchronous API, so it should be avoided whenever possible.
* **IndexedDB**: An object-based database (No-SQL) with an asynchronous API that is good for web performance. IndexedDB can store structured and binary data client-side. It is typically what you will use to store data, like what you'd get from or send as an API request. It's also useful to save data locally immediately and later on sync it to the server. The [IndexedDB API](https://developer.mozilla.org/docs/Web/API/IndexedDB_API) is used to interact with the database.
* **Cache storage**: A collection of HTTP request and response pairs you can use to store and retrieve resources — with their HTTP headers — exactly as they are delivered from the server. The [Cache Storage API](https://developer.mozilla.org/docs/Web/API/CacheStorage) allows you to store, retrieve, update and delete network requests, for example for your assets, even when offline.

{% Aside 'warning' %}
You may have heard about WebSQL and ApplicationCache. These two solutions are deprecated, and you shouldn't use them in your PWA.
{% endAside %}

### The need for service workers

A PWA can store its assets in Cache Storage and IndexedDB,
but how can we use those assets to deliver a fast and offline experience to your users. The answer? Service workers.

With a service worker, you can serve assets without going to the network, send notifications to a user, add a badge to your PWA icon, update content in the background, and even make your whole PWA work offline. Learn more about service workers in the [next chapter](/learn/pwa/service-workers/).

## Offline-ready

Users expect your application to offer a fast and always-ready experience.
That means your app should work offline.

Being offline-ready doesn't mean that all your content or services should be available without a network connection.
However having at least a basic experience when the user is offline, like a page that asks you to connect to the Internet to continue, will provide for a better user experience, keeping the user within the experience of your app instead of a generic browser error.
In some browsers this is a must-have feature to pass the PWA installation criteria.
Displaying your PWA's user interface, along with cached content, is better.
Letting users continue using your whole PWA and syncing server changes when they're back online is the gold standard for working offline.

To make your app available offline, you will need to cache the assets necessary for your offline experience and make your service worker serve them later. Make sure to add the offline assets to your cache before you need them. This is a particular case where you cannot cache them when requested.

{% Aside %}
Asset caching happens independently from PWA installation,
and will work even from a browser tab, allowing for faster asset delivery and an offline experience regardless of how a user chooses to use your PWA.
{% endAside %}

### Frequently used cache approaches

In your PWA, you are in charge of all the decisions. You can choose the best approach to cache or install assets based on your needs.
Some decisions to make are:

* Precaching: pick the assets you'd like to install on the first load; those should include the HTML and the minimal assets to render the app. When using precache keep in mind you are using the device's space and network. Be conscious and responsible when downloading assets and caching them.
* Cache as needed: used to add assets to the cache when they are requested. Typically these are assets that can change independently of your app version, like images or content. See the [caching](/learn/pwa/caching) section for different strategies on how to cache as needed.
* APIs and web services: API calls can be cached; or, instead of caching the API responses, you can store their data in IndexedDB.

{% Aside 'gotchas' %}
With platform-specific apps, the most common pattern is to include all the app's assets in its package; that's why these apps are commonly larger than 500 MB. On the other hand, A PWA can initially install only the minimum set of resources to offer an offline and fast experience and download the rest later, with PWAs using considerably less storage on installation.
{% endAside %}

### Updating assets
In the standard app model for app catalog installed apps, when developers need to update their app, they publish a new package. Users need to download the whole package again, even if most of the assets haven't changed.
With PWAs, using the approaches on the section above, you decide how and when to update assets.
Here are different options for how to update assets:

* Full Update: in this case, every time you make a change in the app, even a minor one, your code will download all the assets again in the cache.
* Partial Update: in this approach, you create a method to define which assets have been updated, and you update only those, with or without the user's intervention.
* Continuous Update: using this technique, your assets will be checked and updated automatically on every PWA usage individually

{% Aside %}
When caching assets, you need to decide on a cache swap or clean up policy that defines when the user will see an updated asset; taking into account storage usage and the balance between a fast experience and displaying a slightly stale asset.
{% endAside %}

## Size and Lifespan

Usually platform-specific apps don't deal with size limits; at installation, apps can be gigabytes or more in size. As long as the device has the capacity the installation will be allowed. Also, while the app is installed, it will use that total amount of storage no matter if you use the app or not.
Storage is handled differently for PWAs. The browser will store your assets based on policies that you define in your PWA's logic.

{% Aside %}
The users are always in control, and they can delete the assets at any time. For PWAs, manual eviction happens via the browser's settings.
{% endAside %}

Size limits depend on the browser.
It's not as flexible as for platform-specific apps, but it's typically good enough for most web apps. You can find the specific limitations by browser in [this article](/storage-for-the-web/#how-much).

Browsers can evict assets based on storage pressure, or after some weeks of inactivity, if the user is using your PWA in the browser. On some platforms, if the user installs your PWA, eviction won't happen. Where available, code can request persistent storage through an API to avoid that eviction.

{% Aside %}
If storage eviction happens for any reason and the user installed your PWA, the PWA will still work if you have a network connection. When you open that app again, the browser will start the service worker lifecycle again, loading your app from the network.
{% endAside %}

##  Resources

- [Storage on the Web](/storage-for-the-web/)
- [MDN: Web Storage](https://developer.mozilla.org/docs/Web/API/Web_Storage_API)
- [MDN: IndexedDB](https://developer.mozilla.org/docs/Web/API/IndexedDB_API)

# Caching

Cache storage is a powerful tool. It makes your apps less dependent on network conditions. With good use of caches you can make your web app available offline and serve your assets as fast as possible in any network condition. As mentioned in [Assets and Data](/learn/pwa/assets-and-data/) you can decide the best strategy for caching the necessary assets. To manage the cache your service worker interacts with the [Cache Storage API](https://developer.mozilla.org/docs/Web/API/CacheStorage).
{% BrowserCompat 'api.CacheStorage' %}

{% Aside %}
When installing platform-specific apps, the device stores the icon and other app assets in the operating system, in one step. For PWAs, the process has two separate steps. A PWA can store assets on your device any time after the first visit in the browser, even without installation. Install is a separate action that is covered later in this course.
{% endAside %}

The Cache Storage API is available from different contexts:

- The window context (your PWA's main thread).
- The service worker.
- Any other workers you use.

One advantage of managing your cache using service workers is that its lifecycle is not tied to the window, which means you are not blocking the main thread. Be aware that to use the Cache Storage API most of these contexts have to be under a TLS connection.

## What to cache

The first question you may have about caching is what to cache. While there is no single answer to that question, you can start with all the minimum resources that you need to render the user interface.

Those resources should include:

- The main page HTML (your app's start_url).
- CSS stylesheets needed for the main user interface.
- Images used in the user interface.
- JavaScript files required to render the user interface.
- Data, such as a JSON file, required to render a basic experience.
- Web fonts.
- On a multi-page application, other HTML documents that you want to serve fast or while offline.

{% Aside 'warning' %}
Remember that you are downloading and storing assets on users' devices, so use that space and bandwidth responsibly. You need to find the balance between having enough on-device assets to render a fast or offline experience without consuming too much data.
{% endAside %}

### Offline-ready

While being offline-capable is one of the requirements for a Progressive Web App, it's essential to understand that not every PWA needs a full offline experience, for example cloud gaming solutions or crypto assets apps. Therefore, it's OK to offer a basic user interface guiding your users through those situations.

Your PWA should not render a browser's error message saying that the web rendering engine couldn't load the page. Instead use your service worker to show your own messaging, avoiding a generic and confusing browser error.

{% Aside 'caution' %}
If you [publish your PWA to Google Play Store](https://chromeos.dev/en/publish/pwa-in-play), your PWA should never render an HTTP error message from the browser to avoid penalizations within the store listings. Check [Changes to Quality Criteria for PWAs](https://blog.chromium.org/2020/06/changes-to-quality-criteria-for-pwas.html) for more information.
{% endAside %}

There are many different caching strategies you could use depending on the needs of your PWA. That's why it is important to design your cache usage to provide a fast and reliable experience. For example if all your app assets will download fast, don't consume a lot of space, and don't need to be updated in every request, caching all your assets would be a valid strategy. If on the other hand you have resources that need to be the latest version you might want to consider not caching those assets at all.

{% Aside 'caution' %}
The cache storage content and eviction rules are set per origin and not per PWA, since it's possible to have more than one in a single origin. If you share your origin for many PWAs, it's a good idea to add a prefix to your cache names to avoid collision problems between each PWA's data storage.
{% endAside %}

## Using the API

Use the Cache Storage API to define a set of caches within your origin, each identified with a string name you can define. Access the API through the `caches` object, and the `open` method enables the creation, or opening of an already created cache. The open method returns a promise for the cache object.

```js
caches.open("pwa-assets")
.then(cache => {
  // you can download and store, delete or update resources with cache arguments
});
```

### Downloading and storing assets

To ask the browser to download and store the assets use the `add` or `addAll` methods. The `add` method makes a request and stores one HTTP response, and `addAll` a group of HTTP responses as a transaction based on an array of requests or URLs.

```js
caches.open("pwa-assets")
.then(cache => {
  cache.add("styles.css"); // it stores only one resource
  cache.addAll(["styles.css", "app.js"]); // it stores two resources
});
```

{% Aside %}
Both `add()` and `addAll()` return a promise with no arguments; if it's fulfilled, you know the assets were downloaded and cached, and if it fails, the API couldn't download one or more resources, and it didn't modify the cache.
{% endAside %}

The cache storage interface stores the entirety of a response including all the headers and the body. Consequently, you can retrieve it later using an HTTP request or a URL as a key. You will see how to do that in [the Serving chapter](/learn/pwa/serving).

{% Aside %}
To download and store the assets, you must specify all the URLs explicitly. Otherwise the API cannot know all the assets you need or want to cache.
{% endAside %}

### When to cache

In your PWA, you are in charge of deciding when to cache files. While one approach is to store as many assets as possible when the service worker is installed, it is usually not the best idea. Caching unnecessary resources wastes bandwidth and storage space and could cause your app to serve unintended outdated resources.

You don't need to cache all the assets at once, you can cache assets many times during the lifecycle of your PWA, such as:

- On installation of the service worker.
- After the first page load.
- When the user navigates to a section or route.
- When the network is idle.

You can request caching new files in the main thread or within the service worker context.

### Caching assets in a service worker

One of the most common scenarios is to cache a minimum set of assets when the service worker is installed. To do that, you can use the cache storage interface within the `install` event in the service worker.

Because the service worker thread can be stopped at any time, you can request the browser to wait for the `addAll` promise to finish to increase the opportunity of storing all the assets and keeping the app consistent. The following example demonstrates how to do this, using the  `waitUntil` method of the event argument received in the service worker event listener.

```js/3,5
const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", event => {
   event.waitUntil(
      caches.open("pwa-assets")
      .then(cache => {
         return cache.addAll(urlsToCache);
      });
   );
});
```

The [`waitUntil()` method](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil) receives a promise and asks the browser to wait for the task in the promise to resolve (fulfilled or failed) before terminating the service worker process. You may need to chain promises and return the `add()` or `addAll()` calls so that a single result gets to the `waitUntil()` method.

You can also handle promises using the async/await syntax. In that case, `waitUntil()` needs a promise-based function as an argument, so you need to create a function that returns the promise to make it work, as in the following example:

```js/3
const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", (event) => {
   event.waitUntil(async () => {
      const cache = await caches.open("pwa-assets");
      return cache.addAll(urlsToCache);
   });
});
```

### Cross-domain requests and opaque responses

Your PWA can download and cache assets from your origin and cross-domains, such as content from third-party CDNs. With a cross-domain app, the cache interaction is very similar to same-origin requests. The request is executed and a copy of the response is stored in your cache. As with other cached assets it is only available to be used in your app's origin.

The asset will be stored as an [opaque response](https://fetch.spec.whatwg.org/#concept-filtered-response-opaque), which means your code won't be able to see or modify the contents or headers of that response. Also, opaque responses don't expose their actual size in the storage API, affecting quotas. Some browsers expose large sizes, such as 7Mb no matter if the file is just 1Kb.

{% Aside 'caution' %}
Remember that when you cache opaque responses from cross-domains, `cache.add()` and `cache.addAll()` will fail if those responses don't return with a 2xx status code. Therefore, if one CDN or cross-domain fails, all the assets you are downloading will be discarded, even successful downloads in the same operation.
{% endAside %}

### Updating and deleting assets

You can update assets using `cache.put(request, response)` and delete assets with `delete(request)`.

{% Aside 'caution' %}
The Cache Storage API doesn't update your assets if you change them on your server nor does it delete them. Your code should manage both situations, and for that, there are different design patterns. You'll learn about a library to help with these situations in the [Workbox chapter](/learn/pwa/workbox).
{% endAside %}

Check the [Cache object documentation](https://developer.mozilla.org/docs/Web/API/Cache) for more details.

{% Glitch 'learn-pwa-asset-caching' %}

## Debugging Cache Storage
Many browsers offer a way to debug the contents of cache storage within their DevTools Application tab. There, you can see the contents of every cache within the current origin. We'll cover more about these tools in the [Tools and Debug chapter](/learn/pwa/tools-and-debug/).

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/wY3mk9ILrGxlM9xEbfHh.png", alt="Chrome DevTools debugging Cache Storage contents.", width="800", height="506" %}

{% Aside %}
Web Inspector on Safari on macOS doesn't have a way to see the contents of cache storage. For that purpose, you can use the free [Service Worker Detector Safari extension](https://apps.apple.com/app/service-worker-detector/id1530808337?l=en&mt=12) created by [Thomas Steiner](https://twitter.com/tomayac).
{% endAside %}

##  Resources

- [Cache Storage on MDN](https://developer.mozilla.org/docs/Web/API/CacheStorage)
- [The Cache API: A quick guide](/cache-api-quick-guide/)
- [The Offline Cookbook](/offline-cookbook/)

# Capabilities

Progressive Web Apps can do more than just rendering content on the screen or connecting to web services. PWAs can deal with files from the file system, they can interact with the system's clipboard, they can access hardware that is connected to the device, and much more. Every Web API is available for your PWA, and there are some extra APIs available when your app is installed.

You can use [What Web Can Do Today](https://whatwebcando.today/) to know what's possible on each platform. For individual APIs or capabilities, you can use [Can I Use](https://caniuse.com) or the browser compatibility tables on [MDN](https://developer.mozilla.org/).

## Always check for feature support

The first letter in PWA stands for progressive, and it comes from the idea of [progressive enhancement](https://developer.mozilla.org/docs/Glossary/Progressive_Enhancement) and [feature detection](https://developer.mozilla.org/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection). You should not expect your app to work the same way on every device. The diversity of contexts and abilities on billions of devices in different countries makes PWAs an excellent platform, thanks to their progressiveness.

This means that you need to develop your app in layers that may not be available on every device and to check availability before usage.

You need to check with JavaScript if an API exists before using it or ask an API if a service is available on that particular device.

## Powerful web

The web is super powerful today. For example:

* You can build a [hyperlocal](https://en.wikipedia.org/wiki/Hyperlocal) video chat app with WebRTC, geolocation, and push messages.
* You can make an app installable.
* You can add video effects with WebAssembly.
* You can even bring it into virtual reality with WebGL and WebXR.

{% Aside 'gotchas' %}
While there are many capabilities on the web, there are still gaps, and that's where the [web capabilities project](https://www.chromium.org/teams/web-capabilities-fugu/) comes in. The project  describes a group of APIs to increase what the web is capable of. We discussed this project and how you can participate in it in the [Experimental chapter](/learn/pwa/experimental).
{% endAside %}

## Empowering your PWA

Let's split the PWA capabilities APIs into four groups:

* Green: APIs available on every browser on every platform, when technically possible. Most of them have been shipped for many years, they are considered mature, and you can use them with confidence. An example API from this group is the geolocation API.
* Light green: APIs are available only on some browsers. Considering the lack of support on some platforms, they matured within the supported subgroup of browsers so that you can use the capability confidently on them. An example API from this group is WebUSB.
* Yellow: experimental APIs. These APIs are not yet mature; they are only available on some browsers, and within tests or trials. We talked some about these capabilities in the [Experimental chapter](/learn/pwa/experimental).
* Red: the group for APIs that you can't use in a PWA, and where plans to add them are still long term. An example API from this group is geofencing.

{% Aside %}
Some capabilities require user permission: in most cases, the permission dialog appears on first usage. Today, you can request a single permission at a time, but in the future, it may be possible to request many permissions in one dialog on some platforms, using the [Permissions API](https://w3c.github.io/permissions/).
{% endAside %}

### Green capabilities

Below is a list of the most important capabilities you can use in your PWA.

#### Basics
- *Caching files locally* using the Cache API, as seen in the [Caching chapter](/learn/pwa/caching).
- *Executing tasks in threads* using web workers, as we saw in the [Complexity management chapter](/learn/pwa/complexity).
- *Managing network requests* with different strategies in a service worker, as seen in the [Service workers chapter](/learn/pwa/service-worker).
- *2D Canvas* for rendering 2D graphics on the screen using the [Canvas API](https://developer.mozilla.org/docs/Web/API/Canvas_API).
- *2D and 3D high-performance Canvas*, or [WebGL](https://developer.mozilla.org/docs/Web/API/WebGL_API), for rendering 3D graphics.
- *WebAssembly*, or [WASM](https://developer.mozilla.org/docs/WebAssembly), for executing low-level compiled code for performance.
- *Real-Time communication*, using the [WebRTC API](https://developer.mozilla.org/docs/Web/API/WebRTC_API).
- *Web Performance* APIs to measure and help provide a better experience. See [the Performance API guide](https://developer.mozilla.org/docs/Web/API/Performance_API) for more information.
- *Store data locally* with IndexedDB and storage management to query quota and request persistent storage, as seen in the [Offline data chapter](/learn/pwa/offline-data).
- *Low-level audio* thanks to the [Web Audio API](https://developer.mozilla.org/docs/Web/API/Web_Audio_API).
- *Foreground detection* using the [Page Visibility API](https://developer.mozilla.org/docs/Web/API/Page_Visibility_API).
- *Network communication* using the [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) and the [WebSocket API](https://developer.mozilla.org/docs/Web/API/WebSockets_API).

#### Hardware and sensors

- *Geolocation* obtains the user's location through different providers, such as satellite or Wi-Fi through the [Geolocation API](https://developer.mozilla.org/docs/Web/API/Geolocation_API).
- *Camera and microphone* receive media streams from cameras and microphones using the [Media devices](https://developer.mozilla.org/docs/Web/API/MediaDevices) interface.
- *Sensors*  gather real-time information from the accelerometer, gyroscope, magnetometer, and others using the [Sensors API](https://developer.mozilla.org/docs/Web/API/Sensor_APIs) or older interfaces, such as [DeviceMotionEvent](https://developer.mozilla.org/docs/Web/API/DeviceMotionEvent) and [DeviceOrientationEvent](https://developer.mozilla.org/docs/Web/API/DeviceOrientationEvent). On Safari, you need to use a [non-standard permission dialog request](https://medium.com/flawless-app-stories/how-to-request-device-motion-and-orientation-permission-in-ios-13-74fc9d6cd140) to use them.
- *Touch and pointer* access information about all the touches and pointer-based clicks you make with your finger, a mouse, a trackpad, or a pen, thanks to [Pointer events](https://developer.mozilla.org/docs/Web/API/Pointer_events) and [Touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).

{% Aside %}
Safari also supports [Gesture events](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW23), a non-standard API for detecting rotation and pinching gestures, which should be used with care.
{% endAside %}

- *Gamepads* to read information coming from standard gamepads and joysticks connected to the device using the [Gamepad API](https://developer.mozilla.org/docs/Web/API/Gamepad_API/Using_the_Gamepad_API).
- *Biometric authentication* (such as face or fingerprint recognition) using [Web Authentication or WebAuthn](https://webauthn.guide/).

#### Operating system integration

- *Speech synthesis and voice recognition* use the platform's installed voices to speak to the user and to recognize what the user is saying, thanks to the [Web Speech API](https://developer.mozilla.org/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API).
- *Share content* from your PWA to other apps and places on the device, thanks to the [Web Share API](https://developer.mozilla.org/docs/Web/API/Web_Share_API), as we'll see in the [OS integration chapter](/learn/pwa/os-integration).
- *Access the clipboard* to save and retrieve content from the clipboard in different formats, thanks to the [Clipboard API](https://developer.mozilla.org/docs/Web/API/Clipboard_API), as I showed in the [OS integration chapter](/learn/pwa/os-integration).
- *Manage user's credentials and passwords* using the [Credential Management API](https://developer.mozilla.org/docs/Web/API/Credential_Management_API).
- *Enable picture-in-picture* video playing within the OS using the [picture-in-picture API](https://developer.mozilla.org/docs/Web/API/Picture-in-Picture_API).
- *Render content in fullscreen* thanks to the [Fullscreen API](https://developer.mozilla.org/docs/Web/API/Fullscreen_API), as I showed in the [Windows chapter](/learn/pwa/windows).

{% Aside %}
You can integrate your PWA with many platform-specific apps using URI schemes and universal URLs, as I showed in the [OS Integration chapter](/learn/pwa/os-integration).
{% endAside %}

### Light-green capabilities

Here is a list of the most important capabilities you can use in your PWA, with the caveat that they may not be available on every browser.

#### The basics

- *WebGL 2.0*, the [new version of the WebGL spec](https://developer.mozilla.org/docs/Web/API/WebGL2RenderingContext) to match OpenGL 3.0.
- *Codecs*, low-level access to the individual frames of a video stream and chunks of audio; useful for web applications that require full control over the way media is processed through [the Web Codecs API](https://developer.mozilla.org/docs/Web/API/WebCodecs_API).

#### Hardware and sensors

- *Advanced camera controls* to access [pan, tilt, and zoom controls](/camera-pan-tilt-zoom/), in addition to the Media APIs.
- *Bluetooth LE* to communicate with Bluetooth low-energy devices near the user using the [Web Bluetooth API](https://developer.mozilla.org/docs/Web/API/Web_Bluetooth_API). Check out [communicating with Bluetooth devices over JavaScript](/bluetooth/) for more information.
- *Near-field communication* to exchange data over NFC via light-weight NFC data exchange format (NDEF) messages, such as an NFC tag or card using the [WebNFC API](https://developer.mozilla.org/docs/Web/API/Web_NFC_API). You can also read [Interact with NFC devices on Chrome for Android](/nfc) for more details.
- *Serial peripheral* for low-level access to devices connected to the device using a serial port, USB, or serial over Bluetooth using the [Web Serial WPI](https://developer.mozilla.org/docs/Web/API/Web_Serial_API). In the following link you can learn how to [read from and write to a serial port](/serial).

- *USB device* access to communicate with devices connected via USB [WebUSB API](https://developer.mozilla.org/docs/Web/API/WebUSB_API). Check out [access to USB devices on the web](/usb/) for more information.
- *Human interface devices* let your PWA interact with any kind of device prepared for human interaction that is [uncommon](/hid/), using the [WebHID API](https://developer.mozilla.org/docs/Web/API/WebHID_API). Check out this guide on [connecting to uncommon HID devices](/hid).

{% Aside %}
[Accessing hardware devices on the web](/devices-introduction/) offers a comprehensive guide to understanding how different hardware APIs interact with each other.
{% endAside %}

- *Ambient Light* reads the current light level or illuminance of the ambient light around the device, in addition to the [Sensors API](https://developer.mozilla.org/docs/Web/API/AmbientLightSensor).
- *Vibration* gives the user haptic feedback when something happens, if the device supports it, through the [Vibration API](https://developer.mozilla.org/docs/Web/API/Vibration_API).
- *Recording media* captures the data generated by a MediaStream or HTMLMediaElement object (such as a `<video>` tag) for analysis, processing, or saving to disk, thanks to the [MediaRecorder API](https://developer.mozilla.org/docs/Web/API/MediaRecorder).
- *Applying a wake Lock to the screen*  prevents the device from dimming, or locking the screen, when your PWA needs to keep running, using the [Screen Wake Lock API](https://developer.mozilla.org/docs/Web/API/Screen_Wake_Lock_API).
- *Virtual reality* enables you to use a headset and other devices in your PWA, thanks to the [WebXR Device API](https://developer.mozilla.org/docs/Web/API/WebXR_Device_API).
- *Augmented reality* can be achieved in your PWA in many ways, such as using the [WebXR Device API](https://developer.mozilla.org/docs/Web/API/WebXR_Device_API) or the [Safari Quick Look app for AR content](https://webkit.org/blog/8421/viewing-augmented-reality-assets-in-safari-for-ios/).
- *Detect inactive users* with the [Idle Detection API](/idle-detection/).
- *Orientation lock* locks the orientation to portrait or landscape while the PWA is on the screen, thanks to the [Screen Orientation API](https://developer.mozilla.org/docs/Web/API/Screen_Orientation_API), or the `orientation` property of the [Web App Manifest](/learn/pwa/web-app-manifest) for installed apps.
- *Present content* on projectors and secondary displays, thanks to the [Presentation API](https://developer.mozilla.org/docs/Web/API/Presentation_API).
- *Lock a pointer* to receive delta movement information from pointers (mice, trackpads, and pointers) instead of position values—useful for some games—thanks to the [Pointer Lock API](https://developer.mozilla.org/docs/Web/API/Pointer_Lock_API).

#### Operating system integration

- *Read and write files* on the device, thanks to the [File System Access API](https://developer.mozilla.org/docs/Web/API/File_System_Access_API), as you saw in the [OS Integration](/learn/pwa/os-integration) chapter.
- *Get content from other apps* thanks to [Web Share Target](/web-share-target/), as I showed in the [OS integration](/learn/pwa/os-integration) chapter.
- *Get contact data* using the [Contact Picker API](https://developer.mozilla.org/docs/Web/API/Contact_Picker_API), as shown in the [OS integration](/learn/pwa/os-integration) chapter.
- *Sync in the background* while the PWA is not used, thanks to the [Background Synchronization API](https://developer.mozilla.org/docs/Web/API/Background_Synchronization_API).
- *Task scheduling* while the PWA is not in use, thanks to the [Web Periodic Background Synchronization API](https://developer.mozilla.org/docs/Web/API/Web_Periodic_Background_Synchronization_API).
- *Send notifications* using [Web Push](https://developer.mozilla.org/docs/Web/API/Push_API) and [Web Notifications APIs](https://developer.mozilla.org/docs/Web/API/Notifications_API).
- *Transfer files in the background* while the user is not using your PWA, thanks to the [Background Fetch API](https://developer.mozilla.org/docs/Web/API/Background_Fetch_API).
- *Integrate your media playing* with the operating system using the [Media Session API](https://developer.mozilla.org/docs/Web/API/Media_Session_API).
- *Manage payments in your PWA*, thanks to the [Payment Request API](https://developer.mozilla.org/docs/Web/API/Payment_Request_API). Apple also offers an [Apple Pay JS library](https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api) on top of the Payment Request API.
- *Query network status*, such as connection type (4G, WiFi) and a Save Data flag using the [Network Information API](https://developer.mozilla.org/docs/Web/API/Network_Information_API).
- *Capture the user's screen* for screencast or screen sharing using the [Screen Capture API](https://developer.mozilla.org/docs/Web/API/Screen_Capture_API/Using_Screen_Capture).
- *Detect shapes* using on-device hardware-accelerated detectors, including barcodes (human faces and text OCR are still in development) using the [Shape Detection API](/shape-detection/).
- *Query a device's memory* using the [Device Memory interface](https://developer.mozilla.org/docs/Web/API/Device_Memory_API).
- *One-time passwords over SMS* let you automatically receive a code via SMS sent from your server using the [WebOTP API](https://developer.mozilla.org/docs/Web/API/WebOTP_API). Safari implements a solution subset based on the `<input>` element. Read more about it in [WebKit's blog](https://developer.apple.com/news/?id=z0i801mg).
- *Manage the virtual keyboard* that appears on mobile devices screens using the [Virtual Keyboard API](/virtualkeyboard/).

{% Aside %}
If you publish a PWA to some app catalogs and stores, you may access additional APIs. For example, if you publish a PWA to Google Play using a [Trusted Web Activity](https://developer.chrome.com/docs/android/trusted-web-activity/), you can use the [Digital Goods API](https://github.com/WICG/digital-goods/blob/main/explainer.md) to charge your users for subscriptions and premium content.
{% endAside %}

{% Aside 'gotchas' %}
If you have a legitimate use case that cannot be realized with the present set of APIs, you can submit a request to analyze the use case for a possible future web API, as we'll see in the [Experimental chapter](/learn/pwa/experimental).
{% endAside %}

##  Resources

- [MDN: Web APIs](https://developer.mozilla.org/docs/Web/API)
- [What Web Can Do Today](https://whatwebcando.today/)
- [What PWA Can Do Today](https://whatpwacando.today/)
- [Can I Use](https://caniuse.com/)
- [iOS/iPadOS Approximate location](https://firt.dev/ios-14/#geolocation-changes)
- [Meet Face ID and Touch ID for the Web](https://webkit.org/blog/11312/meet-face-id-and-touch-id-for-the-web/)

# Complexity management

In his talk [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy/), Rich Hickey discusses the qualities of simple versus complex things. He describes simple things as focusing on:

> "One role, one task, one concept, or one dimension."

But emphasizes that simplicity isn't about:

> "Having one instance or performing one operation."

Whether or not something is simple is about how interconnected it is.

Complexity comes from binding, weaving, or, to use Rich's term, complecting things together. You can calculate complexity by counting the number of roles, tasks, concepts, or dimensions something manages.

Simplicity is essential in software development because simple code is easier to understand and maintain. Simplicity is also necessary for web apps because it may help to make our app fast and accessible in every possible context.

## Managing PWA complexity
All JavaScript we write for the web touches the main thread at one point. The main thread, though, comes with a lot of complexity out-of-the-box that you, as a developer, have no control over.

The main thread is:

* Responsible for drawing the page, which itself is a complex, multi-step process involving calculating styles, updating and compositing layers, and painting to screen.
* Responsible for listening to and reacting to events, including events such as scrolling.
* Responsible for loading and unloading the page.
* Managing media, security, and identity.
That's all before any code you write can even execute on that thread, such as:
* Manipulating the DOM.
* Accessing sensitive APIs, for example, device capabilities, or media/security/identity.

As Surma put it in his [2019 Chrome Dev Summit talk](https://www.youtube.com/watch?v=7Rrv9qFMWNM&ab_channel=GoogleChromeDevelopers), the main thread is overworked and underpaid.

And yet, most application code lives on the main thread too.

All that code adds to the complexity of the main thread. The main thread is the only one that the browser can use to lay out and render content on the screen. Therefore, when your code requires more and more processing power to complete, we need to run it quickly, because every second it takes to perform application logic is a second the browser can't respond to user input or redraw the page.

When interactions don't connect to input, when frames drop, or when it takes too long to use a site, users get frustrated, they feel the application is broken, and their confidence in it decreases.

The bad news? Adding complexity to the main thread is an almost sure-fire way to make meeting these goals difficult. The good news? Because what the main thread needs to do is clear: it can be used as a guide to help reduce reliance on it for the rest of your application.

### Separations of concerns

There are lots of different kinds of work that web applications do, but broadly speaking, you can break it down into work that directly touches the UI and work that doesn't. UI work is work that:

* Directly touches the DOM.
* Uses APIs that touch device capabilities, for example, notifications or file system access.
* Touches identity, for example, user cookies, local, or session storage.
* Manages media, for example, images, audio, or video.
* Has security implications that would require user intervention to approve, such as the web serial API.

Non-UI work can include things such as:

* Pure calculations.
* Data access (fetch, IndexedDB, etc.).
* Crypto.
* Messaging.
* Blob or stream creation, or manipulation.

Non-UI work is often bookended by UI work: a user clicks a button that triggers a network request for an API that returns parsed results that are then used to update the DOM. When writing code, this end-to-end experience is often considered, but where each part of that flow lives usually is not.
The boundaries between UI work and non-UI work are as important to consider as the end-to-end experiences, as they are the first place you can reduce main thread complexity.

#### Focus on a single task

One of the most straightforward ways of simplifying code is breaking out functions so each focuses on a single task. Tasks can be determined by the boundaries identified by walking through the end-to-end experience:

* First, respond to user input. This is UI work.
* Next, make an API request. This is non-UI work.
* Next, parse the API request. This again is non-UI work.
* Next, determine changes to the DOM. This may be UI work, or if you're using something such as a virtual DOM implementation, it may not be UI work.
* Finally, make changes to the DOM. This is UI work.

The first clear boundaries are between UI work and non-UI work. Then there are judgment calls that need to be made: is making and parsing an API request one task or two? If DOM changes are non-UI work, are they bundled with the API work? In the same thread? In a different thread? The proper level of separation here is key to both simplifying your codebase and being able to successfully move pieces of it off the main thread.

#### Composability
To break up large end-to-end workflows into smaller parts, you need to think about your codebase's composability. Taking cues from functional programming, consider:

* Categorizing the types of work your application does.
* Building common input and output interfaces for them.

For instance, all API retrieval tasks take in the API endpoint and return an array of standard objects, and all data-processing functions take in and return an array of standard objects.

JavaScript has a [structured clone algorithm](https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) meant for copying complex JavaScript objects. Web workers use it when sending messages and IndexedDB uses it to store objects. Choosing interfaces that you can use with the structured cloning algorithm will make them even more flexible to run.

With this in mind, you can create a library of composable functionality by categorizing your code and creating common I/O interfaces for those categories. Composable code is a hallmark of simple codebases: loosely coupled, interchangeable pieces that can sit “next” to each other and build on each other, as opposed to complex code that is deeply interconnected and therefore cannot be easily separated. And on the web, composable code can mean the difference between overworking the main thread or not.

With composable code in hand, it's time to get some of it off the main thread.

### Using web workers to reduce complexity

Web workers, an often underutilized but widely available web capability, let you move work off the main thread.

Web workers let a PWA run (some) JavaScript outside of the main thread.

There are three kinds of workers.

*Dedicated workers*, what's most commonly thought of when describing web workers, can be used by a single script in a single running instance of a PWA. Whenever possible, work that doesn't directly interact with the DOM should be moved to a web worker to improve performance.

*Shared workers* are similar to dedicated workers, except multiple scripts can share them across multiple open windows. This provides the benefits of a dedicated worker but with a shared state and internal context between windows and scripts.

A shared worker could, for instance, manage access and transactions for a PWA's IndexedDB and broadcast transaction results across all calling scripts to let them react to changes.

The final web worker is one covered extensively in this course: *service workers*, which act as a proxy for network requests and are shared between all instances of a PWA.

### Try it yourself

It's code time! Build a PWA from scratch based on everything you've learned in this module.

{% Aside 'codelab' %}
[Progressive Web Apps: Working with Workers](https://developers.google.com/codelabs/pwa-training/pwa06--working-with-workers#0)
{% endAside %}

##  Resources

- [Simple Made Easy (video)](https://www.infoq.com/presentations/Simple-Made-Easy/)
- [Using Web Workers](https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Using_web_workers)
- [Workers overview](/workers-overview/)
- [Use web workers to run JavaScript off the browser's main thread](/off-main-thread/)

# Conclusion

Congratulations! You've made it to the end! We hope that you have enjoyed this course of Progressive Web Apps. In case you are using a library or a framework to create your web apps, you can check out the following additional resources:
##  Resources

- [React with CRA: Making a PWA](https://create-react-app.dev/docs/making-a-progressive-web-app/)
- [Next.js: PWA Sample](https://github.com/vercel/next.js/tree/canary/examples/progressive-web-app)
- [Vue: CLI PWA Plugin](https://cli.vuejs.org/core-plugins/pwa.html)
- [Angular: Service Worker and PWA Documentation](https://angular.io/guide/service-worker-intro)
- [Svelte: Build a PWA](https://blog.logrocket.com/building-a-pwa-with-svelte/)
- [Nuxt.js: PWA](https://pwa.nuxtjs.org)
- [Jekyll PWA Plugin](https://github.com/lavas-project/jekyll-pwa)
- [Gatsby: PWA](https://www.gatsbyjs.com/docs/progressive-web-app/)
- [ASP.NET: Build PWAs with ASP.NET Core Blazor WebAssembly](https://docs.microsoft.com/en-us/aspnet/core/blazor/progressive-web-app?view=aspnetcore-6.0&tabs=visual-studio)
- [Django: Make PWA of a Django Project](https://www.geeksforgeeks.org/make-pwa-of-a-django-project/)
- [Flutter: Building a web application with Flutter](https://docs.flutter.dev/get-started/web)
- [Wordpress: PWAs for Wordpress](https://wpengine.com/resources/wordpress-progressive-web-apps/)

## Brought to you by

{% include 'partials/authors-stack.njk' %}

# Detection

You can detect if the user is using your PWA in the browser or in standalone mode. On Chromium-based browsers (Android and desktop), you can also detect the following events:

* Installation invitation dialog status and result.
* Installation finished.
* Navigation transfer from browser to PWA window and conversely.
* PWA installation status.
* Related app installed from an app store.

You can use this data for analytics, to understand your user's preferences, and to customize their experience. To capture these events, you can use tools such as media queries, events from the `window`, or using the capabilities APIs that you can find [listed here](https://developer.chrome.com/blog/fugu-status/).

## Detecting display mode

To track how users launch your PWA, you can use `matchMedia()` to test the `display-mode` media query.

```js
window.addEventListener('DOMContentLoaded', () => {
  let displayMode = 'browser tab';
  if (window.matchMedia('(display-mode: standalone)').matches) {
    displayMode = 'standalone';
  }
  // Log launch display mode to analytics
  console.log('DISPLAY_MODE_LAUNCH:', displayMode);
});
```

If you use this example, remember to match the display mode from your web app manifest, for instance, `standalone`, `minimal-ui` or `fullscreen`. You can also match multiple queries in the media query string using comma-separated conditions.

You can also add a query parameter to your manifest's `start_url` that you can capture with analytics to track stats about when, in what way, and how much your PWA is being used.

{% Aside 'caution' %}
If you use a query parameter on your `start_url` to capture metrics, make sure to set the `id` field on your manifest to uniquely identify your app. Read how to set up this field in [Uniquely identifying PWAs with the web app manifest id property](https://developer.chrome.com/blog/pwa-manifest-id/)
{% endAside %}

## App installation

When a user accepts the install prompt in the browser, the `appinstalled` event fires on Chromium-based browsers. A great use for this event handler is to remove any in-app installation promotion you've added.

```js
window.addEventListener('appinstalled', () => {
  // If visible, hide the install promotion
  hideInAppInstallPromotion();
  // Log install to analytics
  console.log('INSTALL: Success');
});
```

Remember, on Android devices with WebAPK, the event is fired when the user accepts the dialog, and not after the WebAPK is minted and installed. There may be a delay of some seconds before the app is fully installed.

The [Installation Prompt chapter](/learn/pwa/installation-prompt) explains how to detect if the installation prompt is available and what choice the user makes.

{% Aside 'warning' %}
The `appinstalled` event is available only in Chromium-based browsers, and it's part of an [incubator for the manifest spec](https://wicg.github.io/manifest-incubations/#onappinstalled-attribute)
{% endAside %}

## Session transfer

Users can use your PWA within the browser and in the installed standalone form. On desktop browsers, you can transfer the current navigation between these contexts using badges or menu items, as seen in the following image.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/260YbAY9W4qFitqUHhQ5.png", alt="Navigation transfer between a browser tab and a PWA window.", width="800", height="321" %}

On Android, there is a menu item similar to the one on desktop from the browser that transfers the navigation to the app. In this case, the current URL is opened but it will be a new page navigation in the app.

In the following image you can see the menu item in Android when the app is already installed.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/rpMHjK1uhwwJONJKTj2r.png", alt="Chrome on Android shows menu item to open a new navigation in a PWA window.", width="800", height="1689" %}

### Transfer after installation

From desktop browsers, the current navigation is immediately transferred to the app on installation. The browser's tab is closed, and the newly installed app is opened, continuing what the user was doing.

On mobile browsers, your current navigation stays in the browser when you install the app. If the users want to move to the app, they need to open the app manually, and it will be a new navigation.

### Detecting the transfer

To detect the transfer between browser and window, you can use a media query:

```js
window.addEventListener('DOMContentLoaded', () => {
  // replace standalone with your display used in manifest
  window.matchMedia('(display-mode: standalone)')
      .addListener(event => {
          if (event.matches) {
             // From browser to standalone
          } else {
             // From standalone to browser
          }
      });
});
```

### iOS and iPadOS storage isolation

On iOS and iPadOS, there is no navigation or URL transfer between the browser and the installed icon. Even if it's the same PWA, every PWA icon that the user installs will have its own storage, isolated from Safari's tab and other icons.
When a user opens the installed icon, no storage is shared with Safari. If your PWA needs a login, the user will need to log in again. If the app was added to the home screen several times, for each PWA instance, the user has a different session.

## Related applications
{% BrowserCompat 'html.manifest.related_applications' %}

A website indicates a relationship with an app via the manifest. To do so, use the [`related_applications` member](https://developer.mozilla.org/docs/Web/Manifest/related_applications) of the Web App Manifest spec.
The `related_applications` key is an array of objects that represent each related application. Each entry contains `platform`, `url`, and an optional `id`.

These are the possible [platform values](https://github.com/w3c/manifest/wiki/Platforms):
* `play`: Google Play apps (Android and ChromeOS).
* `itunes`: Apple App Store (macOS, iOS, and iPadOS).
* `windows`: Microsoft Store (Windows 10 and 11).
* `amazon`: Amazon AppStore (FireOS).
* `webapp`: installed PWA.

### Prefer a related app

When the user installs an app, you can redirect the user to a related app if you set the `prefer_related_applications` field to `true` in your manifest. With this setup, on compatible browsers the install flows won't install the PWA; instead they trigger a store installation from the `url` or `id` that you specified in the `related_applications` entry.

The related application could be your PWA and it will be installed via an app store. One advantage of this configuration is that, at the moment, only apps installed through the app store are recovered with a backup or when you switch to a new device.

```json
{
  ...
  "related_applications:" [
     {
       "platform": "play",
       "url": "https://play.google.com/..."
     }
  ],
  "prefer_related_applications": true
}
```

{% Aside %}
Using `prefer_related_applications: true` with only a `webapp` preferred application doesn't make any difference in how your PWA is offered and installed.
{% endAside %}

#### Apple Smart App Banners

Safari doesn't support the `related_applications` member, but it offers [Smart App Banners](https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners) for apps in the App Store. So if you want to promote a PWA or other app you have published in the App Store, you can include meta tags in your PWA's HTML to invite the user to install the app (see the link just provided), or transfer the navigation if it is already installed.

### Detecting related installed apps

The [`getInstalledRelatedApps()`](/get-installed-related-apps/) method allows your website to check whether your iOS/Android/desktop app or PWA is installed on the user's device.

Checking if a related app is installed already helps you to implement features such as hiding custom-installed prompts or redirecting the user directly to the installed app, instead of going to a general purpose website.
To use the `getInstalledRelatedApps()` method, both the installed app and the website need to configure their connection with each other. Each app, depending on its platform, includes metadata to recognize the website and the website includes the expected installed app in the `related_applications` field in the manifest.

Tools such as [BubbleWrap](https://github.com/GoogleChromeLabs/bubblewrap) or [PWA Builder](https://www.pwabuilder.com/), which allow you to publish your PWA to app stores, already add the required metadata so your website can use `getInstalledRelatedApps()` right away.
To detect whether a PWA is already installed using `getInstalledRelatedApps()`, define `webapp` in the manifest `related_applications` field with the URL to your manifest:

```json
...
"related_applications": [{
   "platform": "webapp",
   "url": "https://example.com/manifest.json",
}],
...
```

`getInstalledRelatedApps()` returns an array of app objects. If the array is empty, the related app is not installed.

```js
const relatedApps = await navigator.getInstalledRelatedApps();
const PWAisInstalled = relatedApps.length > 0;
```

#### Detect installation from outside the PWA's scope

From Chrome on Android 89, you can detect if a PWA is installed, even from outside the PWA's scope. Your PWA must set a JSON file within the `/.well-known/` folder, giving permission to the other scope, as described in [this article](/get-installed-related-apps/#check-pwa-out-of-scope).

##  Resources

- [Is your app installed? getInstalledRelatedApps() will tell you!](/get-installed-related-apps/)
- [MDN: Related Applications](https://developer.mozilla.org/docs/Web/Manifest/related_applications)
- [MDN: AppInstalled event](https://developer.mozilla.org/docs/Web/API/Window/appinstalled_event)
- [Apple: Promoting Apps with Smart App Banners](https://developer.apple.com/documentation/webkit/promoting_apps_with_smart_app_banners)

# Enhancements

There are many enhancements that can improve the conversion and usage of your PWA.

## App shortcuts

[App shortcuts](https://w3c.github.io/manifest/#shortcuts-member) is a static list of deep links to your PWA, they are written in your manifest. [Web App Manifest spec](/learn/pwa/web-app-manifest). It lets you define a list of shortcuts to different parts or features in your PWA, they accelerate navigation to frequently accessed sections.

App shortcuts are available on most desktop operating systems and Android with WebAPK, and they appear in a contextual menu on the app's icon in the home screen, dock, or taskbar, as in the following image:

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/SYm7meKqd286Z62gehX9.png", alt="App shortcuts in Android and macOS.", width="800", height="280" %}

To access this menu, users have to right-click or long-press on the PWA's icon.

{% Aside %}
App shortcuts are only available if the user installs your PWA.
{% endAside %}

{% Aside 'warning' %}
Once the user has installed your PWA, you can't add or remove shortcuts until you update your manifest on the server and the [update algorithm](/learn/pwa/update) is triggered.
{% endAside %}

Shortcuts are defined in the `shortcuts` member of the manifest. It takes an array of members with the following properties:
`name`
: The text that will be shown to the user, typically in a context menu.
`start_url`.
: The URL the PWA should load when the user starts it from this shortcut. It should be a URL within your PWA scope, and it should deep-link to the feature the `name` or `short_name` describes.
`short_name`
(Optional) A shorter name used when there is not enough room to display the full value of the `name` field.
`description`
: (Optional) A description of what this shortcut will do
`icons`
: (Optional) An array of icon objects with `src`, `type`, `sizes`, and optional `purpose` fields, describing what images should represent the shortcut

You should treat App shortcuts as a best-effort ability. That means that you can't rely on these shortcuts to appear consistently, and even if they appear, you don't know how many shortcuts will appear or if the platform will ignore the icons as its at the discretion of the browsers. A full discussion per platform is out of scope but below you have an idea of how it works on Android and desktop. The best way to deal with this uncertainty is to order the items by priority.

{% Aside 'caution' %}
Chrome and Edge on desktop renders the first 10 items, while Chrome on Android only renders the first three shortcuts in the manifest's list, so it's better if you order them by priority. Chrome on Android also adds access to "App Info" and "Site Settings" from the menu after your custom list.
{% endAside %}

{% Aside %}
If you publish your PWA to app catalogs and stores, you can convert the shortcuts in the manifest to platform-specific implementations using APIs specific to each operating system, such as Quick Actions on iOS and shortcuts on Android. [BubbleWrap](https://github.com/GoogleChromeLabs/bubblewrap) supports App shortcuts for Android and ChromeOS and [PWA Builder](https://www.pwabuilder.com/) for Android, ChromeOS, iOS and iPadOS.
{% endAside %}

The following code sample defines different app shortcuts you can try if you install the app on Android with Chrome or on desktop with Edge or Chrome.

{% Glitch 'mlearn-pwa-app-shortcuts' %}

## iOS and iPadOS

When publishing PWAs, there are some enhancements that can improve the experience for users on Safari on iOS/iPadOS.

{% Aside 'warning' %}
As we mentioned in previous chapters, PWAs on iOS and iPadOS are only installable from Safari; other browsers are not able to install PWAs in the home screen.
{% endAside %}

### Splash screens

As seen in the [Web App Manifest chapter](/learn/pwa/web-app-manifest), Android creates splash screens automatically based on the manifest's values. That's not the case for iOS and iPadOS. In these devices, you should define the splash screens in the HTML as static images using `<link>` elements.

These images are known as startup images on Apple devices and they use the `rel` property with `apple-touch-startup-image` value, as in:

```html
<link rel="apple-touch-startup-image" href="ios-startup.png">
```

The challenge is that the startup image must have the exact window size that your PWA will have on opening. So, different iOS and iPadOS devices will need different images. More situations need to be covered on the iPad, such as landscape/portrait openings and rendering the PWA in multitask mode (such as 1/3,1/2, or 2/3 of the screen).

You can check an updated list of iOS and iPadOS screen sizes at the [Apple Human Interface Guidelines]( https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/)

Different versions of the launch image can be set with a media query inside the `media` attribute:

```html
<link rel="apple-touch-startup-image" href="ios-startup.png"
      media="orientation: portrait">
<link rel="apple-touch-startup-image" href="ios-startup-landscape.png"
      media="orientation: landscape">
```
{% Aside 'warning' %}
If you want to provide all possible options combining screen definitions, orientations, and multitask mode, you will end up with more than 25 different images you need to create and link in your HTML. If you don't provide a startup image for your user's iOS or iPadOS context, a white screen will appear instead in the opening animation, and while your PWA is loading
{% endAside %}

#### Design patterns for iOS startup images

Defining startup images is hard work, so we have a couple of tools for automated generation and configuration:

* Static generation integrates with your build system, creates all the PNG static images and gives you the HTML code with `<link>` elements to inject into your document. [PWA Asset Generator](https://github.com/onderceylan/pwa-asset-generator) is an example of such a tool.
* Client-side generator, a JavaScript tool that can embed one or more base64 versions of the startup image into `<link>` injected elements based on the current device's type and screen size. You can use an in-memory canvas, render the image and convert it into a `data:` URI with a PNG file. The [PWA Compat library](https://github.com/GoogleChromeLabs/pwacompat) is an easy-to-use client-side library that does this by cloning the Android's typical launch screen.

### Detecting a PWA on Apple mobile platforms

While you should use Progressive Enhancement and feature detection in your PWA, there may be some edge cases where we need to know if the user is in a PWA on Apple mobile platforms, such as when you want to offer installation instructions or add links to platform-specific apps that are iOS-only.

To avoid reading the user agent string, check the `standalone` property of the `navigator` object. This is a non-standard property, and it's only available on the WebKit engine on iOS and iPadOS.

* If `navigator.standalone` is `undefined` it means the user is not on an iPadOS or iOS device.
* If `navigator.standalone` is `false` it means the user opened the PWA in the browser and is using it there.
* If `navigator.standalone` is `true` it means the user opened the PWA from the home screen and is getting the standalone PWA experience.

### Fullscreen support

On Safari on iOS and iPads, only `display: standalone` is supported as a [display mode for your PWA's icon](/learn/pwa/app-design/#display-modes). While `display: fullscreen` is not supported as on Android devices, it's possible to use a non-standard meta-tag to make your PWA enter fullscreen mode.

In the next image, you can see at the left a default standalone design with a theme color, and at the right a PWA with a fullscreen iOS mode that lets you render content behind the status bar.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/SYjZ1upKyQaMuF1nrv7Y.png", alt="A standalone default behavior (left) and a fullscreen iOS screen (right).", width="800", height="216" %}

If you add the following tag in your HTML your PWA on iOS and iPadOS will enter full-screen mode, but it is different from Android.

```html
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
```

In this mode, the device's status bar (the top where you see the clock, battery level, and notification icons) is still visible but rendered on top of your content with a transparent background.

{% Aside 'warning' %}
The theme color is ignored in this mode, and the notification bar is rendered over a transparent background. Also, your app's [0, 0] pixel is now the [0, 0] pixel of the physical screen and not after the safe area.
{% endAside %}

When using this mode, be careful with your design because the operating system will always render the icons in white, so you should always contrast your backgrounds for the top of the screen with light content. Also, it's important to use [CSS environment variables](https://developer.mozilla.org/docs/Web/CSS/env()) to render content in the safe area, as seen in [App Design Chapter](/learn/pwa/app-design/#safe-areas).

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/WZSHybaKkUvpLcphGJ8y.png", alt="The top 0px of your viewport is below the status bar by default; if you add a black-translucent meta tag, the top 0px of your viewport will match the physical top of the screen", width="800", height="219" %}


### Installation reliability

Safari on iOS and iPadOS before 15.4 only loads the manifest file from the network when the user opens the share sheet -using the share icon within the browser- and not when the page loads. Therefore, Safari doesn't check if your website is a PWA until that moment, which can lead to situations where the manifest can't be loaded or takes too much time, and Safari ignores it.

When Safari can't load the manifest on time, pressing "Add to Home Screen" places an icon on the home screen, but does not provide an app experience; it will merely be a shortcut to a Safari tab.

{% Aside 'warning' %}
If Safari can't load the manifest, it will fall back to check if your PWA has some deprecated meta tags, such as `apple-mobile-web-app-capable`. You should not use these metatags. They provide a home screen app experience without essential attributes for your PWA, such as honoring the `start_url` or the `scope` attributes, making a terrible app experience.
{% endAside %}

##  Resources

- [PWA Asset Generator](https://github.com/onderceylan/pwa-asset-generator)
- [Get things done quickly with app shortcuts](/app-shortcuts)
- [PWA Compat Library](https://github.com/GoogleChromeLabs/pwacompat)
- [Define App Shortcuts](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/shortcuts)

# Experimental features

The web is a powerful platform, but there are still gaps in what it can solve. Those who want to develop for the web but need more different capabilities are forced to bundle their web apps in wrappers and publish them in app stores.

Developers may choose to ship their own custom browser as platform-specific apps, which disproportionately increases the size of their web apps. This will also  force them to take on the additional security and maintenance burden of keeping both the browser fork and wrapper up to date.

This approach also loses the reach of the web, often being forced to choose what devices and operating systems to support, which often require different wrappers, and which further expands the security and maintenance burden.

Filling these capabilities gaps is the key to fixing this and thereby enabling the web to be the software platform of the future, covering as many use cases as possible, in comparison with platform-specific SDKs.

## Project Fugu

This is where the capabilities project, known as [Project Fugu](https://www.chromium.org/teams/web-capabilities-fugu), comes in.
The [capabilities project](https://developer.chrome.com/blog/fugu-status/), or Project Fugu, is a cross-company effort to make it possible for web apps to have the same capabilities as platform-specific apps by exposing the capabilities of these platforms to the web, while maintaining user security, privacy, trust, and other core tenets of the web.

### Track capabilities

There is a [public tracker](https://goo.gle/fugu-api-tracker) to keep up with all the work to ship new capabilities.
On the tracker, you can see:

* The status of each API being worked on or considered.
* Platforms the API is targeted for.
* Links and additional information for each API.
* Search and filter capabilities.
* A timeline view.

### Request a capability

What if you want to request a new capability? You can file an issue in the [Chromium bug tracker](https://bugs.chromium.org/p/chromium/issues/list), or you can go to [webwewant.fyi](https://webwewant.fyi) and fill out a form to reach the corresponding  browser vendors.

### The process for each capability

Before launch, there are two states an in-progress API could be in, and both allow you to test them.

* A developer trial: the feature is behind a flag, the API isn't necessarily stable, and you shouldn't implement it for real users. You can enable or disable flags on Chromium-based browsers by going to `about:flags`, allowing you to test on your own browser instance.

{% Aside 'important' %}
Under no circumstances should users ever be told to turn flags on or off. Because such features are still under development, changing flag defaults can have unanticipated consequences for the stability of the browser.
{% endAside %}

* An origin trial: a state where features can be enabled by origin, developers can run tests for a wider audience than their single browser instance, but the feature is still being tested and the implementation can change, more details below.

## Origin trials

Origin trials allow you to try out new features and give feedback to the web standards community on usability, practicality, and effectiveness. APIs available under origin trial are:

* Experimental, they may change and may become unavailable, including not extending beyond the experiment, and may be unavailable for some time, even if they are eventually enabled for all users. So where possible, you should implement feature detection or graceful degradation to handle the case when the feature is unavailable.
* Stable enough to use with real users, but they may change throughout the course of the trial.
* [Limited across all users globally](https://github.com/GoogleChrome/OriginTrials/blob/gh-pages/explainer.md#monitoring-and-limiting-usage) to ensure they don't become a de facto standard, so it's recommended you activate the feature in your codebase following each browser's trial guidelines for a subset of your users.
* Limited to the browser vendor which starts the origin trial, so a Chrome origin trial will not work in Safari, Firefox, or Edge, for instance.

If these requirements are OK for you, you can register an origin to participate in a trial. You can find instructions to sign up for an origin trial in Chrome [here](https://developer.chrome.com/blog/origin-trials/) and for Microsoft Edge follow [this link](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/OriginTrialsGuide/explainer.md)

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/d5ueJjfbepXwq72v2UjU.png", alt="A list of available origin trials for Google Chrome.", width="800", height="510" %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/hSzBgQsAvgkCUN6h1RQN.png", alt="A list of available origin trials for Microsoft Edge.", width="800", height="541" %}

## Safari experimental features

Safari also allows developers to try and test new and unfinished APIs and capabilities, but it doesn't provide origin trials. You can't enable Safari's experimental features for users.

Safari's solution is similar to flags, known as experimental features. Every new version of Safari comes with many experimental features, some of them enabled and some disabled by default.

As a developer, you can change those default settings using:

* The develop, experimental features menu in Safari for macOS.
* The iOS and iPadOS Settings App, by going to Safari, Advanced, Experimental Features.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/Y6agrnMYlpbQ970kYyYp.png", alt="Experimental features available on Safari on iPadOS.", width="800", height="525" %}

## Firefox experimental features

Firefox offers [experimental features](https://developer.mozilla.org/docs/Mozilla/Firefox/Experimental_features) through settings that you can enable or disable by accessing the Configuration Editor using `about:config`.

##  Resources

- [The capabilities project](https://developer.chrome.com/blog/capabilities/)
- [New capabilities status](https://developer.chrome.com/blog/fugu-status/)
- [Fugu Public Tracker](https://goo.gle/fugu-api-tracker)
- [Getting started with Chrome origin trials](https://developer.chrome.com/blog/origin-trials/)
- [Microsoft Edge Origin Trials Guide](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/OriginTrialsGuide/explainer.md)
- [The Web We Want, feedback form](https://webwewant.fyi)
- [Firefox experimental features](https://developer.mozilla.org/docs/Mozilla/Firefox/Experimental_features)
- [WebKit blog](https://webkit.org/blog/)

# Foundations

A solid foundation is the base requirement for building great PWAs. 
 To implement this foundation you need to design and code for the constraints of the web using a couple of principles:

- Use mobile as a focusing constraint. Make sure each view of your design focuses only on the essential content and interactions.
- Emphasize content and core functionality in the design process. 
- Progressively enhance when needed. Start by building a component's core content and functionality with the most straightforward, most widely available tools. Make it accessible. Then, test for advanced features you'd like to use and enhance your component with them.
- Offer a fast and good user experience focused on user-centric web performance metrics, get real user metrics, and push performance for all your users, no matter their network connection, input type, CPU, or GPU power.

{% Aside %}
Accessibility is key for a successful PWA. Please follow [these guidelines](/pwa-checklist/#:~:text=to%20cached%20content%20or%20an%20offline%20indicator%20as%20needed.-,is%20fully%20accessible) to make sure your app is accessible to anyone, anywhere.
{% endAside %}

By following these principles and enhancing with modern patterns and web features, 
you can create great and fast experiences with truly intrinsic designs. 
Designs that are powered by constraints instead of pixels, 
allowing every user access to your content and core functionality in a way that's best suited for their particular browsing context. 

## Responsive web design

Since Ethan Marcotte's 2010 A List Apart article, 
[Responsive Web Design](https://alistapart.com/article/responsive-web-design/), 
designers and developers have been encouraged to create experiences that flex, 
making user interfaces that work across a spectrum of screen sizes and devices. 

Somewhere along the way, though, that became shortened to mobile, tablet, and desktop sizes, 
with widths heavily influenced by iOS screen sizes. 
With modern CSS and a renewed focus on responsive design's original intent, we can put the squish back in squishy sites.

Responsive web design introduces three technical ingredients:

- Fluid grids
- Flexible media
- Media queries

Ethan concludes that these technical requirements aren't enough; 
the way forward also requires a different way of thinking.

### The mobile user myth

In the early days of responsive design assumptions were made in the name of making sites easier to design. 
For example, small experiences were for phones, and they had a 320px width, 
medium experiences were for tablets, and they had a 1024px width, and anything larger than that was for desktops. 
Small screens had touch abilities, large screens didn't. Phone users were rushed and distracted and therefore needed a "light" experience. 

None of this is true; 
they are mobile myths perpetuated by the assumption that a user's needs are fundamentally different based solely on screen size or device type. 
This doesn't hold up to scrutiny.

Take, for example, a social network PWA that you can install today on mobile and desktop. 
On desktop, many users can keep a narrow window with the feed at one side of the screen while working, 
and assuming they are on a mobile device because of the available width would be wrong.

The PWA world that is out of the browser's tab is even adding new challenges to a responsive design world, such as the mini-mode and working with foldable devices.

### Mini-mode
With a PWA installed on a desktop device, 
a window can get really small; smaller than a browser's window, smaller than a mobile viewport. 
This is something new on the web: we can support a mini-mode, a window that can be as small as 200x100 CSS pixels. 

When creating a PWA these days, it's a good idea to think about what to offer in mini-mode, 
thanks to responsive web design, such as just control buttons on a music player, dashboard information, or quick actions.

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/hPR7t2kr42boNc4MfSGQ.mp4", alt="On desktop, a PWA can be rendered in a smaller window than the smallest window you've ever designed for the browser. It adds a new breakpoint for your responsive web design: the mini-mode.", autoplay="true", loop="true", muted="true" %}

On desktop, a PWA can be rendered in a smaller window than the smallest window you've ever designed for the browser. It adds a new breakpoint for your responsive web design: the mini-mode.

### Foldables and hybrid

Foldable and hybrid devices are also common these days:

- Small clamshell phones.
- Foldable devices that can be used as phones or tablets.
- Laptops that can be transformed into tablets.
- Tablets that can act as laptops with keyboard and trackpad.
- Phones then can be converted to desktop with a hub.

While the challenge exists for every website, with a Progressive Web App you are in control and responsible for the window when the app is installed. Therefore, your design should react and offer the best experience in every context.

{% Aside %}
It's becoming common to transfer an app's navigation between devices, so your PWA can be rendered in a smartwatch after receiving notification; the navigation can be transferred to a phone, and then to a laptop. Supporting all modes and devices is key to avoiding user frustration.
{% endAside %}

## Everything first

But where should you get started? Mobile first, content first, offline first? When designing for the flexibility of the web, which is it? Well, the answer is yes, *everything first*.
The term _mobile first_ has been interpreted in many ways since Luke Wroblewski first coined it in 2009: from emulating platform-specific UI and UX patterns on the web to building mobile apps before building web apps to just using min-width media queries and calling it a day. Its original intent, though, is this: *mobile forces you to focus*. As Luke said:

{% Blockquote 'Luke Wroblewski' %}
Mobile devices require software development teams to focus on only the most important data and actions in an application. There simply isn't room in a 320 by 480-pixel screen for extraneous, unnecessary elements. You have to prioritize.
So when a team designs Mobile First, the result is an experience focused on the key tasks users want to accomplish without the detours and interface debris that litter today's desktop-accessed websites. That's a good user experience and good for business.
{% endBlockquote %}

Focus each view of your website on only the essential tasks a user wants to accomplish there, 
and don't add more stuff to the idea just because they have more screen real estate.

The second principle is hinted at in Responsive Web Design: the "gradient of different experiences." 
A single, identical, pixel-perfect experience for every single user should not be the goal of your work; it's all but impossible. 

{% Aside 'caution' %}
There are countless combinations of screen sizes, capabilities, devices, and contexts a user may be browsing with, and as a designer, you do not control what that final mix will be. 
{% endAside %}

Instead of thinking about your web experiences as a fixed thing, 
think of it as a set of recommendations that the user's device will use to build the best experience for their current context. To do so, progressive enhancement needs to be embraced. 

### Progressive enhancement

Progressive Enhancement is a pattern that lets us write code that runs everywhere, starting from standard HTML, CSS, and JavaScript, and adding layers of capabilities on top of that with proper fallbacks when an API is not available.

How do you enhance? Feature detection is a pattern where you perform a test for support and react based on that test results. There are several built-in web platform tools and practices for doing this.

Using `@supports`, check for browser support of a CSS feature, and apply rules based on the result. 
This applies to both CSS properties and values; if a property is supported and a value is not, it will fail, as will an unsupported property. JavaScript code can access this through the [`CSSSupportsRule`](https://developer.mozilla.org/docs/Web/API/CSSSupportsRule)

Most new web platform features are attached to existing objects, so ‘feature' in object style detection works well in JavaScript, as will other similar lookups, like checking for properties or methods on elements.

To ship modern JavaScript, you can use the module/nomodule pattern to provide more robust features with a smaller payload to more modern browsers and a fallback experience to older browsers. This has the bonus of guaranteeing a new baseline of JavaScript features, like promises, classes, arrow functions, and `const` and `let` are available for browsers that support ES Modules. 

You can even combine multiple forms of feature detection to create your enhanced baseline. Coined by the BBC News team, this is called Cutting the Mustard and lets you ship a core experience to everyone and start enhancing the experience only after a specific feature-detected bar is reached.

{% Aside %}
The P in PWA comes from Progressive, and it emphasizes the idea of adding features and abilities progressively, and using Feature Detection is key for that goal.
{% endAside %}

#### Avoid device detection

You should directly test for feature support instead of making support assumptions based on the User-Agent string. 

User-agent strings have never been truly reliable. 
They rely on having near-perfect knowledge of every browser, operating system, 
and device combination in existence to "guess right". 
Even then they are susceptible to user spoofing, for example, desktop site redirects on mobile browsers are often as simple as spoofing a desktop user-agent string.

Moreover, browsers are working on freezing their User-Agent strings, 
with user-agent strings for feature detection specifically called out as a reason for deprecation, 
making them even more unreliable than they previously were for identifying a user and device.

{% Aside %}
After saying that device detection is a bad practice, it's also important to clarify that there are still situations where we don't have any other solution, such as detecting iOS devices to offer specific platform instructions. Treat these practices as hacks and be careful to re-test and update these hacks on every new version of the browser on these platforms.
{% endAside %}

### Content first

Another principle of designing for the web is: start with *your content first*. For example, a real-time  stock ticker with a graph of a stock's prices is, at its core, a table of stocks with their price over some time, maybe with a link to refresh the site. 

That can then be enhanced with JavaScript and fetch requests to update the table's values on a timer or enhanced with sockets to provide real-time push-based updates. It can be enhanced again to graph the results, maybe with CSS, maybe with SVG, maybe with Canvas. But the core starts with content.

## Intrinsic design

- Mobile as a focusing constraint for user experience.
- Emphasizing content and core functionality in the design process.
- Progressively enhancing with advanced functionality where available.

These principles combine to give us something new: _intrinsic design_.
In her talk [Designing Intrinsic Layouts](https://www.youtube.com/watch?v=AMPKmh98XLY), Jen Simmons talks about using modern CSS tools, like Grid, Flexbox, flow layout, and writing modes, to design and build user interfaces. With these tools, she says:

{% Blockquote 'Jen Simmons' %}
You can really make the layout be intrinsic to the content that we have and the design that we want to do.
{% endBlockquote %}

This new CSS allows designers to regain some control over layout but do so in a way that aligns with the latest web design principles. Instead of creating fixed forms based on fixed screen sizes, you define content-based rules by which layout  happens by tapping into intrinsic properties of that content, like how small or large it can be, the size of the text, and the available space, all at once. They allow you to realize your design as it interacts with your content without needing to control every pixel's placement.

Intrinsic layouts bring the conversation about control on the web full-circle, giving it definition. Control on the web isn't about dictating devices or screen sizes or colors or fonts or layouts or capabilities for each visitor to your site. Control on the web is about writing the rules a browser will use to assemble your experience, building it uniquely for each user in your Progressive Web App.

## Web performance

The last but not least important foundation for our PWA is Web Performance. 
Having a great experience for users is mandatory; 
it will lead to more conversions in every possible way.

Web performance involves several steps:

- Understand the key user-centric metrics available.
- Set goals for every metric.
- Measure our PWA.
- Improve our metrics by applying techniques and best practices statically in our code or server.
- Measure again.
- Improve the experience to each user, live, based on the user's context.

Web performance metrics today measure how fast your content appears on the screen, 
but also how interactive your website is and how users perceive the experience.

### Web Vitals

During the past decade, we've been dealing with different metrics to measure success in web performance. 
Today, a set of recommended metrics are grouped under the project [Web Vitals](/vitals/). 
Web Vitals focus metrics in three key areas affecting web performance and perception:

- Loading
- Interactive
- Visual Stability

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/gu948vCUtGMKb6dKcSpZ.png", alt="A set of metrics from Core Web Vitals showing a website's performance results.", width="800", height="225" %}


With Core Web Vitals, you can see at a glance, how good or bad is your PWA in web performance and user experience.

## PWA foundations
It's important that your PWA has a solid foundation in responsive design, mobile and everything first, intrinsic design, and web performance as a foundation for a great experience for all your users.

##  Resources

- [Learn Responsive Web Design](/learn/design)
- [The new responsive: Web design in a component-driven world](/new-responsive/)
- [Progressive Enhancement](https://developer.mozilla.org/docs/Glossary/Progressive_Enhancement) 
- [Ten modern layouts in one line of CSS](/one-line-layouts/)
- [Web Vitals](/vitals/)
- [Designing Intrinsic Layouts talk](https://www.youtube.com/watch?v=AMPKmh98XLY)

# Getting started

Progressive Web Apps are still websites, with enhanced features and capabilities.
They are not attached to a particular technology stack and you can start from scratch with a new site or update your existing website without a complete overhaul.
In this guide you'll learn to create a good implementation of the PWA pattern.
Here are some strategies to get you started:

### Make it installable

Start small! This approach includes beginning with a basic manifest file, a simple offline page, and a service worker to serve the offline page and cache some critical CSS and JavaScript. Thanks to the critical CSS and JavaScript caching, you will get your existing web app ready to work offline while improving its performance.

### Focus on a feature

Pick one new feature—such as push notifications or file handling—that will significantly impact your users or your business. This will allow you to dip your toes into the PWA pool without making too many changes at once.

### Build a simple version

Take an existing section of your application or a specific user journey, like video playback or access to a boarding pass, and make it work front-to-back as an offline-first PWA, either stand-alone or in context. This allows for a low-stakes experiment enabling you to rethink an experience for your users with PWAs.

### Start from the ground up

If you're going through a redesign of your website or can start from scratch, this strategy makes a lot of sense. It enables you to more easily build in PWA design patterns than other strategies, in particular allowing you to take advantage of all the power of service workers from the get-go.

## Upgrading a store app

With the ability to publish a PWA to app stores,
it's possible to wrap your PWA into a PWA launcher and upload it to stores, such as Google's Play Store or Windows Store.
If you have an existing platform-specific app, you can replace it with your PWA published in the store.

With this approach, your existing users get an upgrade of their experiences to the PWA,
and new users can still use or install your PWA from the browser, or the app stores.
And, you will have one app for everyone, saving costs, time and improving user experience.

## PWA checklist

A Progressive Web App is a website, which leads to the question: When does it become a Progressive Web App?
The answer is not so simple, as the PWA concept doesn't refer to a specific technology or stack, PWA is instead a pattern including various technical components.

While there are no unique rules among all browsers, there are a set of recommendations,
called the [Progressive Web App Checklist](/pwa-checklist/), to help you create a PWA that users will love.

### Core requirements

Because PWAs span all devices,
from mobile through desktop,
the core Progressive Web App Checklist is about what you need to do to make your app installable and reliable for _all_ users,
regardless of screen size or input type.

The core requirements are:

#### Starts fast, stays fast

Performance plays a significant role in the success of any online experience, as high-performing sites engage and retain users better than poorly performing ones. Sites should focus on optimizing for user-centric performance metrics.

#### Works in any browser

Progressive Web Apps are web apps first, which means they need to work across browsers, not just in one of them. The experience doesn't have to be identical in all browsers, though. There can be features that aren't supported by one browser, with a fallback to ensure a good experience.

#### Responsive to any screen size

Users can use your PWA on any screen size, and all content is available at any viewport size.

#### Provides a custom offline page

When users are offline, keeping them in your PWA provides a more seamless and native-like experience than dropping back to the default browser offline page.

#### Is installable

Users who install or add apps to their home screens tend to engage with those apps more, and when the PWA is installed it can take advantage of more abilities for a better user experience.

### Optimal PWA characteristics

To create a genuinely great Progressive Web App,
one that feels like a best-in-class app, you need more than just the core checklist.
The optimal Progressive Web App checklist is about making your PWA feel capable and reliable while taking advantage of what makes the web powerful.

#### Provides an offline experience

By allowing users to use your PWA while offline, you'll create an authentic app-like experience for them. Do this by identifying those features that don't require connectivity, so that users can access at least some functionality.

{% Aside 'gotchas' %}
When we say that the PWA should provide an offline experience, it doesn't mean that all the services and content should be available offline. For example a note taking app can't sync its notes when there is no connectivity, but it can allow the users to write the note and sync new changes when they are back online. At the very least you should render the app's user interface with a proper message if your app needs a live connection.
{% endAside %}

#### Is fully accessible

Ensure all the application's content and interactions are understood by screen readers, usable with just a keyboard, that focus is indicated, and color contrast is strong. By making your PWA accessible, you ensure it's usable for everyone.

#### Uses powerful capabilities where available

From push messaging, WASM, and WebGL to file system access, contact pickers, and integration with app stores. The tools to create highly capable, deeply integrated PWAs are here, allowing you to create a fully-featured user experience, previously reserved for platform apps, that your users can take with them wherever they go.

#### Is discoverable through search

More than half of all website traffic comes from organic search. Making sure that canonical URLs exist for content and that search engines can index your site is critical for users to find your PWA.

#### Works with any input type

Users should be able to switch between input types while using your application seamlessly, and input methods should not depend on screen size.

#### Provides context for permission requests

Only trigger prompts for permissions like notifications, geolocation, and credentials, after providing in-context rationale to improve chances of accepting the prompts from the user.

#### Follows best practices for healthy code

Keeping your application up-to-date and your codebase healthy makes it easier for you to deliver new features that meet the other goals laid out in this checklist.

{% Aside %}
While the PWA Checklist has a set of best practices for all developers,
some browsers also have _PWA Criteria_.

The PWA criteria is a set of technical requirements that your website must comply with to be treated as a PWA. Your PWA will receive special treatment when that happens, such as firing new events, rendering an install badge or dialog, or adding a new Install menu within the browser.{% endAside %}

## Resources

- [PWA checklist](/pwa-checklist/)

# Installation

Once the user installs your PWA, it will:

- Have an icon in the launcher, home screen, start menu, or launchpad.
- Appear as a result when a user searches for the app on their device.
- Have a separate window within the operating system.
- Have support for specific capabilities.

{% Aside %}
While installation differs per browser and operating system, you don't need to create any kind of package or executable for your PWA to be installed from a browser.
{% endAside %}

## Installation criteria

Every browser has a criterion that marks when a website or web app is a Progressive Web App and can be installed for a standalone experience.
The metadata for your PWA is set by a JSON-based file known as the Web App Manifest, which we will cover in detail in the [next module](/learn/pwa/web-app-manifest/).

As a minimum requirement for installability, most browsers that support it use the Web App Manifest file and certain properties such as the name of the app, and configuration of the installed experience. An exception to this is Safari for macOS, which does not support installability.

The requirements to allow installation differ among the different browsers, [this article](/install-criteria/) details the criteria for Google Chrome and includes links to requirements for other browsers.

Because the test that a PWA meets installability requirements can take several seconds, installability itself may not be available as soon as a URLs response is received.

{% Aside %}
The process for uninstalling a PWA is different on each combination of operating system and browser. In most situations, the app can be uninstalled the same as any other platform-specific app; in other situations, the PWA window offers a menu with an uninstall option. Deleting the icon may not clear the storage that a PWA is using.
{% endAside %}

### Desktop installation

Desktop PWA installation is currently supported by Google Chrome and Microsoft Edge on Linux, Windows, macOS, and Chromebooks. These browsers will show an install badge (icon) in the URL bar (see the image below), stating that the current site is installable.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/aNv7ezpI3iO6YpIlHt9J.png", alt="Chrome and Edge on desktop with the install badge in the URL bar", width="800", height="751" %}

When a user is engaged with a site, they may see a popup such as the one below inviting users to install it as an app.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/YVHGuBQDUKGZXT7cGuHO.png", alt="Google chrome in-product help suggesting the PWA installation.", width="800", height="366" %}

The browser's drop-down menu also includes an "Install <name of the app>" item that the user can use:

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/WBZ15ArNciZnrvJY6yUt.png", alt="Chrome and Edge menu items for PWA installation.", width="800", height="533" %}

{% Aside %}
Chromium-based browsers on desktop let you see all the installed PWAs with that browser using `about:apps`.
{% endAside %}

Only standalone and minimal-ui [display modes](/learn/pwa/app-design#display-modes) are supported on desktop operating systems.

PWAs installed on desktops:

- Have an icon in the Start menu or Start screen on Windows PCs, in the dock or desktop in Linux GUIs, in the macOS launchpad, or a Chromebook's app launcher.
- Have an icon in app switchers and docks when the app is active, was recently used, or is opened in the background.
- Appear in the app search, for example, search on Windows or Spotlight on macOS.
- Can set a badge number on their icons, to indicate new notifications. This is done with the [Badging API](https://developer.mozilla.org/docs/Web/API/Badging_API).
- Can set a contextual menu for the icon with [App Shortcuts](https://developer.mozilla.org/docs/Web/Manifest/shortcuts).
- Can't be installed twice with the same browser.

{% Aside %}
Installation may unlock other capabilities that are not available for PWAs running within the browser's tab. We'll talk more about this in the [Capabilities Chapter](/learn/pwa/capabilities).
{% endAside %}

After installing an app on the desktop, users can navigate to `about:apps`, right-click on a PWA, and select "Start App when you Sign In" if they want your app to open automatically on startup.

### iOS and iPadOS installation

A browser prompt to install your PWA doesn't exit On iOS and iPadOS. In these platforms PWAs are also known as *home screen web apps*. These apps have to be added manually to the home screen via a menu that is available only in Safari. It is recommended that you add the tag [`apple-touch-icon`](https://developer.chrome.com/docs/lighthouse/pwa/apple-touch-icon/) to your html.
To define the icon, include the path to your icon to your HTML `<head>` section, like this:

```html
<link rel="apple-touch-icon" href="/icons/ios.png">
```
 Safari will use that information to create the shortcut and if you don't provide a specific icon for Apple devices, the icon on the home screen will be a screenshot of your PWA when the user installed it.

It's important to understand that PWA installation is only available if the user browses your website from Safari. Other browsers available in the App Store, such as Google Chrome, Firefox, Opera, or Microsoft Edge, cannot install a PWA on the home screen.

The steps to add apps to the home screen are:

1. Open the Share menu, available at the bottom or top of the browser.
1. Click **Add to Home Screen**.
1. Confirm the name of the app; the name is user-editable.
1. Click **Add**.
On iOS and iPadOS, bookmarks to websites and PWAs look the same on the home screen.

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/UhWxRAtIB6KQpbMYnDSe.mp4", autoplay="true", controls="true" %}

On iOS and iPadOS, only the standalone [display mode](/learn/pwa/app-design) is supported. Therefore, if you use minimal UI mode, it will fall back to a browser shortcut; if you use fullscreen, it will fall back to standalone.

{% Aside  'caution' %}
On Apple devices, you can install the same PWA multiple times; each installation will have its own isolated storage, and it will be treated as a different app.
{% endAside %}

PWAs installed on iOS and iPadOS:

- Appear in the home screen, Spotlight's search, Siri Suggestions, and App Library search.
- Don't appear in App Gallery's categories folders.
- Lack support for capabilities such as badging and app shortcuts.

Incidentally, Safari uses a native technology known as [Web Clips](https://developer.apple.com/documentation/devicemanagement/webclip) to create the PWA icons in the operating system. They are just XML files in Apple's Property List format stored in the filesystem.

{% Aside 'gotchas' %}
When users use the PWA, they are not using an instance of the Safari app (like they use an instance of Chrome when doing so), they are using something known as *Web.app*, so you should expect slight differences between your PWA rendered in Safari and a PWA window. Both Safari and Web.app use the same core from WebKit and the same JavaScript runtime, but they run in different processes and may have different implementations, such as having isolated storage.
{% endAside %}

### Android installation

On Android, PWA install prompts differ by device and browser. Users may see:

- Variations in the wording of the menu item for install such as **Install** or **Add to Home Screen**.
- Detailed installation dialogs.

In the following image you can see two different versions of an installation dialog, a simple mini-infobar (left) and a detailed installation dialog (right).

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/qqVFLVmurQkr5RGauvGK.png", alt="Mini info bar and installation dialogs on Android.", width="800", height="417" %}

Depending on the device and browser, your PWA will either be installed as a WebAPK, a shortcut, or a QuickApp.

#### WebAPKs

A WebAPK is an Android package (APK) created by a trusted provider of the user's device, typically in the cloud, on a WebAPK _minting server_. This method is used by Google Chrome on devices with Google Mobile Services (GMS) installed, and by Samsung Internet browser, but only on Samsung-manufactured devices, such as a Galaxy phone or tablet. Together, this accounts for the majority of Android users.

When a user installs a PWA from Google Chrome and a WebAPK is used, the minting server "mints" (packages) and signs an APK for the PWA. That process takes time, but when the APK is ready, the browser installs that app silently on the user's device. Because trusted providers (Play Services or Samsung) signed the APK, the phone installs it without disabling security, as with any app coming from the store. There is no need for sideloading the app.

PWAs installed via WebAPK:

- Have an icon in the app launcher and home screen.
- Appear on Settings, Apps.
- Can have several capabilities, such as [badging](/badging-api/), [app shortcuts](/app-shortcuts/), and [capture links within the OS](/declarative-link-capturing/).
- Can [update](/manifest-update) the icon and app's metadata.
- Can't be installed twice.

{% Aside 'gotchas' %}
You, as a PWA developer, don't need to build or sign any package when a WebAPK is used. It's all handled transparently between the browser, device, and minting server.
{% endAside %}

#### Shortcuts

While WebAPKs provide the best experience for Android users, they can't always be created. When they can't, browsers fall back to creating a website shortcut. Because Firefox, Microsoft Edge, Opera, Brave, and Samsung Internet (on non-Samsung devices) don't have minting servers they trust, they'll create shortcuts. Google Chrome will too if the minting service is unavailable or your PWA doesn't meet installation requirements.

PWAs installed with shortcuts:

- Have a browser-badged icon on the home screen (see the following examples).
- Don't have an icon in the Launcher or on **Settings, Apps**.
- Can't use any capabilities that require installation.
- Can't update their icons and app metadata.
- Can be installed many times, even using the same browser; when this happens, all will point to the same instance, and use the same storage.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/79QaL12M28cHhIrJLRyM.png", alt="A PWA installed with different browsers on the same device.", width="800", height="432" %}

#### QuickApps

Some manufacturers, including Huawei and ZTE, offer a platform known as [QuickApps](https://developer.huawei.com/consumer/en/huawei-quickApp/) to create light web apps similar to PWAs but using a different technology stack. Some browsers on these devices, like the Huawei browser, can install PWAs that get packaged as QuickApp, even if you are not using the QuickApp stack.

When your PWA is installed as a QuickApp, users will get a similar experience to the one they would have with shortcuts, but with an icon badged with the QuickApps icon (a lightning image). The app will also be available to launch from the QuickApp Center.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/iHhjBvDriV4hZVnmVapW.png", alt="QuickApps on a Huawei or ZTE home screen.", width="800", height="497" %}

## Prompting for installation

In Chromium-based browsers on desktop and Android devices, it's possible to trigger the browser's installation dialog from your PWA. The [Installation Prompt chapter](/learn/pwa/installation-prompt), will cover [patterns for doing so](/promote-install/) and how to implement them.

{% Aside 'warning' %}
If you provide instructions to the user, remember that menu items' names vary by language.
{% endAside %}

## App catalogs and stores

Your PWA can also be listed in app catalogs and stores to increase its reach and let users find it in the same place they find other apps.
Most app catalogs and stores support technologies that let you publish a package that doesn't include the whole web app (such as your HTML and assets). These technologies let you create just a launcher to a standalone web rendering engine that will load the app and let the service worker cache the necessary assets.

The app catalogs and stores that support publishing a PWA are:

- [Google Play Store for Android and ChromeOS](https://chromeos.dev/en/publish/pwa-in-play), using a [Trusted Web Activity](https://developer.chrome.com/docs/android/trusted-web-activity/).
- Apple App Store for iOS, macOS, and iPadOS, using WKWebView and [App-Bound Domains](https://webkit.org/blog/10882/app-bound-domains/).
- [Microsoft Store for Windows 10 and 11](https://docs.microsoft.com/en-us/windows/uwp/publish/pwa/overview), using APPX packages.
- [Samsung Galaxy Store](https://samsunginternet.github.io/introducing-progressive-web-apps-to-samsung-galaxy-store/), using the Samsung WebAPK minting server.
- Huawei AppGallery, using a [QuickApp container for your HTML application](https://developer.huawei.com/consumer/en/doc/development/quickApp-Guides/quickapp-h5-to-quickapp-introduction-0000001150075595).

If you want to learn more about how to publish a PWA to app catalogs and stores, check out [BubbleWrap CLI](https://github.com/GoogleChromeLabs/bubblewrap) and [PWA Builder](https://pwabuilder.com).

{% Aside 'warning' %}
Some app catalogs and stores have technical or business requirements that before your PWA is accepted for publication. Check each store's requirements before starting.
{% endAside %}

## Resources

- [What does it take to be installable](/install-criteria/)
- [WebAPKs on Android](/webapks/)
- [Patterns for promoting PWA installation](/promote-install/)
- [Using a PWA in your Android app](/using-a-pwa-in-your-android-app/)
- [List your Progressive Web App in Google Play](https://chromeos.dev/en/publish/pwa-in-play)
- [Submit your PWA to the Microsoft Store](https://docs.microsoft.com/en-us/windows/uwp/publish/pwa/overview)
- [Publishing a PWA to App Store](https://firt.dev/pwa-stores/)
- [WebKit: App-Bound Domains](https://webkit.org/blog/10882/app-bound-domains/)

# Installation prompt

Users may not be familiar with the PWA install process. As the developer, you will understand when it is the right time to invite the user to install the app. The default browser installation prompts can also be enhanced. Let's check out the tools available.

## Enhancing the install dialog

Browsers provide default installation prompts when PWAs pass the install criteria. The browser uses the `name` and `icons` properties from your [Web App Manifest](/learn/pwa/web-app-manifest) to build the prompt.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/Ekh5btJPBqmnX85DonZK.png", alt="Microsoft Edge installation prompt.", width="800", height="426" %}

Some browsers enhance the installation prompt experience using the [promotional fields in the manifest](/learn/pwa/web-app-manifest/#promotional-fields), including `description`, `categories`, and `screenshots`. For example, using Chrome on Android, if your PWA provides values for the `description` and `screenshots` fields, the installation dialog experience transforms from a small **Add to home screen** info bar to a bigger, more detailed dialog, similar to the install prompts from an app store.

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/eU7EiYjZKtVsBrQ3xfBz.mp4" %}

See promotional fields in action:

{% Glitch 'learn-pwa-web-app-manifest-promotional' %}

## The beforeinstallprompt event

The browser's installation prompts are the first step in getting  users to install your PWA. To implement your own install experience, your app still needs to pass the install criteria: when the browser detects that your app is installable, it fires the `beforeinstallprompt` event. You need to implement this event handler to customize the user's experience. Here's how:

1. Listen for the `beforeinstallprompt` event.
1. Save it (you'll need it later).
1. Trigger it from your UI.

{% Aside 'caution' %}
Not all browsers support this event, and it has been moved from the Web App Manifest spec to a [separate incubator](https://wicg.github.io/manifest-incubations/).
{% endAside %}

Check the code below for an example of an event listener for the `beforeinstallprompt` event, its capture and later custom use.

```js
// This variable will save the event for later use.
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
  // Prevents the default mini-infobar or install dialog from appearing on mobile
  e.preventDefault();
  // Save the event because you'll need to trigger it later.
  deferredPrompt = e;
  // Show your customized install prompt for your PWA
  // Your own UI doesn't have to be a single element, you
  // can have buttons in different locations, or wait to prompt
  // as part of a critical journey.
  showInAppInstallPromotion();
});
```

Then, if the user clicks on your customized install button, use the `deferredPrompt` that has previously been saved and call its `prompt()` method, because the user still needs to go through the browser's process to install your app. What you did was delay the event until you gave the user the right context to encourage them to install the PWA.

Capturing the event gives you the opportunity to add hints and incentives for your users to install your app, and to choose to prompt for installation when you know the users are more engaged.

{% Aside 'caution' %}
You can only call `prompt()` on the deferred event once. If the user dismisses it, you need to wait until the `beforeinstallprompt` event is fired again.
{% endAside %}

The event will not fire if:

- The user has already installed the current PWA (valid only for desktop and WebAPK on Android).
- The app does not pass the [PWA installation criteria](/learn/pwa/installation/#installation-criteria).
- The PWA is not installable on the current device for other reasons (for example, a device in kiosk mode or without permissions).

{% Aside 'gotchas' %}
Chrome and Edge on iOS and iPadOS do not support PWA installation, so the `beforeinstallprompt` event can't fire. In this case, the only option is to open the PWA using Safari, where it is installable from the [share, add to the home screen menu](/learn/pwa/installation/#installation-criteria).
{% endAside %}

### The best place to prompt

Where to prompt depends on your application and when your users are most engaged with your content and services. When you capture the `beforeinstallprompt`, you can guide users through the reasons to keep using your app and the advantages they will gain from installing it.
You can choose to display install hints anywhere in your app. Some common patterns are: in the side menu, after a critical user journey such as completing an order, or after a sign-up page. You can read more about this in [Patterns for promoting PWA installation](/promote-install/).

### Gathering analytics

Using analytics will help you to understand better where and when to present your prompts. You can use the `userChoice` property from the `beforeinstallprompt` event; `userChoice` is a promise that will resolve with the action the user took.

```js
// Gather the data from your custom install UI event listener
installButton.addEventListener('click', async () => {
  // deferredPrompt is a global variable we've been using in the sample to capture the `beforeinstallevent`
  deferredPrompt.prompt();
  // Find out whether the user confirmed the installation or not
  const { outcome } = await deferredPrompt.userChoice;
  // The deferredPrompt can only be used once.
  deferredPrompt = null;
  // Act on the user's choice
  if (outcome === 'accepted') {
    console.log('User accepted the install prompt.');
  } else if (outcome === 'dismissed') {
    console.log('User dismissed the install prompt');
  }
});
```

{% Aside %}
Chromium browsers trigger the [`appinstalled`](https://developer.mozilla.org/docs/Web/API/Window/appinstalled_event) event on the `window` object. The event is fired when the user accepts the install, whether action was triggered by a custom install button or by the browser.
{% endAside %}

### See it in action

Try the following sample in action on a Chromium browser (desktop or Android).

{% Glitch 'mlearn-pwa-web-app-install-prompt' %}

## Fallback

If the browser doesn't support the `beforeinstallprompt` or the event does not fire, there is no other way to trigger the browser's installation prompt. However, on platforms that allow the user to install PWAs manually, like iOS, you can display these instructions to the user.

You should only render these instructions in browser mode; other display options, such as `standalone` or `fullscreen` mean the user has already installed the app.

To render the element only in browser mode, use the `display-mode` media query:

```css
#installInstructions {
   display: none
}
@media (display-mode: browser) {
   #installInstructions {
     display: block
   }
}
```

## Codelab

{% Aside 'codelab' %}
Try it yourself with the [Make it installable](/codelab-make-installable/) codelab.
{% endAside %}

## Libraries

Check out these libraries for help with rendering a custom install prompt:

- [PWA Builder <pwa-install>](https://github.com/pwa-builder/pwa-install)
- [PWA Installer Prompt for React](https://github.com/shnaveen25/react-pwa-installer-prompt)
- [React PWA Install](https://www.npmjs.com/package/react-pwa-install)
- [Vue PWA Install](https://github.com/Bartozzz/vue-pwa-install)
- [Add to Home Screen](https://github.com/docluv/add-to-homescreen)

## Resources

- [Patterns for Promoting PWA installation](/promote-install/)
- [How to provide your own in-app install experience](/customize-install/)
- [MDN: Add to Home Screen](https://developer.mozilla.org/docs/Web/Progressive_web_apps/Add_to_home_screen)
- [Web Manifest Incubations](https://wicg.github.io/manifest-incubations/)

# Offline data

To build a solid offline experience, your PWA needs storage management. In the [caching chapter](/learn/pwa/caching) you learned that cache storage is one option to save data on a device. In this chapter, we'll show you how to manage offline data, including data persistence, limits, and the available tools.

## Storage
Storage is not just about files and assets, but can include other types of data. On all browsers that support PWAs, the following APIs are available for on-device storage:

- [IndexedDB](https://developer.mozilla.org/docs/Web/API/IndexedDB_API): A NoSQL object storage option for structured data and blobs (binary data).
- WebStorage: A way to store key/value string pairs, using local storage or session storage. It's not available within a service worker context. This API is synchronous so it's not recommended for complex data storage.
- Cache Storage: As covered in the [Caching module](/learn/pwa/caching).

{% Aside %}
On supported platforms, you can also use the [FileSystem Access API](/file-system-access/) to read and write to and from the user's local filesystem, with permission. Since you are writing files directly to the file system the browser won't assign the data to your origin's quota, and any other application can interact with those files, if the user allows it.
{% endAside %}

You can manage all device storage with the [Storage Manager API](https://developer.mozilla.org/docs/Web/API/StorageManager) on supported platforms.
The Cache Storage API and IndexedDB provide asynchronous access to persistent storage for PWAs and can be accessed from the main thread, web workers, and service workers. Both play essential roles in making PWAs work reliably when the network is flaky or non-existent. But when should you use each?

Use the *Cache Storage API* for network resources, things you'd access by requesting them via a URL, such as HTML, CSS, JavaScript, images, videos, and audio.

Use *IndexedDB* to store structured data. This includes data that needs to be searchable or combinable in a NoSQL-like manner, or other data such as user-specific data that doesn't necessarily match a URL request. Note that IndexedDB isn't designed for full-text search.

{% Aside 'caution' %}
All storage, no matter how you use it, is tied not just to the PWA it is used for, but to the PWA's origin, too. Therefore, if you deploy more than one PWA to an origin (which is not recommended), keep in mind that IndexedDB databases, cache storage, and the other browser storage will share quotas across all service workers and PWAs.
{% endAside %}

## IndexedDB
To use [IndexedDB](https://developer.mozilla.org/docs/Web/API/IndexedDB_API), first open a database. This creates a new database if one does not exist.
IndexedDB is an asynchronous API, but it takes a callback instead of returning a Promise. The following example uses Jake Archibald's [idb library](https://github.com/jakearchibald/idb), which is a tiny, Promise wrapper for IndexedDB. Helper libraries are not required to use IndexedDB, but if you want to use the Promise syntax the `idb` library is an option.

The following example creates a database to hold cooking recipes.

### Creating and opening a database

To open a database:

1. Use the `openDB` function to create a new IndexedDB database called `cookbook`. Because IndexedDB databases are versioned, you need to increase the version number whenever you make changes to the database structure. The second parameter is the database version. In the example is set to 1.
1. An initialization object containing an `upgrade()` callback is passed to `openDB()`. The callback function is called when the database is installed for the first time or when it upgrades to a new version. This function is the only place where actions can happen. Actions might include creating new object stores (the structures IndexedDB uses to organize data), or indexes (that you'd like to search on). This is also where data migration should happen. Typically, the `upgrade()` function contains a `switch` statement without `break` statements to allow each step to happen in order, based on what the old version of the database is.

```js
import { openDB } from 'idb';

async function createDB() {
  // Using https://github.com/jakearchibald/idb
  const db = await openDB('cookbook', 1, {
    upgrade(db, oldVersion, newVersion, transaction) {
      // Switch over the oldVersion, *without breaks*, to allow the database to be incrementally upgraded.
    switch(oldVersion) {
     case 0:
       // Placeholder to execute when database is created (oldVersion is 0)
     case 1:
       // Create a store of objects
       const store = db.createObjectStore('recipes', {
         // The `id` property of the object will be the key, and be incremented automatically
           autoIncrement: true,
           keyPath: 'id'
       });
       // Create an index called `name` based on the `type` property of objects in the store
       store.createIndex('type', 'type');
     }
   }
  });
}
```

The example creates an object store inside the `cookbook` database called `recipes`, with the `id` property set as the store's index key and creates another index called `type`, based on the `type` property.

Let's take a look at the object store that's just been created. After adding recipes to the object store and opening DevTools on Chromium-based browsers or Web Inspector on Safari, this is what you should expect to see:

{% Img src="image/SeARmcA1EicLXagFnVOe0ou9cqK2/OdDiXwJBMrsOgS1Phoz7.png", alt="Safari and Chrome showing IndexedDB contents.", width="800", height="538" %}

### Adding data

IndexedDB uses transactions. Transactions group actions together, so they happen as a unit. They help ensure that the database is always in a consistent state. They're also critical, if you have multiple copies of your app running, for preventing simultaneous writing to the same data.
To add data:

1. Start a transaction with the `mode` set to `readwrite`.
1. Get the object store, where you'll add data.
1. Call `add()` with the data you are saving. The method receives data in dictionary form (as key/value pairs) and adds it to the object store.  The dictionary must be cloneable using [Structured Cloning](https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). If you wanted to update an existing object, you'd call the `put()` method instead.


Transactions have a `done` promise that resolves when the transaction completes successfully, or rejects with a [transaction error](https://developer.mozilla.org/docs/Web/API/IDBTransaction/error).

As the [IDB library documentation](https://www.npmjs.com/package/idb?activeTab=readme) explains, if you're writing to the database, `tx.done` is the signal that everything was successfully committed to the database. However, it's beneficial to await individual operations so that you can see any errors that cause the transaction to fail.

```js
// Using https://github.com/jakearchibald/idb
async function addData() {
  const cookies = {
      name: "Chocolate chips cookies",
      type: "dessert"
	    cook_time_minutes: 25
  };
  const tx = await db.transaction('recipes', 'readwrite');
  const store = tx.objectStore('recipes');
  store.add(cookies);
  await tx.done;
}
```

Once you've added the cookies, the recipe will be in the database with other recipes. The ID is automatically set and incremented by indexedDB. If you run this code twice you will have two identical cookie entries.

{% Glitch 'learn-pwa-offline-data-saving' %}

### Retrieving data

Here is how you get data from IndexedDB:

1. Start a transaction and specify the object store or stores, and optionally transaction type.
1. Call `objectStore()` from that transaction. Make sure you specify the object store name.
1. Call `get()` with the key you want to get. By default the store uses its key as an index.

```js
// Using https://github.com/jakearchibald/idb
async function getData() {
  const tx = await db.transaction('recipes', 'readonly')
  const store = tx.objectStore('recipes');
// Because in our case the `id` is the key, we would
// have to know in advance the value of the id to
// retrieve the record
  const value = await store.get([id]);
}
```

{% Glitch 'learn-pwa-offline-data-get' %}

{% Aside 'codelab' %}
[Progressive Web Apps: IndexedDB](https://developers.google.com/codelabs/pwa-training/pwa03--indexeddb#0).
{% endAside %}

## The storage manager

Knowing how to manage your PWA's storage is particularly important to storing and streaming network responses correctly.

Storage capacity is shared among all storage options, including Cache Storage, IndexedDB, Web Storage, and even the service worker file and its dependencies.
However, the amount of storage available varies from browser to browser. You're not likely to run out; sites could store megabytes and even gigabytes of data on some browsers. Chrome, for instance, allows the browser to use up to 80% of the total disk space, and an individual origin can use up to 60% of the entire disk space. For browsers that support the Storage API, you can know how much storage is still available for your app, its quota, and its use.
The following example uses the Storage API to get estimate quota and usage, then calculates the percentage used and remaining bytes. Note that `navigator.storage` returns an instance of `StorageManager`. There is a separate `Storage` interface and it is easy to get them confused.

```js
if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}
```

{% Glitch 'learn-pwa-offline-data-storage' %}

In Chromium DevTools, you can see your site's quota and how much storage is used broken down by what's using it, by opening the **Storage** section in the **Application** tab.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/NAXXvUU099wqtSbzvt9m.png", alt="Chrome DevTools in Application, Clear Storage section", width="800", height="567" %}

Firefox and Safari don't offer a summary screen for seeing all storage quota and usage for the current origin.

### Data persistence

You can ask the browser for persistent storage on compatible platforms to avoid automatic data eviction after inactivity or on storage pressure. If granted, the browser will never evict data from storage. This protection includes the service worker registration, IndexedDB databases, and files in cache storage. Note that users are always in charge, and they can delete the storage at any time, even if the browser has granted persistent storage.

To request persistent storage, call the `StorageManager.persist()`. As before, the `StorageManager` interface is access through the `navigator.storage` property.

```js
async function persistData() {
  if (navigator.storage && navigator.storage.persist) {
    const result = await navigator.storage.persist();
    console.log(`Data persisted: ${result}`);
}
```

You can also check if persistent storage is already granted in the current origin by calling `StorageManager.persisted()`. Firefox requests permission from the user to use persistent storage. Chromium-based browsers give or deny persistence based on a [heuristic](/persistent-storage/#chrome-and-other-chromium-based-browsers) to determine the importance of the content for the user. One criteria for Google Chrome is, for example, PWA installation. If the user has installed an icon for the PWA in the operating system, the browser may grant persistent storage.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/W89sHSgKqkh9xV8nVD0C.png", alt="Mozilla Firefox asking the user for storage persistence permission.", width="800", height="279" %}

{% Aside 'caution' %}
The `StorageManager` interface has `persist()` and `persisted()` methods that both return Promises that resolve with a boolean. The `persist()` function asks for enabling persistent storage and returns the result, and `persisted()` returns the current state without affecting it.
{% endAside %}

{% Aside %}
[Content Indexing API](/content-indexing-api/) is an experimental API that's available in some Chromium browsers which lets your PWA expose the pieces of content that you have indexed offline.
If you register your offline-ready content using this API, the user will see them in Downloads within the browser even when there is no network connection.
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/b1o5a6iCgjqOVMVfcbuj.png", alt="The Content Indexing API results available in Chrome for Android.", width="800", height="1480" %}
{% endAside %}

## API Browser support

### Web Storage
{% BrowserCompat 'api.Window.localStorage' %}

### File System Access
{% BrowserCompat 'api.FileSystemHandle' %}

### Storage Manager
{% BrowserCompat 'api.StorageManager' %}

##  Resources

- [Storage on the Web](/storage-for-the-web/)
- [FileSystem Access API](/file-system-access/)
- [Persistent Storage](/persistent-storage/)
- [MDN: Storage API](https://developer.mozilla.org/docs/Web/API/Storage_API)
- [MDN: Client-side storage](https://developer.mozilla.org/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage)
- [Content Indexing](/content-indexing-api/)

# OS Integration

Web apps have a big reach. They run on multiple platforms. They are easy to share via links. But traditionally they lacked integration with the operating system. Not long ago they were not even installable. Luckily that has changed and now we can take advantage of that integration to add useful features to our PWAs. Let's explore some of those options.

## Working with the file system

A typical user workflow using files looks like this:
* Pick a file or folder from the device and open it directly.
* Make changes to those files or folders, and save the changes back directly.
* Make new files and folders.

Before the [File System Access API](/file-system-access/), web apps couldn't do this. Opening files required a file upload, saving changes required users to download them, and the web had no access at all to make new files and folders in the user's filesystem.

### Opening a file

To open a file we use the `window.showOpenFilePicker()` method. Note that this method requires a user gesture, such as a button click. Here is the rest of the setup for opening a file:
1. Capture the [file handle](https://developer.mozilla.org/docs/Web/API/FileSystemHandle) from the file system access's file picker API. This gives you basic information about the file.
2. Using the handle's `getFile()` method, you'll get a special kind of [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob) called a [`File`](https://developer.mozilla.org/docs/Web/API/File) that includes additional read-only properties (such as name and last modified date) about the file. Because it's a Blob, Blob methods can be called on it, such as `text()`, to get its content.

```js
// Have the user select a file.
const [ handle ] = await window.showOpenFilePicker();
// Get the File object from the handle.
const file = await handle.getFile();
// Get the file content.
// Also available, slice(), stream(), arrayBuffer()
const content = await file.text();
```

### Saving changes

To save changes to a file, you also need a user gesture; then:
1. Use the file handle to create a [`FileSystemWritableFileStream`](https://developer.mozilla.org/docs/Web/API/FileSystemWritableFileStream).
1. Make changes to the stream. This won't update the file in place; instead, a temporary file is typically created.
1. Finally, when you've finished making changes, you close the stream, which moves the changes from temporary to permanent.

Let's see this in code:

```js
// Make a writable stream from the handle.
const writable = await handle.createWritable();
// Write the contents of the file to the stream.
await writable.write(contents);
// Close the file and write the contents to disk.
await writable.close();
```

{% Glitch 'mlearn-pwa-os-integration-file' %}

{% Aside 'caution' %}
Safari implements the File System Access API, not for the public system, but as an [origin-private sandbox](/file-system-access/#accessing-files-optimized-for-performance-from-the-origin-private-file-system). You can only read and write files in that virtual file system using this API.
{% endAside %}

## File handling

The File System Access API lets you open files from within your app, but what about the other way around? Users want to set their favorite app as their default to open files with. The [file handling API](/file-handling/) is an experimental API that lets installed PWAs:
Register as a file handler on a user's device, specifying the MIME type and file extension that your PWA supports in your web app manifest. You can specify custom file icons for your supported extensions.

Once registered, your installed PWA will show up as an option from the user's file system, allowing them to open the file directly into it.
Here is an example of the manifest setup for a PWA to read text files:
```json
...
"file_handlers": [
     {
         "action": "/open-file",
         "accept": {
             "text/*": [".txt"]
         }
     }
]
...
```


## URL handling

With URL handling, your PWA can capture links that are part of its scope from the operating system and render them within a PWA window, instead of the default browser's tab. For example, if you receive a message linking to the PWA, or click on a deep link (a URL that points to a specific piece of content) in your PWA, the content will open in a standalone window.

This behavior is automatically available on Android when WebAPK is used, such as when users install a PWA with Chrome. It's impossible to capture URLs on PWAs installed on iOS and iPadOS from Safari.

For desktop browsers, the web browser community created a new spec. This spec is currently [experimental](/learn/pwa/experimental); it adds a new manifest file member: `url_handlers`. This property expects an array of origins that the PWA wants to capture. The origin of your PWA will be granted automatically, and each other origin must accept that handling operating through a file named `web-app-origin-association`.
For example, if your PWA's manifest is hosted on the web.dev, and you want to add the app.web.dev origin, it would look like this:

```json
"url_handlers": [
    {"origin": "https://app.web.dev"},
]
```
In this case, the browser will check if a file exists at `app.web.dev/.well-known/web-app-origin-association`, accepting the URL handling from the PWA scope URL. The developer has to create this file. In the following example, the file looks like this:

```json
{
    "web_apps": [
        {
            "manifest": "/mypwa/app.webmanifest",
            "details": {
                "paths": [ "/*" ]
            }
        }
    ]
}
```

{% Aside 'gotchas' %}
On Android with WebAPKs, PWAs are automatically registered as handlers for the manifest's scope with an Android intent filter, and it is not possible to add more origins or scopes to it. For iOS and iPadOS, you can only handle URLs with PWAs published in the AppStore, such as those created with [PWABuilder](https://pwabuilder.com).
{% endAside %}

## URL protocol handling

URL handling works with standard `https` protocol URLs, but it is possible to use custom URI-schemes, such as `pwa://`. In several operating systems, installed apps gain this ability by apps registering their schemes.

For PWA, this capability is enabled using the [URL protocol handler API](/url-protocol-handler/), available only on desktop devices. You can only allow custom protocols for mobile devices by distributing your PWA on app stores.

{% Aside 'caution' %}
For PWAs using the URL protocol handler API, the protocol name has to be one of the [safelisted schemes](https://html.spec.whatwg.org/multipage/system-state.html#safelisted-scheme), or it must use a `web+` prefix. So, in our example, a link should point to `web+pwa://` to open our PWA.
{% endAside %}

To register, you can use the [registerProtocolHandler() method](https://developer.mozilla.org/docs/Web/API/Navigator/registerProtocolHandler), or use the `protocol_handlers` member in your manifest, with the desired scheme and the URL you want to load in your PWA's context, such as:

```json
...
{
  "protocol_handlers": [
    {
      "protocol": "web+pwa",
      "url": "/from-protocol?value=%s"
    },
  ]
}
...
```

You can route the URL `from-protocol` to the correct handler and get the query string `value` in your PWA. The `%s` is a placeholder for the escaped URL that triggered the operation, so if you have a link somewhere such as `<a href="web+pwa://testing">`, your PWA will open `/from-protocol?value=testing`.

### Calling other apps

You can use URI schemes to connect to any other installed app (PWA or not) in users' devices on every platform. You just need to create a link or use `navigator.href` and point to the URI scheme you want, passing the arguments in URL-escaped form.

You can use well known standard schemes, such as `tel:` for phone calls, `mailto:` for email sending, or `sms:` for text messaging; or you can learn about other apps' URL schemes, for example from well known messaging, maps, navigation, online meetings, social networks, and app stores.

{% Aside %}
Instead of using private URI schemes to communicate with messaging and social media apps, you can use the generic Web Share API
{% endAside %}

## Web Share
{% BrowserCompat 'api.Navigator.share' %}

With the [Web Share API](https://developer.mozilla.org/docs/Web/API/Web_Share_API), your PWA can send content to other installed apps in the device through the shared channel.

The API is only available on operating systems with a `share` mechanism, including Android, iOS, iPadOS, Windows, and ChromeOS.
You can share an object containing:

* Text (`title` and `text` properties)
* A URL (`url` property)
* Files (`files` property).

To check if the current device can share, for simple data, like text, you check for the presence of the `navigator.share()` method, to share files you check for the presence of the `navigator.canShare()` method.

You request the share action by calling [`navigator.share(objectToShare)`](https://developer.mozilla.org/docs/Web/API/Navigator/share). That call returns a Promise that resolves with `undefined` or rejects with an exception.

{% Glitch 'mlearn-pwa-os-integration-web-share' %}


{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/wpB9v8QQTw4wB1iEGqvT.png", alt="Chrome on Android and Safari on iOS opening the Share Sheet thanks to Web Share.", width="800", height="661" %}

## Web Share Target

[Web Share Target API](/web-share-target/) lets your PWA be a target of a share operation from another app on that device whether it is a PWA or not. Your PWA receives the data shared by another app.

It's currently available on Android with WebAPK and ChromeOS, and it works only after the user has installed your PWA. The browser registers the share target within the operating system when the app is installed.

You set up web share target in the manifest with the `share_target` member defined in the [Web Share Target draft spec](https://w3c.github.io/web-share-target/). `share_target` is set to an object with some properties:

`action`
: URL that will be loaded in a PWA window that is expected to receive the shared data.
`method`
: HTTP verb method will be used for the action, such as `GET`, `POST`, or `PUT`.
`enctype`
: (Optional) Encoding type for the parameters, by default is `application/x-www-form-urlencoded`, but it can also be set as `multipart/form-data` for methods such as `POST`.
`params`
: An object that will map share data (from the keys: `title`, `text`, `url` and `files` from Web Share) to arguments that the browser will pass in the URL (on `method: 'GET'`) or in the body of the request using the selected encoding.


{% Aside %}
You can parse a `POST` request server-side or within your service worker if you want to avoid a trip to the network. Check [this sample](/web-share-target/#processing-post-shares) for further details.
{% endAside %}

For example, you can define for your PWA that you want to receive shared data (title and url only) by adding in your manifest:

```json
...
"share_target": {
   "action": "/receive-share/",
   "method": "GET",
   "params": {
      "title": "shared_title",
      "url": "shared_url"
   }
}
...
```
From the previous sample, if any app in the system is sharing a URL with a title, and the user picks your PWA from the dialog, the browser will create a new navigation to your origin's `/receive-share/?shared_title=AAA&shared_url=BBB`, where AAA is the shared title, and BBB is the shared URL. You can use JavaScript to read that data from the `window.location` string by parsing it with the [`URL` constructor](https://developer.mozilla.org/docs/Web/API/URL/URL).

The browser will use the PWA name and icon from your manifest to feed the operating system's share entry. You can't pick a different set for that purpose.

{% Aside %}
Make sure the page that handles the shared data is accessible offline. You don't want users choosing your app and finding an error because they don't have a connection at the moment.
{% endAside %}

For more detailed examples and how to receive files, check [Receiving shared data with the Web Share Target API](/web-share-target/)

## Contact Picker
{% BrowserCompat 'api.ContactsManager' %}

With the [Contact Picker API](https://developer.mozilla.org/docs/Web/API/Contact_Picker_API), you can request the device to render a native dialog with all the user's contacts so the user can choose one or more. Your PWA can then receive the data you want from those contacts.

The Contact Picker API is mainly available on mobile devices, and everything is done through the [`navigator.contacts`](https://developer.mozilla.org/docs/Web/API/Navigator/contacts) interface on compatible platforms.

You can request the available properties to query with `navigator.contacts.getProperties()`, and request a single or multiple contact selection with a list of desired properties.

Some sample properties are `name`, `email`, `address`, and `tel`. When you ask the user to pick one or more contacts, you can call `navigator.contacts.select(properties)`, passing an array of properties you want to get in return.

{% Aside 'caution' %}
The API doesn't guarantee that the returned objects will have all the requested properties, so you should recheck for their presence.
{% endAside %}

The following sample will list the contacts received by the picker.

```js
async function getContacts() {
   const properties = ['name', 'email', 'tel'];
   const options = { multiple: true };
   try {
     const contacts = await navigator.contacts.select(properties, options);
     console.log(contacts);
   } catch (ex) {
     // Handle any errors here.
   }
}
```

{% Glitch 'mlearn-pwa-os-integration-contacts' %}

##  Resources

- [The File System Access API: simplifying access to local files](/file-system-access/)
- [Let installed web applications be file handlers](/file-handling/)
- [Handle files in Progressive Web Apps](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/handle-files)
- [Integrate with the OS Sharing UI with the Web Share API](/web-share/)
- [Share content with other apps](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/share)
- [Receiving shared data with the Web Share Target API](/web-share-target/)
- [A contact picker for the web](/contact-picker/)

# Progressive Web Apps

A Progressive Web App (PWA) is a web app that uses progressive enhancement to provide users with a more reliable experience,
uses new capabilities to provide a more integrated experience, and can be installed.
And, because it's a web app, it can reach anyone, anywhere, on any device, all with a single codebase.
Once installed, a PWA looks like any other app, specifically:

- It has an icon on the home screen, app launcher, launchpad, or start menu.
- It appears when you search for apps on the device.
- It opens in a standalone window, wholly separated from a browser's user interface.
- It has access to higher levels of integration with the OS, for example, URL handling or title bar customization.
- It works offline.

## The web platform

The web is an incredible platform.
Its mix of universality across devices and operating systems,
its user-centered security model,
and the fact that no single company controls its specification or implementation make it a powerful platform
for delivering software.

Combined with the web's inherent linkability,
it's possible to search across it and share what you've found with anyone, anywhere.
Whenever you go to a website,
it's the latest version the publisher deployed,
and your experience with that site can be as temporary or as permanent as you'd like.

Web applications can reach anyone, anywhere, on any device with a single codebase.
For developers, the web also offers a transparent and straightforward deploying mechanism.
There is no need for packaging, no extra content review, or delays on updates.
Users always get the latest version when they visit your app.
With new capabilities and techniques, a web app can now allow you to interact or see content even when offline,
a hurdle that was impossible to overcome a few years ago.

## Platform-specific apps

Platform-specific apps, on both mobile and desktop,
are known for being rich and reliable. They're ever-present, on home screens, docks, and taskbars.
They work regardless of network connection, and launch in their own standalone experience.
They can read and write files from the local file system,
access hardware connected via USB, serial, or Bluetooth,
and interact with data stored on your devices, such as contacts and calendar events.
In platform-specific applications, you can take pictures, play songs listed on the home screen, or control media playback while in another app.
These applications feel like part of the device they run on.

{% Aside %}
In modern mobile operating systems,
platform-specific apps are installed mostly from app stores,
with rules and limitations on who can publish and what can be published for their users.
These apps are typically shipped as a large, indivisible package, and every update needs re-packaging, re-signing, re-approval, and on-device re-installation.
{% endAside %}

A challenge for platform-specific apps is that they are not compatible with multiple platforms and devices,
so it's not easy, if even possible,
to move an Android app to iOS or an iOS to Windows or ChromeOS without creating a new app from scratch.

## Bringing the best of both worlds

If you think about platform apps and web apps in terms of capabilities and reach,
platform apps represent the best of capabilities,
whereas web apps represent the best of reach.
Progressive Web Apps sit at the intersection of the capabilities of platform apps and the reach of web apps.
A Progressive Web App includes features from both worlds.

<div class="switcher">
<div>

### Web

- Linkability
- Accessible by default
- Ubiquitous
- Easy to Deploy
- Easy to Update
- Everyone can publish

</div>
<div>

### Platform apps

- Offline-capable
- High performance
- Device Integration
- Standalone experience
- Installed Icon
- Rich and reliable
</div>
</div>

{% Aside %}
People tend to think of Progressive Web Apps as an app that the user can install from a browser instead of an app store.
However, a PWA can be listed in many app stores today as an optional distribution channel,
including Google Play Store (for Android and ChromeOS), Microsoft Store (for Windows 10 and 11),
and Apple AppStore (for iOS, iPadOS, and macOS). For these cases, you must follow all store rules and requirements,
but you will still get some of the advantages of a PWA.
{% endAside %}

## Adoption has its benefits

Hulu, a video streaming service in the USA,
created a Progressive Web App version of their experience to replace their desktop apps which had poor user reviews and poor usage.
As shared at [Google I/O 2019](https://blog.chromium.org/2019/05/google-io-2019-whats-new-with-chrome.html),
one developer could research and implement this experience from their existing web application in two weeks.

Within five months, 96% of their legacy app users had adopted the PWA,
with a 27% increase in return visits and a 5.5% increase in engagement.
Because it's in the launcher and on taskbars, PWAs are easier to return to than if they just lived in a tab.

[JD.ID](/jdid/), an e-commerce platform in Indonesia providing delivery services for many products,
wanted to expand its online presence by focusing on performance and a network-independent solid experience for their PWA.
With this enhanced experience, they increased their overall mobile conversion rate by 53%,
200% for installed users, and increased their daily active users by 26%.

[Clipchamp](/clipchamp/) is an in-browser,
desktop-class online video editor that empowers anyone to tell stories worth sharing through video.
They saw 9% higher user retention with their PWA versus their standard desktop app users and have seen their PWA installations increasing at a rate of 97% each month in its first five months launched.

Corel Corporation's [Gravit Designer](/gravit-designer/) is a powerful,
desktop-class vector design tool that serves tens of thousands of daily active users demanding rich,
affordable, accessible vector illustration software.
Since adding a PWA as an install option for users,
they've seen PWA users are 24% more active,
the PWA accounts for 31% more repeat users, and PWA users are 2.5 times more likely to purchase Gravit Designer PRO,
as compared to their other platforms and install options.

{% Aside %}
Many other companies have implemented PWA and seen a benefit.
Large companies have already published PWAs on various products, including Apple (AppStore Connect, Feedback Assistant), Microsoft (Office 365, Windows 365), Google (Duo, YouTube Music, Drive), Amazon (Luna), Facebook (Instagram Lite, Gaming).
{% endAside %}

### The streaming game changer

A great example of the power of Progressive Web Apps is the industry of streaming platforms,
including cloud gaming and remote computing.
Since 2021, most cloud game providers have launched Progressive Web Apps,
letting you play console games from any device and just a browser or a PWA installation:
iPhone, Android, iPad, laptops, Macs, or PCs.
Amazon Luna, Microsoft Xbox Cloud Gaming, Facebook Gaming, Google Stadia, Nvidia GeForce Now, and BlueStacks X offer cloud gaming solutions over the browser as PWAs.
They all provide a great experience with performance close to native on all platforms thanks to web technologies such as WebRTC, WebAssembly, and GamePad APIs.

## Challenges

Having covered the advantages of using the web platform to publish PWAs,
it's also important to be aware of the challenges you may face.

### Cross-browser compatibility

Apple is a crucial company for the multi-device world,
owning iOS, iPadOS, macOS, and Safari.
While Apple has never used the term PWA in public,
they've been supporting the technologies to make a PWA installable and offline-capable since 2018 on Safari for iPhones and iPads.

However, Apple's implementation of the PWA specs misses many features possessed by other browsers,
in particular browsers powered by the Chromium engine.

In the middle, we also have Firefox and its Gecko engine with implementations including more PWA specs on Android,
and fewer installation capabilities on desktop.

Limitations include the lack of push notifications, integration APIs (such as Web Bluetooth or WebNFC),
and installation promotion techniques that help users know they can install the current website to get an app experience.
In addition, there are several bugs with implemented features.

As with all web development, testing your experience on every platform is mandatory when releasing your PWA,
and when a major new browser or OS version is released.
You should always provide fallback solutions or alternative experiences when a feature is not available.

### Awareness of PWAs

As a PWA developer,
you will probably encounter an awareness problem,
both on the business and user sides.
Some business owners won't know about PWAs or will have misconceptions about the power and challenges of Progressive Web Apps.

When you publish a PWA,
your next challenge is ensuring users understand that the website is installable, leading to an installed app experience.

The installation challenge is more significant on some platforms, such as iOS and iPadOS,
and sometimes UX designers include screens that explain to the user how to install the app.

## Compatibility

You need to remember that a Progressive Web App is just a web app,
so content and services are running on top of standard specs and protocols.
Therefore, a PWA technically runs everywhere the web runs; you don't need the platform to be compatible with any "PWA spec."

However, when we are talking about PWA and compatibility, typically, we are thinking about the capabilities to cross the boundaries of the browser and online-only contexts: icon installation and offline support.

{% Aside %}
A PWA should work everywhere, even when the icon installation or the offline support capabilities are unavailable.
Always plan your PWA to work without capabilities by checking support and offering fallback solutions.
{% endAside %}

On top of the classic web platform support, let's check the support for basic app functionality, such as icon installation and offline capabilities.

<ul class="stats auto-grid bg-state-good-bg color-state-good-text">
  <div class="stats__item flow">
    <p class="font-brand text-size-6">
      97
      <sub>%</sub>
    </p>
    <p>Offline-ready browsers</p>
  </div>
  <div class="stats__item flow">
    <p class="font-brand text-size-6">
      88
      <sub>%</sub>
    </p>
    <p>Web users can install a PWA</p>
  </div>
</ul>

_Data sourced from StatCounter and Can I Use._

### Desktop and laptops

In a world of multifactor devices,
it's challenging to know what a desktop device is anymore.
Still, at least from an operating system point of view,
these browsers and stores are compatible with PWA installation and offline capabilities:

Windows 10 and 11
: Google Chrome (from version 73), Microsoft Edge (from version 79), Microsoft Store

ChromeOS
: built-in Chrome browser  (from version 72), Play Store (from version 85)

macOS, Linux, and Windows 7 and 8.x
: Google Chrome (from version 73), Microsoft Edge

In the following video the user installs a PWA from the browser on a desktop computer,
and then accesses it like any other app with its standalone window.

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/d0cR0VyUhy30DkXEgGOt.mp4", alt="the user can install a PWA from the browser on a desktop computer, and then the user can access it like any other app with its standalone window", autoplay="true", loop="true", muted="true" %}

{% Aside 'caution' %}
On desktop, Safari and Firefox do not support PWA installation.
They do support offline capabilities, but the experience will always start within the browser user interface.
It may get fullscreen, but never a standalone window on desktop.
{% endAside %}

### Mobile devices

Talking about mobile phones and tablets,
a Progressive Web App is installable with offline capabilities using the following browsers and app stores:

iOS and iPadOS
: Safari (since iOS 11.3), AppStore (since iOS/iPadOS 14, with some limitations), mobile configuration for enterprise distribution.

Android
: Firefox, Google Chrome, Samsung Internet, Microsoft Edge, Opera, Brave, Huawei Browser, Baidu, UCWeb, Play Store (from version 72 with Google Chrome installed, or browsers compatible with TWA), Galaxy Store, Managed Play iframe for enterprise distribution.

{% Aside 'caution' %}
On iOS and iPadOS, PWAs are only installable if the user is using Safari. That means that users won't install PWAs if they use different browser apps, such as Google Chrome, Firefox, or Microsoft Edge. On both Android and iOS, users can't install PWAs from many in-app browsers, such as Facebook Mobile Browser, Instagram, Google Search App, or Gmail.
{% endAside %}

In the following video the user installs a PWA from the browser on a mobile device using the browser dialog, and also using the **Add to Home screen** menu.

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/Nj9yCzWOm6wWqpNN9Ojz.mp4", alt="the user can install a PWA from the browser on mobile devices on Android and iPhones, using the browser dialog or the 'Add to Home screen' menu.", autoplay="true", loop="true", muted="true" %}

### Other devices

Some other small devices support PWAs, such as game consoles (Xbox with Microsoft Store) or XR devices (Microsoft Hololens, plans for Facebook's Oculus). However, the rest of the devices with a browser do not typically accept PWAs, including:

- Game consoles
- Smart TVs
- Smartwatches
- Cars

Your PWA will always work in the browser of all devices with their specific limitations.
This ability to work in many devices, lets you create multi-device journeys,
where the user can start a task in one device and complete it on another device, with data synced across them, with the exact same deployed app.

##  Resources

- [Introduction to Progressive Web Apps on MDN](https://developer.mozilla.org/docs/Web/Progressive_web_apps/Introduction)
- [Progressive Web Apps Compatibility list](https://firt.dev/notes/pwa)
- [How Progressive Web Apps can drive business success](/drive-business-success/)
- [Clipchamp's video editor PWA installs see a 97% monthly growth](/clipchamp/)
- [PWA users are 2.5x more likely to purchase Gravit Designer PRO](/gravit-designer/)

# Service workers

Users expect apps to start on slow or flaky network connections, or even when offline.
They expect the content they've most recently interacted with, such as media tracks or tickets and itineraries, to be available and usable.
When a request isn't possible, they expect the app to tell them instead of silently failing or crashing. And users wish to do it all quickly. As we can see in this study [Milliseconds make millions](/milliseconds-make-millions/), even a 0.1 second improvement in load times can improve conversion by up to 10%. In summary: users expect PWAs to be reliable and that's why we have service workers.

## Hello service workers

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/iKWO7c2WNobLt30VZx9C.png",
alt="A service worker as a middleware proxy, running device-side, between your PWA and servers, which includes both your own servers and cross-domain servers.", width="800", height="354" %}

When an app requests a resource covered by the service worker's scope, including when a user is offline, the service worker intercepts the request, acting as a network proxy. It can then decide if it should serve the resource from the cache via the Cache Storage API, from the network as normally would happen without a service worker, or create it from a local algorithm. This lets you provide a similar experience to that provided by a platform app. It can even work entirely off line.

{% Aside 'gotchas' %}
Not all browsers support service workers. Even when present your service worker won't be available on first load or while it's waiting to activate. Therefore, treat it as optional and do not require it for core functionality.
{% endAside %}

## Registering a service worker

Before a service worker takes control of your page, it  must be registered for your PWA. That means the first time a user comes to your PWA, network requests will not go directly to your server because the service worker is not yet in control of your pages.

After checking if the browser supports the Service Worker API, your PWA can register a service worker. When loaded, the service worker sets up shop between your PWA and the network, intercepting requests and serving the corresponding responses.

```js
if ('serviceWorker' in navigator) {
   navigator.serviceWorker.register("/serviceworker.js");
}
```

{% Glitch 'learn-pwa-sw-registration' %}

{% Aside %}
There is only one service worker per PWA, but that doesn't mean you need to place the code only in one file. A service worker can include other files using [`importScripts`](https://developer.mozilla.org/docs/Web/API/WorkerGlobalScope/importScripts) in every browser or using [ECMAScript module imports](/es-modules-in-sw/) in some modern browsers.
{% endAside %}

### Verify if a service worker is registered

To verify if a service worker is registered, use developer tools in your favorite browser.

In Firefox and Chromium-based browsers (Microsoft Edge, Google Chrome, or Samsung Internet):

1. Open developer tools, then click the **Application** tab.
1. In the left pane, select **Service Workers**.
1. Check that the service worker's script URL appears with the status "Activated". (You'll learn what this status means in the lifecycle section in this chapter). On Firefox the status can be "Running" or "Stopped".

In Safari:

1. Click the **Develop** menu then the **Service Workers** submenu.
1. Check that an entry with the current origin appears in the submenu. It opens an inspector over the service worker's context.

<figure>
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/QMsYbKeQ6OJSm0FeqFxG.png", alt="Service worker developer tools on Chrome, Firefox and Safari.", width="800", height="296" %}
  <figcaption>Service worker developer tools on Chrome, Firefox and Safari.</figcaption>
</figure>

{% Aside %}
You can remotely inspect a phone or tablet from your desktop browser when you want to check service worker registration status on a mobile device. You will see details on how to do that in the [Tools and Debug chapter](/learn/pwa/tools-and-debug)
{% endAside %}

### Scope

The folder your service worker sits in determines its scope. A service worker that lives at `example.com/my-pwa/sw.js` can control any navigation at the *my-pwa* path or below, such as `example.com/my-pwa/demos/`. Service workers can only control items (pages, workers, collectively "clients") in their scope. Scope applies to browser tabs and PWA windows.

Only *one* service worker per scope is allowed. When active and running, only one instance is typically available no matter how many clients are in memory (such as PWA windows or browser tabs).

{% Aside 'warning' %}
You should set the scope of your service worker as close to the root of your app as possible. This is the most common setup as it lets the service worker intercept all the requests related to your PWA. Don't put it inside, for instance, a JavaScript folder or have it loaded from a CDN. {% endAside %}

Safari has more complex scope management, known as partitions, affecting how scopes work if you have cross-domain iframes. To read more about WebKit's implementation, read [their blog post](https://webkit.org/blog/8090/workers-at-your-service/).

## Lifecycle

Service workers have a lifecycle that dictates how they are installed, this is separate from your PWA installation.
The service worker lifecycle starts with registering the service worker. The browser then attempts to download and parse the service worker file. If parsing succeeds, its `install` event is fired. The `install` event only fires once.

Service worker installation happens silently, without requiring user permission, even if the user doesn't install the PWA. The Service Worker API is even available on platforms that do not support PWA installation, such as Safari and Firefox on desktop devices.

{% Aside 'gotchas' %}
Service worker *registration* and *installation*, while related, are different events. Registration happens when a page requests a service worker by calling `register()` as described previously. Installation happens when a registered service worker exists, can be parsed as JavaScript, and doesn't throw any errors during its first execution.
{% endAside %}

After the installation, the service worker is not yet in control of its clients, including your PWA. It needs to be activated first. When the service worker is ready to control its clients, the `activate` event will fire. This doesn't mean, though, that the page that registered the service worker will be managed. By default, the service worker will not take control until the next time you navigate to that page, either due to reloading the page or re-opening the PWA.

You can listen for events in the service worker's global scope using the `self` object.

{% Label %}serviceworker.js{% endLabel %}

```js
// This code executes in its own worker or thread
self.addEventListener("install", event => {
   console.log("Service worker installed");
});
self.addEventListener("activate", event => {
   console.log("Service worker activated");
});
```

### Updating a service worker

Service workers get updated when the browser detects that the service worker currently controlling the client and the new (from your server) version of the same file are byte-different.

{% Aside 'warning' %}
When updating your service worker, do so without renaming it. Do not even add file hashes to the filename. Otherwise, the browser will never get the new version of your service worker!
{% endAside %}

After a successful installation, the new service worker will wait to activate until the existing (old) service worker no longer controls any clients. This state is called "waiting", and it's how the browser ensures that only one version of your service worker is running at a time.
Refreshing a page or reopening the PWA won't make the new service worker take control. The user needs to close or navigate away from all tabs and windows using the current service worker and then navigate back. Only then will the new service worker to take control.
Visit this [service worker lifecycle article](/service-worker-lifecycle/) for more information.

## Service worker lifespan

Once installed and registered, a service worker can manage all network requests within its scope. It runs on its  own thread, with activation and termination controlled by the browser. This lets it work even before or after your PWA is open. While service workers run on their own thread, there is no guarantee that in-memory state will persist between runs of a service worker, so make sure anything you want to reuse on each run is available either in IndexedDB or some other persistent storage.

If not already running, a service worker will start whenever a network request in its scope is asked for, or when a triggering event, like periodic background sync or a push message, is received.

Service workers don't live indefinitely. While exact timings differ between browsers, service workers will be terminated if they've been idle for a few seconds, or if they've been busy for too long. If a service worker has been terminated and an event occurs that would start it up, it will restart.

## Capabilities

With a registered and active service worker, you have a thread with a completely different execution lifecycle than the main one on your PWA. However, by default, the service worker file itself has no behavior. It won't cache or serve any resources, as this has to be done by your code. You'll find out how in the following chapters.

Service worker's capabilities are not just for proxy or serving HTTP requests; other features are available on top of it for other purposes, such as background code execution, web push notifications, and process payments. We'll discuss these additions in the [capabilities chapter](/learn/pwa/capabilities).

##  Resources

- [Service Worker API (MDN)](https://developer.mozilla.org/docs/Web/API/Service_Worker_API)
- [Service Worker mindset](/service-worker-mindset/)
- [WebKit Workers at your service](https://webkit.org/blog/8090/workers-at-your-service/)
- [ES Modules in Service Workers](/es-modules-in-sw/)
- [Service worker lifecycle](/service-worker-lifecycle/)

# Serving

A key aspects of Progressive Web Apps is that they're reliable; they can load assets quickly, keeping users engaged and providing feedback immediately, even under poor network conditions. How is that possible? Thanks to the service worker `fetch` event.

## The fetch event
{% BrowserCompat 'api.FetchEvent' %}

The [`fetch`](https://developer.mozilla.org/docs/Web/API/FetchEvent) event lets us intercept every network request made by the PWA in the service worker's scope, for both same-origin and cross-origin requests. In addition to navigation and asset requests, fetching from an installed service worker allows page visits after a site's first load to be rendered without network calls.

The `fetch` handler receives all requests from an app, including URLs and HTTP headers, and lets the app developer decide how to process them.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/WExZeP8vV28bPDBlpxuG.png", alt="The service worker sits between the client and the network.", width="800", height="439" %}

Your service worker can forward a request to the network, respond with a previously cached response, or create a new response. The choice is yours.
Here's a simple example:

```js
self.addEventListener("fetch", event => {
    console.log(`URL requested: ${event.request.url}`);
});
```

{% Aside 'caution' %}
While you can have more than one fetch event handler per service worker, only one can respond per request. For example, you can have different handlers that will act on different URL patterns. They are executed in the order they were registered until one of them calls `respondWith()`.
{% endAside %}

## Responding to a request

When a request comes into your service worker, there are two things you can do; you can ignore it, which lets it go to the network, or you can respond to it. Responding to requests from within your service worker is how you're able to choose what, and how it gets returned to your PWA, even when the user is offline.

To respond to an incoming request, call `event.respondWith()` from within a `fetch` event handler, like this:

```js/3
// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
    const response = .... // a response or a Promise of response
    event.respondWith(response);
});
```

You must call `respondWith()` synchronously and you must return a [Response](https://developer.mozilla.org/docs/Web/API/Response) object. But you can't call `respondWith()` after the fetch event handler has finished, like within an async call. If you need to wait for the complete response, you can pass a Promise to `respondWith()` that resolves with a Response.

### Creating responses

Thanks to the [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API), you can create HTTP responses in your JavaScript code, and those responses can be cached using the Cache Storage API and returned as if they were coming from a web server.

To create a response, create a new `Response` object, setting its body and options such as status and headers:

```js
const simpleResponse = new Response("Body of the HTTP response");

const options = {
   status: 200,
   headers: {
	'Content-type': 'text/html'
   }
};
const htmlResponse = new Response("<b>HTML</b> content", options)
```

{% Aside 'warning' %}
Be extra careful when creating responses with a service worker buggy code can lead to corner cases and hard to debug issues, such as the browser being unable to load the HTML document that renders your PWA. While debugging, you can always use your browser's reload button with the Shift key pressed, which will bypass the service worker; or use service worker devtools on supported browsers as we'll see in [Tools and Debug](/learn/pwa/tools-and-debug/).
{% endAside %}

{% Glitch 'learn-pwa-serving-synthesize' %}


### Responding from the cache

Now that you know how to serve HTTP responses from a service worker,
it's time to use the [Caching Storage interface](/learn/pwa/caching) to store assets on the device.

You can use the cache storage API to check if the request received from the PWA is available in the cache, and if it is, respond to `respondWith()` with it.
To do that, you first need to search within the cache. The `match()` function, available at the top-level `caches` interface searches all stores in your origin, or on a single open cache object.

The `match()` function receives an HTTP request or a URL as an argument and it returns a promise that resolves with the Response associated with the corresponding key.

```js
// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
   console.log(response ? response : "It's not in the cache");
});

// Cache-specific search
caches.open("pwa-assets").then(cache => {
  cache.match(urlOrRequest).then(response) {
    console.log(response ? response : "It's not in the cache");
  }
});
```

{% Aside 'gotchas' %}
When using `match()` with `respondWith()`, the match promise will resolve either with the found item or with nothing. It will only reject if there was a problem that prevented the search operation from completing. To throw an error if no results are found, you'll need to inspect the results before returning a response to `respondWith()`.
{% endAside %}

## Caching strategies

Serving files only from the browser cache doesn't fit every use case. For example the user or the browser can evict the cache. That's why you should define your own strategies for delivering assets for your PWA.
You're not restricted to one caching strategy. You can define different ones for different URL patterns. For example, you can have one strategy for the minimum UI assets, another for API calls, and a third for image and data URLs.
To do this, read `event.request.url` in `ServiceWorkerGlobalScope.onfetch` and parse it through regular expressions or a [URL Pattern](/urlpattern/). (At the time of writing, URL Pattern is not supported on all platforms).

The most common strategies are:

Cache First
: Searches for a cached response first and falls back to the network if one isn't found.

Network First
: Requests a response from the network first and if none is returned, checks for response in the cache.

Stale While Revalidate
: Serves a response from the cache, while in the background requests the latest version and saves it to the cache for the next time the asset is requested.

Network-Only
: Always replies with a response from the network or errors out. The cache is never consulted.

Cache-Only
: Always replies with a response from the cache or errors out. The network will never be consulted. The assets that will be served using this strategy must be added to the cache before they are requested.

### Cache first

Using this strategy, the service worker looks for the matching request in the cache and returns the corresponding Response if it's cached. Otherwise it retrieves the response from the network (optionally, updating the cache for future calls). If there is neither a cache response nor a network response, the request will error. Since serving assets without going to the network tends to be faster, this strategy prioritizes performance over freshness.

{% Aside %}
Remember the cache storage interface won't return a Response object. The reference will be `undefined`, if the request is not cached.
{% endAside %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/ki9e4T6ik7mfrN67Zysx.png", alt="The Cache First strategy", width="800", height="439" %}

```js
self.addEventListener("fetch", event => {
   event.respondWith(
     caches.match(event.request)
     .then(cachedResponse => {
	   // It can update the cache to serve updated content on the next request
         return cachedResponse || fetch(event.request);
     }
   )
  )
});
```

{% Glitch 'learn-pwa-serving-offline' %}

### Network first

This strategy is the mirror of the Cache First strategy; it checks if the request can be fulfilled from the network and, if it can't, tries to retrieve it from the cache. Like cache first. If there is neither a network response nor a cache response, the request will error. Getting the response from the network is usually slower than getting it from the cache, this strategy prioritizes updated content instead of performance.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/bGCR5LiMRlt9urRcpnk4.png", alt="The Network First strategy", width="800", height="439" %}

```js
self.addEventListener("fetch", event => {
   event.respondWith(
     fetch(event.request)
     .catch(error => {
       return caches.match(event.request) ;
     })
   );
});
```

### Stale while revalidate

The stale while revalidate strategy returns a cached response immediately, then checks the network for an update, replacing the cached response if one is found. This strategy always makes a network request, because even if a cached resource is found, it will try to update what was in the cache with what was received from the network, to use the updated version in the next request. This strategy, therefore, provides a way for you to benefit from the quick serving of the cache first strategy and update the cache in the background.

{% Aside %}
With this strategy, the assets are updated in the background. This means your users won't get the new version of the assets until the next time that path is requested. At that time the strategy will again check if a new version exists and the cycle repeats.
{% endAside %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/C7OcnPRHNdTLe2043JHG.png", alt="The stale while revalidate strategy", width="800", height="439" %}

```js
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
        const networkFetch = fetch(event.request).then(response => {
          // update the cache with a clone of the network response
          const responseClone = response.clone()
          caches.open(url.searchParams.get('name')).then(cache => {
            cache.put(event.request, responseClone)
          })
          return response
        }).catch(function (reason) {
          console.error('ServiceWorker fetch failed: ', reason)
        })
        // prioritize cached response over network
        return cachedResponse || networkFetch
      }
    )
  )
})
```

{% Aside 'caution' %}
The Response's body is a [ReadableStream](https://developer.mozilla.org/docs/Web/API/ReadableStream) that can only be consumed once. That means that if you call `fetch()` to deliver the response to the PWA because the asset was not cached, you cannot reuse the same response for updating it in the cache. You need to call `Response.clone()` to use it twice.
{% endAside %}

{% Glitch 'learn-pwa-serving-stale-while-revalidate' %}

### Network only

The network only strategy is similar to how browsers behave without a service worker or the Cache Storage API. Requests will only return a resource if it can be fetched from the network. This is often useful for resources like online-only API requests.


{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/NGxIKl6Lq8TY9GqXT8r8.png", alt="The Network only strategy", width="800", height="439" %}


### Cache only

The cache only strategy ensures that requests never go to the network; all incoming requests are responded to with a pre-populated cache item. The following code uses the `fetch` event handler with the `match` method of the cache storage to respond cache only:

```js
self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});
```

{% Aside %}
With the cache only strategy you cache your assets before you need them, usually in the service worker's `install` event handler. Because this strategy never goes to the network, these assets will get updated only when you update your service worker and a new `install` event is fired.
{% endAside %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/rDI3LvI9y0SBUFfRCdgm.png", alt="Cache only strategy.", width="800", height="439" %}

{% Glitch 'learn-pwa-serving-cache-only' %}

### Custom strategies

While the above are common caching strategies, you are in charge of your service worker and how requests are handled. If none of these work for your needs, create your own.

You can, for example, use a network first strategy with a timeout to prioritize updated content, but only if the response appears within a threshold you set. You can also merge a cached response with a network response and build a complex response from the service worker.

## Updating assets

Keeping your PWA's cached assets up-to-date can be a challenge. While the stale while revalidate strategy is one way to do so, it's not the only one. In the [Update chapter](/learn/pwa/update) you will learn different techniques to keep your app's content and assets updated.

##  Resources

- [Fetch event on MDN](https://developer.mozilla.org/docs/Web/API/FetchEvent)
- [The Offline Cookbook](/offline-cookbook/)
- [Cache Match on MDN](https://developer.mozilla.org/docs/Web/API/Cache/match)

# Tools and debug

All the tools available for web development are also helpful for progressive web app development, including libraries, frameworks, code editors, builders, developer tools, debuggers, and more. But when working with PWA-specific abilities, such as installability, service workers, offline support, and more, certain tools for PWA are extra helpful. Let's see them in action.

## Simulators and devices

As mentioned in the [Foundations chapter](/learn/pwa/foundations), you should use agnostic design patterns to offer the best experience to every user in every context. However, it's good practice to test your experiences on different devices.

{% Aside 'caution' %}
Installed PWAs are new experiences for web developers to test and debug, but keep in mind that not every tool is compatible with this mode.
{% endAside %}

You probably won't own dozens of physical devices, including iPhones, Android phones, tablets, and desktops or laptops with different operating systems. That's why simulators and emulators exist.

### Simple simulators

Most developer tools within browsers let you test your PWAs in different screen sizes or network conditions while using a single desktop browser engine. Some of these tools can also force a different user agent under these simulations.

Some available simulators are:

* Chromium DevTools: [Device Mode](https://developer.chrome.com/docs/devtools/device-mode/), network throttling and several sensor simulations available
* Firefox Developer Tools: [Responsive Design Mode](https://developer.mozilla.org/docs/Tools/Responsive_Design_Mode)
* Safari Web Inspector: [Responsive Design Mode](https://developer.apple.com/safari/tools/)
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/gnIHqhnkBZcz1loMEcMG.png", alt="Chromium DevTools simulating mobile devices.", width="800", height="513" %}
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/fheSiDVxegbRD6oxERQ1.png", alt="Firefox DevTools simulating mobile devices.", width="800", height="629" %}
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/Opi0TXLgyl6v6PfQ06MM.png", alt="Safari Web Inspector Responsive Design mode.", width="800", height="810" %}
Some commercial and free solutions are optimized for developers and designers, such as the open source [Responsively app](https://responsively.app).
{% Aside 'gotchas' %}
Simple simulators can't simulate and test installation-related abilities, such as `display-mode` related media queries, iOS web app meta tags, app shortcuts, or web share target.
{% endAside %}

### Apple simulators

Apple offers the Simulator app (formerly known as iOS Simulator) which allows you to test your web app on different iPhones and iPads on various operating system versions.

The Simulator app is only available for macOS computers, and it comes with [Xcode, available in [AppStore](https://apps.apple.com/us/app/xcode/id497799835); it simulates iOS and iPadOS with different device configurations. It includes the real Mobile Safari app and the Web.app engine used when your PWA is installed on the home screen, so the final experience you see is fairly representative of an actual device.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/aa4SAqNofV2d1nw3btVF.png", alt="Simulator with Safari rendering websites on iPhones and iPad.", width="800", height="376" %}

To launch the app, once you have installed Xcode, you can open the Simulator in the `Xcode` menu, by selecting `Open Developer Tools` then `Simulator`. Once in the simulator, you can open Safari as if you are in a real iPhone or iPad. You can open other devices by selecting `File` then `Open Simulator` menu.

Some useful shortcuts for web developers while using Simulator to test PWAs are:

* `Command-Shift-H`: go to the Home screen.
* `Control-Command-Shift-H`: access the App Switcher.
* `Command-Right` and `Command-Left`: rotate the device.

Simulator is not a virtual machine, but an app running on top of your macOS that looks like an iPhone or iPad, so it doesn't have its own TCP stack. Therefore, if you use `localhost` within Simulator, Safari will point to your macOS `localhost` device.


By default, Xcode only installs the latest version of iOS, but you can go to Xcode, use the `Preferences` menu, and download older Simulators from the `Components` tab.

It's good practice to test your PWA on the latest version of iOS, the previous minor version, and at least one previous major version.

### Android emulators

The Android ecosystem offers different emulators, but the ones available within the [Android SDK](https://developer.android.com/studio/run/emulator) are the most commonly used.

As a PWA developer, you also need browsers in your Android emulator, which will add a layer of complexity to testing, because AOSP (Android Open Source Project) doesn't include Google Chrome or Play Store to download browsers. Therefore, not every Android emulator is helpful for PWA testing.

The Android SDK comes with two tools useful for emulation:

* SDK Manager: downloads and updates different operating system versions and plugins.
* AVD Manager: adds, edits, and deletes Android Virtual Devices (AVDs), each of them representing one device with one Android OS installed, similar to a virtual machine instance.

You can only install the Android SDK or [Android Studio](https://developer.android.com/studio), a free IDE including the Android SDK with the emulators. With the SDK, you will have to use the command line to open and set up your emulators. With Android Studio, you can open the tools needed from the Welcome screen's menu.
Once in the AVD Manager, you can create as many devices as you want, with different combinations of screen size, abilities, and Android OS version.

{% Aside 'caution' %}
Each Android Virtual Device can take more than 5GB of your hard drive. Be mindful of that when creating images.
{% endAside %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/QQH4XtxtnRe7UmgCG47D.png", alt="The AVD manager with an Android Virtual device browsing a website", width="800", height="569" %}

{% Aside 'caution' %}
Android devices are virtual machines on top of your host computers, so they have their own TCP stacks. Therefore, `localhost` in an Android browser within an AVD won't be the same as your `localhost` in your host desktop computer. Later in this chapter, we will see how to solve this restriction with port forwarding.
{% endAside %}

With an Android emulator, you can check your PWA installation support, the entire user experience, and if the abilities you are using are working as expected.

#### Using Google Chrome

To use Google Chrome in the Android emulator, you have to create an AVD with Play Services inside. To do that, make sure the SDK you use for your AVD has the Play icon, as you can see in the following image:

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/KNBWJ3Nu8SYFbh8KemT9.png", alt="Creating AVDs with an operating system including Play services.", width="800", height="560" %}

AVDs with Play services also include Play Store, so you can update your Chrome with the latest version after setting up your account with your Google account.

#### Using other browsers

If you use an AVD with Play services, you can also download browsers from the Play Store.

Most of the browsers available for Android, including Samsung Internet, Microsoft Edge, Opera, Firefox, and Brave, are available as APKs (Android Packages). If you have the APK for the browser you want to test, you can just drag the file to the emulator or install it through the command-line [using ADB](https://developer.android.com/studio/command-line/adb).

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/Ngc9KZO0UdLiGYF2TGt0.png", alt="Android emulator installing Microsoft Edge from Play store.", width="780", height="746" %}

### Desktop emulators

Emulating a different desktop computer is typically done via a virtual machine system, such as VirtualBox or VMWare. Even with these tools, emulating some environments is impossible, such as emulating macOS on Windows or Linux, and some other options may require a license, such as emulating Windows on macOS or Windows.

### Using physical devices

Using actual devices to test your PWA is also a good idea. We don't need to own several devices as there are some cloud-based solutions where you can use physical devices remotely. There are some free solutions and some commercial solutions with a free-tier available.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/R6nJTg2Uoh5EstlZdr21.png", alt="Remote Test Lab from Samsung with a foldable phone.", width="800", height="460" %}

One of the available solutions is [Samsung Remote Test Lab](https://developer.samsung.com/remote-test-lab), a free solution to test your PWA on Samsung devices, including phones, tablets, and foldable devices.

{% Aside 'gotchas' %}
Some cloud-based device lab solutions are suitable for device-specific app testing. They are not optimized for PWAs, so you can only use them if you plan to create a package to distribute your PWA in an app store.
{% endAside %}

### Remote inspection

When you want to debug your Progressive Web App in an actual device, a simulator, or an emulator, you may want to connect a remote inspection session with your desktop's browser tools.

There are commercial tools available, but all the browsers also offer ways to do it, including:

* [WebKit Remote Inspector](https://webkit.org/web-inspector/enabling-web-inspector/) to connect to Safari and installed PWAs on iOS- and iPadOS-connected devices and simulators.
* [Chromium DevTools Remote Debugging](https://developer.chrome.com/docs/devtools/remote-debugging/) to connect to Chrome, Edge, Samsung Internet, and other Chromium-based browsers on Android and PWAs installed from those browsers, including connected physical devices and emulators.
* [Firefox Remote Debugging](https://developer.mozilla.org/docs/Tools/Remote_Debugging) to connect to Firefox for Android on connected actual devices and emulators.

#### Port forwarding for Android

When testing PWAs available on `localhost` on Android physical devices or emulators, you will have a problem, as `localhost` will point to the Android TCP stack and not your development machine.

You may want to use your local IP address as a replacement to `localhost`, but that's not a good idea as service workers and many abilities will only work with HTTPS connections, with the exception of `localhost`, so your PWA won't work offline or pass PWA criteria.


You can solve the problem by enabling port forwarding on a Chromium browser on your desktop computer. In that case, you can bridge a port on `localhost` on the Android device to any origin and port from your host computer, including your development computer's `localhost`. Check [this guide](https://developer.chrome.com/docs/devtools/remote-debugging/local-server/) for more information.

## Chromium browsers

Chromium browsers offer many tools for debugging and testing Progressive Web Apps, starting from DevTools.

Most Chromium-based browsers, including Samsung Internet, Microsoft Edge, and Google Chrome, offer different channels, such as Stable, Beta, and Canary. You can install separate versions on desktop and Android to test your PWA on future versions of the browser. This allows you to build and test features that are not yet widely available, or to test deprecations and changes, and work out how your app will behave in newer versions.


Using remote inspection, you can use all these tools to debug and test your PWA on desktop and Android devices.


### Service worker tools

Chromium DevTools has a complete set of tools to debug service workers and their APIs' "Application" tab. From the "Service Workers" section, you can:

* See service workers' installation status and lifecycle.
* Update and unregister the service worker.
* Follow the update cycle.
* See current service workers' clients.
* Send a push message to a service worker.
* Register Background Sync and Periodic Background Sync operations.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/WJ0fBXggrFnhifcAIcBb.png", alt="Service Worker debugging tools con Chromium DevTools.", width="800", height="491" %}

[Read more about these tools](https://developer.chrome.com/docs/devtools/progressive-web-apps/#service-workers).

### Storage tools

Within `Application` then `Storage`, you can see, preview, update, and delete data from your origin, such as Web Storage entries or IndexedDB stores.
Inside `Application`, `Cache` then `Cache Storage`, you can see all the caches stored in current origin, preview content, and delete entries. [Read more about the cache tool](https://developer.chrome.com/docs/devtools/storage/cache/).

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/WJ0fBXggrFnhifcAIcBb.png", alt="Cache Inspector in Chromium DevTools", width="800", height="491" %}

Also, selecting from `Application` then `Storage`, you can see the current quota used, simulate custom quota storage, and clear all your data, including the service worker registration, using `Clear site data`.

#### Background services

Chromium DevTools also has a set of background services event recording tools, found by clicking `Application` then `Background Services`. This lets you see what happens with some events in the background on top of the service workers' API. [Read more about these tools](https://developer.chrome.com/docs/devtools/javascript/background-services/).

### Web app manifest tools

Chromium DevTools has a section for Web App Manifest and installability criteria under `Application`, `Manifest`. In this section, you can check whether the manifest has loaded correctly, the manifest's values, how the icons look, the [app id](/learn/pwa/web-app-manifest/#basic-fields), and a quick checker for [maskable icons](/learn/pwa/web-app-manifest/#maskable-icons).

Warnings and errors around [installability criteria](/learn/pwa/installation/#installation-criteria) issues are also shown in this section.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/uBOt9BBbF15lX7Cxju6t.png", alt="Debugging Web App Manifest in Chromium DevTools.", width="800", height="713" %}

[Read more about these tools](https://developer.chrome.com/docs/devtools/progressive-web-apps/).

{% Aside %}
Chromium-based browsers have some flags that may be useful while testing PWAs. Check all the available options by browsing to `about://flags/`
{% endAside %}

### Installation debugging

On Android devices using [WebAPK installation mode](/learn/pwa/installation/#webapks), you can access a list of installed apps by browsing to `about:webapk` on Chromium browsers.

You will see the current update status and request a WebAPK update from here.

On desktop computers, you can see a user-friendly list of installed PWAs by browsing to `about:apps`, and a debug version by browsing to `about:app-service-internals`.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/exwzkevoGROml8uH5ZxL.png", alt="Google Chrome WebAPK debug screen on Android.", width="800", height="400" %}

## Safari

At the time of writing, Safari has a more limited set of tools available for PWA testing and debugging. There are no tools to see and debug the state and lifecycle of service workers, no inspector for the  cache's content, and no tools for web app manifest support and installability on iOS and iPadOS.

{% Aside 'gotchas' %}
You can only inspect and debug PWAs on iOS and iPadOS if you have a macOS computer with an updated OS using Safari desktop or Safari Technology Preview. There are some commercial tools such as [Inspect](https://inspect.dev) that allow you to inspect web apps on iOS and iPadOS from other operating systems.
{% endAside %}


Safari is available only on stable, while [Safari Technology Preview](https://developer.apple.com/safari/technology-preview/) available for macOS will only let you try abilities of future versions of Safari beforehand. The [iOS and iPadOS beta programs](https://beta.apple.com/sp/betaprogram) sometimes include new versions of Safari that you can use for testing.

### Service worker tools

What you can do on Safari (both on macOS and remotely for iOS and iPadOS) is to open an inspector window for a service worker that is currently running.

From Safari on macOS, the `Develop`, `Service Workers` menu will list all the currently running service worker sessions. You have to select the device to inspect in the `Develop` menu for remote inspection. Service workers' contexts will appear in the same submenu as window contexts under the origin's or PWA's installed name.

If you select one of them, Safari will open a new window with a restricted inspector, including only `Consoles`, `Sources`, and `Network Tabs`.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/jho0nKOzPq9XPH8g24Hk.png", alt="A Service Worker Web Inspector from a PWA in Safari.", width="800", height="427" %}

{% Aside %}
[Service Worker Detector](https://apps.apple.com/app/service-worker-detector/id1530808337) is a free Safari extension available in AppStore that will let you see service worker registration status and the cache storages available under the current origin, abilities which are not available on WebKit's Inspector.
{% endAside %}

## Firefox

Firefox supports service workers on all platforms and App Manifest for installation only on Android. You can access the tools for PWAs on desktop and Android by a [USB remote inspection session](https://developer.mozilla.org/docs/Tools/about:debugging).

You can use the desktop version known as [Firefox Developer Edition](https://www.mozilla.org/firefox/developer/). As with Chromium browser, Firefox has versions in different channels on desktop and Android, including stable, beta, and dev versions.

### Tools for PWAs

The service worker inspector on Firefox is a basic tool available in Developer Tools under `Application`, `Service Workers`. It lets you see the currently registered service worker, check its running status, and unregister it. Debugging the service worker's code may only be available on some developer versions of Firefox.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/AihFdYbhvY7mpqWVQCuH.png", alt="Firefox Developer Tools for Service Worker and Manifest.", width="800", height="454" %}

The manifest tool is available under `Application`, `Manifest`, and it only renders the manifest's values with a preview of the icons.

Under `Storage`, you can manage the origin's storage, including IndexedDB and Cache Storage.

You can read more about [Firefox developer tooling for web apps](https://developer.mozilla.org/docs/Tools/Application).

{% Aside %}
To develop your PWA, you can use any code editor, IDE, and toolchain of your choice. If you are using Visual Studio code as your code editor, you may want to check the [PWA Studio](https://blog.pwabuilder.com/posts/announcing-pwa-studio-the-vs-code-extension-for-building-progressive-web-apps!/?WT.mc_id=M365-MVP-4025164) free extension from the PWABuilder team. This has many tools for PWA developers such as an icon resizer, a service worker generator, and a quick way to create PWAs launchers–useful for app store distribution.
{% endAside %}

##  Resources

- [Chrome DevTools: Debug Progressive Web Apps](https://developer.chrome.com/docs/devtools/progressive-web-apps/)
- [Debug PWAs on Edge](https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/progressive-web-apps/)
- [Firefox Developer Tools: Application Tab](https://developer.mozilla.org/docs/Tools/Application)
- [Debugging Service Workers in Chrome (video)](https://www.youtube.com/watch?v=tuRPSaSiK_c)

# Update

You have published your PWA: some users use it from the browser, others install it on their devices. When you update the app, it's important to apply best practices to avoid pitfalls.

You may update:

* App data.
* Assets already cached in devices.
* The service worker file, or its dependencies.
* Manifest metadata.

Let's check out the best practices for each of these elements.

## Updating data

To update data, such as that stored in IndexedDB, you can use tools such as Fetch, WebRTC, or WebSockets API. If your app supports any offline features, remember to keep the data that supports the features updated too.

On compatible browsers, there are options to sync data, not only when the user opens the PWA but also in the background. These options are:

* [Background synchronization](https://developer.mozilla.org/docs/Web/API/Background_Synchronization_API): saves requests that failed and retries them using sync from the service worker.
* [Web periodic background sync](https://developer.mozilla.org/docs/Web/API/Web_Periodic_Background_Synchronization_API): syncs data periodically in the background, at specific times, allowing the app to provide updated data even if the user hasn't opened the app yet.
* [Background Fetch](https://developer.mozilla.org/docs/Web/API/Background_Fetch_API): downloads large files, even when the PWA is closed.
* [Web push](https://developer.mozilla.org/docs/Web/API/Push_API): sends a message from the server that wakes up the service worker and notifies the user. This is commonly called a 'push notification'. This API requires the user's permission.

All these APIs are executed from the service worker context. They are currently available only on Chromium-based browsers, on Android, and desktop operating systems. When you use one of these APIs, you can run code in the service worker thread; for example, to download data from your server and update your IndexedDB data.

{% Aside %}
The Web Push API is the only API to notify the user from the background and its `push` message can include a small amount of data: it can carry a payload of up to around 2KB.
{% endAside %}

## Updating assets

Updating assets includes any changes to files you use to render the app's interface, such as HTML, CSS, JavaScript, and images. For example, a change in your app's logic, an image that is part of your interface, or a CSS stylesheet.

### Update patterns

Here are some common patterns to handle app updates, but you can always customize the process to your own needs:

* Full update: every change, even a minor one, triggers the replacement of the entire cache content. This pattern mimics how device-specific apps handle updates, and it will consume more bandwidth and will take more time.
* Changed assets update: only the assets that have changed since the last update get replaced in cache. It is often implemented using a library such as [Workbox](/learn/pwa/workbox). It involves creating a list of cached files, a hash representation of the file, and timestamps. With this information, the service worker compares this list with the cached assets and decides which assets to update.
* Individual assets update: each asset is updated individually when it changes. The stale while revalidate strategy described in the [Serving chapter](/learn/pwa/serve) is an example of updating assets individually.

### When to update

Another good practice is to find a good time to check for updates and apply them. Here are some options:

* When the service worker wakes up. There is no event to listen for this moment, but the browser will execute any code in the service worker's global scope when it wakes up.
* In the main window context of your PWA, after the browser loaded the page, to avoid making the app load slower.
* When background events are triggered, such as when your PWA receives a push notification or a background sync fires. You can update your cache then and your users will have the asset's new version the next time they open the app.

{% Aside 'warning' %}
When checking for updates, make sure you don't interrupt the loading process and impact your app's performance. Do not wait for an update check before rendering the app as it will harm your user experience and reflect on your [core web vitals](/web-vitals). If you need to update part of your app frequently, use the [stale while revalidate](/learn/pwa/serving/#stale-while-revalidate) caching strategy.
{% endAside %}

### Live updates

You can also choose whether to apply an update when the app is open (live) or closed. With the app closed approach, even though the app has downloaded new assets, it won't make any changes and will use the new versions on the next load.

A live update means as soon as the asset is updated in the cache, your PWA replaces the asset in the current load. It is a complex task not covered in this course. Some tools that help to implement this update are [livereload-js](https://www.npmjs.com/package/livereload-js) and CSS asset update [CSSStyleSheet.replace() API](https://developer.mozilla.org/docs/Web/API/CSSStyleSheet/replace).

## Updating the service worker

The browser triggers an update algorithm when your service worker or its dependencies change. The browser detects updates using a byte-by-byte comparison between the cached files and the resources coming from the network.

Then the browser tries to install the new version of the service worker, and the new service worker will be in the *waiting* state, as described in the [Service workers chapter](/learn/pwa/service-workers/#updating-a-service-worker). The new installation will run the `install` event for the new service worker. If you are caching assets in that event handler, assets will also be re-cached.

{% Aside 'caution' %}
If you delete or rename your service worker file, the browser won't remove the previously registered service worker from its clients. To completely remove a service worker, you need to use the [getRegistrations()](https://developer.mozilla.org/docs/Web/API/ServiceWorkerContainer/getRegistrations) and the [unregister()](https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration/unregister) methods.
{% endAside %}


{% Aside %}
Installing a new service worker version doesn't automatically remove previously cached assets. You should explicitly delete assets you no longer need.
{% endAside %}

### Detecting service worker changes

To detect that a new service worker is ready and installed, we use the `updatefound` event from the service worker registration. This event is fired when the new service worker starts installing. We need to wait for its state to change to `installed` with the `statechange` event; see the following:

```js
async function detectSWUpdate() {
  const registration = await navigator.serviceWorker.ready;

  registration.addEventListener("updatefound", event => {
    const newSW = registration.installing;
    newSW.addEventListener("statechange", event => {
      if (newSW.state == "installed") {
         // New service worker is installed, but waiting activation
      }
    });
  })
}
```

### Force override

The new service worker will be installed but waiting for activation by default. The wait prevents the new service worker from taking over old clients that might not be compatible with the new version.

Even though it is not recommended, the new service worker can skip that waiting period and start the activation immediately.

{% Aside 'caution' %}
`skipWaiting()` means that your new service worker is probably controlling pages that were loaded with an older version. This means some of your page's fetches will have been handled by your old service worker, but your new service worker will be handling subsequent fetches. If this might prevent your app from working, don't use `skipWaiting()`.
This warning comes from [service worker lifecycle](/service-worker-lifecycle/). Check out the article for more best practice advice.
{% endAside %}

```js
self.addEventListener("install", event => {
   // forces a service worker to activate immediately
   self.skipWaiting();
  });

self.addEventListener("activate", event => {
  // when this SW becomes activated, we claim all the opened clients
  // they can be standalone PWA windows or browser tabs
  event.waitUntil(clients.claim());
});
```

The `controllerchange` event fires when the service worker controlling the current page changes. For example, a new worker has skipped waiting and become the new active worker.

```js
navigator.serviceWorker.addEventListener("controllerchange", event => {
   // The service worker controller has changed
 });
```

## Updating metadata

You can also update your app's metadata, which is mainly set in the [web app manifest](/learn/pwa/web-app-manifest). For example, update its icon, name, or start URL, or you can add a new feature such as [app shortcuts](/app-shortcuts/).
But what happens with all the users who have already installed the app with the old icon on their devices? How and when do they get the updated version?

The answer depends on the platform. Let's cover the options available.

{% Aside 'gotchas' %}
The `id` property uniquely identifies your PWA; changing `id` means your PWA will be considered a completely new PWA. To avoid unexpected behavior, before you set or change the `id` property, read [Uniquely identifying PWAs with the web app manifest id property](https://developer.chrome.com/blog/pwa-manifest-id/).
{% endAside %}

### Safari on iOS, iPadOS, and Android browsers

On these platforms, the only way to get the new manifest metadata is to re-install the app from the browser.

{% Aside %}
If you modify your `start_url` the browser may install the app as a completely new app. However, it has been a common practice to add a manual version identifier within the `start_url` property, such as `/?version=3` to identify the version. From Chrome 96 [you can add an `id` into the manifest](​​https://developer.chrome.com/blog/pwa-manifest-id/) to identify your app.
{% endAside %}

### Google Chrome on Android with WebAPK

When the user has installed your PWA on Android using Google Chrome with [WebAPK](/learn/pwa/installation/#webapks) activated (most of the Chrome PWA installations), the update will be detected and applied based on an algorithm. Check out  the details in this [manifest updates](/manifest-updates/) article.

Some additional notes about the process:

If the user doesn't open your PWA, its WebAPK won't be updated.
If the server doesn't respond with the manifest file (there is a 404 error), Chrome won't check for updates for a minimum of 30 days, even if the user opens the PWA.

Go to `about:webapks` in Chrome on Android to see the status of the "needing update" flag, and request an update. In the [Tools and debug chapter](/learn/pwa/tools-and-debug), you can read more about this debugging tool.


### Samsung Internet on Android with WebAPK

The process is similar to the Chrome version. In this case, if the PWA manifest requires an update, during the next 24 hours the WebAPK will be updated on Wi-Fi after [minting the updated WebAPK](/learn/pwa/installation/#webapks).

### Google Chrome and Microsoft Edge on desktop

On desktop devices, when the PWA is launched, the browser determines the last time it checked the local manifest for changes. If the manifest hasn't been reviewed since the browser last started or hasn't been checked in the last 24 hours, the browser will make a network request for the manifest and then compare it against the local copy.

When [selected properties](/manifest-updates/#cr-desktop-trigger) are updated, it will trigger an update after all windows have been closed.

## Alerting the user

Some updating strategies need a reload or a new navigation from the clients. You'll want to let the user know there is an update waiting but give them the chance to update the page when it is best for them.

To inform the user, there are these options:

* Use the DOM or [canvas API](https://developer.mozilla.org/docs/Web/API/Canvas_API) to render a notice on the screen.
* Use the [Web Notifications API](https://developer.mozilla.org/docs/Web/API/notification). This API is part of the push permission to generate a notification in the operating system. You will need to request web push permission to use it, even if you don't use the push messaging protocol from your server. This is the only option we have if the PWA is not opened.
* Use the [Badging API](/badging-api/) to show that updates are available in the PWA's installed icon

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/s20eK3XJWqdxYvH4HwZV.png", alt="An update notification shown in the DOM.", width="800", height="821" %}.


### More about the Badging API

The [Badging API](/badging-api/) lets you mark your PWA's icon with a badge number, or a badge dot on compatible browsers. A badge dot is a tiny mark within the installed icon that expresses something is waiting inside the app.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/yicjcQZkdbS2sj732BEp.webp", alt="Example of Twitter with eight notifications and another app showing a flag type badge.", width="800", height="252" %}

You need to call `setAppBadge(count)` on the `navigator` object to set a badge number. You can do this from the window or service worker's context when you know there is an update to alert the user.

```js
let unreadCount = 125;
navigator.setAppBadge(unreadCount);
```
To clear the badge, you call `clearAppBadge()` on the same object:

```js
navigator.clearAppBadge();
```

{% Aside %}
The Badging API works on a best-effort mechanism; the browser will do its best to match your request, but sometimes the browser will revert to a different approach. For example, a badge number is not available on some Android devices, so a dot badge is used, no matter the number you specify.
{% endAside %}

##  Resources

- [Service Worker Lifecycle](/service-worker-lifecycle/)
- [How Chrome handles updates to the web app manifest](/manifest-updates/)
- [Synchronize and update a PWA in the Background](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/background-syncs)
- [Richer offline experiences with the Periodic Background Sync API](/periodic-background-sync/)
- [Push API](https://developer.mozilla.org/docs/Web/API/Push_API)
- [Push notifications overview](/push-notifications-overview/)
- [Badging for app icons](/badging-api/)
- [Workbox 4: Implementing refresh-to-update-version flow using the workbox-window module](https://medium.com/google-developer-experts/workbox-4-implementing-refresh-to-update-version-flow-using-the-workbox-window-module-41284967e79c)

# Web app manifest

The web app manifest is a file you create that tells the browser how you want your web content to display as an app in the operating system. The manifest can include basic information such as the app's name, icon, and theme color; advanced preferences, such as desired orientation and app shortcuts; and catalog metadata, such as screenshots.

{% Aside 'warning' %}
A web app manifest is a required [installability criteria](/learn/pwa/installation/#installation-criteria) in every browser. Your PWA will not install without it.
{% endAside %}

Each PWA should include a single manifest per application, typically hosted in the root folder, and linked on all HTML pages your PWA can be installed from. Its official extension is `.webmanifest`, so you could name your manifest something like `app.webmanifest`.

{% Aside %}
While the recommended extension is `.webmanifest`, any filename will work as long as it's delivered with the `application/manifest+json` content type or another JSON-valid content type, such as `text/json`. As such, many PWAs, particularly older ones, use `manifest.json` instead.
{% endAside %}

## Adding a web app manifest to your PWA

To create a web app manifest, first make a text file with a JSON object that contains at least a `name` field with a string value:
{% Label %}app.webmanifest:{% endLabel %}

```json
{
   "name": "My First Application"
}
```

But creating the file is not enough, the browser needs to know it exists, too.

### Linking to your manifest

To make the browser aware of your web app manifest, you need to link it to your PWA using a `<link>` HTML element and the `rel` attribute set to `manifest` on all of your PWA's HTML pages. This is similar to how you link a CSS stylesheet to a document.

{% Label %}index.html:{% endLabel %}

```html/3
<html lang="en">
  <title>This is my first PWA</title>
  <link rel="manifest" href="/app.webmanifest">
```

{% Aside 'caution' %}
If your PWA includes multiple HTML pages, make sure to link its manifest to all of them.
{% endAside %}

### Debugging the manifest

To ensure the manifest is set up correctly, you can use Inspector in Firefox and DevTools in every Chromium-based browser.

{% Aside 'gotchas' %}
If you see a message saying that the browser detected no manifest and you've included a `<link>` to it correctly, check to make sure you can load the manifest in the browser and that its content type is correctly set. You can also try renaming it to `manifest.json`.
{% endAside %}


### For Chromium browsers

In DevTools

1. In the left pane, under **Application**, select **Manifest**.
1. Check the fields of the manifest as parsed by the browser.

### For Firefox

1. Open the Inspector.
1. Go to the Application tab.
1. Select the Manifest option in the left panel.
1. Check the fields of the manifest as parsed by the browser.

{% Aside 'caution' %}
It's not possible to debug web app manifests in Safari, the only option you have to see if it's working is to try to install your PWA on iOS or iPadOS.
{% endAside %}

## Designing your PWA experience

With your PWA now connected to its manifest, it's time to fill out the rest of the fields to define the experience for your users.

{% Aside 'warning' %}
Before the web app manifest spec was defined, several browsers, including Safari on iOS/iPadOS and Chrome on Android, supported custom `<meta>` elements to describe the application experience, such as `apple-mobile-web-app-capable`. Do not use these `<meta>` elements today; it's no longer recommended, and may harm the installation experience when the browser can't load the manifest properly; the experience you get as a fallback may be different and unexpected.
{% endAside %}

### Basic fields

The first set of fields represents the core information about your PWA. They are used to build the installed PWA's icon and window and determine how it starts up. They are:

`name`
: Full name of your PWA. It will appear along with the icon in the operating system's home screen, launcher, dock, or menu.

`short_name`
: Optional, a shorter name of your PWA, used when there is not enough room to display the full value of the `name` field. Keep it under 12 characters to minimize the possibility of truncation.

`icons`
: Array of icon objects with `src`, `type`, `sizes`, and optional `purpose` fields, describing what images should represent the PWA.

`start_url`
: The URL the PWA should load when the user starts it from the installed icon. An absolute path is recommended, so if your PWA's home page is the root of your site, you could set this to ‘/' to open it when your app starts. If you don't provide a start URL, the browser can use the URL the PWA was installed from as a start. It can be a deep link, such as the details of a product instead of your home screen.

`display`
: One of `fullscreen`, `standalone`,  `minimal-ui`, or `browser`, describing how the OS should draw the PWA window. You can read more about the different display modes in the [App Design chapter](/learn/pwa/app-design/#display-modes). [Most](https://almanac.httparchive.org/en/2021/pwa#top-manifest-display-values) use cases implement `standalone`.

`id`
: A string that uniquely identifies this PWA against others that may be hosted on the same origin. If it's not set, the `start_url` will be used as a fallback value. Keep in mind that by changing the `start_url` in the future (such as when changing a query string value) you may be removing the browser's ability to detect that a PWA is already installed.

{% Aside 'caution' %}
If you published a PWA before September 2021 read about the best practice for adding an `id` property now in [Uniquely identifying PWAs with the web app manifest id property](https://developer.chrome.com/blog/pwa-manifest-id/).
{% endAside %}

{% Aside 'caution' %}
Some manifest fields are not supported by every browser. When a browser doesn't support a field, it's just ignored and your manifest is still valid. You can learn more about each field at [Web App Manifests](https://developer.mozilla.org/docs/Web/Manifest).
{% endAside %}

#### Icons

Your PWA's icon is its visual identity across your users' devices when installed, so it's important to define at least one. Because the `icons` property is a collection of icon objects, you can define several icons in different formats to provide the best icon experience for your users. Each browser will pick one or more icons based on its needs and the operating system it's installed on, the icons closer to the specifications needed.

{% Aside 'caution' %}
While PNGs can include transparency, providing transparent icons may cause unexpected issues on some operating systems. For example, iOS, iPadOS, and Android 8 and later fill in the transparency with a background color out of your control. For better compatibility, use a square non-transparent icon.
{% endAside %}

If you need to pick only one icon size, it should be 512 by 512 pixels. However, providing more sizes is recommended including 192 by 192, 384 by 384, and 1024 by 1024 pixel-sized images, too.

```json
"icons": [
   {
      "src": "icons/512.png",
      "type": "image/png",
      "sizes": "512x512"
   },
   {
      "src": "icons/1024.png",
      "type": "image/png",
      "sizes": "1024x1024"
   }
]
```

{% Aside 'caution' %}
Some resources will suggest you add more icon sizes for Android, such as 48 by 48, 72 by 72, 96 by 96, 144 by 144, 168 by 168, 256 by 256. While you can add as many sizes as you want, these are no longer necessary as they are Android icon sizes for legacy devices; even if you still have some users expecting those resolutions, the browser will resize one of your shipped icons.
{% endAside %}

If you don't provide an icon or the icons are not in the recommended sizes, on some platforms you won't pass [installation criteria](/learn/pwa/installation#installation-criteria). On other platforms, the icon will be automatically generated, for instance from a screenshot of the PWA or by using a generic icon.

##### Maskable icons

Some operating systems, such as Android, adapt icons to different sizes and shapes. For example, on Android 12, different manufacturers or settings can change the shape of icons from circles to squares to rounded-corner squares. To support these kinds of adaptive icons, you can provide a maskable icon using the `purpose` field.

To do so, provide a square image file that has its main icon contained within a “safe zone”, a circle centered in the icon with a radius of 40 percent of the width of the icon. (See the image below.) Devices that support maskable icons will mask your icon as needed.


{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/TcH5a39fkg9wYN34V4Qg.png", alt="The safe area marked as a 40 percent radius centered circle within the square icon", width="800", height="533" %}


{% Aside 'caution' %}
If you don't provide a maskable icon, devices that expect them may shrink your icon and make it into the shape they need with a white background.
{% endAside %}

Here's an example of a maskable icon rendered in a number of commonly used shapes:

In the following image, if you use the icon at the left as a maskable icon, you will end up with poor results on devices when a shape mask is applied.


{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/kKuLmXu1wuztin157EeD.png", alt="An icon that is not suitable for a maskable icon.", width="800", height="533" %}

This image could be made usable with more padding.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/KVcK8eRlJBlvlfOt3BbG.png", alt="The icon with more padding is suitable for masks.", width="800", height="533" %}

Maskable icons should be 512 by 512 at least. With one created, you can add it to your `icons` collection to improve the experience for supported devices:

```json/13
"icons": [
   {
      "src": "/icons/512.png",
      "type": "image/png",
      "sizes": "512x512"
   },
   {
      "src": "/icons/1024.png",
      "type": "image/png",
      "sizes": "1024x1024"
   },
   {
      "src": "/icons/512-maskable.png",
      "type": "image/png",
      "sizes": "512x512",
      "purpose": "maskable"
   },
]
```
In most cases, if your maskable icon isn't displaying well, you can improve it by adding more padding. [Maskable.app](https://maskable.app) is a free online tool to test and create a maskable version of your icon.

### Recommended fields

The next set of fields to include are ones that will improve your user's experience, even though they're not required for installability.

`theme_color`
: Default color for the application, sometimes affecting how the OS displays the site (for instance, the window and title bar color on desktop, or the status bar color on mobile devices). This color can be overridden by the HTML `theme-color` `<meta>` element.

`background_color`
: Placeholder color to display in the application's background before its stylesheet is loaded. Safari on iOS and iPadOS and most desktop browsers currently ignore this field.

`scope`
: Changes the navigation scope of the PWA, allowing you to define what is and isn't displayed within the installed app's window. For example, if you link to a page outside of the scope, it will be rendered in an in-app browser instead of within your PWA window. This will not, however, change the scope of your service worker.

The next image shows how the `theme_color` field is used for the title bar on a desktop device when you install a PWA.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/KWRGFZ2yIb0KNSGG3fI0.png", alt="The same PWA installed on desktop with a different theme color.", width="800", height="533" %}

{% Aside %}
If you want to provide different theme colors for dark and light modes, you can override the manifest's value with a meta tag in the HTML using a media query, such as with `<meta name="theme-color" content="red" media="(prefers-color-scheme: dark)">`
{% endAside %}

When defining colors in the manifest, such as within `theme_color` and `background_color`, you should use CSS named colors, such as `salmon` or `orange`, RGB colors such as `#FF5500`, or color functions without transparency such as `rgb()` or `hsl()`. Check the [App design chapter](/learn/pwa/app-design/#theming-your-app) for more information.

{% Aside 'warning' %}
Do not use transparency, CSS variables, gradient functions, or color functions with transparency (such as `rgba()`) as they are not supported by most browsers. You will get inconsistent results.
{% endAside %}

#### Try it

{% Glitch 'learn-pwa-web-app-manifest' %}

#### Splash screens

On some devices, a static image is rendered while your PWA is being loaded to provide immediate feedback to the user.

Android uses the `theme_color`, `background_color`, and `icon` values to generate the splash screen.

When you install a PWA on Android, the device will generate a splash screen with the information that comes from your manifest as seen in the following diagram.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/uO7fu1MHNzfipVZnbS7H.png", alt="A PWA on Android splash screen taking different values from the manifest.", width="800", height="533" %}

Safari on iOS and iPadOS, on the other hand, doesn't use the web app manifest to generate splash screens. Instead, they use an image linked from a proprietary `<link>` element similar to how they handle icons. Check the [Enhancement chapter](/learn/pwa/enhancements) for more details.

### Extended fields

The next set of fields offers additional information about your PWA. They are all optional.

`lang`
: A language tag specifying the primary language of the manifest's values, such as `en` for English, `pt-BR` for Brazilian Portuguese, or `in` for Hindi.

`dir`
: The direction to display direction-capable manifest fields (such as `name`, `short_name`, and `description`). Valid values are `auto`, `ltr` (left-to-right), and `rtl` (right-to-left).

`orientation`
: Desired orientation for the app once installed. A game may set this to request a landscape-only orientation. [Several values](https://developer.mozilla.org/docs/Web/Manifest/orientation#values) are accepted, but if included it's typically `portrait` or `landscape` explicitly.

{% Aside %}
The Web Application Manifest spec doesn't allow internationalization within the file to localize fields' values and images. To support multilingual PWAs with different web app manifest values you need to implement a custom solution to change those values per language. Watch [5 tips for your PWA](https://www.youtube.com/watch?v=baSiSIyTGSk&ab_channel=GoogleChromeDevelopers) for more ideas.
{% endAside %}

### Promotional fields

The fourth set of fields lets you provide promotional information about your PWA, for instance, in install flows, listings, and search results.

`description`
: An explanation of what the PWA does.

`screenshots`
: Array of screenshot objects with `src`, `type`, and `sizes` (similar to the `icons` object) intended to showcase the PWA. There are no size restrictions.

`categories`
: Array of categories the PWA should belong to be used as hints for listings, optionally from the list of [known categories](https://www.w3.org/TR/manifest-app-info/#categories-member)]. These values are typically lowercase.

`iarc_rating_id`
: The International Age Rating Coalition certification code for the PWA, if you have one. It is intended to be used to determine which ages your PWA is appropriate for.

{% Aside 'caution' %}
Promotional fields have been moved to their own spec: [Web App Manifest - Application Information](https://www.w3.org/TR/manifest-app-info/). Check that spec for the latest additions to these fields.
{% endAside %}

You can see these promotional fields in action today. On Android, for example, if your PWA is installable and you provide values for at least the `description` and `screenshots` fields, the installation dialog experience transforms from a simple "Add to the home screen" info bar, to a richer installation dialog similar to the one from an app store.

On Android, you can get a nicer installation UI if you provide values for the promotional fields, as you can see in the next video

{% Video src="video/RK2djpBgopg9kzCyJbUSjhEGmnw1/eU7EiYjZKtVsBrQ3xfBz.mp4" %}

See these promotional fields in action:

{% Glitch 'learn-pwa-web-app-manifest-promotional' %}


### Capabilities Fields

Finally, there are a number of fields related to different capabilities that your PWA can use in supported browsers, such as the `shortcuts`, `share_target`, `display_overrides` fields as we cover in the [Capabilities chapter](/learn/pwa/capabilities). There are also fields, like `related_apps` and `prefer_related_apps` (see the [Detection chapter](/learn/pwa/detection) for more information), to connect your PWA to installed apps, often from an app store.

Many new fields may appear in the future while browsers add more capabilities to Progressive Web Apps.

##  Resources

- [Add a Web App Manifest](/add-manifest/)
- [Adaptive icon support in PWAs with maskable icons](/maskable-icon/)
- [Richer PWA installation UI](https://developer.chrome.com/blog/richer-pwa-installation/)
- [MDN: Web App Manifest](https://developer.mozilla.org/docs/Web/Manifest)

# Window management

Running on your own window, managed by your PWA, has all the advantages and responsibilities of any window in that operating system, such as:

* The ability to resize and move the window around on multi-window operating systems, like Windows or ChromeOS.
* Sharing the screen with other app windows, as in iPadOS split mode or Android split-screen mode.
* Appearing in docks, taskbars, and in the alt-tab menu on desktop, and multi-task window lists on mobile devices.
* The ability to minimize, move the window across screens and desktops, and close it at any time.

### Moving and resizing the window

Your PWA window can be of any size and positioned anywhere on the screen on desktop operating systems. By default, when the user opens the PWA for the first time after installation, the PWA gets a default window size of a percentage of the current screen, with a maximum resolution of 1920x1080 positioned at the top-left corner of the screen.

The user can move and resize the window, and the browser will remember the last preference, so the next time the user opens the app, the window will retain the size and position from the previous usage.

There is no way to define your PWA's preferred size and position within the manifest. You can only reposition and resize the window using the JavaScript API. From your code, you can move and resize your own PWA window using the [`moveTo(x, y)`](https://developer.mozilla.org/docs/Web/API/Window/moveTo) and [`resizeTo(x, y)`](https://developer.mozilla.org/docs/Web/API/Window/resizeTo) functions of the `window` object.

For example, you can resize and move your PWA window when the PWA loads using:

```js
document.addEventListener("DOMContentLoaded", event => {
   // we can move only if we are not in a browser's tab
   isBrowser = matchMedia("(display-mode: browser)").matches;
   if (!isBrowser) {
      window.moveTo(16, 16);
      window.resizeTo(800, 600);
   }
});
```

You can query the current screen size and position using the `window.screen` object; you can detect when the window is resized using the `resize` event from the `window` object. There is no event for capturing the window move, so your option is to query the position frequently.

{% Aside %}
Instead of moving and resizing the window absolutely, you can move relatively and resize using `moveBy()` and `resizeBy()`.
{% endAside %}


{% Aside %}
On mobile devices, moving or resizing your window won't make any changes on the screen.
{% endAside %}

### Browsing to other sites
If you want to send the user to an external site that is out of the scope of your PWA, you can do so with a standard `<a href>` HTML element, using `location.href` or opening a new window on compatible platforms.

Currently on all browsers, if your PWA is installed, when you browse to a URL that is out of the [scope of your manifest](/learn/pwa/web-app-manifest/#recommended-fields), the browser engine of your PWA will render an in-app browser within the context of your window.

Some features of the in-app browsers are:

* They appear on top of your content.
* They have a static URL bar showing the current origin, the window's title, and a menu. Typically, they're themed with the `theme_color` of your manifest.
* From the contextual menu, you can open that URL in the browser.
* Users can close the browser or go back.

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/0SsThiNz4GDkJy6OiTHj.png", alt="An in-app browser on a desktop PWA when browsing a URL that is out-of-scope.", width="800", height="497" %}

{% Aside %}
While the in-app browser is on the screen, your PWA is waiting in the background, as if another window is obscuring it.
{% endAside %}

{% Aside 'gotchas' %}
On iOS and iPadOS, the in-app browser uses SafariViewController, a Safari-rendering engine isolated from your PWA storage. Therefore, if the user has a session in Safari, it won't appear in your PWA, but it will appear within an in-app browser in your PWA.
{% endAside %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/Gr4qJUx6hAFMyPLPyfQY.png", alt="An in-app browser on an iPhone when browsing a URL that is out-of-scope within a standalone PWA.", width="800", height="370" %}

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/UyohW4R5Sy79ffHri8cz.png", alt="An in-app browser on Android when browsing a URL that is out-of-scope within a standalone PWA.", width="800", height="1644" %}


#### Authorization flows

Many web authentication and authorization flows involve redirecting the user to a different URL in a different origin to acquire a token that will return to your PWA's origin, such as using [OAuth 2.0](https://oauth.net/2/).

In these cases, the in-app browser follows the following process:

1. The user opens your PWA and clicks login.
1. Your PWA redirects the user to a URL that is out of the scope of the PWA so that the rendering engine will open an in-app browser within your PWA.
1. The user can cancel the in-app browser and go back to your PWA at any time.
1. The user logs into the in-app browser. The authentication server redirects the user to your PWA origin, sending the token as an argument.
1. The in-app browser closes itself when it detects a URL that is part of the scope of the PWA.
1. The engine redirects the main PWA window navigation to the URL that the authentication server went to while in the in-app browser.
1. Your PWA gets the token, stores the token, and renders the PWA.

#### Forcing a browser's navigation

If you want to force open the browser with a URL and not an in-app browser, you can use the `_blank` target of `<a href>` elements. This works only on desktop PWAs; on mobile devices, there is no option to open a browser with a URL.

```js
function openBrowser(url) {
	window.open("url", "_blank", "");
}
```

### Opening new windows

On desktop, users can open more than one window of the same PWA. Each window will be a different navigation to the same `start_url`, as if you were opening two browser tabs of the same URL.
From the menu in the PWA, users can select File then New window, and from your PWA code, you can open a new window with the `open()` function. Check the [documentation](https://developer.mozilla.org/docs/Web/API/Window/open) for details.

```js
function openNewWindow() {
	window.open("/", "new-window", "width=600,height=600");
}
```
{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/CURym4RD66CqcTw4iPl5.png", alt="The same installed PWA with several windows opened on a desktop operating system.", width="800", height="580" %}

Calling `open()` within a PWA window on iOS or iPadOS returns `null` and doesn't open a window. Opening new windows on Android creates a new in-app browser for the URL—even if the URL is within the scope of your PWA—that typically doesn't trigger an external browsing experience.

{% Aside 'warning' %}
The second argument of `open()` is the window's name. If the name you used is already opened, the engine will replace the opened window with that name with a new navigation. If you always want to open a new window, you must use different string values for a name.
{% endAside %}


{% Glitch 'mlearn-pwa-windows-basic' %}


{% Aside 'gotchas' %}
The functions `open()`, `moveTo()`, and `resizeTo()` don't need the `window.` prefix when writing JavaScript because `window` is the global object. You can just call `moveTo(0, 0)`. However, calling `window.moveTo(0, 0)` makes the code easier to understand.
{% endAside %}

### Window title

The `<title>` element was primarily used for SEO purposes as the space within a browser tab is limited. When you move from the browser to your window in a PWA, all the title bar space is available to you.

You can define the contents of the title bar:

* Statically in your HTML `<title>` element.
* Dynamically changing the `document.title` string property at any time.

On desktop PWAs, the title is essential, and it's used in the title bar of the window and sometimes in the task manager or multi-task selection. If you have a single-page application, you may want to update your title on every route.

{% Aside %}
To reduce phishing within PWAs, some desktop browsers may have additional measures on the window's title. For example, if you don't use your app's name in the title, the browser may add a prefix with your PWA's name on it. Other browsers may render the current origin in the title bar for a few seconds when you change the title to highlight where the user navigated.
{% endAside %}

### Tabbed mode

An experimental capability, known as *tabbed mode*​ will let your PWA have a tab-based design similar to a web browser. In this case, the user can have several tabs opened from the same PWA but all tied together in the same operating system window, as you can see in the following video:

{% Video src="video/W3z1f5ZkBJSgL1V1IfloTIctbIF3/b1SL9QwJcgRXrVDeLKmK.mp4",
loop="true",
muted="true",
playsinline="true",
controls="true",
poster="image/W3z1f5ZkBJSgL1V1IfloTIctbIF3/emg7quu4DyvYwlyzgDE1.png"
%}

You can read more about this experimental capability at [Tabbed application mode for PWA](/tabbed-application-mode/).

{% Aside %}
In the [Experimental chapter](/learn/pwa/experimental), you will see how you can start using experimental capabilities.
{% endAside %}

### Window controls overlay

We've mentioned that you can change the window's title by defining the value of the `<title>` element or the `document.title` property. But it's always a string value. What if we could design the title bar as we wish, with HTML, CSS, and images?
That's where Window Controls Overlay comes in, a new experimental capability in Microsoft Edge and Google Chrome for desktop PWAs.

{% Aside %}
Tabbed mode and window controls overlay capabilities define new values for the manifest's `display` member. To create compatibility with all devices, the manifest group has created a way to replace the [fallback `display` chain](/learn/pwa/app-design/#display-modes), so you can specify what `display` value to use if your first option is not available. Read more about it at [Preparing for the display modes of tomorrow](/display-override/).
{% endAside %}

You can read more about this capability at [Customize the window controls overlay of your PWA's title bar](/window-controls-overlay/).

{% Img src="image/kheDArv5csY6rvQUJDbWRscckLr1/B5UDAJzKTqCRdSy6B5is.png", alt="With window controls overlay, you can render content in the title bar.", width="800", height="544" %}

## Multi-screen window placement

With multiple screens, users will want to use all the space available to them. Users may:

* Open a presentation on an external monitor.
* Restore an opened window's position on the screen.
* Favor screens that support touch.

The [Multi-Screen Window Placement API](/multi-screen-window-placement/) allows PWAs to do just that and more.

### Getting screen details

The Multi-Screen Window Placement API adds a new method, `window.getScreenDetails()`, that returns an object with screens as an immutable array of attached screens. There's also a live object accessible from `ScreenDetails.currentScreen`, corresponding to the current `window.screen`.

{% Aside 'gotchas' %}
On some browsers, calling `window.getScreenDetails()` requires the user to grant permission to your PWAs.
{% endAside %}

The returned object also fires a [`screenschange` event](/multi-screen-window-placement/#the-screenschange-event) when the `screens` array changes. (This does not happen when attributes on individual screens are changed.) Individual screens, either `window.screen` or a screen in the `screens` array, also fire a `change` event when their attributes change.

```js
// Request an object with a screen objects
const screenDetails = await window.getScreenDetails();
screenDetails.screens[0].isPrimary;  // e.g. true
screenDetails.screens[0].isInternal;  // e.g. true
screenDetails.screens[0].pointerTypes;  // e.g. ["touch"]
screenDetails.screens[0].label;  // e.g. 'Samsung Electric Company 28"'

// Access the live object corresponding to the current `window.screen`.
// The object is updated on cross-screen window placements or device changes.
screenDetails.currentScreen;
screenDetails.addEventListener('screenschange', function() {
 // NOTE: Does not fire on changes to attributes of individual screens.
  const screenCount = screenDetails.screens.length;
  const currentScreen screenDetails.currentScreen.id;
});
```

If the user or the operating system moves your PWA's window from one screen to another, a [`currentscreenchange` event](/multi-screen-window-placement/#the-currentscreenchange-event) will also be fired from the screen details object.

{% Aside %}
You may also want to check the [Presentation API](https://developer.mozilla.org/docs/Web/API/Presentation_API) to display web content through large presentation devices such as projectors and network-connected televisions.
{% BrowserCompat 'api.Presentation' %}
{% endAside %}

{% Glitch 'mlearn-pwa-windows-screens' %}


## Screen wake lock

Imagine this: you're in the kitchen following a recipe on your tablet. You've just finished prepping your ingredients. Your hands are a mess, and you turn back to your device to read the next step. Disaster! The screen's gone black! The [Screen Wake Lock API](https://developer.mozilla.org/docs/Web/API/Screen_Wake_Lock_API) is here for you and lets a PWA prevent screens from dimming, sleeping, or locking, allowing users to stop, start, leave, and return without worry.

```js
// Request a screen wake lock
const wakeLock = await navigator.wakeLock.request();

// Listen for wake lock release
wakeLock.addEventListener('release', () => {
 console.log(`Screen Wake Lock released: ${wakeLock.released}`);
});
// Manually release the wake lock
wakeLock.release();
```

## Virtual keyboard

Touch-based devices, such as phones and tablets, offer a virtual on-screen keyboard so the user can type when form elements of your PWA are in focus.

Thanks to the [VirtualKeyboard API](/virtualkeyboard/), your PWA can now have more control of the keyboard on compatible platforms using the `navigator.virtualKeyboard` interface, including:

* Showing and hiding the virtual keyboard with the functions `navigator.virtualKeyboard.show()` and `navigator.virtualKeyboard.hide()`.
* Telling the browser that you are taking care of closing the virtual keyboard yourself by setting `navigator.virtualKeyboard.overlaysContent` equal to `true`.
* Knowing when the keyboard appears and disappears with the event `geometrychange` of `navigator.virtualKeyboard`.
* Setting the virtual keyboard policy on editing host elements (using `contenteditable`) with the `virtualkeyboardpolicy` HTML attribute. A policy lets you decide if you want the virtual keyboard to be handled automatically by the browser using the `auto` value, or handled by your script using the `manual` value.
* Using CSS environmental variables for getting information about the virtual keyboard appearance, such as `keyboard-inset-height` and `keyboard-inset-top`.

You can read more about this API on [Full control with the VirtualKeyboard API](/virtualkeyboard/).

##  Resources

- [Managing several displays with the Multi-Screen Window Placement API](/multi-screen-window-placement/)
- [Tabbed application mode for PWAs](/tabbed-application-mode/)
- [Stay awake with the Screen Wake Lock API](/wake-lock/)
- [Full control with the VirtualKeyboard API](/virtualkeyboard/)
- [Customize the window controls overlay of your PWA's title bar](/window-controls-overlay/)
- [Display content in the title bar](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/window-controls-overlay)

# Workbox

Maintaining your service worker and cache storage logic can be a challenge as your PWA grows. [Workbox](https://developer.chrome.com/docs/workbox/what-is-workbox/), is a set of open-source libraries to help with that. Workbox encapsulates the low-level APIs, like the Service Worker API and Cache Storage API, and exposes more developer-friendly interfaces.

Some tasks that it can help with are matching caching strategies to paths (or routing patterns), working with streams, and using features like background sync with proper fallbacks.

Workbox can help you with managing your asset caching and serving needs. It's also the most used library for service workers; used by [54% of mobile sites](https://almanac.httparchive.org/en/2022/pwa#workbox-usage) and it is used in many build tools and CLIs, including the Angular CLI, Create-React-App, and Vue CLI. There are plugins to most other libraries and frameworks, too, such as Next.js.

<div class="w-stats">
  <div class="w-stat">
    <p class="w-stat__figure">54<sub class="w-stat__sub">%</sub></p>
    <p class="w-stat__desc">Mobile sites with service workers use the Workbox library</p>
  </div>
 </div>

{% Aside %}
While Workbox is the most common set of libraries for service workers in the PWA community, there are other solutions such as [sw-tools](https://github.com/veiss-com/sw-tools) and [UpUp](https://www.talater.com/upup/)
{% endAside %}

## Workbox modules

Workbox includes several [libraries](https://developer.chrome.com/docs/workbox/modules/)&mdash;called modules internally&mdash;each focused on a different aspect of managing your assets and service worker behavior.

Workbox modules work in different contexts, such as:

- **Within a service worker context**: you import the modules you need and use them from your service worker file, for example to help manage caching and serve files with different strategies.
- **Within the main `window` context**: helping to register a service worker and communicating with it
- **As part of a build system**: for example, webpack, for purposes such as creating a manifest of your assets, or even generating your entire service worker.

Some popular modules are:

- [workbox-routing](https://developer.chrome.com/docs/workbox/modules/workbox-routing/): When the service worker intercepts requests this module routes those requests to different functions that provide responses; it's an implementation of the `fetch` event handler as mentioned in the [Serving chapter](/learn/pwa/serving).
- [workbox-strategies](https://developer.chrome.com/docs/workbox/modules/workbox-strategies/): A set of runtime caching strategies that handle responding to a request, such as cache first and stale while revalidate; it's an implementation of the different strategies mentioned in the [Serving chapter](/learn/pwa/serving).
- [workbox-precaching](https://developer.chrome.com/docs/workbox/modules/workbox-precaching/): It's an implementation of caching files in the `install` event handler of the service worker (also known as precaching), as mentioned in the [Caching chapter](/learn/pwa/caching). With this module you can easily precache a set of files and efficiently manage updates to those assets. We'll cover updating assets in the [Update chapter](/learn/pwa/update).
- [workbox-expiration](https://developer.chrome.com/docs/workbox/modules/workbox-expiration/): It is a plugin used with the caching strategies to remove cached requests based on the number of items in a cache or based on the age of the cached request. It helps manage your caches and sets limits on time and the number of items in each cache.
- [workbox-window](https://developer.chrome.com/docs/workbox/modules/workbox-window/): A set of modules intended to run in the window context, which is to say, inside of your PWA web pages. You can simplify the process of service worker registration and updates and enable easier communication between code running in the service worker context and the window context.

## Using Workbox

Workbox provides different ways to integrate into your PWA. You can choose which fits best with your app's architecture:

- [Workbox CLI](https://developer.chrome.com/docs/workbox/modules/workbox-cli/): A command-line utility that generates a complete service worker, injects a precache manifest, or copies needed Workbox files.
- [Workbox Build](https://developer.chrome.com/docs/workbox/modules/workbox-build/): An npm module that generates a complete service worker, injects a precache manifest, and copies the Workbox files. This is meant to be integrated with your own build process.
- [workbox-sw](https://developer.chrome.com/docs/workbox/modules/workbox-sw/): A way to load Workbox service worker packages from a CDN that doesn't use a build process.

Workbox CLI provides a wizard that steps you through creating your service worker. To run the wizard, type the following at a command line:

```bash
npx workbox-cli wizard
```

{% Img src="image/RK2djpBgopg9kzCyJbUSjhEGmnw1/GTRYFMjNWIGjgp3Sqzba.png", alt="Workbox CLI in action in a terminal", width="800", height="394" %}

## Caching and serving with Workbox

A common use of Workbox is using the routing and strategies modules together to cache and serve files.

The module [*workbox-strategies*](https://developer.chrome.com/docs/workbox/modules/workbox-strategies/) provides, out of the box, the caching strategies discussed in the [Assets and data](/learn/pwa/assets-and-data) and [Serving](/learn/pwa/serving) chapters.

The [*workbox-routing*](https://developer.chrome.com/docs/workbox/modules/workbox-routing/) module helps to sort incoming requests to your service worker and match them to the caching strategies or functions to get responses for those requests.

After the matching of routes to strategies, Workbox also offers the ability to filter which responses will be added to the cache with the [*workbox-cacheable-response* plugin](https://developer.chrome.com/docs/workbox/modules/workbox-cacheable-response/). With this plugin you can for example cache only responses that returned without errors.

{% Aside 'caution' %}
While Workbox is distributed as npm modules, service workers themselves don't support ES modules syntax in every browser, so it's better to compile this sample code with a bundler before deploying it.
{% endAside %}

The following code sample uses a cache first strategy (via the `CacheFirst` module) to cache and serve page navigations.

```js
import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';

const pageStrategy = new CacheFirst({
  // Put all cached files in a cache named 'pages'
  cacheName: 'pages',
  plugins: [
    // Only requests that return with a 200 status are cached
    new CacheableResponsePlugin({
      statuses: [200],
    }),
  ],
});
```

The plugin allows you to tap into Workbox's caching and request resolution lifecycle. Here, the `CacheableResponsePlugin` is used to only cache requests that result in a 200 status, preventing bad requests from being saved into the cache.

With the strategy created, it's time to register a route to use it. The following example calls `registerRoute()`, passing a Request object to its callback. If `request.mode` is `"navigate"` it uses the `CacheFirst` strategy (here called `pageStrategy`) defined in the previous code example.

```js
// Cache page navigations (HTML) with a Cache First strategy
registerRoute( ({ request }) => request.mode === 'navigate',
  pageStrategy );
```

Read the [Workbox documentation](https://developer.chrome.com/docs/workbox/) for more examples and best practices.

## Offline fallback

The _workbox-routing_ module also has an exported `setCatchHandler()`, that provides handling if a route throws an error. You can use this to set up an offline fallback to notify users that their requested route isn't currently available.

Here, a combination of Workbox and the Cache Storage API provides an offline fallback using a cache-only strategy.
First, during the service worker's install lifecycle, the `offline-fallbacks` cache is opened, and the array of offline fallbacks is added to the cache.

```js
import { setCatchHandler } from 'workbox-routing';

// Warm the cache when the service worker installs
self.addEventListener('install', event => {
  const files = ['/offline.html']; // you can add more resources here
  event.waitUntil(
    self.caches.open('offline-fallbacks')
        .then(cache => cache.addAll(files))
  );
});
```

Then, in `setCatchHandler()`, the destination of the request that threw an error is determined, and the `offline-fallbacks` cache is opened. If the destination is a document, the content of the offline fallback is returned to the user. If that doesn't exist, or the destination isn't a document (such as an image or stylesheet), an error response is returned. You can extend this pattern not just for documents but for images, videos, fonts, really anything that you'd want to provide as an offline fallback.

```js
// Respond with the fallback if a route throws an error
setCatchHandler(async (options) => {
  const destination = options.request.destination;
  const cache = await self.caches.open('offline-fallbacks');
  if (destination === 'document') {
    return (await cache.match('/offline.html')) || Response.error();
  }
  return Response.error();
});
```

## Recipes

Several routing and caching patterns, like `NetworkFirst` navigations and offline fallbacks, are common enough to be encapsulated into reusable recipes. Check [workbox-recipes](https://developer.chrome.com/docs/workbox/modules/workbox-recipes/) as they can help you if they provide a solution suitable for your architecture. They are usually available as one line of code that you need to add to your service worker's code.

### Caching and updating assets

Caching assets also involves updating them. Workbox helps with updating your assets in whatever way you decide is best. It could be keeping them updated if they change on the server, or waiting until you have a new version of your app.
You'll learn more about updating in the [Update chapter](/learn/pwa/update).

## Play with Workbox

You can play with Workbox right away using the following code lab:

{% Aside 'codelab' %}
[Working With Workbox](https://developers.google.com/codelabs/pwa-training/pwa03--working-with-workbox?hl=pt#).
{% endAside %}

## Resources

- [Get Started with Workbox](https://developer.chrome.com/docs/workbox/)
- [Workbox Modules](https://developer.chrome.com/docs/workbox/modules/)
- [The ways of Workbox](https://developer.chrome.com/docs/workbox/the-ways-of-workbox/)