CSS3 Selector compatibility #44

Closed
barraponto opened this Issue Dec 19, 2010 · 44 comments

Projects

None yet
@barraponto

I believe the move to CSS3 selectors has become huge and, so far, Sizzle lacks support to several of the new selectors. The table on http://selectivizr.com/ shows how far behind it is compared to other Javascript frameworks. It shouldn't be too much of a hassle, and it would fix some of the issues in the issue queue.

Edit:

:lang()
:link
:visited
:target
:hover // this requires adding a special event to the DOM in unsupported browsers, we're not going to do this
:nth-last-child
:nth-of-type
:nth-last-of-type
:first-of-type
:last-of-type
:only-of-type
:root
@MarcusJT

Agreed and upvoted.

(Readers should also see https://github.com/jeresig/sizzle/issues/issue/11 for related discussion on this topic)

@davidmurdoch

updated link: #11

@timmywil timmywil referenced this issue Jan 23, 2012
Closed

:nth-of-type() #11

@timmywil timmywil was assigned Jan 23, 2012
@timmywil timmywil referenced this issue Jan 24, 2012
Closed

Support `:root` #89

@jeffbski

:root is a useful selector, if you are inside of a nested find and want to be able to specify local substitutions and also some at a higher level. Without having access to :root, you can't chain or just deal with a single jquery node.

It simply cleans up the code by being able to have access to :root in your selectors.

@roryokane

Support for many CSS3 selectors, including :nth-of-type() and :root, was removed on purpose in 2008. See John Resig’s blog post about it, linked from Sizzle’s wiki.

(I currently have no opinion on whether those selectors are worth adding back in.)

@MarcusJT
MarcusJT commented May 4, 2012

"What’s fascinating is that no one has ever, ever, requested that these features be added back in. They have virtually zero real-world use and applicability." - not true anymore.

But regardless, IMHO jQuery should be fully compliant with the full range of selectors as defined in the CSS3 spec as a matter of principle, not to mention that some developers might actually want to use them, and it's perfectly reasonable to expect them to be available, rather than to have to find a workaround, such as a substitute selector engine, or perhaps even a jQuery CSS3 polyfill?!

@MarcusJT
MarcusJT commented May 4, 2012

Note that Keith Clark curates a "jQuery extended selectors" plugin (effectively a jQuery/Sizzle CSS3 polyfill) which might make a good starting point for implementing the missing selectors in jQuery core / Sizzle, though there may of course be opportunities for optimization of performance & code size - see http://www.keithclark.co.uk/labs/jquery-extended-selectors/ & https://github.com/keithclark/JQuery-Extended-Selectors

PS - this once again surely proves that there IS demand for these selectors...?

@barraponto

"What’s fascinating is that no one has ever, ever, requested that these features be added back in."

Here I am. @MarcusJT thanks for the polyfill.

@timmywil
Member

Support for :active has been added for 1.8. Other selectors will get more consideration in 1.9 mainly due to time and size constraints. Please upvote your favorite css3 selector that is not yet supported in Sizzle!

@jeffbski

+1 :root - my thoughts are above

@timmywil
Member

Currently, the unsupported selectors are

:link
:visited
:target
:hover // this requires adding a special event to the DOM in unsupported browsers, we're not going to do this
:nth-last-child
:nth-of-type
:nth-last-of-type
:first-of-type
:last-of-type
:only-of-type
:root

I am currently +1 for :link, and don't feel too strongly about the rest.

Note: The link in this ticket from selectivizr is no longer accurate. We do accomodate for empty-string attributes in 1.8.

@barraponto

:target would be handy. :XXXX-of-type is useful.

@Yaffle
Contributor
Yaffle commented Jul 1, 2012

@barraponto, :XXXX-of-type too slow to be usefull

@barraponto

@Yaffle current implementations might be slow, but we can always improve. A user who needs to target the :nth-of-type pseudo-class will select using the type, then filter on node position. Providing :nth-of-type, even if just a wrapper, would make CSS-turned-jquery developers lives easier.

@Yaffle
Contributor
Yaffle commented Jul 3, 2012

but we can always improve

@barraponto, how ?

@barraponto

I didn't read current implementation, but the more eyeballs read it, the more likely it is we find a better implementation.

@ttk
ttk commented Jul 14, 2012

Definitely want to support as many CSS3 selectors are possible. Sure, I agree that they aren't used often, but one can make the same argument about many other features of jQuery. When you need it, then you wish it's there. For example, I have a need for the :nth-of-type selector, and it's a pain to find a workaround. +1 for CSS3 selectors!

@runspired

+1 for :nth-of-type :first-of-type :last-of-type and :link

I often use all four of these in CSS when styling nav components, but they are additionally useful for tables and article styling. For instance, styling the first letter of the first line of the first paragraph of an article.

:link is actually pretty critical and I'm surprised resig ever considered it unnecessary. CSS distinguishes between anchor tags with href and those without when applying default styles, and it is often necessary to mirror this distinction in both direct CSS formatting and programmatic style application.

@MauriceSchoenmakers

+1 :root

@mattbrundage

+1 :nth-* and :*-of-type

Or, better yet, +1 them all. We shouldn't have to think about which CSS3 selectors are still not supported.

@danjo519

There also appears to be an issue relating to jQuery 1.8.2 and the nth-of-type selector relating to tables. Take a look at the following three jsfiddles. The following was tested on Chrome 22 on Linux.

nth-of-type on table (1.8.0) - works as expected - http://jsfiddle.net/XJsrf/4/
nth-of-type on table (1.8.2) - does not work (check console for error) - http://jsfiddle.net/6bf5G/6/
nth-of-type on paragraph (1.8.2) - works - http://jsfiddle.net/Bsksb/

@timmywil
Member

nth-of-type is not yet supported. However, in browsers that support QSA, nth-of-type may work depending on how well it is supported by that browser.

@ngnpope
ngnpope commented Oct 9, 2012

It seems that :target used to work in jQuery 1.7, but has since been broken in 1.8+

See the following: http://jsfiddle.net/gilly3/NPNFg/3/

If you comment out the $.expr[':'].target, it works with 1.7.2 and not with 1.8.2. If you add that bit of code back in it works again in v1.8.2

(I'm using Chromium 18.)

@timmywil
Member
timmywil commented Oct 9, 2012

:target has not yet been supported in Sizzle.

@ngnpope
ngnpope commented Oct 12, 2012

Apologies, but did you look at the example or are you saying that it hasn't officially been supported? Because :target has definitely worked before 1.8 and, even if it hasn't been supported before, the fact that it did and now doesn't is surely a regression?

@timmywil
Member

Sizzle itself will simply defer to QSA: http://jsbin.com/azovir/4/

However, I understand why your example seems to break. Event delegation in jQuery no longer uses the native selector paths (deferring to QSA or matchesSelector) in order to maintain context in all situations. Regardless, since :target has never worked across all browsers, there is no regression.

@ngnpope
ngnpope commented Oct 16, 2012

I see. It is indeed event delegation where I was having the problem - thanks for the explanation.

@gibson042
Member

As of 2ffeccb, Sizzle supports the following:

:nth-last-child
:nth-of-type
:nth-last-of-type
:first-of-type
:last-of-type
:only-of-type
@barraponto

So we're now only missing:

:link
:visited
:target
:hover // this requires adding a special event to the DOM in unsupported browsers, we're not going to do this
:root
@timmywil timmywil pushed a commit to timmywil/sizzle that referenced this issue Dec 14, 2012
Timmy Willison Add :target and :root selector support. Supplements gh-44. 45982ce
@timmywil
Member

After more investigation, support for :link, :visited, and :hover cannot be added without adding events to the DOM to keep track of state. These will remain unsupported to minimize Sizzle's footprint on the DOM. However, :target and :root incoming.

@timmywil timmywil closed this Dec 14, 2012
@markelog markelog pushed a commit to markelog/sizzle that referenced this issue May 26, 2013
Timmy Willison Add :target and :root selector support. Supplements gh-44. 1f3eb4f
@usmonster

Hi folks! I know this is an old closed issue, but I just wanted to know if there were any details available on @timmywil's investigation on ways to support ":hover" and friends? I'm not quite sure that special events would be necessary. Also, what Sizzle-supported browsers (other than IE6) don't already have native, standards-mode ":hover" support? (Tried to engage on IRC in #jquery-dev, but this might be the more appropriate place?)

@timmywil
Member

@usmonster If you can provide a sample implementation to support :hover without adding events to the DOM, we'd be happy to take a look.

This also affects IE7 and some old versions of Safari and Firefox (mobile browsers don't need hover), but the implementation could get used in any browser if the qSA path is not followed for whatever reason.

@usmonster

@timmywil Thanks for the quick response! Though according to Microsoft, IE7 in standards-mode should be ok with :hover.

One possibly easier issue to resolve, though, is that an "unsupported pseudo" syntax error is always thrown when filtering with :hover, regardless of whether or not the browser supports it natively and correctly. The example I mentioned on IRC is that $('body:hover') works, but $('body:hover').is(':hover') throws the error. This seems inconsistent. I think it might be worth it to reserve the error only for browsers that are known to not support the pseudoselector, i.e. "silently succeed" where it can, while still leaving a note in the doc that it's not officially supported (though not explicitly disallowed).

Thoughts?

@timmywil
Member

IE7 in standards-mode should be ok with :hover.

That's CSS. This is about javascript selection. IE7 doesn't have qSA, so how could it support it?

I think it might be worth it to reserve the error only for browsers that are known to not support the pseudoselector

I would be fine with this except we encountered incorrect results in some browsers. It's debatable whether we still care about that though.

@gibson042
Member

One possibly easier issue to resolve, though, is that an "unsupported pseudo" syntax error is always thrown when filtering with :hover, regardless of whether or not the browser supports it natively and correctly.

This looks very much like a request to define Sizzle.selectors.pseudos["hover"] = function() { return false; } for the sake of accepting :hover as valid. I'm willing to consider it, but honestly would rather keep such workarounds in downstream code instead of ours.

@usmonster

That's CSS. This is about javascript selection. IE7 doesn't have qSA, so how could it support it?

@timmywil, you're absolutely right, and I was originally thinking of a workaround to support IE8, which does have qSA.

I'm willing to consider it, but honestly would rather keep such workarounds in downstream code instead of ours.

@gibson042, I agree that a workaround for this inconsistency might be better suited for inclusion in, e.g., @jquery, rather than directly in Sizzle. The main issue it that it's a shame to be using a browser where :hover should work fine, and then it works only inconsistently (even if it's not officially supported).

I take it, then, that I should file an issue there? Unless you're still considering adding the return false; workarounds to silently fail the unsupported-but-valid-CSS3 selectors and just letting the documentation explain, rather than explicitly throwing an error?

@usmonster

(Also, thanks for your informative and enlightening comments on a year+-old closed issue, and great work! :)

@gibson042
Member

Even farther downstream than that, actually. You can set it yourself via jQuery.expr.pseudos as a user of jQuery.

@usmonster

You can set it yourself via jQuery.expr.pseudos as a user of jQuery.

@gibson042 I do know that users can add support for the pseudo themselves, but, as a user, I still consider it inconsistent that jQuery partially supports it, through its background use of qSA. To have certain uses of :hover "silently" succeed and others result in an error is the issue for me. If qSA is available and the browser correctly (or even partially) supports the :hover pseudo, I would advocate that all uses of it in jQuery should be allowed to succeed, rather than only certain kinds of uses needlessly fail. (The alternative, less nice but equally-consistent solution would be to throw an explicit error for all uses of it.) In any case, it can and should by all means remain officially unsupported in the docs, since it won't work for all Sizzle/jQuery-supported browsers. And even though there are some precedents in jQuery for documented features that don't work the same way everywhere due to the quirks and limitations of some browsers, I understand that this is trying to be avoided.

I would be fine with this except we encountered incorrect results in some browsers. It's debatable whether we still care about that though.

@timmywil Do you still have a list of which browsers gave incorrect results? Though I kind of agree that, as long as it's documented as not officially supported, I'm not sure it matters much.

@usmonster

After some more investigation, it seems that the most recent versions jQuery (1.x and 2.x) do indeed behave as expected for pretty much all browsers that support both qAS and :hover--except for IE8 (standards mode). I haven't yet actively looked for where in the support detection code this switch is, but it might be a bug (or more likely I just don't understand why the choice was made).

Related side note: This is further complicated for users of jQuery migrate, which seems to restore the pseudo-selector error on most browsers, including those that wouldn't normally throw the error.

@timmywil
Member

jQuery (1.x and 2.x) do indeed behave as expected for pretty much all browsers that support both qSA

Oh. Right! This is why I initially didn't grok the need for a pseudo that just returns false. We attempt to pass the selector to qSA before calling tokenize. However, if the selector fails qSA for any reason (e.g. it contains a selector extension), tokenize will throw an error. Whatever side we come down on this, I think this issue is now lower in priority.

@gibson042
Member

In any case, it can and should by all means remain officially unsupported in the docs

That's precisely what I'm advocating. :hover is not supported by Sizzle, so using it without explicitly extending Sizzle.selectors.pseudos will result in...

I still consider it inconsistent that jQuery partially supports it, through its background use of qSA. To have certain uses of :hover "silently" succeed and others result in an error is the issue for me.

jQuery doesn't support :hover at all, it just happens to work under certain conditions. Inconsistent behavior is the hallmark of unsupported use.

@usmonster

if the selector fails qSA for any reason (e.g. it contains a selector extension), tokenize will throw an error.

@timmywil That's the part I need to debug in IE8, which seems to be the only browser I've tested so far that unexpectedly fails in certain cases. It's definitely a much lower priority than I originally thought, though.

jQuery doesn't support :hover at all, it just happens to work under certain conditions. Inconsistent behavior is the hallmark of unsupported use.

@gibson042 I think my meaning would have been clearer if I said "I still consider it inconsistent that jQuery even allows it..." I completely understand that it's unsupported, but I think it's reasonable to be consistent if one goes so far as to throw an error when the user attempts to use the unsupported thing. All things considered, it works as expected in probably every case, except for IE8, which seems to pass the qSA test (works for jQuery() and maybe .find()), but then barfs somewhere else down the line (errors on .is() and .filter()-related uses).

It's just a curiosity worth investigating, though clearly very low priority.

@gibson042
Member

All things considered, it works as expected in probably every case

Only because you're not mixing it with buggy or Sizzle-specific selectors. :hover:input, for example, will fail on all browsers.

except for IE8, which seems to pass the qSA test (works for jQuery() and maybe find), but then barfs somewhere else down the line (errors on .is() and .filter()-related uses).

It's because IE8 lacks a matchesSelector:

  1. https://github.com/jquery/jquery/blob/2.1.0/src/traversing/findFilter.js#L81
  2. https://github.com/jquery/jquery/blob/2.1.0/src/traversing/findFilter.js#L32
  3. https://github.com/jquery/jquery/blob/2.1.0/src/traversing/findFilter.js#L48
  4. https://github.com/jquery/sizzle/blob/1.10.18/src/sizzle.js#L845
  5. https://github.com/jquery/sizzle/blob/1.10.18/src/sizzle.js#L287
  6. https://github.com/jquery/sizzle/blob/1.10.18/src/sizzle.js#L1893
@usmonster

@gibson042 Ah, thanks for this! Very helpful, and probably answers all of my questions. :]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment