Reputation: 5566
So, this might be a bug... I mistyped a CSS path to check for elements that had been processed to have a particular onclick function beginning "ajaxLoad("
document.querySelectorAll( 'a[onclick^="ajaxLoad("' )
As you can see, I forgot to close the attribute accessor, with ]
, like so :
document.querySelectorAll( 'a[onclick^="ajaxLoad(]"' )
Weirdly, it worked!
Edit - no I didn't, I actually ran the correct CSS selector:
document.querySelectorAll( 'a[onclick^="ajaxLoad("]' )
... but as mentioned in the comments apparently this further typo also works!
This is obviously invalid. I spotted it when I came to add another type of link, of class tc-link
, and was wondering if I could just chain it like in CSS stylesheets as :
document.querySelectorAll( 'a[onclick^="ajaxLoad(", a.tc-link' )
The answer is that you can by closing that bracket, but not when this typo is left in.
Uncaught DOMException: Failed to execute 'querySelectorAll' on 'Document': 'a[onclick^="ajaxLoad(", a tc-link' is not a valid selector.
It works on ^=
, $=
, and *=
, and from what I can see doesn't happen in Firefox or Opera (and I don't have any other browsers to test in).
I was thinking this was a language quirk at first but revised question: can anyone work out which level (DOM? V8? Er.. webkit? I don't know the ins and outs that well) of Javascript/browser code this relates to, and where it can get reported/fixed?
Upvotes: 17
Views: 1154
Reputation: 4241
This is primarely opinion-based and is nowhere close to a definitive answer.
Browsers are EXTREMELY complex. Done! Nothing is predictable on them.
First, let's analyze a list of faulty selectors:
a[onclick^="ajaxLoad("
(missing ]
)a[onclick^="ajaxLoad(]"
(missing ]
)a[onclick=""
(missing ]
)a[onclick="][onclick
(missing "]
or missing "
and ]
based on what you need)a[onclick=""][onclick
(missing ]
)a[onclick="
(missing "]
)a[onclick
(missing ]
)a:not([onclick]
(missing )
)a:not([onclick
(missing ])
)a:not([onclick="
(missing "])
)a:nth-child(5):not([onclick="
(missing "])
)a:-webkit-any(:not([onclick="
(missing "]))
)So far, this is the list found. I can confirm that these work on Google Chrome 41.0.2272.89m on Windows 7.
Notice the pattern? It's simple: Chrome still can use there selectors to match the elements by filling with basic missing characters, but only at the end!
What is missing is so predictable it doesn't require too much effort to fix.
But not every selector can/will be 'fixed' (E.g.: a,
, can be fixed by adding *
).
This may be a bug or a feature (aka, an embarrassing bug submitted as a feature) to soften the eagerness of the CSS engine. This also affects jQuery since jQuery only uses Sizzle if document.querySelectorAll()
doesn't exist or throws an exception.
With some time we can find many more.
Disclaimer:
This behaviour shouldn't be relied upon and may change in the future.
This is all based on invalid selectors and invalid syntax (like some IE CSS Hacks for older versions). ALL the working selectors on the list above are against the spec.
The 'unfixed' selector given as an example (a,
) works in jQuery, but that is unrelated to this question. Essentially, jQuery will execute it as a
.
Upvotes: 7
Reputation: 9275
The reason why most browsers accept the missing closing bracket is that they're all following the same algorithm from CSS specification. There is a discussion about this on the Chromium bugtracker; here's the relevant excerpt from the comment that closed the bug as WontFix:
When you parse the string 'a[b=c' (from the example link), the CSS parser turns that into:
IDENT(A) SIMPLE [ BLOCK: IDENT(B) DELIM(=) IDENT(C)
The fact that the square-bracket block was unclosed is lost. You can think of this as the parser "auto-closing all unclosed blocks". If you're using a spec-compliant parser, it is literally impossible to detect an unclosed block unless you do a separate ad hoc parsing on your own just for that purpose.
(I know I'm gravedigging an old question here, but since this still comes up from time to time, the link and explanation may be useful.)
Upvotes: 6