Virtualization supports variable-height items #64964
Draft
+829
−19
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.
High level requirements:
#25058 (comment)
This is WIP. Sample changes are not part of the fix.
Visualization of how the sample works with the initial implementation (scrolling with the scroll & jumps with Ctrl + Home or Ctrl + End):
Working-Variable-Height.mp4
Description
Scenarios that we should consider (test/document/log as a separate issue):
Dynamic Height Changes After Initial Render - covered, test added (
DynamicContent_ItemHeightChangesUpdateLayout)If an item's height changes after it's been measured (e.g., image loads, async content expands, user expands an accordion), the cached measurement should not become stale. If an item that is out of view expands (e.g. item 2 when view is focused on items 10-14), current view does not shift.
Window/Container Resize - covered, tests added (
VariableHeight_ContainerResizeWorks)When the container width changes, text wrapping changes, causing item heights to change. The cached measurements become invalid.
Extreme Height Variance
If items vary from 20px to 2000px, the average-based estimation for un-measured items can be wildly inaccurate, causing large scroll jumps.
Memory Pressure from Measurement Cache
_measuredHeightsdictionary grows unbounded. With 1 million items and user scrolling through all of them, we store 1 million floats. Very large datasets or long user sessions with extensive scrolling might be problematic.Scroll Position Stability (Scroll Anchoring)
When spacer heights recalculate after measurements update, the browser may "jump" even with overflow-anchor: none. Users might see content shift.
ItemsProviderwith Variable Heights - covered, async tests added, slow big load tested manually (see the video)Currently we test with
Items(synchronous). When using asyncItemsProvider, measurements happen as items load. If loading is slow, we might calculate wrong positions.Async-delay.mp4
CSS Transform/Scale on Container
We have
getCumulativeScaleFactor()but it only checks transform matrix. Other CSS that affects layout (zoom, perspective) might not be handled.RTL (Right-to-Left) Layout
Height calculations should be unaffected, but scroll behavior and spacer positioning might differ.
Horizontal Virtualization Interaction
If someone uses Virtualize inside a horizontal scroll container, our height-based logic doesn't apply. This is probably out of scope, but worth documenting.
Placeholder Height Mismatch
Placeholders use
ItemSizefor height. If actual items are much taller/shorter, there's a visual jump when the real item replaces the placeholder. What would happen with placeholders with heights very different from actual content?First Item at Non-Zero Index
Related to issue Virtualize first render has upper spacer #64029. If the first visible item isn't index 0, measurements may start from wrong indices.
Empty or Single-Item Lists
Items Collection Mutations
If items are added/removed from the
Itemscollection, cached measurements reference stale indices. Adding items at beginning, removing items in middle etc.Test on Multiple Browsers
Different browsers may fire callbacks at slightly different thresholds or with different batching. Chrome, Firefox, Safari all throttle scroll events differently.
getBoundingClientRect()returns sub-pixel values that differ by browser.scrollTopmay round differently (integer vs float).IntersectionObserveris a core of virtualization feature. it's mostly standarized acros browsers but edge cases might exist. It would be good to be aware of them.Contributes to #25058.