I noticed today that jQuery's :visible
selector shows an unexpected behaviour when combined with an attribute selector. Its behaviour differs depending on
a) whether it is used inline or within the filter method
b) the type of attribute selector it's combined with
Examples:
Given the following markup
<input required name="name" type="text" />
The following is true for jQuery
$('[required="required"]').filter(':visible').length == 0; //true
$('[required="required"]:visible').length == 0; //false - why does jquery find the input?
The disabled
attribute shows similar behaviour. However, data attributes do not show the same behaviour:
Given the following markup
<input data-boolean name="name" type="text" />
The following is true for jQuery
$('[data-boolean="true"]').filter(':visible').length == 0; //true
$('[data-boolean="true"]:visible').length == 0; //true
Here's a link to a fiddle that demonstrates the problem.
I wouldn't expect [required="required"] to match an element with a blank required attribute, and it doesn't when used as a selector on its own, but it does when paired with the :visible selector. Why is this?
The root cause of the difference seems to be that Sizzle (the non-native selector code in jQuery) matches boolean attributes like required
when an explicit test is made for the formal default attribute value. The native querySelectorAll()
code, however, does not, unless the attribute actually had the value in the original HTML.
Boolean selectors like required
or readonly
can be expressed in HTML without a value, but that implies that the value is to be taken as the attribute name itself.
When you use a pseudo-class like :visible
, then Sizzle realizes that the native code won't work so it takes over. It's not the :visible
test itself that causes the problem; you get the same effect with :text
or any other extension supported by Sizzle (and which doesn't change the sense of the selector, obviously).
Personally I would consider this a bug, though it may be somewhat difficult to fix because the attribute value really is reported as being required
when the DOM node is interrogated via getAttribute()
.
If HTML code were to be meticulously written with the attributes fully specified:
<input required=required ...>
then there'd be no perceived difference, but that seems a little burdensome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With