StringMasonry Module
A lightweight, high-performance masonry layout engine. StringMasonry arranges child elements into optimal vertical columns, minimizing gaps and handling dynamic content like images and DOM mutations automatically. It uses transform for movement, ensuring 60fps animations during layout shuffles.
Activation primer: Add
string="masonry"to the container element. The module will automatically position all direct children of that container.
HTML Attributes
| Attribute | Type | Default | Controls | Practical notes |
|---|---|---|---|---|
string-masonry-cols | breakpoint-dimension | 2|640:3|1024:4 | Number of columns at different breakpoints | Format: val|bp:val|bp:val. E.g., 1|768:2|1200:3 |
string-masonry-gap | breakpoint-dimension | 16|640:24|1024:32 | Gutter size (px) between items and columns | Format matches cols. Controls both horizontal and vertical spacing. |
string-masonry-mode | string (auto|manual) | auto | Layout triggers | auto reacts to resize/mutations. manual waits for external events or prop updates. |
string-masonry-position-time | child attribute | 0.6 (from default) | Duration (s) for position transitions | Add to child items, not the container. |
string-masonry-position-easing | child attribute | cubic-bezier(0.25, 1, 0.5, 1) | Easing curve for movement | Add to child items. |
string-masonry-size-time | child attribute | 0.6 (from default) | Duration (s) for width resizing | rarely needed unless column count changes animate width. |
Module Snapshot
- Activation attribute:
string="masonry" - Layout method: Absolute positioning via
translate3d. - Responsive: Native breakpoint syntax for columns and gaps.
- Dynamic: Auto-updates on window resize, image loads, and DOM node addition/removal.
- Performance: Batches DOM reads/writes; animates layout changes with FLIP-like transitions.
- Requirements: Children should be
display: block(or similar) and will be forced toposition: absolute.
Basic Usage
import StringTune, { StringMasonry } from '@fiddle-digital/string-tune';
const stringTune = StringTune.getInstance();
stringTune.use(StringMasonry);
stringTune.start(60);
<div class="grid" string="masonry" string-masonry-cols="1|768:2|1024:3" string-masonry-gap="20|1024:40">
<div class="card">...</div>
<div class="card">...</div>
<div class="card">...</div>
</div>
Advanced: Manual Mode & Event Control
For applications with complex filtering or external state management (e.g., React/Vue lists), use manual mode to precisely control when the layout recalculates.
1. Set Manual Mode
<div string="masonry" string-id="product-grid" string-masonry-mode="manual">...</div>
2. Trigger Updates via Events
Use stringTune.emit() to send commands to specific masonry instances using their string-id.
| Channel | Payload | Description |
|---|---|---|
masonry:update:<id> | { mode?: string, cols?: number, gap?: number } | Updates settings and forces a layout shuffle. |
Examples:
- Force a layout refresh (e.g., after filter changes):
// Triggers a layout calculation using current DOM elements
stringTune.emit('masonry:update:product-grid', {});
- Change columns dynamically:
// Switches to 4 columns and 20px gap, animating items to new positions
stringTune.emit('masonry:update:product-grid', {
cols: 4,
gap: 20,
});
- Switch modes:
stringTune.emit('masonry:update:product-grid', { mode: 'auto' });
Lifecycle Events
Listen to these events to coordinate other animations or UI updates (like fading in a footer after the grid settles).
| Channel Pattern | Payload | Fired When | Use Cases |
|---|---|---|---|
masonry:shuffle:start | { object: StringObject } | The grid detects a change and begins animating items. | Disable pointer events, show loader. |
masonry:shuffle:end | { object: StringObject } | All items have reached their target positions and the container height is final. | Enable pointer events, scroll to position, trigger "entry" animations. |
resize | true | The container height changed significantly. | Global scroll refresh (handled automatically by StringTune). |
Usage Example
// Log when the grid starts moving
stringTune.on('masonry:shuffle:start', ({ object }) => {
if (object.id === 'product-grid') {
console.log('Grid is reshuffling...');
document.body.classList.add('is-animating');
}
});
// React when it finishes
stringTune.on('masonry:shuffle:end', ({ object }) => {
if (object.id === 'product-grid') {
console.log('Grid settled. New height:', object.htmlElement.offsetHeight);
document.body.classList.remove('is-animating');
}
});
How It Works
- Grid Calculation: computes column width based on container width, column count, and gap settings.
- Positioning: iterates through children, placing each item into the shortest available column (top-down, left-to-right filling).
- Applies Transforms: calculates
translate3d(x, y, 0)for each item. - Container Height: updates the container's height to match the tallest column, ensuring proper document flow below the grid.
- Animation: if the layout changes (resize, filter, load), items smoothly interpolate to their new positions using the configured duration and easing.
Tips & Gotchas
- Images: The module automatically monitors
<img>tags inside items. You do not need external libraries likeimagesLoaded; the layout will self-correct as images decode and render. - CSS: Do not manually set
position: absoluteortop/lefton children in your CSS; the module forces these styles inline. - Performance: Transitions use
transformandwidth(only if column width changes). For the smoothest 60fps experience, avoid adding heavy CSS effects (like box-shadow or blur) to the moving cards themselves during animation.