1. Introduction
"Masonry" is the common name for a form of layout that’s somewhat "halfway" between Flexbox and Grid layout: you pre-define some tracks in one axis (either rows or columns), and child elements flow into those tracks, automatically distributing themselves across them to keep the "heights" of the tracks as similar as possible.
The end result is similar to an auto-flowed Grid, but "packed tighter", rather than requiring the elements to line up in both rows and columns. Alternately, it’s similar to a Flexbox, except the "lines" are pre-defined and the items automatically distribute themselves across them, rather than filling one line at a time until it’s full.
This proposal is intentionally just a sketch of the full spec; for the most part, the final spec will closely resemble that of the Grid spec [css-grid-1], so any "missing" parts should be assumed to be identical to Grid, mutatis mutandi.
2. Masonry Containers
2.1. Establishing Masonry Containers: the masonry and inline-masonry display values
Name: | display |
---|---|
New values: | masonry | inline-masonry |
- masonry
-
This value causes an element to generate a masonry container box that is block-level when placed in flow layout.
- inline-masonry
-
This value causes an element to generate a masonry container box that is inline-level when placed in flow layout.
3. Defining the Masonry
A masonry container contains a masonry grid: a set of one or more masonry tracks, which masonry items are flowed into.
The direction that the masonry tracks extend is the masonry container’s main axis (the block axis for column masonry containers; the inline axis for row masonry containersd), and the perpendicular direction, which tracks are stacked in, is the cross axis.
3.1. Defining Tracks: the masonry-template-tracks property
Name: | masonry-template-tracks |
---|---|
Value: | <masonry-track-list> | <masonry-auto-track-list> | <masonry-intrinsic-track-list> | subgrid <line-name-list>? |
Initial: | repeat(auto-areas, auto) |
Applies to: | masonry containers |
Inherited: | no |
Percentages: | n/a |
Computed value: | by computed value type per item in the computed track list |
Canonical order: | per grammar |
Animation type: | if list lengths match, by computed value type; otherwise, discrete |
The masonry-template-tracks property defines, as a space-separated track list, the line names and track sizing functions of the masonry.
<masonry-track-list> = [ <line-names>? <masonry-track-component> ]+ <line-names>? <masonry-track-component> = <extrinsic-track-size> | <extrinsic-fixed-repeat> <extrinsic-track-size> = <extrinsic-breadth> | minmax( <fixed-breadth>, <extrinsic-breadth> ) <extrinsic-breadth> = <length-percentage [0,∞]> | <flex [0,∞]> <extrinsic-fixed-repeat> = repeat( <integer [1,∞]>, [ <line-names>? <extrinsic-track-size> ]+ <line-names>? ) <masonry-auto-track-list> = [ <line-names> | <masonry-track-list> ]? <extrinsic-auto-repeat> [ <line-names> | <masonry-track-list> ]? <extrinsic-auto-repeat> = repeat( [ auto-areas | auto-fill ] , [ <line-names>? <extrinsic-track-size> ]+ <line-names>? ) <masonry-intrinsic-track-list> = <line-names>? <masonry-intrinsic-repeat> <line-names>? <masonry-intrinsic-repeat> = repeat( [ <integer [1,∞]> | auto-areas | auto-fill ] , <line-names>? <intrinsic-track-size> <line-names>? ) <intrinsic-track-size> = <intrinsic-breadth> | minmax( <inflexible-breadth>, <intrinsic-breadth> ) | fit-content( <length-percentage [0,∞]> ) <intrinsic-breadth> = auto | min-content | max-content
Your track list can be any combination of:
-
fixed sizes (lengths/percentages)
-
flexible sizes (fr units)
-
minmax() of fixed/flexibles sizes
-
repeat() with integer repetitions and fixed/flexible sizes
Alternately, it can be a single repeat() (with any repetition count) using intrinsic sizes, like auto or min-content.
Or as a third option, it can be a subgrid keyword, which takes tracks from its parent grid container or masonry container according to its span.
While similar to grid-template-columns/grid-template-rows, masonry-template-tracks has a slightly different set of allowed values.
Grid can use:
-
any combination of fixed, flexible, or intrinsic tracks, either directy or in integer repeat()
-
only fixed or flexible tracks in auto-fill/auto-fit repeat().
While Masonry can use:
The subgrid value indicates that the masonry will adopt the spanned portion of its parent grid or parent masonry.
3.1.1. Track Sizes
- <length-percentage [0,∞]>
-
A non-negative length of percentage, as defined by CSS Values. [css-values-3]
<percentage> values are relative to the inner cross size of the masonry container. If the size of the masonry container depends on the size of its tracks, the the <percentage> must be treated as the default masonry size, for the purpose of calculating the intrinsic sizes of the masonry container, and then resolve against that resulting masonry container size for the purpose of laying out the masonry and its items.
- <flex [0,∞]>
-
A non-negative dimension with the unit fr specifying the track’s flex factor. Each <flex>-sized track takes a share of the remaining space in proportion to its flex factor. For example, given a track listing of 1fr 2fr, the tracks will take up 1/3 and 2/3 of the leftover space, respectively.
- minmax(min, max)
-
Defines a size range greater than or equal to min and less than or equal to max. If the max is less than the min, then the max will be floored by the min (essentially yielding minmax(|min|, |min|).)
As a maximum, a <flex> value sets the track’s flex factor; it is invalid as a minimum.
- auto
-
As a maximum: represents the largest max-content contribution among all the masonry items, corrected for spanning; but unlike max-content, allows expansion of the track by the align-content and justify-content properties.
As a minimum: represents the largest minimum size among all the masonry items, corrected for spanning. (This initially is often, but not always, equal to a min-content minimum—see XXX.)
When appearing outside a minmax() notation: equivalent to minmax(auto, auto), representin the range between the minimum and maximum described above. (This behaves similarly to minmax(min-content, max-content) in the most basic cases, but with extra abilities.)
- max-content
-
Represents the largest max-content contribution among all the masonry items, corrected for spanning.
- min-content
-
Represents the largest min-content contribution among all the masonry items, corrected for spanning.
- fit-content( <length-percentage> )
-
...
Note: For single-track items, correcting for spanning has no effect.
3.1.2. Repeating Tracks: the repeat() notation
There are two distinct syntaxes for repeat() in Masonry:
-
repeat( [ <integer> | auto-areas | auto-fill ],
+ ) , which allows you to specify one or more tracks to repeat, using <length-percentage>, <flex>, or minmax() of those. -
repeat( [ <integer> | auto-areas | auto-fill ],
) , which allows you to specify a single track to repeat, using the intrinsic sizes (auto, min-content, max-content, or minmax() of them).
An <integer> repeat simply represents the same thing as repeating the tracks specified by the second argument. For example, repeat(2, 1em 300px) is identical to writing 1em 300px 1em 300px.
An auto-fill repeat represents repeating the second argument the largest whole number of times that wouldn’t cause the masonry grid (including tracks not in the repeat(), gaps, etc) to overflow the content box of the masonry container (minimum of one repetition).
An auto-areas repeat depends on the value of masonry-template-areas:
-
if masonry-template-areas is none, behaves as auto-fill.
-
otherwise, represents enough repetitions of the second argument (with the final repetition possibly being only partial) to match the number of tracks specified by masonry-template-areas.
3.2. Named Areas: the masonry-template-areas property
Name: | masonry-template-areas |
---|---|
Value: | none | <string> |
Initial: | none |
Applies to: | masonry containers |
Inherited: | no |
Percentages: | n/a |
Computed value: | the keyword none or a string |
Canonical order: | per grammar |
Animation type: | discrete |
This property specifies named masonry areas, which can be referenced from the masonry-placement properties.
Values have the following meanings:
- none
-
Indicates no named masonry areas are defined by this property.
Note: Named masonry areas can still be created implicitly, by manually naming lines like foo-start and foo-end to create a foo area between them.
- <string>
-
The string is parsed into a number of cells, as follows:
-
Tokenize the string into a list of the following tokens, using longest-match semantics:
-
A sequence of ident code points, representing a named cell token with a name consisting of its code points.
-
A sequence of one or more "." (U+002E FULL STOP), representing a null cell token.
-
A sequence of whitespace, representing nothing (does not produce a token).
-
A sequence of any other code points, representing a trash token.
-
-
-
A null cell token represents an unnamed area in the masonry container, covering one masonry track.
-
A named cell token creates a named masonry area with the same name. Multiple adjacent named cell tokens with the same name instead create a single named area that spans the corresponding number of masonry tracks.
-
A trash token is a syntax error, and makes the declaration invalid.
-
If the string doesn’t define at least one cell token, the declaration is invalid. If the string defines multiple named areas with the same name, the declaration is invalid.
Defined areas give implicit-assigned names to grid lines in the masonry container.
-
3.3. Masonry Track Direction: the masonry-direction property
Name: | masonry-direction |
---|---|
Value: | row | column | row-reverse | column-reverse |
Initial: | column |
Applies to: | masonry containers |
Inherited: | no |
Percentages: | n/a |
Computed value: | as specified |
Canonical order: | per grammar |
Animation type: | discrete |
The masonry-direction property specifies how masonry items are placed in the masonry container, by setting the direction of the masonry container’s main axis, and its main-start and main-end directions.
- column
-
The masonry container’s main axis is its block axis, and its main-start direction is its block-start.
- column-reverse
-
The masonry container’s main axis is its block axis, and its main-start direction is its block-end.
- row
-
The masonry container’s main axis is its inline axis, and its main-start direction is its inline-start.
- row-reverse
-
The masonry container’s main axis is its inline axis, and its main-start direction is its inline-end.
The masonry container’s cross axis is perpendicular to its main axis; its cross-start direction is determined by masonry-fill. The main-end and cross-end directions are opposite the main-start and cross-start directions.
A masonry container is a column masonry container if its main axis is the block axis, or a row masonry container if its main axis is the inline axis.
3.4. Masonry Cross Direction: the masonry-fill property
Name: | masonry-fill |
---|---|
Value: | normal | reverse |
Initial: | normal |
Applies to: | masonry containers |
Inherited: | no |
Percentages: | n/a |
Computed value: | as specified |
Canonical order: | per grammar |
Animation type: | discrete |
masonry-fill determines what direction masonry items are laid out in when multiple tracks are tied for "shortest".
- normal
-
The masonry container’s cross-start direction is its inline-start or block-start direction (whichever is in its cross axis). (This means that ties are broken by filling from start to end.)
- reverse
-
The masonry container’s cross-start direction is its inline-end or block-end direction, instead.
3.5. Masonry Flow Directions: the masonry-flow property
Name: | masonry-flow |
---|---|
Value: | <'masonry-direction'> || <'masonry-fill'> |
Initial: | see individual properties |
Applies to: | see individual properties |
Inherited: | see individual properties |
Percentages: | see individual properties |
Computed value: | see individual properties |
Animation type: | see individual properties |
Canonical order: | per grammar |
The masonry-flow property is a shorthand for the masonry-direction and masonry-fill properties.
3.6. Masonry Definition Shorthand: the masonry property
Name: | masonry-template |
---|---|
Value: | <'masonry-template-areas'> || <'masonry-template-tracks'> || <'masonry-direction'> || <'masonry-fill'> |
Initial: | see individual properties |
Applies to: | see individual properties |
Inherited: | see individual properties |
Percentages: | see individual properties |
Computed value: | see individual properties |
Animation type: | see individual properties |
Canonical order: | per grammar |
The masonry-template shorthand sets masonry-template-areas, masonry-template-tracks, and masonry-direction at the same time.
4. Placing Grid Items
masonry-track, masonry-track-start, masonry-track-end, and masonry-area, with the obvious definitions matching grid-row/etc.
Spans are clamped at layout time to the defined masonry tracks; there is no "implicit grid".
4.1. Precision During Filling: the masonry-slack property
Name: | masonry-slack |
---|---|
Value: | <length-percentage> |
Initial: | 1em |
Applies to: | masonry containers |
Inherited: | no |
Percentages: | relative to the main axis content box size of the masonry container |
Computed value: | a computed length |
Canonical order: | per grammar |
Animation type: | discrete |
Masonry containers are filled by placing each masonry item in whichever masonry track is currently the least filled. When multiple tracks are tied for least-filled, placing the items in order looks good. But if tracks are only very slightly different heights, it can look strange to have them not fill in order, as the height differences aren’t perceived as meaningfully different.
masonry-slack specifies what the threshold is for considering tracks to be "the same height", causing them to fill in order.
- <length>
-
Specifies the tie threshold for the masonry container. Placement positions are considered to be equally good ("ties") if they are within the specified distance from the shortest position.
Note: The initial value is a "small" distance (1em) that is probably appropriate to represent "close enough".
Do we want a dense option, a la grid-auto-flow? It’s much more expensive in Masonry, as you have to lay out the element in every possible gap spot to see if it’s short enough to fit; Grid gets to just juggle some integers. Leaving it out for now; we can add it later if needed.
4.2. Masonry Placement Algorithm
Masonry distributes its items as evenly as possible among its tracks, always choosing the least-filled track to place the next item into.
An important property that this distribution maintains is that it always "moves forward" when there are ties: If multiple tracks are tied for shortest, it will still evenly distribute items to them one-by-one, even if they remain tied after each item is placed (because the item is zero height, or the tie threshold is a large value).
Note: This algorithm refers to the "index" of tracks, and talks about indexes being "smaller" or "larger" than each other; this implies numbering them from the cross-start side to the cross-end side (and is thus dependent on masonry-fill).
-
Generate anonymous masonry items.
-
For each masonry track, maintain a fill height, initially 0px for all tracks.
-
Let placement cursor be an index into the track list, initially pointing to the first track.
-
For each masonry item item in order-modified document order:
-
Let chosen start track be an index into the track list, initially unset.
-
If item has a definite track position, set chosen start track to that position.
Otherwise, choose a start track, given item, the masonry tracks and their fill heights, the masonry container’s tie threshold, and placement cursor, and set chosen start track to the result.
-
Let spanned tracks be the chosen start track plus following tracks according to item’s span.
-
Lay out item into spanned tracks, as specified in .
Let item height be the main size of item after layout.
-
Let max fill height be the largest fill height among spanned tracks.
Update all of spanned tracks’s fill heights to be max fill height + item height.
-
If item did not have a definition track position initially, set placement cursor to the first track following spanned tracks; if there are no tracks following spanned tracks, set it to the first track. (Definite-position items don’t update the cursor.)
-
To choose a start track given:
-
a masonry item item
-
a set of masonry tracks tracks and their fill heights
-
a tie threshold threshold
-
a track index placement cursor
-
Let extra span be item’s span - 1.
-
Let possible start tracks be all but the last N tracks, where N is extra span.
-
Let each item of possible start tracks have a spanning fill height, which is the largest fill height among the track itself and the next extra span tracks.
-
Let min fill height be the smallest spanning fill height among tracks.
-
Let choosable tracks be all the possible start tracks whose spanning fill height is within threshold of min fill height.
-
If any of the choosable tracks indexes are equal or greater than placement cursor, remove any items from choosable tracks whose index is smaller than placement cursor.
-
Return the item of chooseable tracks with the smallest index.
5. Alignment and Spacing
Like Grid Layout [css-grid-1], the align-* properties align in the masonry container’s block axis, and justify-* in the inline axis (rather than being based on the main axis and cross axis, like in Flexbox).
For column masonry containers:
- justify-content on the masonry container
-
The alignment subjects are the masonry tracks. The alignment container is the masonry container’s context box.
- align-content on the masonry container
-
The alignment subjects are runs of consecutive single-track masonry items in a given track between the start/end of the track or spanning items. The alignment container is the available space in the track between the two things bounding the run. (See Issue 10275.)
- justify-self on the masonry items
-
The alignment subject is the masonry item. The alignment container is the available space in the masonry area the item is placed in.
- align-self on the masonry items
-
No effect.
For row masonry containers, swap all the axises above.