David made a comment on Twitter about some markup he was working on:
Feels dirty setting id’s on main HTML5 page header and footer, but overriding inheritance they cause seems needlessly laborious.
I know the feeling. I don’t like using IDs at all, unless I want part of a document to be addressable through the fragment identifier portion of the URL. While I think it’s desirable to use the id
attribute to create in-document permalinks, I don’t think it’s desirable to use the id
attribute just as a styling hook. Its high specificity may seem a blessing but, in my experience, it quickly leads to duplicated CSS. IDs are often used as a substitute for understanding the cascade.
Nicole feels the same way about ID selectors, and she knows a thing or two about writing efficient CSS.
Back to David’s dilemma. Let’s say you’re targetting header
and footer
elements used throughout your document in section
s, article
s, etc. All you need to use is an element selector:
header {
// regular header styles
}
But what about the document-level header
and footer
? They’re probably styled very differently from the headings of section
s and article
s.
You could try using a child selector:
body > header
But there’s no guarantee that the document header
will be a direct child of the body
element. Hence the use of the id
attribute—header id="ID"
:
header#ID {
// page header styles
}
There is another way. In HTML5 you can, for the first time, use ARIA roles and still have a valid document. ARIA landmark roles add an extra layer of semantics onto your document, distinguishing them as navigational landmarks for assistive technology.
Some of these landmark roles—like IDs—are to be used just once per document:
Within any document or application, the author SHOULD mark no more than one element with
That’s useful for two reasons. One, the existence of role="main"
means it is not necessary for HTML5 to provide an element whose only semantic is to say “this is the main content of the document.”
A lot of people have asked for such an element in HTML5. “We’ve got header
, footer
and aside
,” they say. “Why not maincontent
too?”
But whereas header
, footer
and aside
can and should be used multiple times per document, a maincontent
element would, by necessity, only be used once per document. There are very few elements in HTML that are like that: the html
element itself, the title
element, head
and body
(contrary to popular opinion—likely spread by SEO witch-doctors—the h1
element can be used more than once per document).
Now the desired functionality of semantically expressing “this is the main content of the document” can be achieved, not with an element, but with an attribute value: role="main"
.
The rough skeleton of your document might look like this:
<header role="banner"></header>
<div role="main"></div>
<footer role="contentinfo"></footer>
Now you can see the second advantage of these one-off role
values. You can use an attribute selector in your CSS to target those specific elements:
header[role="banner"] {
// page header styles
}
Voila! You can over-ride the default styling of header
s and footer
s without resorting to the heavy-handed specificity of the ID selector.
And, of course, you get the accessibility benefits too. ARIA roles are supported in JAWS, NVDA and Voiceover