Style matching tries a third of the rules, queries prepare their selector once, sibling walks stay fast
Pages restyle and query themselves faster, and old pages without a doctype now style correctly. Style matching tries about a third of the rules it used to, because rules written for the page root, for an attribute, or wrapped in :where() and :is() go straight to the elements they can match. querySelector, matches and closest prepare a selector once instead of again for every element they test, walking a long list with nextSibling no longer slows down as the list grows, and reading an element's parent, children, siblings, name, id or class skips the full member lookup. In pages without a doctype, class and id selectors ignore letter case, as they do in the reference browser.
Style matching tries a third of the rules
To style an element the engine only tries the rules whose last part could match it: rules for its tag, its classes or its id. A rule whose last part had none of those was tried against every element on the page. A code-hosting page has over a thousand such rules - hundreds of theme blocks written for the page root, rules keyed on an attribute such as a colour mode, and design-system rules wrapped in :where() - so every full restyle tried three million rules to make twenty-six thousand matches. Rules for the page root now go to the root element only, attribute rules to elements carrying that attribute, and :where(.x) and :is(.x) rules to elements with class x. The matcher still decides every match; it is simply asked a third as often.
Queries prepare their selector once
querySelectorAll already prepared its selector once for the whole search. querySelector, matches and closest split the selector list and read every part again for each element they tested. All four now share one prepared form, kept for the next call with the same selector, with simple selectors such as a class or a tag compared directly.
Walking siblings stays fast on long lists
nextSibling and previousSibling found an element's position by scanning its parent's children on every read, so walking a list of n items cost n times n steps. The position of the last answer is now remembered and checked first, so each step of a walk is one comparison. The most read node links and names - parent, children, siblings, nodeName, tagName, id and className - are also answered directly from the document instead of through the full member lookup, and every such answer can be checked against the full lookup with a switch.
What changed 5 changes
Try it in your browser
Each check runs live in the browser you are reading with. Nothing is sent anywhere.