content-visibility vs Virtualization for Long Lists
Run a matched 2,000-row fixture, inspect DOM and anchoring ownership, test find and focus behavior, and export a requirement-driven strategy receipt.
content-visibility vs virtualization is a choice about which long-list costs stay in the browser and which move into application code. This comparison uses one bounded 2,000-row fixture to record DOM nodes, rendering, long tasks, anchors, focus, find behavior, and dynamic-height error before recommending full DOM, CSS skipping, windowing, or measure first.
content-visibility vs virtualization: define the cost
content-visibility vs virtualization is not a shorthand for “CSS versus JavaScript.” The two strategies remove different work. CSS content-visibility can let the browser skip rendering work for off-screen subtrees while those elements remain in the DOM. Windowed list virtualization keeps only a moving slice of rows mounted, reducing DOM and framework work while making the application own more geometry and lifecycle.
Start with the bottleneck. Record row count, DOM nodes, startup scripting, style and layout, paint, retained memory, scroll work, long tasks, dynamic-height changes, browser find expectations, focus navigation, selection persistence, printing, deep links, and assistive-technology requirements. A large list performance problem may come from data transforms or event handlers that neither rendering strategy fixes.
The CSS Containment specification defines content visibility and skipped contents. It does not promise removal of DOM creation, framework reconciliation, or application state. Treat it as a rendering boundary with platform-specific behavior to verify.
Use the long animation frames diagnostic model to locate expensive work before redesigning the list. The matched lab freezes 2,000 dependency-free rows and compares three architecture receipts. It can recommend measure first when the declared constraints or evidence do not justify either optimization.
| Strategy | DOM | Rendering | Application-owned risks |
|---|---|---|---|
| Full DOM | All rows | All rows | Startup and scale |
| content-visibility | All rows | Browser skips off-screen work | Intrinsic size and platform verification |
| Virtualization | Window only | Window only | Height, anchor, focus, search, semantics |
Reading rule: labels, order, values, shapes, and line styles carry the conclusion; color is supplementary.
Map three long-list architectures
Full DOM gives the browser all rows and keeps native document operations straightforward. It is often correct for modest lists, searchable documents, print-heavy views, and interfaces where every row may need immediate semantic presence. Its cost is proportional to the complete tree and application work.
CSS content-visibility keeps the complete tree but allows off-screen subtrees to skip style, layout, and paint work under defined conditions. An intrinsic-size estimate stabilizes scroll geometry before the real subtree is rendered. The browser owns reveal timing, but the application still created the nodes and may still reconcile their components.
List virtualization replaces off-screen rows with spacers or translated windows. It can cut node count dramatically, yet must own range calculation, overscan, row identity, height measurement, anchor correction, focus handoff, selection state, find behavior, deep linking, and cleanup. “Only 40 rows mounted” is not the full contract.
The ownership figure shows these layers explicitly: data, DOM, render skip, height model, scroll anchor, focus, search, and accessibility semantics. content-visibility vs virtualization becomes a tractable decision when every layer has an owner. A content-visibility vs virtualization review should identify that owner before comparing syntax. If the bottleneck is a long synchronous filter, use scheduler.yield for responsive long tasks or move work rather than expecting either list architecture to erase it.
Build one matched 2,000-row fixture
A valid comparison uses identical data, row markup, typography, interaction handlers, container size, and user sequence. The lab creates 2,000 deterministic rows with stable IDs, short and long text classes, one selectable action, and a seeded variable-height pattern. No framework or network request is involved.
For each strategy, record provenance. DOM node counts and elapsed local task durations can be observed. Estimated style, paint, memory, and off-screen work in this artifact are models, labeled as such. A mutation that reports a model as a measurement must fail. Browser and framework conclusions require target builds with their own traces.
The sequence is bounded: initial render, ten page-sized scrolls, jump to row 1,400, expand a variable-height row above the viewport, focus a row action, search for a unique token, and return to the anchor. Each phase emits row range, node count, scroll offset, anchor ID, focus ID, and modeled height error.
Use PerformanceObserver to debug INP in a real application to connect interactions with event and rendering work. The synthetic lab cannot reproduce production component cost, but it can make architecture responsibilities and failure fixtures concrete before a library choice is embedded in the product.
Compare startup and scroll work
Full DOM pays creation and framework cost up front, then lets native scrolling operate over the complete document. content-visibility:auto may reduce initial rendering below the fold while preserving DOM cost. A virtual window reduces mounted nodes but executes range, placement, measurement, and recycling logic as scrolling proceeds.
Record startup scripting separately from first visible rendering. A strategy can improve paint while leaving a costly component mount unchanged. During scroll, record task duration, number of range changes, rows measured, style and layout work, and dropped or delayed input. Use medians and tails over repeated identical sequences, not one warm pass.
The fixture ledger exposes observed and modeled fields. DOM node count, focus result, and anchor displacement are observed locally. Render cost is represented by a deterministic unit model so the lab remains stable and zero-network. The receipt explicitly refuses to convert those units into universal milliseconds.
content-visibility vs virtualization should produce a nondominated frontier rather than a winner. Full DOM may satisfy native find and focus with acceptable cost. CSS skipping may preserve that behavior while reducing rendering. Windowing may be necessary for severe DOM or framework limits. If all three pass or evidence is weak, choose the simplest architecture and schedule a target-device trace.
- Estimate row 620 at 64 pixels.
- The row expands above the viewport.
- Measure its actual height at 112 pixels.
- Compute a positive 48-pixel delta.
- Add 48 pixels to scroll offset so visible row 1,400 stays anchored.
Reading rule: labels, order, values, shapes, and line styles carry the conclusion; color is supplementary.
Handle variable heights and scroll anchoring
Fixed-height virtualization is simple because index maps directly to offset. Real rows wrap, expand, load media, or reveal validation. An estimate that is wrong above the viewport shifts every following offset. The virtualizer must measure actual heights, update its prefix sums, and compensate scroll position so the reader’s anchor does not jump.
The height timeline figure begins with an estimated spacer, expands row 620 above visible row 1,400, applies a measured delta, and shows two outcomes: uncompensated jump or restored anchor. In content-visibility vs virtualization, these estimates belong to different owners. IDs and numeric offsets make the conclusion legible without animation or color.
CSS content-visibility uses the contain-intrinsic-size property as a placeholder for skipped contents. MDN’s content-visibility reference explains the property and related containment behavior. Estimates still matter for scrollbar stability; actual platform behavior should be tested with the content and browsers you ship.
The independent oracle recomputes the prefix-height ledger from raw row heights and confirms the corrected offset. It kills a mutation that treats dynamic rows as fixed. For either optimization, preserve stable row identity, reserve known media dimensions, and keep correction bounded. A strategy that saves startup work but repeatedly moves the reader’s place has failed the product requirement.
Test search, focus, selection, and accessibility
Native browser find can search text present in the document, but virtualized rows that are not mounted may be absent from the current page. Product search over the data model can compensate, but it must reveal and focus the result, communicate position, and preserve the query independently of browser find. Do not silently change the user contract.
Focus creates a similar ownership problem. If a focused row leaves the virtual window, decide whether it stays mounted, focus moves intentionally, or scrolling is constrained. Recycling a focused element for a different row is especially dangerous. Selection belongs to stable row IDs, never node positions.
The WAI-ARIA Authoring Practices describe an ARIA feed pattern for dynamically loaded article sequences. That pattern is not a blanket prescription for every list, but it illustrates explicit reading order, position metadata, focus movement, and loading behavior. Test the actual semantics with browser and assistive-technology combinations.
The lab asks whether browser find, unbroken tab order, persistent multi-selection, print, and complete semantic presence are hard requirements. Its oracle rejects windowing when those requirements lack an implemented alternative. An accessible tree view in React offers a related example of state, focus, and identity staying separate from rendered node positions.
| Evidence and requirement pattern | Candidate |
|---|---|
| Complete native document behavior within budgets | Full DOM |
| Measured off-screen rendering cost, DOM acceptable | content-visibility |
| Proven DOM ceiling, owned behavior contracts | Virtualization |
| List already passes or bottleneck is elsewhere | Neither |
| Modeled evidence or unresolved accessibility | Measure first |
Reading rule: labels, order, values, shapes, and line styles carry the conclusion; color is supplementary.
Use a requirement matrix, including neither
Choose full DOM when complete native document behavior is required and target traces stay within startup, memory, and interaction budgets. Choose CSS content-visibility when rendering below the fold is the measured problem, keeping all rows in the DOM is valuable, and intrinsic-size behavior is acceptable. Choose list virtualization when DOM or framework cost is proven material and the team will own range, height, focus, search, and semantic contracts.
Choose neither optimization when the list is small enough, the bottleneck is elsewhere, or complexity would outrun measured benefit. Choose measure first when evidence is modeled, target devices are missing, or accessibility requirements are unresolved. These are first-class outcomes, not indecision.
The decision matrix gives hard requirements priority over estimated speed. Browser find, print completeness, and unrestricted tab order can eliminate a naïve window. Severe DOM caps can eliminate full DOM and CSS skipping. High height variance raises the implementation cost of windowing. Framework reconciliation cost weakens the case for CSS-only skipping.
content-visibility vs virtualization is therefore an ownership decision with a performance input. The smallest strategy that passes the full matrix wins provisionally. Keep the matrix beside the trace so a future engineer can see whether the decision came from a DOM ceiling, a rendering bottleneck, or a behavior promise.
Export a fallback and regression receipt
The strategy receipt contains fixture version, row generator seed, count, height distribution, viewport, interaction sequence, requirement matrix, observed fields, modeled fields, architecture ownership, oracle decision, unresolved risks, and fallback. It never labels synthetic cost units as production timings.
JSON supports regression comparison; CSV exposes one phase per row. Reparse both, verify provenance columns, stable row order, anchor calculations, focus and find outcomes, and decision parity. Mutation fixtures ignore DOM cost, assume fixed heights, hide browser-find behavior, drop focus requirements, and relabel modeled values. Every mutation must disagree with the independent oracle or fail validation.
After choosing, implement an escape hatch. A virtualized view may need an accessible full-results or print mode. A CSS-skipped view may need containment disabled for platform defects. Full DOM may need pagination or server filtering when data grows. Record the trigger and ownership of that fallback.
Finally, run the production component on representative low- and mid-tier devices with realistic data and assistive technology. Compare startup, memory, scroll, INP, anchor movement, find, focus, and selection against the receipt’s budgets. Revisit content-visibility vs virtualization when row complexity, data size, browsers, or behavior promises change; do not refresh the date for cosmetic edits alone.
Runnable local artifact — The lab records one local synthetic fixture and modeled ownership costs; it does not establish universal browser, framework, assistive-technology, or device performance.
Compare full DOM, content-visibility, and windowing over one matched fixture; inspect height, focus, find, and cost evidence; export a provisional strategy receipt.