Skip to content

Editor: Stop :has() selectors recalculating the whole document on every block selection - #81471

Open
Mamaduka wants to merge 1 commit into
trunkfrom
perf/block-selection-has-selectors
Open

Editor: Stop :has() selectors recalculating the whole document on every block selection#81471
Mamaduka wants to merge 1 commit into
trunkfrom
perf/block-selection-has-selectors

Conversation

@Mamaduka

Copy link
Copy Markdown
Member

What?

Related #81457.

Rewrites four :has() rules in the editor and interface styles so that each :has() compound is the subject of its own rule.

Why?

Clicking a paragraph in a 1000-paragraph post ran about 8 full document-style recalcs in the post.php frame. The cause is body:has(.editor-editor-interface.is-distraction-free) #wpadminbar { display: none }. Blink treats a :has() whose subject sits below the anchor differently from one where the anchor is the subject: it cannot tell which descendants are affected, so it flags the anchor's entire subtree and recalculates it on every DOM change during the React commit. The same pattern appeared in the revisions timeline and the collab sidebar rules.

Splitting the distraction-free rule in two confirmed where the cost was. The inherited custom property half is free, and the #wpadminbar half accounts for all of it.

How?

The distraction-free state now reaches the admin bar through a second inherited custom property, so body stays the subject of its own :has(). The revisions timeline rules are unnested, since their subjects exist only in revisions mode and do not require the extra scoping. The collab sidebar header is targeted by its own class instead of a :has() on the skeleton sidebar.

Results

Measured across two real builds with the arms alternating within one session, since sequential A/B blocks are not reliable at this size.

Metric Trunk This PR
Selecting blocks perf metric (median of 40 clicks) 32.86 ms 27.32 ms
First click after load (median) 55.5 ms 43.6 ms
Style recalc, first click 20.3 ms 6.3 ms
Elements recalculated, first click 6178 476
Largest single recalc pass 850 elements 142 elements
BODY subtree invalidations per click 8 0

The document has 792 elements, so the whole document recalcs are gone.

The Selecting blocks metric discards the first click, so it reports the steady state improvement of about 17 percent rather than the larger first click one. Head won all four rounds with no overlap between the per-round ranges.

Testing Instructions

Some of these have e2e test coverage, so the smoke test affected features:

  • Enabled distraction-free mode. The adminbar should be hidden.
  • Open editor revisions. The sidebar should be rendered as before, no double scrollbars.
  • The floating notes sidebar shouldn't render a header and shadow.

Testing Instructions for Keyboard

Same.

Use of AI Tools

Assisted by Claude

@Mamaduka Mamaduka self-assigned this Aug 12, 2026
@Mamaduka Mamaduka added the [Type] Performance Related to performance efforts label Aug 12, 2026
@github-actions github-actions Bot added [Package] Editor /packages/editor [Package] Edit Post /packages/edit-post [Package] Edit Site /packages/edit-site labels Aug 12, 2026
@github-actions

Copy link
Copy Markdown

Size Change: +80 B (0%)

Total Size: 7.71 MB

📦 View Changed
Filename Size Change
build/styles/edit-post/style-rtl.css 3.34 kB +17 B (+0.51%)
build/styles/edit-post/style-rtl.min.css 1.99 kB +13 B (+0.66%)
build/styles/edit-post/style.css 3.34 kB +17 B (+0.51%)
build/styles/edit-post/style.min.css 1.99 kB +13 B (+0.66%)
build/styles/edit-site/style-rtl.css 21.6 kB +16 B (+0.07%)
build/styles/edit-site/style-rtl.min.css 17.7 kB +13 B (+0.07%)
build/styles/edit-site/style.css 21.6 kB +17 B (+0.08%)
build/styles/edit-site/style.min.css 17.7 kB +13 B (+0.07%)
build/styles/editor/style-rtl.css 31.7 kB -12 B (-0.04%)
build/styles/editor/style-rtl.min.css 27 kB -7 B (-0.03%)
build/styles/editor/style.css 31.8 kB -13 B (-0.04%)
build/styles/editor/style.min.css 27 kB -7 B (-0.03%)

compressed-size-action

@Mamaduka

Copy link
Copy Markdown
Member Author

The Selecting blocks metric discards the first click.

I think we should remove this throwaway case, as it can mask an actual regression. For example, the editable root change (removed in #81184) affected the first selection significantly, but switching between blocks was cheaper. So, as a user opening a large post, the first selection was junky, but this was missed by our specs.

The downside is that our metrics will probably jump, but they'll show numbers close to the actual median.

cc @ellatrix, @youknowriad, @tyxla

@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@Mamaduka

Copy link
Copy Markdown
Member Author

Here are the metrics from the last two CI runs.

Screenshots

CleanShot 2026-08-12 at 13 33 45 CleanShot 2026-08-12 at 14 33 59

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

Labels

[Package] Edit Post /packages/edit-post [Package] Edit Site /packages/edit-site [Package] Editor /packages/editor [Type] Performance Related to performance efforts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant