SSR-рендеринг
Masonry-раскладка зависит от реально измеренных размеров, которых не существует на сервере — и не существует ещё один клиентский кадр до первого измерения движка. Вместо того чтобы рендерить пустоту (или вспышку нестилизованного/наложенного друг на друга содержимого) в этом окне, каждый адаптер вместо этого рендерит приближение через CSS columns, а затем сменяет его на точную transform-раскладку в тот самый момент, когда движок реально измеряет карточки — в том же кадре, без заметной вспышки.
Число колонок для SSR-приближения
MasonryOptions.ssrColumns
ssrColumns
number · опционально
Явное число колонок для чистого CSS-приближения columns, которое адаптер фреймворка рендерит до появления движка. Сам движок никогда не читает это поле — оно резолвится через экспортируемый ядром хелпер resolveSsrColumns() и целиком используется адаптером, так что задавать его имеет смысл, даже несмотря на то, что сам createMasonryEngine() с ним ничего не делает.
Порядок разрешения (через resolveSsrColumns(spec, explicit)):
- Явный
ssrColumnsпобеждает всегда. - Иначе, если
columns(илиrows, приdirection: 'horizontal') уже является конкретнымnumberили объектом с брейкпоинтами — измерение для их разрешения не требуется — значение переиспользуется как есть (объект с брейкпоинтами резолвится в своё значениеdefault, поскольку реальная ширина контейнера ещё не известна). 'auto'или не заданное значение откатывается к консервативному дефолту2— безопасно и на мобильной, и на десктопной ширине, никогда неудобно узко.
const engine = createMasonryEngine(container, {
columns: 'auto', // реальное число колонок разрешится, как только контейнер реально измерят
ssrColumns: 3, // но до этого рендерить приближение через CSS columns на 3 колонки
})От CSS-приближения к реальной раскладке
До первого срабатывания события layout движка <MasonryGrid> рендерит свой корневой элемент с:
columns: <разрешённый ssrColumns>;
column-gap: <разрешённый поперечный отступ>px;а каждая обёртка карточки получает break-inside: avoid плюс margin-bottom: <главный отступ>px — прилично выглядящее, пусть и не попиксельно точное, приближение masonry-раскладки исключительно средствами CSS, которые браузер уже понимает, без единой строчки JavaScript. Именно это рендерится во время SSR (нет window, нет движка вообще) и один клиентский кадр до завершения первого реального измерения при гидратации.
В момент первого срабатывания события layout движка адаптер полностью убирает этот CSS (не остаётся ни columns, ни column-gap, ни break-inside) и переключает каждую карточку на реальную расстановку через position: absolute + transform: translate() — управляется булевым флагом (hasLaidOut), который собственная реактивность Vue/React применяет ещё до следующей отрисовки, так что нет ни одного видимого кадра, где присутствовали бы обе раскладки одновременно или где содержимое дёргалось бы между ними.
Обёртку вроде <ClientOnly>/паттерн useIsomorphicLayoutEffect нигде не нужно добавлять самостоятельно — оба адаптера, и Vue, и React, уже сами обрабатывают разделение сервер/клиент внутри (собственный useLayoutEffect React предупреждает, если срабатывает на сервере, поэтому адаптер сам откатывается там на useEffect).