We bring to your attention a translation of an article about a technique that will be useful to developers using CSS in their work.In this guide, we will cover all the steps of the algorithm for automatically placing elements from the CSS Grid Layout module. Each stage is controlled by the
grid-auto-flow
property. In his other articles, β
Introducing the CSS Grid Layout β and β
Seven Ways You Can Place Your Elements Using the CSS Grid Layout, β the author reviewed the CSS Grid specification and analyzed how using the Grid to position elements on a web page. However, in these materials, the position of a single element was explicitly specified in the grid. The remaining elements were placed using a certain algorithm.
')
Now we will analyze this algorithm. And the next time you find that the item was not where you need it, you wonβt have to scratch your head and wonder how it happened.
Basic principles
Before delving into the details, consider some basic principles.
- Anonymous grid items . If you put the text directly into the grid container, without wrapping it in any tag, it will turn into an anonymous grid element. Styles cannot be applied to such elements, but they also inherit style rules from parent containers. Note that the white space inside the grid container does not create an anonymous item.
- The value of the grid interval (Value of grid spans) . Unlike positioning in the grid, the algorithm does not contain separate rules for determining the value of the interval in the grid. If the value is not specified, then by default it is equal to 1 (the element occupies only its own cell).
- Implicit grid . A grid built on the basis of the values ββof the
grid-template-rows
, grid-template-columns
and grid-template-areas
properties is called an explicit grid . If we now determine the position of the element so that it is outside the bounds of the explicit grid, the browser will generate additional grid lines that will capture this element. These lines, together with an explicit grid, form an implicit grid. You can read more about this in β Where's the CSS Grid Layout Working Draft β. The auto-arrange algorithm can also cause additional columns or rows to appear in the implicit grid.
Now you need to note this. The default value of the
grid-auto-flow
property, with which we manage the algorithm, is
row
. The same value will be used in the subsequent explanation of the algorithm. If you explicitly set the
column
value for the property, do not forget in this explanation to replace all instances of the row row with the column. For example, β
Placing elements using the row-position setting, not column β will turn into β
Placing elements using the column-position setting, not row β.
Now activate in your favorite modern browser the
possibility of using experimental functions , and consider the details of the algorithm when building the layout.
Stage # 1: Generating Anonymous Grid Elements
The first thing the algorithm does when it tries to put all the elements in the grid is that it creates anonymous elements. As mentioned above, you cannot apply styles to such elements, because there is simply nothing to apply them to.
The following code generates an anonymous mesh element from inter-element text:
<div class="container"> <span class="nonan">1</span> Anonymous Item <div class="nonan floating">2</div> <div class="nonan">3</div> <div class="nonan floating">4</div> <div class="nonan">5</div> </div>
In this example, it should be noted that the algorithm ignores CSS floats applied to div 2 and div 4.
β
CodePen DemoStage # 2: Placing items in clearly indicated positions
For this and the next few steps, we will use a grid of nine different elements.
<div class="container"> <div class="item a">A</div> <div class="item b">B</div> <div class="item c">C</div> <div class="item d">D</div> <div class="item e">E</div> <div class="item f">F</div> <div class="item f">G</div> <div class="item f">H</div> <div class="item f">I</div> </div>
The first elements in the grid will be placed for which
positions are explicitly indicated . In our case, let it be elements A and B. For now, ignore all the others. Set the positions for A and B:
.a { grid-area: 1 / 2 / 2 / 3; } .b { grid-area: 2 / 1 / 4 / 3; }
The algorithm places A and B according to their values ββof the
grid-area
property:
- Based on the first and second values, the
grid-area
sets the position of the upper left corner for both elements. - Based on the third and fourth values, the
grid-area
sets the position of the lower right corner for both elements.
β
CodePen DemoStage # 3: Placing elements using row-position settings, not column
Now the algorithm places an element with
explicitly specified row-positions in the
grid-row-start
and
grid-row-end
properties.
Set the value of grid-row for C and D elements:
.c { grid-row-start: 1; grid-row-end: 3; } .d { grid-row-start: 1; grid-row-end: 2; }
To determine the column position, which is not explicitly specified, the algorithm operates in one of two scenarios in accordance with the
packing mode :
- Sparse packing (default).
- Dense packing.
Sparse placement on stage # 3
This is the default behavior. The initial row of the column (column-start line) of our item will receive the minimum possible line index (line index). This way we avoid overlapping space for the current element and cells already occupied by other elements.
The initial row of the column should also go after the element already placed in the same row
at this stage . We emphasize:
at this stage, and
not up to this stage.
Consider an example: the element D did not move to the left of A, even though it could fit there without any overlaps. The fact is that the elements with an
explicitly given row-position, and not column- , the algorithm does not place
in front of another, similarly positioned element in this row (in our example - C). If element C is to remove grid-row values, then D moves to the left of A.
In other words, the element D, which is explicitly given a row-position, and not column, can be placed before A, but only if it does not interfere with C. And in this case it interferes, because C, like in D, a row position is defined, not a column, and it is in the same row as D.
β
CodePen DemoTight Stage # 3
If you need to fill D with an empty space before A, then you will have to assign
row dense
to the
grid-auto-flow
property.
.container { grid-auto-flow: row dense; }
In this case, the initial row of the column will again get the minimum possible index so that there are no overlaps with other elements. But if there is an empty space in the row where our element can fit without overlaps, then it will be placed there without taking into account the previous element from the same row and with the same positioning values ββ(in our example, C).
β
CodePen DemoStep # 4: Determine the number of columns in the implicit grid
Next, the algorithm tries to determine the number of columns in the implicit grid. It happens like this:
- The algorithm takes the number of columns in the explicit grid.
- Then it goes through all elements with a given column position and adds columns to the beginning and end of the explicit grid to cover all elements.
- Then the algorithm goes through all elements without a given column position. If the largest value of the interval (span) of one of them is greater than the width of the implicit grid, then the algorithm adds columns at the end to cover this interval.
Stage # 5: Placing Remaining Items
By this time, the algorithm has already placed all the elements whose positions are clearly defined, as well as elements with known row positions. Now it starts placing the remaining elements in the grid.
But before considering this process, we introduce a new term: the
auto-placement cursor . This is the current insertion point in the grid, determined by the intersection of a pair of coordinates - a row and a column. Initially, the cursor is placed at the intersection point of the initial row and column of the implicit grid.
Recall that the positioning of the elements depends on the mode of placement (packing mode), specified by the property
grid-auto-flow
.
Sparse placement on stage # 5
By default, the remaining items are placed in a
sparse mode . This is how it happens.
If the element does not have a position on any axis:
- The algorithm increments the column position of the cursor until:
a) until there is an overlay between the current element and the previously placed ones,
b) either until the sum βvalue of column-position of cursor + value of column-interval of the elementβ exceeds the number of columns of the implicit grid.
- If the algorithm finds a position without overlaps, then assigns the cursor positions to the
row-start
and column-start
values ββof the inserted element. Otherwise, the algorithm increases the row-
by 1, column-start
assigns the value of the initial row in the implicit grid, and repeats the previous step.
If element is set to column position:
- The column value of the cursor position is assigned to the value of the
column-start
element of the element. If the value of the new position is less than the previous column, the position of the cursor, the row-position is increased by 1.
- Next, the row position increases by 1 until a value is reached at which the element does not overlap any of the already occupied cells. If necessary, additional rows can be added to the implicit grid. Now the value of the initial row of the row of the element is assigned to the row-position of the cursor, and the end row of the row of the element is set in accordance with its interval.
To make it clearer, consider an example.
Placing elements E and F when no positions are specified on any axis
When processing the element E, for which
neither column- nor row-position is specified, the values ββof row 1 and column 1 are set for the cursor. Element E occupies only one cell, it can fit in the upper left corner without overlays. That is, the algorithm simply places the
element E at the position of row 1 / column 1 .
The next element without specified positions on both axes is F. The value of the column position of the cursor increases to 2. But the position of row 1 / column 2 is already occupied by element A. The algorithm has to increase the value of the column position again until it reaches 4. There are no more columns , and then the row position of the cursor is increased by 1, and the column position is reset to 1: row 2 / column 1. The algorithm starts increasing the column position again by 1 until it reaches 4. Place with coordinates
row 2 / column 4 while which is free and can be occupied by the element F. The algorithm places it and proceeds to the next element.
Placing the elements G and H when the column position is set
Let's start with G. The column position of the cursor is determined by the same as the
grid-column-start
property of element G - 3. Since they are smaller than the previous value of column (4), the row-position increases by 1. That is, it becomes row 3 / column 3. The space with such coordinates is currently free, and G can be placed there without overlaps, which the algorithm does. Then everything is the same for element H.
β
CodePen DemoTight placement on stage # 5
When the
row dense
assigned to the
grid-auto-flow
property, a different procedure is performed. If the inserted element does not have a specific position, then the current position of the cursor is determined in accordance with the line at the intersection of the initial row and column of the implicit grid,
before the position of the element is determined.
Element I is placed to the left of H, because the cursor position is
reset to the line located at the intersection of the initial row and column of the implicit grid , instead of starting from the last placed element. The algorithm searches for a suitable position without overlaps, finds a place to the left of H and places an element there.
β
CodePen DemoConclusion
In this article, we walked through all the stages of the automatic placement algorithm from the CSS Grid Layout module. This algorithm is controlled by the
grid-auto-flow
property.
Try yourself to calculate the last position of different elements from different layouts in order to better understand the operation of the algorithm.