aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>2019-08-19 18:41:03 +0200
committerGitHub <noreply@github.com>2019-08-19 18:41:03 +0200
commitdf6a7f7f0f615149266b1a51064293b748b29900 (patch)
tree3a738ca53fe3c9eabc5fd4db4d8d4ec8c93217aa /src
parent7bdf307b51e4d4a891b123a96d4899e31bfba024 (diff)
downloadjquery-df6a7f7f0f615149266b1a51064293b748b29900.tar.gz
jquery-df6a7f7f0f615149266b1a51064293b748b29900.zip
Selector: Leverage the :scope pseudo-class where possible
The `:scope` pseudo-class[1] has surprisingly good browser support: Chrome, Firefox & Safari have supported if for a long time; only IE & Edge lack support. This commit leverages this pseudo-class to get rid of the ID hack in most cases. Adding a temporary ID may cause layout thrashing which was reported a few times in [the past. We can't completely eliminate the ID hack in modern browses as sibling selectors require us to change context to the parent and then `:scope` stops applying to what we'd like. But it'd still improve performance in the vast majority of cases. [1] https://developer.mozilla.org/en-US/docs/Web/CSS/:scope Fixes gh-4453 Closes gh-4454 Ref gh-4332 Ref jquery/sizzle#405
Diffstat (limited to 'src')
-rw-r--r--src/selector.js29
-rw-r--r--src/selector/support.js17
2 files changed, 35 insertions, 11 deletions
diff --git a/src/selector.js b/src/selector.js
index 913f7486f..3e187a159 100644
--- a/src/selector.js
+++ b/src/selector.js
@@ -4,12 +4,13 @@ define( [
"./var/indexOf",
"./var/pop",
"./var/push",
+ "./selector/support",
// The following utils are attached directly to the jQuery object.
"./selector/contains",
"./selector/escapeSelector",
"./selector/uniqueSort"
-], function( jQuery, document, indexOf, pop, push ) {
+], function( jQuery, document, indexOf, pop, push, support ) {
"use strict";
@@ -230,24 +231,30 @@ function find( selector, context, results, seed ) {
// Thanks to Andrew Dupont for this technique.
if ( nodeType === 1 && rdescend.test( selector ) ) {
- // Capture the context ID, setting it first if necessary
- if ( ( nid = context.getAttribute( "id" ) ) ) {
- nid = jQuery.escapeSelector( nid );
- } else {
- context.setAttribute( "id", ( nid = expando ) );
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
+
+ // We can use :scope instead of the ID hack if the browser
+ // supports it & if we're not changing the context.
+ if ( newContext !== context || !support.scope ) {
+
+ // Capture the context ID, setting it first if necessary
+ if ( ( nid = context.getAttribute( "id" ) ) ) {
+ nid = jQuery.escapeSelector( nid );
+ } else {
+ context.setAttribute( "id", ( nid = expando ) );
+ }
}
// Prefix every selector in the list
groups = tokenize( selector );
i = groups.length;
while ( i-- ) {
- groups[ i ] = "#" + nid + " " + toSelector( groups[ i ] );
+ groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
+ toSelector( groups[ i ] );
}
newSelector = groups.join( "," );
-
- // Expand context for sibling selectors
- newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
- context;
}
try {
diff --git a/src/selector/support.js b/src/selector/support.js
new file mode 100644
index 000000000..86cd2d9ae
--- /dev/null
+++ b/src/selector/support.js
@@ -0,0 +1,17 @@
+define( [
+ "../var/document",
+ "../var/support"
+], function( document, support ) {
+
+"use strict";
+
+// Support: IE 9 - 11+, Edge 12 - 18+
+// IE/Edge don't support the :scope pseudo-class.
+try {
+ document.querySelectorAll( ":scope" );
+ support.scope = true;
+} catch ( e ) {}
+
+return support;
+
+} );