惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Commits to openclaw:main
Recent Commits to openclaw:main
L
LangChain Blog
月光博客
月光博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 【当耐特】
宝玉的分享
宝玉的分享
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
博客园_首页
T
Tailwind CSS Blog
P
Proofpoint News Feed
雷峰网
雷峰网
D
Darknet – Hacking Tools, Hacker News & Cyber Security
IT之家
IT之家
V
Vulnerabilities – Threatpost
阮一峰的网络日志
阮一峰的网络日志
C
CERT Recently Published Vulnerability Notes
Attack and Defense Labs
Attack and Defense Labs
S
Schneier on Security
Security Archives - TechRepublic
Security Archives - TechRepublic
L
Lohrmann on Cybersecurity
V
Visual Studio Blog
云风的 BLOG
云风的 BLOG
WordPress大学
WordPress大学
The Register - Security
The Register - Security
N
Netflix TechBlog - Medium
Hugging Face - Blog
Hugging Face - Blog
Project Zero
Project Zero
博客园 - 叶小钗
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
S
SegmentFault 最新的问题
C
Cyber Attacks, Cyber Crime and Cyber Security
Google Online Security Blog
Google Online Security Blog
Recorded Future
Recorded Future
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
L
LINUX DO - 最新话题
Google DeepMind News
Google DeepMind News
P
Privacy International News Feed
I
InfoQ
F
Fortinet All Blogs
Vercel News
Vercel News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Threatpost
T
Tenable Blog
B
Blog RSS Feed

Mathias Bynens

A horrifying globalThis polyfill in universal JavaScript JavaScript engine fundamentals: optimizing prototypes JavaScript engine fundamentals: Shapes and Inline Caches Asynchronous stack traces: why await beats Promise#then() ECMAScript regular expressions are getting better! Unicode property escapes in JavaScript regular expressions ES2015 const is not about immutability Valid JavaScript variable names in ES2015 Unicode-aware regular expressions in ES2015 Dear Google, please fix plain text emails in Gmail PBKDF2+HMAC hash collisions explained JavaScript has a Unicode problem Processing Content Security Policy violation reports Hiding JSON-formatted data in the DOM with CSP enabled Loading JSON-formatted data with Ajax and xhr.responseType='json' Reserved keywords in JavaScript How to support full Unicode in MySQL databases How to speedrun Dropbox’s Dropquest 2012 Unquoted font family names in CSS Unquoted property names / object keys in JavaScript Valid JavaScript variable names in ES5 CSS character escape sequences JavaScript’s internal character encoding: UCS-2 or UTF-16? The smallest possible valid (X)HTML documents JavaScript character escape sequences JavaScript foo.prototype.bar notation Ambiguous ampersands HTML element + attribute notation How I detect and use localStorage: a simple JavaScript pattern The end-tag open (ETAGO) delimiter Using the oninput event handler with onkeyup/onkeydown as its fallback Everything you always wanted to know about touch icons In defense of CSS hacks — introducing “safe CSS hacks” AirPlay video support in iOS Safari — a bookmarklet Completing Dropbox’s Dropquest 2011 in 60 seconds Using CSS without HTML How to create simple Mac apps from shell scripts Using setTimeout to speed up window.onload Bulletproof JavaScript benchmarks Thoughts on Safari Reader’s generated HTML How to enable Safari Reader on your site? The XML serialization of HTML5, aka ‘XHTML5’ The id attribute got more classy in HTML5 The three levels of HTML5 usage The HTML5 document.head DOM tree accessor Bulletproof HTML5 <details> fallback using jQuery Displaying hidden elements like <head> using CSS Inline <script> and <style> vs. external .js and .css — what’s the size threshold? Using Showdown/PageDown with and without jQuery
Unquoted attribute values in HTML and CSS/JS selectors
Mathias · 2011-06-13 · via Mathias Bynens

This is one of those posts I wrote just to be able to link back to it later. I see a lot of questions on the subject, and even though I don’t mind explaining the same thing over and over again, it’s probably easier to just write it down once.

Unquoted attribute values in HTML

Most people are used to quoting all attribute values in the HTML they write. For example:

<a href="foo" class="bar">baz</a>

Single quotes can be used too:

<a href='foo' class='bar'>baz</a>

However, the following is valid HTML as well:

<a href=foo class=bar>baz</a>

This is nothing new — in fact, the use of unquoted attribute values has been supported since HTML 2.0 (the first HTML standard). It is, however, not allowed in XHTML. (But seriously, who uses XHTML‽)

In HTML, an attribute value can be used without the quotes on certain conditions. For example, if you try to use an attribute value with spaces in it without quoting it, stuff breaks:

<!-- This does what you’d expect: -->
<p class="foo bar">

<!-- This is something entirely different: -->
<p class=foo bar>
<!-- …since it’s equivalent to: -->
<p class="foo" bar="">

Of course, bar is not a valid HTML attribute. So, just by omitting two quotes, you end up with invalid code and a <p> element that doesn’t get the bar classname you wanted it to have. And this is just one of the many examples…

If that didn’t scare you, you’ll probably want to know what the requirements for unquoted attribute values in HTML are. Let’s find out!

The HTML specification says:

Attributes are placed inside the start tag, and consist of a name and a value, separated by an = character. The attribute value can remain unquoted if it doesn’t contain spaces or any of " ' ` = < or >. Otherwise, it has to be quoted using either single or double quotes. The value, along with the = character, can be omitted altogether if the value is the empty string.

Note that instead of “spaces”, it should really say “space characters” there (see below). It’s not clear from this explanation that the empty string isn’t a valid unquoted attribute value either. (See bug #12938 which has now been fixed.) Thankfully, this is explained elsewhere in the spec:

The attribute name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN character (=), followed by zero or more space characters, followed by the attribute value, which […] must not contain any literal space characters, any U+0022 QUOTATION MARK characters ("), U+0027 APOSTROPHE characters ('), U+003D EQUALS SIGN characters (=), U+003C LESS-THAN SIGN characters (<), U+003E GREATER-THAN SIGN characters (>), or U+0060 GRAVE ACCENT characters (`), and must not be the empty string.

Note that the term “space characters” is a microsyntax that is used throughout the spec, grouping a number of whitespace characters:

The space characters, for the purposes of this specification, are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN (CR).

So, after cross-referencing these three different sections of the HTML spec, we can finally conclude that a valid unquoted attribute value in HTML is any string of text that is not the empty string and that doesn’t contain spaces, tabs, line feeds, form feeds, carriage returns, ", ', `, =, <, or >.

Unquoted attribute values in CSS (and JavaScript) selectors

You can use unquoted attribute values in CSS as well. However, the rules are a little different.

a[href="bar"] { /* declarations go here */ }
a[href^="http://"] { /* declarations go here */ }

Single quotes can be used too:

a[href='bar'] { /* declarations go here */ }
a[href^='http://'] { /* declarations go here */ }

Just like in HTML, there are cases where the quotes around the attribute value can be omitted, but doing it blindly will likely result in broken code:

/* This will work: */
a[href=bar] { /* declarations go here */ }

/* This, on the other hand, is an invalid CSS selector: */
a[href^=http://] { /* declarations go here */ }

So when is it acceptable to omit the quotes?

Both the CSS 2.1 and the CSS3 specifications say:

Attribute values must be identifiers or strings.

The spec says the following about strings:

Strings can either be written with double quotes or with single quotes.

Identifiers are defined as follows:

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_).

ISO 10646 defines the Universal Character Set, which correlates to the Unicode standard. Note that they’re actually talking about the hyphen-minus character — not the hyphen character, which is U+2010. The code point for hyphen-minus is U+002D, and for underscore (low line) it’s U+005F. The highest code point currently allowed by Unicode is U+10FFFF. So, any character matching the regular expression [-_a-zA-Z0-9\u00A0-\u10FFFF] is allowed in an identifier.

The spec continues:

[Identifiers] cannot start with a digit, two hyphens, or a hyphen followed by a digit. Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code […]. For instance, the identifier B&W? may be written as B\&W\? or B\26 W\3F .

This was later relaxed to allow -- at the start of identifiers with the introduction of custom properties.

Translated into regex: any string that matches ^-?\d is not a valid CSS identifier. (I’ve explained how to escape any character in CSS before.)

The empty string isn’t a valid CSS identifier either. For example, p[class=] is an invalid CSS selector. The same goes for a single hyphen: - is not a valid identifier.

So, a valid unquoted attribute value in CSS is any string of text that is not the empty string, is not just a hyphen (-), consists of escaped characters and/or characters matching /[-_\u00A0-\u10FFFF]/ entirely, and doesn’t start with a digit or two hyphens or a hyphen followed by a digit.

Note that any valid CSS selector can also be used with the Selectors API in JavaScript. If you use an invalid unquoted attribute value, the entire CSS selector becomes invalid, and will throw a DOMException if used with querySelector or querySelectorAll. (Note that most JavaScript libraries make use of these internally.) It’s important to get it right.

Mothereffing unquoted attributes

Even with these simplified definitions, it’s still a pain to remember all the rules for unquoted attribute values, especially as they differ between HTML and CSS. When in doubt, it’s probably best to just use quotes. If you’re confused, it’s likely to confuse your colleagues too. If you’re using user input in an attribute value, always quote (and escape) it to prevent XSS security vulnerabilities. Note that I don’t mean to recommend the use of unquoted attribute values with this article — this is just me reading the spec so you don’t have to.

That said, if you want to find out if a certain string is a valid unquoted attribute value in HTML or CSS, you can just use mothereff.in/unquoted-attributes.

Unquoted attribute value validator

It’s a small tool that I made for Paul Irish’s TXJS presentation. It was meant as a joke, but it’s actually kind of useful. Enjoy!