Tag: HTML

What’s the Difference Between Width/Height in CSS and Width/Height HTML attributes?

Some HTML elements accept width and height as attributes. Some do not. For example:

<!-- valid, works, is a good idea --> <img width="500" height="400" src="..." alt="..."> <iframe width="600" height="400" src="..."></iframe> <svg width="20" height="20"></svg>  <!-- not valid, doesn't work, not a good idea --> <div width="40" height="40"></div> <span width="100" height="10"></span>

Those attributes are sometimes referred to as presentational attributes. The thing to know about them is that they are overridden by any other styling information whatsoever. That makes them ideal as a fallback.

So, if CSS loads and has a declaration like:

img {   width: 400px; }

…that is going to override the width="500" on the <img> tag above. Presentational attributes are the weakest kind of styling, so they are overridden by any CSS, even selectors with very low specificity.

What might be a smidge confusing is that presentational attributes seem like they would have high specificity. These inline styles, for instance, are very strong:

<img style="width: 500px; height: 400px;" src="..." alt="...">

Using an inline style (which works on any element, not a select few), we’ve moved from the weakest way to apply width and height to one of the strongest. Regular CSS will not override this, with a selector of any specificity strength. If we need to override them from CSS, we’ll need !important rules.

img {   width: 400px !important; }

To reiterate, presentational attributes on elements that accept them (e.g. <img>, <iframe>, <canvas>, <svg>, <video>) are a good idea. They are fallback sizing and sizing information as the page is loading. They are particularly useful on <svg>, which may size themselves enormously in an awkward way if they have a viewBox and lack width and height attributes. Browsers even do special magic with images, where the width and height are used to reserve the correct aspect-ratio derived space in a situation with fluid images, which is great for a smooth page loading experience.

But presentational attributes are also weak and are usually overridden in the CSS.

The post What’s the Difference Between Width/Height in CSS and Width/Height HTML attributes? appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,

A Web Component with Different HTML for Desktop and Mobile

Christian Schaefer has a great big write-up about dealing with web advertisements. The whole thing is interesting, first documenting all the challenges that ads present, and then presenting modern solutions to each of them.

One code snippet that caught my eye was a simple way to design a component that renders different HTML depending on the screen size.

<div class="ad">   <template class="ad__mobile">     // Mobile ad HTML code with inline script   </template>   <template class="ad__desktop">     // Desktop ad HTML code with inline script   </template>   <script>     const isMobile = matchMedia('(max-device-width: 20em)').matches;     const ad = document.currentScript.closest('.ad');     const content = ad       .querySelector(isMobile ? '.ad__mobile' : '.ad__desktop')       .content;          ad.appendChild(document.importNode(content, true));   </script> </div> 

Clever. Although note that Christian ends up going a totally different route in the article.

Here’s that same code where I use a custom element and move the JavaScript to JavaScript just ‘cuz.

See the Pen
A Web Component with Different HTML for Desktop and Mobile
by Chris Coyier (@chriscoyier)
on CodePen.

The post A Web Component with Different HTML for Desktop and Mobile appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Why do we use .html instead of .htm?

Interesting question from Andy:

The most likely answer from the thread: DOS was a massive operating system for PCs for a long time and it had a three-character limit on file extensions.

Interesting that the first book on HTML covers this specifically:

Where my mind went was server software. I know that web servers automatically do different things with different file types. In a test on my own server (set up to serve a WordPress site), I put some files at the root that all contain the exact same content: <h1>Cool</h1>

  • file.text = file is rendered as plain text in browser (Content-Type: text/plain)
  • file.html = file renders as HTML in browser (Content-Type: text/html)
  • file.htm = file renders as HTML in browser (Content-Type: text/html)
  • file.fart = file is downloaded by browser (Content-Type: application/octet-stream)

You can write code to serve files with whatever content types you want, but in lieu of that, file extensions do matter because they affect how default web servers choose to serve file type headers.

The post Why do we use .html instead of .htm? appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

The Order of CSS Classes in HTML Doesn’t Matter

That’s right! And I can prove it, too. Let’s look at some CSS first:

.a {   color: red; }  .b {   color: blue; }

And now let’s look at some markup:

<div class="a b">Here’s some text</div>

The text is going to be blue because .b is defined last in the CSS, right? But what if we go about and switch the order in which those classes are called in HTML:

<div class="b a">Here’s some text</div>

What color do you think the text should be? Red or blue?

This certainly might sound like a silly question but it tends to trip up a lot of folks who happen to be familiar with CSS-in-JS solutions. And this week I’ve spoken to two very senior front end engineers who thought similarly as well!

But the text in the example above will always be blue no matter what order those CSS classes are in. And that’s because the markup is just reading the CSS in the order that it’s written — the cascade wins in this example.

The post The Order of CSS Classes in HTML Doesn’t Matter appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Quoting in HTML: Quotations, Citations, and Blockquotes

It’s all too common to see the incorrect HTML used for quotes in markup. In this article, let’s dig into all this, looking at different situations and different HTML tags to handle those situations.

There are three major HTML elements involved in quotations:

  • <blockquote>
  • <q>
  • <cite>

Let’s take a look.

Blockquotes

Blockquote tags are used for distinguishing quoted text from the rest of the content. My tenth grade English teacher drilled it into my head that any quote of four lines or longer should be set apart this way. The HTML spec has no such requirement, but as long as the text is a quote and you want it to be set apart from the surrounding text and tags, a blockquote is the semantic choice.

By default, browsers indent blockquotes by adding margin on each side.

See the Pen
The Blockquote Tag
by Undead Institute (@undeadinstitute)
on CodePen.

As a flow element (i.e. “block level” element), blockquote can contain other elements inside it. For example, we can drop paragraphs in there with no problem:

<blockquote>   <p></p>   <p></p> </blockquote>

But it could be other elements, too, like a heading or an unordered list:

<blockquote>     <h2></h2>     <ul>       <li></li>       <li></li>     </ul> </blockquote>

It’s important to note that blockquotes should only be used for quotations rather than as a decorative element in a design. This also aids accessibility as screen reader users can jump between blockquotes. Thus a blockquote element used solely for aesthetics could really confuse those users. If you need something more decorative that falls outside the bounds of extended quotations, then perhaps a div with a class is the way to go.

blockquote, .callout-block {   /* These could share styling */ }

Quoting with Q

Q tags (<q>) are for inline quotes, or what my tenth grade teacher would say are those under four lines. Many modern browsers will automatically add quotation marks to the quote as pseudo elements but you may need a backup solution for older browsers.

See the Pen
The Q Tag
by CSS-Tricks (@css-tricks)
on CodePen.

Typical quotation marks are just as valid for inline quotes as the <q> element. The benefits of using <q>, however, are that it includes a cite attribute, automatic handling of quotation marks, and automatic handling of quote levels. <q> elements should not used for sarcasm (e.g. “you would use a <q> tag for sarcasm, wouldn’t you?”), or signifying a word with air quotes (e.g. “awesome” is an “accurate” description of the author). But if you can figure out how to mark up air quotes, please let me know. Because that would be “awesome.”

The citation attribute

Both <q> and blockquotes can use a citation (cite) attribute. This attribute holds a URL that provides context and/or a reference for the quoted material. The spec makes a point of saying that the URL can be surrounded by spaces. (I’m not sure why that’s pointed out, but if you want to anger the semantic code deities, you’ll have to do more than throw spaces around.)

<p>The officer left a note saying <q cite="https://johnrhea.com/summons">You have been summoned to appear on the 4th day of January on charges of attempted reader bribery.</q></p>

That cite attribute isn’t visible to the user by default. You could add it in with a sprinkle of CSS magic like the following demo. You could even fiddle with it further to make the citation appear on hover.

See the Pen
Attributable citations
by CSS-Tricks (@css-tricks)
on CodePen.

Neither of those options are particularly great. If you need to cite a source such that users can see it and go to it, you should do it in HTML and probably with the <cite> element, which we’ll cover next.

The citation element

The <cite> tag should be used for referencing creative work rather than the person who said or wrote the quote. In other words, it’s not for quotes. Here are the examples from the spec:

<p>My favorite book is <cite>The Reality Dysfunction</cite> by Peter F. Hamilton. My favorite comic is <cite>Pearls Before Swine</cite> by Stephan Pastis. My favorite track is <cite>Jive Samba</cite> by the Cannonball Adderley Sextet.</p>

Here’s another example:

See the Pen
Cite This!
by CSS-Tricks (@css-tricks)
on CodePen.

If the author of this article told you he’d give you a cupcake, and you <cite> him by name, that would be semantically incorrect. Thus no cupcakes would change hands. If you cited the article in which he offered you a cupcake, that would be semantically correct, but since the author wouldn’t do that, you still wouldn’t get a cupcake. Sorry.

By default, browsers italicize cite tags and there’s no requirement that a <q> or <blockquote> be present to use the cite element. If you want to cite a book or other creative work, then slap it in the cite element. The semantic deities will smile on you for not using either <i> or <em> elements.

But where to put the cite element? Inside? Outside? The upside down? If we put it inside the <blockquote> or the <q>, we’re making it part of the quote. That’s forbidden by the spec for just that reason.

<!-- This is apparently wrong --> <blockquote>   Quote about cupcake distribution from an article   <cite>The Article</cite> </blockquote>

Putting it outside just feels wrong and also requires you to have an enclosing element like a <div> if you wanted to style them together.

<div class="need-to-style-together">   <blockquote>     Quote about cupcake distribution from an article   </blockquote>   <cite>The Article</cite> </div>

N.B. If you google this issue you may come across an HTML5 Doctor article from 2013 that contradicts much of what’s laid out here. That said, every time it links to the docs for support, the docs agree with the article you’re currently reading rather than the HTML5 Doctor article. Most likely the docs have changed since that article was written.

Hey, what about the figure element?

One way to mark up a quotation — and in a way that pleases the semantic code deities — is to put the blockquote within a figure element. Then, put the cite element and any other author or citation information in a figcaption.

<figure class="quote">   <blockquote>     But web browsers aren’t like web servers. If your back-end code is getting so big that it’s starting to run noticably slowly, you can throw more computing power at it by scaling up your server. That’s not an option on the front-end where you don’t really have one run-time environment—your end users have their own run-time environment with its own constraints around computing power and network connectivity.   </blockquote>   <figcaption>     &mdash; Jeremy Keith, <cite>Mental models</cite>   </figcaption> </figure>

While this doubles the number of elements needed, there are several benefits:

  1. It’s semantically correct for all four elements.
  2. It allows you to both include and encapsulate author information beyond citing the name of the work.
  3. It gives you an easy way to style the quote without resorting to divs, spans or wretchedness.

See the Pen
It Figures You’d Say That
by CSS-Tricks (@css-tricks)
on CodePen.

None of this is for dialogue

Not <dialog>! Those are for attention-grabbing modals. Dialogue, as in, conversational exchanges between people speaking or typing to each other.

Neither <blockquote> nor <q> nor <cite> are to be used for dialogue and similar exchanges between speakers. If you’re marking up dialogue, you can use whatever makes the most sense to you. There’s no semantic way to do it. That said, the spec suggests <p> tags and punctuation with <span> or <b> tags to designate the speaker and <i> tags to mark stage directions.

Accessibility of quotes

From the research I’ve done, screen readers should not have any issue with understanding semantic-deity-approved <q>, <blockquote>, or <cite> tags.

[VIDEO]

More “ways” to “quote”

You can add quotation marks to a <blockquote> using CSS pseudo elements. The <q> element comes with quotation marks baked in so they need not be added, however adding them as pseudo-elements can be a workaround for older browsers that don’t automatically add them. Since this is how modern browsers add the quotation marks there’s no danger of adding duplicate quotes. New browsers will overwrite the default pseudo elements, and older browsers that support pseudo elements will add the quotes.

But you can’t, like I did, assume that the above will always give you smart opening and closing quotes. Even if the font supports smart quotes, sometimes straight quotes will be displayed. To be safe, it’s better to use the quotes CSS property to up the intelligence on those quotation marks.

blockquote {   quotes: "“" "”" "‘" "’"; }

See the Pen
"Quot-a-tizing" the blockquote
by CSS-Tricks (@css-tricks)
on CodePen.

Multi-level quoting

Now let’s look at quote levels. The <q> tag will automatically adjust quote levels.

Let’s say you’re in an area that uses the British convention of using single quotes. You could use the CSS quotes rule to put the opening and closing single quotes first in the list. Here’s an example of both ways:

See the Pen
Quote Within a Quote
by CSS-Tricks (@css-tricks)
on CodePen.

There is no limit to nesting. Those nested <q> elements could even be within a blockquote that’s within a blockquote.

If you add quotation marks to a blockquote, know that the blockquote does not change the quote level the way a <q> tag does. If you expect to have quotes within a blockquote, you may want to add a descendant selector rule to start <q> elements within a blockquote at the single quote level (or double quotes if you follow British conventions).

 blockquote q {   quotes: "‘" "’" "“" "”"; }

The last quote level you put in will continue through subsequent levels of quotation. To use the double, single, double, single… convention, add more levels to the CSS quotes property.

q {   quotes: "“" "”" "‘" "’" "“" "”" "‘" "’" "“" "”"; }

Hanging punctuation

Many typography experts will tell you that hanging the quotation marks on blockquotes looks better (and they’re right). Hanging punctuation is, in this case, quotation marks that are pushed out from the text so that the characters of the text line up vertically.

One possibility in CSS is using a slightly negative value on the text-indent property. The exact negative indentation will vary by font, so be sure to double check the spacing with the font you end up using.

blockquote {   text-indent: -0.45em; }

There is a nicer way to handle this by using the hanging-punctuation CSS property. It’s only supported in Safari at the time of this writing, so we’ll have to progressively enhance:

/* Fallback */ blockquote {   text-indent: -0.45em; }  /* If there's support, erase the indent and use the property instead */ @supports ( hanging-punctuation: first) {   blockquote {     text-indent: 0;     hanging-punctuation: first;   } }

Using hanging-punctuation is better because it’s less fiddly. It’ll just work when it can.

See the Pen
Hanging Your Punctuation
by CSS-Tricks (@css-tricks)
on CodePen.

Can we animate quotation marks?

Of course we can.

See the Pen
Dancing Quotes
by CSS-Tricks (@css-tricks)
on CodePen.

Why you’d need to do this, I’m not totally sure, but the quotation marks in a <q> tag are added are pseudo elements in the UA stylesheet, so we’re able to select and style them — including animation — if we need to.

Wait, maybe we just solved the air quotes thing after all.

The post Quoting in HTML: Quotations, Citations, and Blockquotes appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Some Hands-On with the HTML Dialog Element

This is me looking at the HTML <dialog> element for the first time. I’ve been aware of it for a while, but haven’t taken it for a spin yet. It has some pretty cool and compelling features. I can’t decide for you if you should use it in production on your sites, but I’d think it’s starting to be possible.

It’s not just a semantic element, it has APIs and special CSS.

We’ll get to that stuff in a moment, but it’s notable because it makes the browser support stuff significant.

When we first got HTML5 elements like <article>, it pretty much didn’t matter if the browser supported it or not because nothing was worse-off in those scenarios if you used it. You could make it block-level and it was just like a meaningless div you would have used anyway.

That said, I wouldn’t just use <dialog> as a “more semantic <div> replacement.” It’s got too much functionality for that.

Let’s do the browser support thing.

As I write:

  • Chrome’s got it (37+), so Edge is about to get it.
  • Firefox has the User-Agent (UA) styles in place (69+), but the functionality is behind a dom.dialog_element.enabled flag. Even with the flag, it doesn’t look like we get the CSS stuff yet.
  • No support from Safari.

It’s polyfillable.

It’s certainly more compelling to use features with a better support than this, but I’d say it’s close and it might just cross the line if you’re the polyfilling type anyway.

On to the juicy stuff.

A dialog is either open or not.

<dialog>   I'm closed. </dialog>  <dialog open>   I'm open. </dialog>

There is some UA styling to them.

It seems to match in Chrome and Firefox. The UA stylesheet has it centered with auto margins, thick black lines, sized to content.

See the Pen
Basic Open Dialog
by Chris Coyier (@chriscoyier)
on CodePen.

Like any UA styles, you’ll almost surely override them with your own fancy dialog styles — shadows and typography and whatever else matches your site’s style.

There is a JavaScript API for opening and closing them.

Say you have a reference to the element named dialog:

dialog.show(); dialog.hide();

See the Pen
Basic Togglable Dialog
by Chris Coyier (@chriscoyier)
on CodePen.

You should probably use this more explicit command though:

dialog.showModal();

That’s what makes the backdrop work (and we’ll get to that soon). I’m not sure I quite grok it, but the the spec talks about a “pending dialog stack” and this API will open the modal pending that stack. Here’s a modal that can open a second stacking modal:

See the Pen
Basic Open Dialog
by Chris Coyier (@chriscoyier)
on CodePen.

There’s also an HTML-based way close them.

If you put a special kind of form in there, submitting the form will close the modal.

<form method="dialog">   <button>Close</button> </form>

See the Pen
Dialog with Form that Closes Dialog
by Chris Coyier (@chriscoyier)
on CodePen.

Notice that if you programmatically open the dialog, you get a backdrop cover.

This has always been one of the more finicky things about building your own dialogs. A common UI pattern is to darken the background behind the dialog to focus attention on the dialog.

We get that for free with <dialog>, assuming you open it via JavaScript. You control the look of it with the ::backdrop pseudo-element. Instead of the low-opacity black default, let’s do red with stripes:

See the Pen
Custom Dialog Backdrop
by Chris Coyier (@chriscoyier)
on CodePen.

Cool bonus: you can use backdrop-filter to do stuff like blur the background.

See the Pen
Native Dialog
by Chris Coyier (@chriscoyier)
on CodePen.

It moves focus for you

I don’t know much about this stuff, but I can fire up VoiceOver on my Mac and see the dialog come into focus see that when I trigger the button that opens the modal.

It doesn’t trap focus there, and I hear that’s ideal for modals. We have a clever idea for that utilizing CSS you could explore.

Rob Dodson said: “modals are actually the boss battle at the end of web accessibility.” Kinda nice that the native browser version helps with a lot of that. You even automatically get the Escape key closing functionality, which is great. There’s no click outside to close, though. Perhaps someday pending user feedback.

Ire’s article is a go-to resource for building your own dialogs and a ton of accessibility considerations when using them.

The post Some Hands-On with the HTML Dialog Element appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

The Many Ways to Link Up Shapes and Images with HTML and CSS

Different website designs often call for a shape other than a square or rectangle to respond to a click event. Perhaps your site has some kind of tilted or curved banner where the click area would be awkwardly large as a straight rectangle. Or you have a large uniquely shaped logo where you only want that unique shape to be clickable. Or you have an interactive image that responds differently when different regions of it are clicked.

You can surround those assets with an un-styled <a> tag to get a clickable rectangle that’s approximately the right size. However, you can also control the shape of that region with different techniques, making sure the target for your click area exactly matches what’s visible on the screen.

SVG shapes

If your click target is an image or a portion of an image, and you have the ability to choose SVG as its format, you already have a great deal of control over how that element will behave on your page. The simplest way to make a portion of an SVG clickable is to add an an SVG hyperlink element to the markup. This is as easy as wrapping the target with an <a> tag, just as you would a nested html element. Your <a> tag can surround a simple shape or more complex paths. It can surround a group of SVG elements or just one. In this example the link for the bullseye wraps a single circle element, but the more complex arrow shape is made up of two polygons and a path element.

See the Pen
target svg
by Bailey Jones (@bailey_jones)
on CodePen.

Note that I’ve used the deprecated xlink:href property in this demo to ensure that the link will work on Safari. The href alone would have worked in Internet Explorer, Chrome, and Firefox.

The only trick here is to make sure the <a> tag is inside the SVG markup and that the tag wraps the shape you want to be clickable. The viewbox for this SVG is still a rectangle, so wrapping the entire SVG element wouldn’t have the same effect.

Image maps

Let’s say you don’t have control over the SVG markup, or that you need to add a clickable area to a raster image instead. It’s possible to apply a clickable target to a portion of an <img> tag using an image map.

Image maps are defined separately from the image source. The map will effectively overlay the entire image element, but it’s up to you to define the clickable area. Unlike the hyperlink element in the SVG example, the coordinates in the image map don’t have anything to do with the definition of the source image. Image maps have been around since HTML 3, meaning they have excellent browser support. However, they can’t be styled with CSS alone to provide interactive cues, like we were able to do with SVG on hover — the cursor is the only visual indicator that the target area of the image can be clicked. There are, however, options for styling the areas with JavaScript.

W3 Schools has an excellent example of an image map using a picture of the solar system where the sun and planets are linked to close-up images of those targets — everywhere else in the image is un-clickable. That’s because the coordinates of the areas defined in their image map match the locations of the sun and planets in the base image.

Here’s another example from Derek Fogge that uses uses maps to create more interesting click targets. It does use jQuery to style the areas on click, but notice the way a map overlays the image and coordinates are used to create the targets.

See the Pen
responsive image map demo
by Derek Fogge (@PositionRelativ)
on CodePen.

You can implement image maps on even more complex shapes too. In fact, let’s go back to the same target shape from the SVG example but using a raster image instead. We still want to link up the arrow and the bullseye but this time do not have SVG elements to help us out. For the bullseye, we know the X and Y coordinates and its radius in the underlying image, so it’s fairly easy to define a circle for the region. The arrow shape is more complicated. I used https://www.image-map.net to plot out the shape and generate the area for the image map — it’s made up of one polygon and one circle for the rounded edge at the top.

See the Pen
target image map
by Bailey Jones (@bailey_jones)
on CodePen.

Clip-path

What if you want to use CSS to define the shape of a custom click region without resorting to JavaScript for the styling? The CSS clip-path property provides considerable flexibility for defining and styling target areas on any HTML element.

Here we have a click area in the shape of a five-pointed star. The star is technically a polygon, so we could use a star-shaped base image and an image map with corresponding coordinates like we did in the previous image map example. However, let’s put clip-path to use. The following example shows the same clip-path applied to both a JPG image and an absolutely positioned hyperlink element.

See the Pen
Clip-path
by Bailey Jones (@bailey_jones)
on CodePen.

Browser support for clip-path has gotten much better, but it can still be inconsistent for some values. Be sure to check support and vendor prefixes before relying on it.

We can also mix and match different approaches depending on what best suits the shape of a particular click target. Here, I’ve combined the “close” shape using Bennet Freely’s clippy with an SVG hyperlink element to build the start of a clickable tic-tac-toe game. SVG is useful here to make sure the “hole” in the middle of the “O” shape isn’t clickable. For the “X” though, which is a polygon, a single clip-path can style it.

See the Pen
tic tac toe
by Bailey Jones (@bailey_jones)
on CodePen.

Again, beware of browser support especially when mixing and matching techniques. The demo above will not be supported everywhere.

CSS shapes without transparent borders

The clip-path property allowed us to apply a predefined shape to an HTML element of our choice, including hyperlink elements. There are plenty of other options for creating elements HTML and CSS that aren’t squares and rectangles — you can see some of them in The Shapes of CSS. However, not all techniques will effect the shape of the click area as you might expect. Most of the examples in the Shapes of CSS rely on transparent borders, which the DOM will still recognize as part of your click target even if your users can’t see them. Other tricks like positioning, transform, and pseudo elements like ::before and ::after will keep your styled hyperlink aligned with its visible shape.

Here’s a CSS heart shape that does not rely on transparent borders. You can see how the the red heart shape is the only clickable area of the element.

See the Pen
Clickable heart
by Bailey Jones (@bailey_jones)
on CodePen.

Here’s another example that creates a CSS triangle shape using transparent borders. You can see how the click area winds up being outside the actual shape. Hover over the element and you’ll be able to see the true size of the click area.

See the Pen
clickable triangle
by Bailey Jones (@bailey_jones)
on CodePen.


Hopefully this gives you a good baseline understanding of the many ways to create clickable regions on images and shapes, relying on HTML and CSS alone. You may find that it’s necessary to reach for JavaScript in order to get a more advanced interactive experience. However, the combined powers of HTML, CSS, and SVG provide considerable options for controlling the precise shape of your click target.

The post The Many Ways to Link Up Shapes and Images with HTML and CSS appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Multi-Million Dollar HTML

Two stories:

  • Jason Grigsby finds Chipotle’s online ordering form makes use of an input-masking technique that chops up a credit card expiration year making it invalid and thus denying the order. If pattern="\d\d" maxlength="2" was used instead (native browser feature), the browser is smart enough to do the right thing and not deny the order. Scratchpad math, based on published data, makes that worth $ 4.4 million dollars.
  • Adrian Roselli recalls an all-too-common form accessibility fail of missing a for/id attribute on labels and inputs results in an unusable experience and a scratchpad math loss of $ 18 million dollars to campaigns.

The label/input attribution thing really gets me. I feel like that’s an extremely basic bit of HTML knowledge that benefits both accessibility and general UX. It’s part of every HTML curriculum I’ve ever seen, and regularly pointed at as something you need to get right. And never a week goes by I don’t find some production website not doing it.

We can do this everyone!

<label for="name">Name:</label> <input id="name" name="name" type="text">  <!-- or -->  <label>   Name:   <input name="name" type="text"> </label>

The post Multi-Million Dollar HTML appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

Weekly Platform News: HTML Inspection in Search Console, Global Scope of Scripts, Babel env Adds defaults Query

In this week’s look around the world of web platform news, Google Search Console makes it easier to view crawled markup, we learn that custom properties aren’t computing hogs, variables defined at the top-level in JavaScript are global to other page scripts, and Babel env now supports the defaults query — plus all of last month’s news compiled into a single package for you.

Easier HTML inspection in Google Search Console

The URL Inspection tool in Google Search Console now includes useful controls for searching within and copying the HTML code of the crawled page.

Note: The URL Inspection tool provides information about Google’s indexed version of a specific page. You can access Google Search Console at https://search.google.com/search-console.

(via Barry Schwartz)

CSS properties are computed once per element

The value of a CSS custom property is computed once per element. If you define a custom property --func on the <html> element that uses the value of another custom property --val, then re-defining the value of --val on a nested DOM element that uses --func won’t have any effect because the inherited value of --func is already computed.

html {   --angle: 90deg;   --gradient: linear-gradient(var(--angle), blue, red); }  header {   --angle: 270deg; /* ignored */   background-image: var(--gradient); /* inherited value */ }

(via Miriam Suzanne)

The global scope of scripts

JavaScript variables created via let, const, or class declarations at the top level of a script (<script> element) continue to be defined in subsequent scripts included in the page.

Note:Axel Rauschmayer calls this the global scope of scripts.”)

(via Surma)

Babel env now supports the defaults query

Babel’s env preset (@babel/preset-env) now allows you to target browserslist’s default browsers (which are listed at browsersl.ist). Note that if you don’t specify your target browsers, Babel env will run every syntax transform on your code.

{   "presets": [     [       "@babel/preset-env",       {         "targets": { "browsers": "defaults" }       }     ]   ] }

(via Nicolò Ribaudo)

All the June 2019 news that’s fit to… print

For your convenience, I have compiled all 59 news items that I’ve published throughout June into one 10-page PDF document.

Download PDF

The post Weekly Platform News: HTML Inspection in Search Console, Global Scope of Scripts, Babel env Adds defaults Query appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , , , , , , , ,
[Top]

How to Section Your HTML

The sectioning elements in HTML5 are <nav>, <aside>, <article>, and <section>. <body> is also kind of a sectioning element since all content lying inside of it is part of the default document section.

Here is a brief explanation of each sectioning element and how they are used:

  • <nav> – Equivalent to role="navigation". Major site navigation that consistently appears frequently across the site. Examples include the primary navigation, secondary navigation, and in-page navigation.
  • <aside> – Equivalent to role="complimentary". Content that is only tangentially related (or not related) to the main content. Think of something like a sidebar with supplementary information, a note within an article, or the outer container for a list of related articles at the bottom of a blog post.
  • <article> – Equivalent to role="article". Content that is self-contained in that it makes sense on its own when taken out of context. That could mean a widget, a blog post or even a comment within a blog post.
  • <section> – Equivalent to role="region". Content that needs extra context from its parent sectioning element to make sense. This is a generic sectioning element that is used whenever it doesn’t make sense to use the other more semantic ones.

Contents

This is a very long article that I suspect you will want to come back to and reference multiple times. To make that easier, here is a list of all the article headings:

Jump to article heading
  1. When to use <nav>
    1. A <nav> is unnecessary around a search form
    2. Don’t use the word “nav” or “navigation” in the label
    3. Questions to ask yourself
    4. A <nav> doesn’t have to be a list of links
  2. Avoid nesting an <aside> inside an <aside>
  3. Article is like “Block”; Section is like “Element”
    1. Comments sections
  4. Don’t swap <div> for <section>
  5. Headers and footers
    1. What goes inside headers?
    2. What goes inside footers?
  6. Sectioning elements and the document outline algorithm
    1. No browser supports the document outline algorithm
  7. Sectioning content
  8. The <main> element
  9. You need to label your sections. Here are three methods.
    1. Method 1: Add an aria-label attribute
      1. The aria-label translation issue
      2. Positives
      3. Negatives
    2. Method 2: Add a <h#> element to it
      1. Heading placement
      2. Only one heading of the highest level per sectioning element
      3. The heading always comes first
      4. Making visually hidden section labels out of headings
      5. Headings are well-supported by structure analysis tools
      6. Positives
      7. Negatives
    3. Method 3: Use an aria-labelledby attribute
      1. Labels can be hidden without CSS
      2. Major portability issue
      3. No need to place the label near the sectioning element
      4. Turn non-heading elements into section labels
      5. Positives
      6. Negatives
  10. Only use one method at a time
  11. Adding section labels to our example layout
  12. Making Heading 1 be the first heading
  13. Concerns with the simplified outline algorithm spec
  14. Using aria on the example layout sectioning elements
    1. Using aria-label
    2. Using aria-labelledby
    3. Results of using aria
  15. What happens when you need h7?
  16. Does your site have a good structure?
  17. Download and use a screen reader

When to use <nav>

The <nav> element only ever needs to be used once per navigation block. Sub-navigation that is already contained inside a <nav> element does not need to be wrapped in a second <nav> element.

<nav aria-label="Primary">   <ul>     <li><a href="#">Primary link</a></li>     <li><a href="#">Primary link</a></li>     <li>       <a href="#">Primary link</a>       <!-- <nav> element is *not* needed again here -->       <ul>         <li><a href="#">Secondary link</a></li>         <li><a href="#">Secondary link</a></li>       </ul>     </li>   </ul> </nav>

The <nav> element is intended for only major navigation blocks. “Major” is a very subjective term though. html5doctor.com has a pretty good explanation of when it is and isn’t appropriate to use <nav>, keep in mind that the following are opinions and not official W3C rulings:

The key phrase is ‘major’ navigation. We could debate all day about the definition of ‘major’, but to me it means:

  • Primary navigation
  • Site search
  • Secondary navigation (arguably)
  • In-page navigation (within a long article, for example)

While there isn’t any right or wrong here, a straw poll coupled with my own interpretation tells me that the following shouldn’t be enclosed by <nav>:

  • Pagination controls
  • Social links (although there may be exceptions where social links are the major navigation, in sites like About me or Flavours, for example)
  • Tags on a blog post
  • Categories on a blog post
  • Tertiary navigation
  • Fat footers

html5doctor.com (strikethrough mine)

Breadcrumbs are another piece of content that should be wrapped in a <nav> element as evidenced by this W3C breadcrumb HTML example.

A <nav> is unnecessary around a search form

I disagree with HTML5 Doctor’s opinion that a site search form should be wrapped in a <nav> element (thus why I crossed it out). <nav> is intended to be wrapped around navigation links, not a form. The site search actually has its own special role that defines it as a search landmark. If you add role="search" to the search <form> element, it is announced to screen reader users as a search landmark. Screen reader users will also be able to navigate to it when navigating via landmarks. If there are multiple search forms on the page, they should be differentiated using aria-label or aria-labelledby (more details on these attributes later). Don’t include the word “search” in the aria label though — that’s like saying “image of” in image alt text; it’s unnecessary. Instead, focus on what the search form is searching through. So, for the global site search, giving it aria-label="site" would be appropriate.

<!-- <nav> is not needed on a search form. --> <!-- role="search" is enough --> <form role="search" aria-label="site">   <label>     <span>Search</span>     <input type="search" />   </label>   <buton type="submit">Submit</button> </form>

A role="search" form won’t appear in a document outline but I think this is okay considering search forms are often small and self-contained. It still gets the majority of benefits that you get from using sectioning elements. Adding a sectioning element to the mix bombards the screen reader user with messages telling them that it is a search form (one for the sectioning element, one for the search role, and one for the search input label).

Don’t use the word “nav” or “navigation” in the label

Like with role="search", adding “navigation” to the label of a <nav> element only results in a screen reader saying “navigation” twice.

<nav aria-label="primary navigation">   <!-- Screen reader: "primary navigation navigation landmark" --> </nav>  <nav aria-label="primary">   <!-- Screen reader: "primary navigation landmark" --> </nav>

Questions to ask yourself

That same HTML5 Doctor article lists two questions that you can ask yourself to help you figure out if something should be wrapped in a <nav> or not:

  • Would another sectioning element also be appropriate? If yes, maybe use that instead.
  • Would you add a link to it in a “skip to” block for accessibility? If not, then it might not be worth using a <nav> element.

In those cases where the navigation is too minor to justify the use of the <nav> element, <section> is most likely the element that you should use instead.

A <nav> doesn’t have to be a list of links

The most common use case for a <nav> is to wrap it around a list of links but it doesn’t have to be a list of links. If your navigation works in a different sort of way, you can still use the <nav> element.

<!-- Example taken from the <nav> element specification --> <!-- https://html.spec.whatwg.org/multipage/sections.html#the-nav-element:the-nav-element-5 --> <nav>   <h1>Navigation</h1>   <p>You are on my home page. To the north lies <a href="/blog">my   blog</a>, from whence the sounds of battle can be heard. To the east   you can see a large mountain, upon which many <a   href="/school">school papers</a> are littered. Far up thus mountain   you can spy a little figure who appears to be me, desperately   scribbling a <a href="/school/thesis">thesis</a>.</p>   <p>To the west are several exits. One fun-looking exit is labeled <a   href="https://games.example.com/">"games"</a>. Another more   boring-looking exit is labeled <a   href="https://isp.example.net/">ISP&#x2122;</a>.</p>   <p>To the south lies a dark and dank <a href="/about">contacts   page</a>. Cobwebs cover its disused entrance, and at one point you   see a rat run quickly out of the page.</p> </nav>

In this same vein, it’s okay to have small bits like intro text in the <nav> element as long as the primary focus of the content is on the navigation links. Introductory content is best placed inside a <header> in the <nav> element. I’ll go into more depth on headers and footers later.

<nav>   <header>     <h2>In this section</h2>     <p>This is some intro text describing what you will find in this section.</p>   </header>   <ul>     <li><a href="#">Sub section one</a></li>     <li><a href="#">Sub section two</a></li>   </ul> </nav>

Avoid nesting an <aside> inside an <aside>

In the same way that <nav> shouldn’t really ever be nested inside another <nav> element, <aside> elements also tend not to be nested inside each other. <aside> is used to represent content that is tangentially related to the content around it. That means placing an aside inside an aside is basically announcing a tangent away from something that in itself is a tangent away from the main content.

<!-- Don't do this --> <aside aria-label="Side bar">    <aside>     <h2>Share</h2>     <ul>       <!-- List of social media links -->     </ul>       </aside>    <aside>     <h2>Recommendations:</h2>     <ul>       <li>         <article>           <h2><a href="#">Related article title</a></h2>           <p>Article description</p>         </article>       </li>       <!-- List of recommended articles continues -->     </ul>   </aside>  </aside>

If you have a sidebar that has multiple sections, don’t nest <aside> elements inside of <aside> elements like in the example above. Instead, make the sidebar a single <aside> and then use <section> (or another appropriate sectioning element) to create the different sections.

<!-- Do this instead --> <aside aria-label="Side bar">    <section>     <h2>Share</h2>     <ul>       <!-- List of social media links -->     </ul>       </section>    <section>     <h2>Recommended articles:</h2>     <ul>       <li>         <article>           <h2><a href="#">Related article title</a></h2>           <p>Article description</p>         </article>       </li>       <!-- List of recommended articles continues -->     </ul>   </section>  </aside>

Article is like “Block”; Section is like “Element”

<section> and <article> are easy to get confused with one another. If you are familiar with “Block Element Modifier” (BEM) syntax, then an easy way to think of the difference between the two is that an <article> is a bit like the “B” (or “Block”) in BEM. It is a container that stores self-contained content that still makes sense when placed in a different context. Individual tweets on Twitter and each list item on a search results page would be considered <article> elements.

<section> is like the “E” (or “Element”) in BEM. It is a sub-section that requires context from its parent sectioning element to make sense. <section> is a generic catch-all sectioning element that you use when it doesn’t make sense to use the other sectioning elements. So, if in doubt, go with <section>.

Note that if something is styled as a “Block” in BEM, that doesn’t automatically mean that it is an <article> element. Same goes for BEM “Elements” and <section> elements. The element of something should be based on the meaning of the content, not how the content looks.

Comments sections

Something that may surprise people is that individual comments on a blog post are also considered articles, even though they are in reply to the main blog post. The <article> element wrapping around the main blog post should also wrap around the comments section though. This is to represent that the comments go with the main article.

<article>   <h1>I am an awesome blog post!</h1>   <p>I am some body text content.</p>    <section>     <h2>Comments</h2>     <ul>       <li>         <article>           <h2>Username</h2>           <p>This is the comment body text.</p>           <footer>             <p>               Meta data like post date makes sense               in either the header or the footer.             </p>           </footer>         </article>       </li>     </ul>   </section> </article>

Don’t swap <div> for <section>

Just because we have these fancy sectioning elements now, it doesn’t mean that the good old <div> element has lost all of its usefulness. <div> has no semantic meaning, so it is quite useful whenever we are altering the HTML purely for the sake of styling purposes.

Let’s say that we have a blog post contained inside an <article> element that we need to wrap in something for the sake of styling purposes.

<!-- I need a wrapper element --> <article>   <h1>I am a blog post</h1>   <p>I am some content</p> </article>

Reaching for the <section> element in this circumstance is not the right thing to do.

<!-- Do not do this --> <section class="wrapper">   <article>     <h1>I am a blog post</h1>     <p>I am some content</p>   </article> </section>

Though <section> is technically a generic element, <div> is the far more appropriate option in this circumstance. This new wrapping container is not meant to have any semantic meaning behind it and that is exactly what <div> is designed to be used for.

<!-- Use a <div> if the element is only used for styling purposes --> <div class="wrapper">   <article>     <h1>I am a blog post</h1>     <p>I am some content</p>   </article> </div>

Another way to remember this: if you can’t think of a meaningful heading to apply to a <section>, then it probably shouldn’t be a <section>.

Headers and footers

Although they don’t necessarily need to, sectioning elements may contain a single <header> and a single <footer> with the header being at the top of the section and the footer being at the bottom.

A basic sectioning element with a header and a footer.

Sectioning elements can be nested inside one another as many times as is needed based on the content.

Nested sectioning elements

The header and footer in a sectioning element can also contain sectioning elements.

Headers and footers containing sectioning elements

The one major restriction around nesting sectioning elements is that headers and footers cannot be nested inside other headers and footers.

Nesting headers and footers inside one another is not allowed.

What goes inside headers?

Headers are used for introductory content. Appropriate things to include in <header> elements include (but are not limited to):

  • The heading element (<h1><h6>)
  • An introductory paragraph or statement.
  • A profile picture
  • A logo
  • A search form
  • Primary navigation
  • Author’s name
  • Post/updated date
  • Meta data
  • Social media links

What goes inside footers?

Footer elements primarily hold things like meta data and minor supporting content. Appropriate things to include in <footer> elements include (but are not limited to):

  • Copyright information
  • Legalities
  • Footnotes
  • Low priority site navigation
  • Author’s name
  • Post/updated date
  • Meta data
  • Social media links

You will notice that there is some cross over between the header and the footer in terms of content that is appropriate to both. This is mostly because meta-type content fits well in either element. It mainly comes down to the design that you are trying to achieve. <header> elements do tend to signify that the content inside of them is of greater importance than the content inside of a <footer> element though.

Sectioning elements and the document outline algorithm

An important thing to know about these sectioning elements is that they are all supposed to feature a <h#> element inside of them (or be labeled in some other way, but more on that later). This is primarily for the sake of something called the document outline algorithm. This is an algorithm that uses sectioning elements to help determine what level a heading (<h#>) should be without having to rely exclusively on the number that the developer has provided. So, have you ever wondered whether or not it’s okay to have more than one <h1> on a page? This is meant to make that a non-issue (but hold on for a sec, because there is more to the story).

<!-- No Document outline algorithm --> <article>   <h1>Primary heading</h1>    <h2>Secondary heading</h2>   <p>Some text.</p>    <h3>Tertiary heading</h3>   <p>Some text.</p> </article>
<!-- With document outline algorithm --> <article>   <h1>Primary heading</h1> <!-- Recognized as <h1> -->      <!-- sectioning element sets new heading level context -->   <section>     <h1>Secondary heading</h1> <!-- Recognized as <h2> -->     <p>Some text.</p>      <h2>Tertiary heading</h2> <!-- Recognized as <h3> -->     <p>Some text.</p>   </section>  </article>

There is a lot more to learn about the document outline algorithm. I’ll stop here though because…

No browser supports the document outline algorithm

There is not a single browser that supports this method of creating a heading structure. This is a shame. It would make building accessible websites much easier if we didn’t have to worry so much about using the correct heading level all the time.

As far as I’m aware, there are two main reasons why no browser has implemented the algorithm. One is that browser vendors are afraid of breaking the heading structure of sites that have used sectioning elements incorrectly. The other reason is that the current document outline algorithm spec is difficult to implement and no browser vendor has been willing to put the time into implementing it yet.

In reference to the first reason, there is a long discussion about incorporating a new <h> element instead of using the <h1> element to tell browsers to use the document outline algorithm. I was in favor of this new <h> element idea until I realized that an attribute on the <html> element or adding a <meta> tag to the <head> would work even better as a means of telling browsers it was safe to use the algorithm. It is also better for headings to fall back to a <h1> in unsupported browsers than falling back to a <span>.

If you would like to play around with this <h> concept though, there is a plugin called hfill. It allows you to nest <hx> headings inside sectioning elements to create the document outline without having to worry about heading levels so much. There is a demo available for you to try it out. The major flaw in this plugin though is that the only way to increment heading levels is by nesting sectioning elements inside one another. There is no <h1>-is-greater-than-<h2> dynamic in this plugin which is the main reason I fell out of love with this <h> element idea. This lack of heading hierarchy would make CMS rich text editors far too difficult for clients to use.

As for the issue around implementation difficulty, work is being done to produce a simplified spec that browser vendors are more likely to adopt. The document outline algorithm has been in the HTML specifications for years. Hopefully this simplified spec will allow the algorithm to become a reality.

Although the algorithm is not supported anywhere yet, we can still build with the algorithm in mind. If we build with it in mind, then we gain the following benefits:

  1. We future-proof our sites in case the algorithm ever does get implemented.
  2. We can significantly improve the user experience for screen reader users.
  3. We potentially improve search engine optimization (SEO) due to search engines being able to better understand the site’s content.
  4. We can create a better user experience for users by allowing them to use native browser features that make use of sectioning elements, like Reader Mode.

Sectioning content

Take a look at this mock-up layout I put together and think about how you might split it up into sections.

Mock-up layout featuring a logo, primary nav, and search in the header, a secondary navigation in a left sidebar, and a main content area  in the middle with primary and secondary headings, a sidebar on the right with share links and links to recommended articles.

This is how I would split the layout up into sectioning elements (only the solid lines represent sectioning elements).

Layout showing where various sectioning elements would appear.

In terms of HTML markup, it looks like this:

<body>    <header>     <a href="/" title="Go to home page">       <img src="logo.png" alt="Site logo">     </a>     <nav>       <ul>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>       </ul>     </nav>     <form role="search" aria-label="site">       <label>         <span>Search</span>         <input type="search"/>       </label>       <button type="submit">Submit</button>     </form>   </header>    <nav>     <ul>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>     </ul>   </nav>    <main>     <article>       <h1>Main article heading</h1>       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p>        <h2>Article secondary heading</h2>       <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p>       <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p>     </article>   </main>    <aside>     <section>       <h2>Share</h2>       <ul>         <li><a href="#">Facebook</a></li>         <li><a href="#">Twitter</a></li>         <li><a href="#">Email</a></li>       </ul>     </section>     <section>       <h2>Recommended</h2>       <ul>         <li>           <article>             <h3><a href="#">Related article</a></h3>             <p>Article description</p>           </article>         </li>         <li>           <article>             <h3><a href="#">Related article</a></h3>             <p>Article description</p>           </article>         </li>       </ul>     </section>   </aside>    <footer>     <ul>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>     </ul>   </footer>  </body>

The <main> element

There is a very important semantic element that I used in the markup above that I haven’t covered yet and that is the <main> element. The <main> element represents the primary content of the page. It is not supposed to feature any side bars or navigation elements in it. You also must not have more than one <main> element on the page unless all other <main> elements on the page have a hidden attribute applied to them (this is for the sake of SPAs).

The <main> element is not a sectioning element. This means that it doesn’t help contribute to the document outline algorithm and it can’t feature a <header> or <footer> element as a direct child. It is a landmark element though so screen reader users are able to navigate to it quite easily.

I’m not 100% sure if using <article> in the <main> element like I have done above is necessary. Semantically, it does make sense. The main content is self-contained, thus justifying use of the <article> element in this way. From a document outline algorithm perspective, the <article> element also helps with the document structure.

From a usability point of view, it feels a bit unnecessary and the document outline algorithm doesn’t even work anywhere at the moment. I’m going to continue using it throughout my examples but I would be interested to know what other people think about this in the comments section.

You need to label your sections. Here are three methods.

I am going to be saying the word “label” a lot throughout this article. Keep in mind that I am not talking about the <label> element. The <label> element is not used to label sectioning elements.

Sectioning elements require labels so that screen reader users are able to quickly identify what content they can find inside that particular section of the site. I consider using sectioning elements without providing associated section labels as an accessibility fail, unless it is the only one of its type on the page. It is also recommended that the exact same label text not be used on multiple sectioning elements (or heading elements). This makes each section more recognizable to screen reader users which helps them navigate the site more easily.

There are three ways to label a sectioning element. In the following examples, I refer to “transport” and “portability” as a way of explaining how easy it is to save the section into a component and use that component multiple times in multiple different contexts.

I also provide lists of positives and negatives in the examples as well. In these lists, I assume that you want the section label to be readable by screen readers but hidden from sighted users.

Method 1: Add an aria-label attribute

This is the quickest and easiest way to label a sectioning element.

<section aria-label="Label for this section">   <p>Content for this section</p> </section>
#The aria-label translation issue

The main draw back of aria-label (at the time of writing) is that most browsers are unable to translate these values for users who speak a different language than you. The developers at Google recently fixed this bug in Chrome, however this is still a problem for every other browser.

If your website has a large international audience or you know that many of your users do not speak your language, you should probably avoid using this attribute until all browsers support the translation of this property. If you don’t have those sorts of users, it’s pretty safe to assume that the non-sighted users viewing your site are able to understand your language — well enough to be able to navigate your site, anyway.

If you need more convincing, let’s say your site has very few international users. That means your users generally come from the same country as you. If they come from the same country then they are likely to speak the same language as you, so there is already a fairly small percentage of your users that don’t understand the native language of your site. Now take into account that aria-label only affects screen reader users. That is now only a fraction of an already small percentage of your users who will experience the issue. And now consider that Chrome (by far the most popular browser in the world) now supports translation of the aria-label attribute. The user has to also not be using an up to date version of Chrome as their browser for the translation issue to be a problem. If you factor all of that together, it is highly probable that you may not have any users who are both able to perceive the aria-label attributes and are incapable of comprehending what they say. This makes me feel like the bad multi-lingual support in aria-label isn’t really worth worrying that much about unless you have a large international audience or you have many users that you know do not speak your language.

#Positives
  • Super quick and easy to implement.
  • Doesn’t affect heading structure.
  • Makes components easy to transport.
  • Is invisible to sighted users.
#Negatives
  • Not translated into other languages in non-Chrome browsers (at time of writing).
  • Often not supported by page structure analysis tools.
  • Confusion can arise from not knowing what level other headings inside the section should be at.

Method 2: Add a <h#> element to it

By <h#> I mean <h1>, <h2>, <h3>,<h4>,<h5>, or <h6> depending on what makes sense. Adding a heading to a sectioning element is a quick way to label it.

#Heading placement

The heading can be placed either directly in the sectioning element, like this:

<section>   <h1>Heading</h1>   <p>content</p> </section>

…or placed inside the <header> element:

<section>   <header>     <h1>Heading</h1>     <p>I'm a byline</p>   </header>    <p>Content</p> </section>

You can also place as many <div> wrapper elements between the sectioning element and the heading as you want.

<!-- This is perfectly fine --> <section>   <div>     <header>       <div>         <h1>Heading</h1>         <p>I'm a byline</p>       </div>     </header>      <p>Content</p>   </div> </section>
#Only one heading of the highest level per sectioning element

There should really only be one heading of the highest level in a sectioning element. The spec says that when there are multiple top level headings or headings of a higher level than the first, the browser is supposed to close the previous sectioning element and start a new one of the same type.

The first element of heading content in an element of sectioning content represents the heading for that explicit section. Subsequent headings of equal or higher rank start new implied subsections that are part of the previous section’s parent section. Subsequent headings of lower rank start new implied subsections that are part of the previous one. In both cases, the element represents the heading of the implied section.

HTML 5.3, Headings and Sections

In reality, the browser uses the first heading as the section label but these implied sections are never created. It just announces the heading as is when it encounters it. It’s not earth-shatteringly bad but it is somewhat confusing.

<!-- Avoid this: --> <section>   <h2>Heading level two labeling a section</h2>   <p>Content</p>    <!-- Don't use same level or higher headings as the one labeling the section -->   <h2>This is also a heading level two</h2>   <p>Content</p> </section>   <!-- Do this instead: --> <div>   <section>     <h2>Heading level two labeling a section</h2>     <p>Content</p>   </section>   <section>     <h2>Heading level two labeling a different section</h2>     <p>Content</p>   </section> </div>
#The heading always comes first

If a sectioning element has a <h#> element, that top level heading should always be the very first piece of content inside that sectioning element. Failing to do so counts as an accessibility fail.

If you find yourself needing to place content before your heading (like an image, for example), you can use Flexbox to rearrange the visual order. This will allow it to look like the image comes before the heading but in the markup the heading comes before the image. There is a bug in IE that will sometimes cause text to not wrap in a flex-direction: column; element. You can work around this issue by applying a max-width to the flex-child element.

<!-- Don't do this --> <section>   <img src="image.jpg" alt="Don't place content or images before the heading" />   <h2>Headings should always come first</h2>   <p>Place regular content after the heading</p> </section>  <!-- Do this instead --> <section class="example">   <h2>Headings should always come first</h2>   <img src="image.jpg" alt="Don't place content or images before the heading" />   <p>Place regular content after the heading</p> </section>  <style> .example {   display: flex;   flex-direction: column; } .example img {   order: -1; } </style>

Note that rearranging the visual order to satisfy WCAG Guideline 1.3.2: Meaningful Sequence can conflict directly with WCAG Guideline 2.4.3: Focus Order. For example, if that image is a link to an article and the heading you are placing it above is also a link to the article, placing the heading first breaks the focus order. Placing the image first breaks the meaningful sequence.

In situations like this where these two guidelines conflict with one another, my opinion is that the 1.3.2: Meaningful Sequence guideline is the more important guideline to follow if you aren’t able to resolve the conflict in some way. Failing focus order leads to the user suffering a moment of discomfort as they are tabbing through the content and focus is sent to an unexpected location. Failing to follow a meaningful sequence leads to a confused user unsure of the relationship between different bits of content.

#Making visually hidden section labels out of headings

Headings are visible to sighted users by default. This makes them super useful if you want the heading to be visible. A lot of the time, we don’t want the label for our sectioning element to be visible though. In order to stop our sighted users from seeing the label, we need to use some CSS.

<style> .visually-hidden {   position: absolute;   opacity: 0;   pointer-events: none; } </style>  <section>   <h1 class="visually-hidden">Heading</h1>   <p>content</p> </section>
#Headings are well-supported by structure analysis tools

Headings also have a huge advantage for developers in that any page structure analysis tool that you can find will have support for them. This makes heading structures easy to test and debug. The other two section labeling methods have very poor support in testing tools. Not even the official W3C Validator service supports the alternatives at the moment. I posted an issue to have this fixed — please consider helping to fix the issue if you are good at coding in Java.

#Positives
  • Quick to implement.
  • Reliably appears in page structure analysis tools making it easy to test and debug.
  • All browsers will translate the text into other languages.
  • No confusion over what level other headings inside the section should be.
#Negatives
  • Affects document heading structure.
  • Need to ensure that the heading is at the correct level before use.
  • Visible to the user by default.
  • Requires CSS to hide the heading from visual users.
  • Can make components less portable due to heading structure requirements.

Method 3: Use an aria-labelledby attribute

This is what it looks like to create a hidden section label using aria-labelledby.

<section aria-labelledby="unique-id">   <div hidden id="unique-id">Label for this section</div>   <p>Content for this section</p> </section>
#Labels can be hidden without CSS

Note that I used the hidden attribute in the example to hide the div rather than a visually-hidden CSS class. aria-labelledby is able to read out text that is normally hidden from screen reader users. This adds the bonus effect of preventing the text from being read out twice by the screen reader. Don’t use the aria-hidden attribute though. Screen readers will not find the label text. Well, NVDA couldn’t find the label text when I tested it. I’m not sure about other screen readers.

#Major portability issue

aria-labelledby is the most difficult to use out of all the section labeling methods. The main aspect that makes it difficult to use is that the aria-labelledby attribute works off IDs. Things always get more complicated whenever IDs are involved. This is due to web pages only being allowed to have a single instance of an ID on the page at any one time. This makes component portability difficult.

Due to this portability issue, I would really only recommend this option if you need to support a multi-lingual audience and don’t want to mess around with the heading structure.

#No need to place the label near the sectioning element

You don’t need to place the element with the label text inside or near the section element that it labels. The text for the label can be placed in a completely different location to the sectioning element. This is thanks to the ID linking the two elements together. I’m not necessarily saying that it is a good idea to do this, but it is a feature of aria-labelledby that you should be aware of.

<div hidden id="unique-id">Label for this section</div>  <!-- 1,000 lines of other HTML -->  <section aria-labelledby="unique-id">   <p>Content for this section</p> </section>
#Turn non-heading elements into section labels

There is one other key reason you may want to use aria-labelledby. If you have a visible non-heading element on the page that you want to use as the label for a section, aria-labelledby is perfect for this. A <legend> element inside a <fieldset> is a common use case for this. This doesn’t mean that you have to wrap fieldsets in sectioning elements. I’m just pointing it out in case you spot a need for it.

<section aria-labelledby="section_label">   <fieldset>     <legend id="section_label">       I am both the fieldset legend and the section label     </legend>      <!-- Form fields go here -->      </fieldset> </section>
#Positives
  • All browsers will translate the text into other languages.
  • Can assign a non-heading element as the section label.
  • Text for the label does not need to be placed near the section it is labeling.
#Negatives
  • Requires the use of IDs to work.
  • Difficult to transport.
  • It can potentially be difficult to track down where the text for the label is stored in your source code.
  • Text is visible by default unless a hidden attribute is used.
  • Text might get read out twice by some screen readers if the text is not hidden.
  • Confusion can arise from not knowing what level other headings inside the section should be at.

Only use one method at a time

Don’t use a <h#>, an aria-label and/or an aria-labelledby attribute at the same time on the same sectioning element. Only every use one labeling method at a time for each sectioning element. Using multiple methods is super confusing and leads to the label being overwritten. It’s a bit like declaring the same property twice in CSS. I wasn’t sure how a screen reader would actually handle this so I created the most ridiculous <section> ever and ran it through NVDA.

<!-- Don't do this --> <section aria-label="Is this the section label?" aria-labelledby="is_this_the_label">   <h1>Or is this the section label?</h1>   <p id="is_this_the_label">Only ever use one at a time.</p> </section>

This is the order of priority that NVDA gave to the various labeling methods from strongest to weakest:

  1. aria-labelledby
  2. aria-label
  3. <h#>

Adding section labels to our example layout

For a long time, I used headings as the only means of labeling sections. The poor multi-lingual support provided by aria-label scared me; and aria-labelledby was far too cumbersome to be my primary labeling method. We run into a bit of an issue though if we use only headings to label sections. I’ll show you what I mean.

<style>   .visually-hidden {     position: absolute;     opacity: 0;     pointer-events: none;   } </style>  <body>    <header>     <a href="/" title="Go to home page">       <img src="logo.png" alt="Site logo">     </a>     <nav>       <h2 class="visually-hidden">Primary</h2>       <ul>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>       </ul>     </nav>     <form role="search" aria-label="site">       <label>         <span>Search</span>         <input type="search"/>       </label>       <button type="submit">Submit</button>     </form>   </header>    <nav>     <h2 class="visually-hidden">Secondary</h2>     <ul>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>     </ul>   </nav>    <main>     <article>       <h1>Main article heading</h1>       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p>        <h2>Article secondary heading</h2>       <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p>       <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p>     </article>   </main>    <aside>     <h2 class="visually-hidden">Sidebar</h2>     <section>       <h3>Share</h3>       <ul>         <li><a href="#">Facebook</a></li>         <li><a href="#">Twitter</a></li>         <li><a href="#">Email</a></li>       </ul>     </section>     <section>       <h3>Recommended</h3>       <ul>         <li>           <article>             <h4><a href="#">Related article</a></h4>             <p>Article description</p>           </article>         </li>         <li>           <article>             <h4><a href="#">Related article</a></h4>             <p>Article description</p>           </article>         </li>       </ul>     </section>   </aside>    <footer>     <ul>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>     </ul>   </footer> </body>

If we look at our heading structure now, it will look like this (italics = visually hidden; bold = visible):

    • <h2> Primary [nav]
    • <h2> Secondary [nav]
  • <h1> Main article heading
    • <h2> Article secondary heading
    • <h2> Sidebar
      • <h3> Share
      • <h3> Recommended
        • <h4> Related article
        • <h4> Related article

Notice that our <h1> heading isn’t at the top of the list? It really doesn’t feel right having two <h2> headings above the <h1> heading.

This form of heading structure is actually allowed by the W3C so it doesn’t count as an accessibility fail. I still think that this is a pretty bad UX for screen reader users though. It is not a logical progression from <h1> to <h2>. It makes the most sense if the first heading you encounter on the page is a <h1> then progress into <h2> then <h3> and so on.

Making Heading 1 be the first heading

For a very long time, I thought the absolute best way to handle this conundrum was to make the <h1> visually hidden and have it be the very first piece of content on the page. The thing that everyone thinks is the <h1> actually becomes a <h2>.

This is what that sort of structure looks like in practice:

<style>   .visually-hidden {     position: absolute;     opacity: 0;     pointer-events: none;   } </style>  <!-- Don't do this --> <body>   <header>     <h1 class="visually-hidden">Main article heading</h1>     <a href="/" title="Go to home page">       <img src="logo.png" alt="Site logo">     </a>     <nav>       <h2 class="visually-hidden">Primary</h2>       <ul>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>       </ul>     </nav>     <form role="search" aria-label="site">       <label>         <span>Search</span>         <input type="search"/>       </label>       <button type="submit">Submit</button>     </form>   </header>    <nav>     <h2 class="visually-hidden">Secondary</h2>     <ul>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>     </ul>   </nav>    <main>     <article>       <h2><span class="visually-hidden">Body:</span> Main article heading</h2>       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p>        <h3>Article secondary heading</h3>       <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p>       <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p>     </article>   </main>    <aside>     <h2 class="visually-hidden">Sidebar</h2>     <section>       <h3>Share</h3>       <ul>         <li><a href="#">Facebook</a></li>         <li><a href="#">Twitter</a></li>         <li><a href="#">Email</a></li>       </ul>     </section>     <section>       <h3>Recommended</h3>       <ul>         <li>           <article>             <h4><a href="#">Related article</a></h4>             <p>Article description</p>           </article>         </li>         <li>           <article>             <h4><a href="#">Related article</a></h4>             <p>Article description</p>           </article>         </li>       </ul>     </section>   </aside>    <footer>     <ul>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>     </ul>   </footer> </body>

Now we have a document outline that looks like this (italics = visually hidden; bold = visible):

  • <h1> Main article heading
    • <h2> Primary [nav]
    • <h2> Secondary [nav]
    • <h2> Body: Main article heading
      • <h3> Article secondary heading
    • <h2> Sidebar
      • <h3> Share
      • <h3> Recommended
        • <h4> Related article
        • <h4> Related article

This mostly feels right. The <h1> is at the top and it all flows down perfectly with the <h2> elements representing major page sections and the <h3> elements representing sub sections. The main awkward bit is that the actual <h1> and the thing that everyone thinks is a <h1> are essentially duplicates of one another.

It wasn’t until I wrote up the first version of this article, had it nearly published, then had it thrown out the window, that I started to think differently. I talked with two accessibility consultants about the issue. They both agreed that, though this is a clever technical solution to the problem, it detracts from the experience of the very people that it is trying to help.

The issue is that when every other website in the world places the <h1> heading at the top of the main content area, that is what screen reader users come to expect. When your site is the special snowflake that does things differently, it confuses screen reader users and it takes them some time to figure out how your heading structure is supposed to work.

So, with that in mind, I’ve settled on a new method for handling the labeling of sectioning elements. Basically, any time I would have used a visually hidden heading, I would use an aria-label attribute now instead. If the site has a large non-native speaking audience, I would use aria-labelledby instead of aria-label.

Concerns with the simplified outline algorithm spec

If the simplified outline algorithm is approved in its current state, we will actually need to start structuring our sites like the visually hidden <h1> example anyway (just replace the <h2>, <h3> and <h4> elements with <h1> elements).

The original spec aimed to create the outline through the labeling of sectioning elements. This new spec is clearly aimed at trying to create the outline purely through heading levels. The algorithm basically calculates the heading level based on the number of ancestor sectioning elements a heading has plus the heading’s base heading level value. It’s a bit more nuanced than that in the spec, but that is the general idea of how it works in simple terms.

The simplified algorithm currently makes no mention of aria-label or aria-labelledby. This means that those attributes will not help contribute to the document outline that the simplified algorithm generates. With a lack of aria-label support, this would mean labeling a sectioning element with aria-label could easily lead to skipped heading levels deeper in the tree.

<!-- Simplified algorithm skipped heading levels issue --> <body>   <main>     <h1>Primary heading for the page</h1> <!-- interpreted as <h1> -->     <p>This is some content</p>   </main>    <!-- sectioning elements increase heading levels -->   <aside aria-label="Side bar"> <!-- aria-label does not contribute -->     <section>       <h1>Share</h1> <!-- interpreted as <h3> -->       <ul>         <!-- list of social media links -->       </ul>     </section>      <section>       <h1>Recommended articles:</h1>  <!-- interpreted as <h3> -->       <ul>         <!-- list of recommended articles -->       </ul>     </section>   </aside> </body>

The simplified spec also considers it invalid to:

It does, however, allow for there to be more than one level 1 heading at the root of the document, which I find very odd and bad for accessibility (though my concern about this seems to have been ignored).

I have voiced the issues I have with the spec and proposed possible solutions in the GitHub discussion.

For the moment, it is still best to use aria-label and/or aria-labelledby attributes instead of visually hidden headings to label sectioning elements. It isn’t worth diminishing the experience of our present day users for the sake of a spec that hasn’t even been finalized or accepted yet.

Using aria on the example layout sectioning elements

Using aria-label

This is what the HTML structure looks like if we use aria-label attributes to label the sectioning elements:

<body>   <header>     <a href="/" title="Go to home page">       <img src="logo.png" alt="Site logo">     </a>     <nav aria-label="Primary">       <ul>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>       </ul>     </nav>     <form role="search" aria-label="site">       <label>         <span>Search</span>         <input type="search"/>       </label>       <button type="submit">Submit</button>     </form>   </header>    <nav aria-label="Secondary">     <ul>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>   </ul>   </nav>    <main>     <article>       <h1>Main article heading</h1>       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p>        <h2>Article secondary heading</h2>       <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p>       <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p>     </article>   </main>    <aside aria-label="Sidebar">     <section>       <h2>Share</h2>       <ul>         <li><a href="#">Facebook</a></li>         <li><a href="#">Twitter</a></li>         <li><a href="#">Email</a></li>       </ul>     </section>     <section>       <h2>Recommended</h2>       <ul>         <li>           <article>             <h3><a href="#">Related article</a></h3>             <p>Article description</p>           </article>         </li>         <li>           <article>             <h3><a href="#">Related article</a></h3>             <p>Article description</p>           </article>         </li>       </ul>     </section>   </aside>    <footer>     <ul>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>     </ul>   </footer> </body>

Here is the layout in CodePen in case you want to have a play around with it (sorry mobile users, it’s not mobile friendly):

See the Pen
Mock up page layout v2 (sections article)
by Daniel Tonon (@daniel-tonon)
on CodePen.

Using aria-labelledby

But let’s assume that you have a huge international audience that speaks all sorts of languages. In that case, it is better to use the aria-labelledby attribute. Here is what that would look like:

<body>    <header>     <a href="/" title="Go to home page">       <img src="logo.png" alt="Site logo">     </a>     <nav aria-labelledby="primary-nav-label">       <div id="primary-nav-label" hidden>Primary</div>       <ul>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>         <li><a href="#">Primary nav</a></li>       </ul>     </nav>     <form role="search" aria-labelledby="search-label">       <div id="search-label" hidden>Site</div>       <label>         <span>Search</span>         <input type="search"/>       </label>       <button type="submit">Submit</button>     </form>   </header>    <nav aria-labelledby="secondary-nav-label">     <div id="secondary-nav-label" hidden>Secondary</div>     <ul>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>       <li><a href="#">Secondary nav</a></li>     </ul>   </nav>    <main>     <article>       <h1>Main article heading</h1>       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quae sunt igitur communia vobis cum antiquis, iis sic utamur quasi concessis; Nihil acciderat ei, quod nollet, nisi quod anulum, quo delectabatur, in mari abiecerat. Unum est sine dolore esse, alterum cum voluptate. Laboro autem non sine causa; Theophrasti igitur, inquit, tibi liber ille placet de beata vita? Nihil opus est exemplis hoc facere longius. Duo Reges constructio interrete. Graecum enim hunc versum nostis omnes Suavis laborum est praeteritorum memoria. Haec et tu ita posuisti, et verba vestra sunt.</p>        <h2>Article secondary heading</h2>       <p>Nos commodius agimus. A mene tu? Tantum dico, magis fuisse vestrum agere Epicuri diem natalem, quam illius testamento cavere ut ageretur. Tenesne igitur, inquam, Hieronymus Rhodius quid dicat esse summum bonum, quo putet omnia referri oportere? Nihilo beatiorem esse Metellum quam Regulum. Sed quanta sit alias, nunc tantum possitne esse tanta. Philosophi autem in suis lectulis plerumque moriuntur. Esse enim, nisi eris, non potes.</p>       <p>Sunt enim quasi prima elementa naturae, quibus ubertas orationis adhiberi vix potest, nec equidem eam cogito consectari. Id Sextilius factum negabat. Quorum sine causa fieri nihil putandum est. Quae autem natura suae primae institutionis oblita est?</p>     </article>   </main>    <aside aria-labelledby="sidebar-label">     <div id="sidebar-label" hidden>Sidebar</div>     <section>       <h2>Share</h2>       <ul>         <li><a href="#">Facebook</a></li>         <li><a href="#">Twitter</a></li>         <li><a href="#">Email</a></li>       </ul>     </section>     <section>       <h2>Recommended</h2>       <ul>         <li>           <article>             <h3><a href="#">Related article</a></h3>             <p>Article description</p>           </article>         </li>         <li>           <article>             <h3><a href="#">Related article</a></h3>             <p>Article description</p>           </article>         </li>       </ul>     </section>   </aside>    <footer>     <ul>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>       <li><a href="#">Footer link</a></li>     </ul>   </footer> </body>

Results of using aria

The heading structure for the site at this point looks like this:

  • <h1> Main article heading
    • <h2> Article secondary heading
    • <h2> Share
    • <h2> Recommended
      • <h3> Related article
      • <h3> Related article

The document outline (assuming that the original outline algorithm is implemented) looks like this:

  • <body> Document
    • <nav> Primary
    • <nav> Secondary
    • <article> Main article heading
      • <section (implied)> Article secondary heading
    • <aside> Sidebar
      • <section> Share
      • <section> Recommended
        • <article> Related article
        • <article> Related article

You might be thinking that the document outline looks a bit bare. Shouldn’t things like the header and footer and search be announced in there as well? Keep in mind that this is just the explicit stuff. We get a lot of implicit information provided to the user for free by using correct HTML elements in a good structure. This is a simplified version of how a screen reader user might experience the site:

  • [Text used in the <title> element]
    • Banner landmark
      • Link, site logo [(on focus) “go to home page”]
      • “Primary” navigation landmark
        • [List of navigation links]
      • “Site” search landmark
    • “Secondary” navigation landmark
      • [List of navigation links]
    • Main landmark
      • “Main article heading” article landmark, heading level 1
        • [Content]
        • Heading level 2, “Article secondary heading”
          • [Content]
    • “Sidebar” complimentary landmark
      • “Share” region landmark, heading level 2
        • [List of share links]
      • “Recommended” region landmark, heading level 2
        • List with 2 items
          • Item, “Related article” article landmark, heading level 3
            • [Content]
          • Item, “Related article” article landmark, heading level 3
            • [Content]
    • Content info landmark
      • [List of footer links]

As you can see, the site structure becomes quite clear and understandable to screen reader users when you factor in all of the extra implicit information that you get from using a good HTML structure

So, even though no browser supports the document outline algorithm, it is still worth putting some effort into thinking about the outline. Screen readers still tell users what type of section something is, where sections start and (sometimes) end (depends on the screen reader), and what the section label is. This means that your efforts to make a good document structure do not go to waste.

This type of structure comes with multiple benefits:

  • The page is 100% compatible with the document outline algorithm, future proofing it in-case the algorithm is ever implemented in a real browser.
  • The heading structure is completely logical.
  • Screen reader users navigating via headings can quickly jump to important information.
  • Screen reader users navigating via landmarks have lots of useful landmarks to move about the page.
  • Screen reader users are able to quickly understand what each section contains without having to read any of the content inside of them.
  • Content is grouped into semantic sections, so screen reader users do not get confused when leaving one section and entering another.
  • Search engines are able to better understand what information each section holds, which could potentially improve SEO.
  • Sighted users can take advantage of native browser features like Reader Mode.

What happens when you need h7?

There is one more sticking point when it comes to labeling sectioning elements that I haven’t addressed yet. Let’s say you have somehow managed to use up all six native heading levels and are now stuck needing one more. What do you do?

You could use the aria-labelledby technique if it is just for the sake of labeling a section. Let’s say that you really want this heading to appear in the heading structure though, or maybe you just want to avoid using IDs as much as possible. Whatever the reason, you need an <h7> element but <h7> doesn’t exist.

This is when the aria-level attribute comes to the rescue. The aria-level attribute will define what the heading level should be for elements that have role="heading" applied to them. This is how the W3C recommend creating a <h7> element:

<div role="heading" aria-level="7">This is a valid heading level 7 element</div>

Not all screen readers support this syntax. I know that JAWS treats these like <h2> elements rather than <h7> elements. If you know of any screen readers that this doesn’t work in, please report the bug to the screen reader developer and also leave a comment down below.

When I need to reach for an <h7>, I’ll often use the implied role="heading" from an <h6> element instead. The aria-level attribute will override the implicit “6” level of the <h6> element. This isn’t exactly endorsed by the W3C though. It is cleaner and will allow the heading to still appear in document outline and heading structure testing tools (though they will typically appear as <h6> or <h2> level headings, not as <h7> level headings).

<h6 aria-level="7">This is also a valid heading level 7 element</h6>

By using aria-level, you now have access to an infinite number of heading levels!

Does your site have a good structure?

Now that you know how to do a proper HTML structure, are you able to apply what you have learned to your website?

I found a pretty good browser extension called “Headings Map” that is available for both Chrome and Firefox. This extension will allow you to easily see both a flat heading structure representation of your site (i.e. how all browsers currently read the heading structure) and what the document structure looks like in a browser that supports the document outline algorithm (i.e. how a theoretical future browser that supports the outline algorithm would present the site structure). The HTML5 Outline view needs to be enabled in the settings menu first. This is to prevent users from being fooled into thinking that they are able to use the outline algorithm in production sites.

The Headings Map extension showing the flat heading structure result on the left and the result of the Document Outline Algorithm on the right.

Headings Map does not currently support the aria-label and aria-labelledby attributes on sectioning elements in the HTML5 outline tab. I have been talking with the developer and he is working on fixing this issue. If you know of a good document outline testing tool that already takes aria-label and aria-labelledby into account, please share a link to it in the comments.

Once you have a good document structure testing tool, check that both the heading structure and the document outline display a logical order with no missing headings or missing section labels anywhere.

Download and use a screen reader

The best way to test the implied semantics that you get from using correct HTML is to download an actual screen reader and try navigating your site with it. NVDA is one of the most used screen readers used by real screen reader users. It’s also free!

Be aware that the default settings for NVDA are optimized for usage by blind users. These default settings can drive sighted users insane. To enjoy your time using NVDA, perform the following steps (steps are based on a Windows set up, I don’t have a Mac):

  1. Download NVDA and install it
  2. Create a shortcut to NVDA in your task bar (You will be opening and closing it regularly while testing)
  3. Open NVDA from the task bar
  4. Find NVDA in your system tray

    Location of NVDA on Windows
  5. Right click the tray icon > “preferences” > “settings”
  6. Select “mouse” in the left panel
  7. Deselect “Enable mouse tracking” (You can now move your mouse without NVDA screaming at you)
  8. Press “OK”
  9. Right click the tray icon > “Tools” > “Speech Viewer” (You can now see a log of everything NVDA says, don’t rely purely on this when testing though)
  10. In the Speech Viewer, check the “Show Speech Viewer on Startup” checkbox (It will open the Speech Viewer when you open NVDA)
  11. Familiarize yourself with some of the keyboard controls
  12. To close NVDA, Right click the tray icon > “Exit” > “OK”

NVDA currently doesn’t support <article> and <section> elements. There is an issue on GitHub for supporting <article> elements. When I began writing this article <section> elements were already supported. Support for <section> seems to have dropped for some reason. This means NVDA should be fixed. It doesn’t mean you should stop using the correct semantics in your HTML.

Build your website with the document outline in mind then test the semantics with Headings Map and NVDA (or another screen reader). If you do, you will make your screen reader users very happy. You might even make the search engines happier too. 😊


Special thanks to Eric Bailey (accessibility adviser for CSS Tricks) and Kevin Galvin (a principal consultant at me 2 accessibility) for their advice around the usability issues of using a visually hidden <h1> element at the top of the page and suggesting aria-label as an alternative to using visually hidden headings.

The post How to Section Your HTML appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]