perf(home): grid rows + content-visibility, search filters in place (metric: TBT / Style & Layout) - #7
Open
phyceClaw wants to merge 1 commit into
Open
Conversation
Metric: Total Blocking Time / Style & Layout (mobile home perf 34) The homepage renders all 2048 plugins, giving 20,590 DOM nodes. Lighthouse mobile spends 2,690 ms in Style & Layout and 1,646 ms in Rendering, and Total Blocking Time is 3,162 ms. content-visibility lets the browser skip style, layout and paint for rows that are off screen. It does nothing on a <table>: containment does not apply to internal table elements. Measured in Chrome 151 over 2048 real rows, applying it to <tr> is not merely a no-op but slightly negative, because Chrome pays for bookkeeping it cannot use: <table> today 321.5 ms (412px viewport) <table> + content-visibility 319.5 ms grid rows + content-visibility 50.3 ms -84.4% So the rows become grid boxes with ARIA table roles. Each row repeats the column track list instead of using `subgrid`. content-visibility implies layout containment, and containment forces a subgrid to become an independent grid: the first attempt looked correct in review but rendered every cell full-width, 241px rows instead of 41px. An explicit template per row keeps columns aligned precisely because it does not depend on sibling content. Verified against the compiled CSS that column offsets match between row 0 and row 900. contain-intrinsic-size uses the measured row heights (41px, and 61px below the sm breakpoint where the description wraps to three lines) so the scrollbar stays honest. The `auto` keyword means a row's real height is remembered once it has been rendered. The header search now filters the list in place on the homepage rather than opening a dropdown over the content it is already showing; elsewhere it is unchanged. Ctrl/Cmd+F focuses that box - browser find only matches rendered text, while the search box matches author and tags across every plugin. The shared query is provided by AppLayout rather than module scope so it is per app instance under SSR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Metric targeted: Total Blocking Time (and the Style & Layout / Rendering time behind it)
Homepage mobile scores 34. It renders all 2048 plugins — 20,590 DOM nodes — and Lighthouse mobile spends:
Across all ten pages I audited, the mobile score tracks DOM size almost exactly (
/tophas 802 nodes and scores 87;/top/absolutehas 24,613 and scores 49). This is the first of four PRs — one per heavy page.Why not just add
content-visibilityto the<tr>Because it does nothing. CSS containment doesn't apply to internal table elements, so the declaration is accepted and ignored. Measured in Chrome 151 over 2048 real rows at a 412 px viewport (median of 5, Chrome's own
LayoutDuration+RecalcStyleDuration):<table>today<table>+content-visibilityon<tr>content-visibilitycontent-visibilityAt 1350 px: 369.7 ms → 60.4 ms (−83.7%).
So the rows have to stop being table elements. They become grid boxes carrying
role="table"/"rowgroup"/"row"/"columnheader"/"cell", so the semantics survive.The subgrid trap
Each row repeats the column track list rather than using
subgrid.content-visibilityimplies layout containment, and containment forces a subgrid to become an independent grid — it silently loses the parent's tracks. My first version looked right in review and rendered every cell full-width, at 241 px rows instead of 41 px. An explicit per-row template is immune to this because it doesn't depend on sibling content.I verified in Chrome that column offsets are identical between row 0 and row 900, at both 412 px and 1350 px.
Row height / scrollbar honesty
contain-intrinsic-sizeuses measured heights — 41 px, and 61 px belowsmwhere the description wraps to three lines. Theautokeyword means a row's true height is remembered once rendered, so the estimate only matters for rows never yet on screen. Document height comes out within ~4% of today's at desktop width.Visible change: rows render 41 px instead of 48 px (desktop) — slightly denser. On mobile they are 61 px vs 48 px, so the page is longer there, because the fixed column tracks give the description less width than the old auto table layout did.
Search behaviour (as requested)
provided byAppLayoutrather than living at module scope, which would be shared across requests under SSR.Verification
npm run build,vue-tsc --noEmit,eslint(clean on all touched files) and the PHP suite all pass. The measurements above come from the compiled CSS of this branch rendered over the real 2048-plugin dataset in Chrome 151, not from a synthetic mock.Note on conflicts
Touches
Index.vue, which #5 also touches. I've aligned the colours here with #5'stext-gray-400and carried over its hiddenStatscolumn label, so whichever lands first the other should rebase cleanly.🤖 Generated with Claude Code