Skip to content

Commit 53b7f5d

Browse files
committed
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 jquery/jquery#4453 Ref jquery/jquery#4454 Ref jquery/jquery#4332 Ref gh-405
1 parent 11767a1 commit 53b7f5d

File tree

6 files changed

+97
-22
lines changed

6 files changed

+97
-22
lines changed

dist/sizzle.js

+27-10
Original file line numberDiff line numberDiff line change
@@ -329,24 +329,30 @@ function Sizzle( selector, context, results, seed ) {
329329
// Thanks to Andrew Dupont for this technique.
330330
if ( nodeType === 1 && rdescend.test( selector ) ) {
331331

332-
// Capture the context ID, setting it first if necessary
333-
if ( ( nid = context.getAttribute( "id" ) ) ) {
334-
nid = nid.replace( rcssescape, fcssescape );
335-
} else {
336-
context.setAttribute( "id", ( nid = expando ) );
332+
// Expand context for sibling selectors
333+
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
334+
context;
335+
336+
// We can use :scope instead of the ID hack if the browser
337+
// supports it & if we're not changing the context.
338+
if ( newContext !== context || !support.scope ) {
339+
340+
// Capture the context ID, setting it first if necessary
341+
if ( ( nid = context.getAttribute( "id" ) ) ) {
342+
nid = nid.replace( rcssescape, fcssescape );
343+
} else {
344+
context.setAttribute( "id", ( nid = expando ) );
345+
}
337346
}
338347

339348
// Prefix every selector in the list
340349
groups = tokenize( selector );
341350
i = groups.length;
342351
while ( i-- ) {
343-
groups[ i ] = "#" + nid + " " + toSelector( groups[ i ] );
352+
groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
353+
toSelector( groups[ i ] );
344354
}
345355
newSelector = groups.join( "," );
346-
347-
// Expand context for sibling selectors
348-
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
349-
context;
350356
}
351357

352358
try {
@@ -626,6 +632,17 @@ setDocument = Sizzle.setDocument = function( node ) {
626632
}
627633
}
628634

635+
// Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
636+
// Safari 4 - 5 only, Opera <=11.6 - 12.x only
637+
// IE/Edge & older browsers don't support the :scope pseudo-class.
638+
// Support: Safari 6.0 only
639+
// Safari 6.0 supports :scope but it's an alias of :root there.
640+
support.scope = assert( function( el ) {
641+
docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
642+
return typeof el.querySelectorAll !== "undefined" &&
643+
!el.querySelectorAll( ":scope fieldset div" ).length;
644+
} );
645+
629646
/* Attributes
630647
---------------------------------------------------------------------- */
631648

0 commit comments

Comments
 (0)