HTML5 attribute value normalization

Viewed 256

In XML whitespace in attributes values are normalized to spaces. Thus test="foo#xD#xAbar" (with a CRLF between foo and bar) is normalized to test="foo bar" upon parsing.

But does attribute normalization happen with HTML as well—specifically HTML5? The HTML 5.2 spec on attributes doesn't mention it. A search if html5 normalization of attribute values on the web surprisingly did not immediately reveal any discussion on the matter.

I found an email on a W3C mailing list seeming to state that HTML4 normalized attribute values, but that HTML5 does not. It pointed to W3C HTML5 Bug 13709 from 2011, which provided no additional information. I also found W3C ISSUE-87; this seems to have been closed with prejudice after little to no discussion.

Let me give you an example of application. I have several HTML5 CSS classes that begin with prefix-, including (among others) prefix-foo and prefix-bar. I want to select element example but only if it does not contain a class starting with prefix-—sort of a combination of the |= and the ~= attribute selectors.

<example class="select">this will be blue</example>
<example class="do-not-select prefix-foo">this should not be blue</example>
<example class="prefix-bar do-not-select">this should not be blue</example>
<example class="select-prefix-is-not-a-prefix">but this <em>should</em> be blue</example>

Note that the last example has a prefix- substring, but not as a CSS class token prefix.

I came up with the following selector, which works on the above examples:

example:not([class^="prefix-"]):not([class*=" prefix-"]):
  background-color: blue;
;

My worry is that if the source uses whitespace other than a space whether the selector will still work. For example:

<example class="do-not-select


prefix-foo">this should not be blue either</example>

Surprisingly this works, both on Firefox and Chrome. It would appear that the newline in the attribute source is getting normalized to a space in the DOM. Or maybe there is no normalization happening, but some CSS specification indicates that a space in an attribute selector should match any whitespace (i.e. the normalization is during matching not during parsing).

Now that I've explained my use case, let me simplify the test case. Take this CSS style:

div[class*=" prefix-"] {
  background-color: green;
;

And take this HTML:

<div class="select prefix-foo">this should be green</div>

<div class="select

prefix-foo">this should be green only if whitespace is normalized</div>

Both of those are showing green for me, both in Firefox and in Chrome.

The HTML5 specification for class says that the value is space-separated, which includes any space characters including tabs and newlines. It says nothing about normalization, though.

Could someone please explain, citing relevant authoritative specifications, whether HTML5 normalizes attribute values; and whether spaces in CSS attribute selectors match literally or match any whitespace?

1 Answers

I think the problem is that my test file was an XHTML5 file and the browsers were following XML attribute normalization rules. When served as HTML5, no attribute normalization seems to occur.

My original test case was actually an XHTML5 file stored in e.g. text.xhtml and looked like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">

…

<div class="select prefix-foo">this should be green</div>

<div class="select

prefix-foo">this should be green only if whitespace is normalized</div>

This is perfectly valid XHTML5. I'm using a static site generator which produces HTML5, but I had forgotten that my source was XHTML5. When I tested the file locally from the file system, both Firefox and Chrome were correctly recognizing the file as XML-based, and thereby applying XML attribute normalization rules.

When I ran my static site generator and served these files, without the XML declaration, as text/html files (HTML5), both Firefox and Chrome did not select the second <div>.

So it would appear that HTML5 does not normalize whitespace in attributes. My mistakenly thinking that this was happening stems from the fact that I was inadvertently testing on XHTML5 files following XML normalization rules.

Related