Search code examples
csscss-grid

Grid Precedence: order vs grid-column/grid-row


Question

If there is a conflict, do grid-column and grid-row always take precedence over order in a grid?


Documentation

Placement Shorthands

Grid Item Placement Algorithm

Display Order: the order property

Flex and grid containers lay out their contents in order-modified document order, starting from the lowest numbered ordinal group and going up. Items with the same ordinal group are laid out in the order they appear in the source document.

The auto-placement algorithm works with the grid items in order-modified document order, not their original document order.

From the specification, it seems that order is applied first, and then the placement algorithm runs to apply any necessary changes.


Examples

In the following snippet, a grid with four columns and one row orders its grid items in reverse-source order using the order property.

#grid-container
{
  display: grid;
  grid-template-columns: 100px 100px 100px 100px;
  grid-template-rows: 100px;
}

.grid-item
{
  color: white;
  background-color: darkblue;
  border: 1px solid white;
}

.grid-item:nth-child(1)
{
  order: 4;
}

.grid-item:nth-child(2)
{
  order: 3;
}

.grid-item:nth-child(3)
{
  order: 2;
}

.grid-item:nth-child(4)
{
  order: 1;
}

body
{
  background-color: black;
}
<div id = 'grid-container'>
  <div class = 'grid-item'>1</div>
  <div class = 'grid-item'>2</div>
  <div class = 'grid-item'>3</div>
  <div class = 'grid-item'>4</div>
</div>

In this snippet, the conflicting grid-column and grid-row properties are added, which take precedence over order.

#grid-container
{
  display: grid;
  grid-template-columns: 100px 100px 100px 100px;
  grid-template-rows: 100px;
}

.grid-item
{
  color: white;
  background-color: darkblue;
  border: 1px solid white;
  grid-row: 1 / 2;
}

.grid-item:nth-child(1)
{
  order: 4;
  grid-column: 1 / 2;
}

.grid-item:nth-child(2)
{
  order: 3;
  grid-column: 2 / 3;
}

.grid-item:nth-child(3)
{
  order: 2;
  grid-column: 3 / 4;
}

.grid-item:nth-child(4)
{
  order: 1;
  grid-column: 4 / 5;
}

body
{
  background-color: black;
}
<div id = 'grid-container'>
  <div class = 'grid-item'>1</div>
  <div class = 'grid-item'>2</div>
  <div class = 'grid-item'>3</div>
  <div class = 'grid-item'>4</div>
</div>


Conclusion

Based on small tests like the ones above, and the specification, I think the answer is probably that the placement properties always take precedence over order if there's a conflict. But it would be better to have a definite answer, or to know the cases where order may take precedence.


Solution

  • I think the answer is probably that the placement properties always take precedence over order

    We should not really talk about precedence since both don't do the same thing. The whole placement algorithm consider both order and grid-* properties to place the items. It doesn't consider only one of them.

    From the Specification you can read:

    The auto-placement algorithm works with the grid items in order-modified document order, not their original document order.

    So the algorithm will consider the order of the items to place them. order: 1 will get placed first, order: 2 second, and so one BUT where they will get placed is a different story. I think your confusion is here.

    The order property don't place items, it defines when the items is getting placed. The placement is defined by the grid-* property and following the below algorithm

    1. Position anything that’s not auto-positioned.

    2. Process the items locked to a given row.

    1. Position the remaining grid items.

      If the item has a definite column position:

      If the item has an automatic grid position in both axes:

    In your case, all the items fall into the step (2) since they have a defined column and row position so the browser will first place item4 because it has the order: 1, then item3 and so on. But since all of them have a different place, you will notice nothing and you may thing order is doing nothing.

    Take another example where the items have the same place and you can see the effect of the order property

    #grid-container
    {
      display: grid;
      grid-template-columns: 100px 100px 100px 100px;
      grid-template-rows: 100px;
    }
    
    .grid-item
    {
      color: white;
      background-color: darkblue;
      border: 1px solid white;
      grid-row: 1 ;
    }
    
    .grid-item:nth-child(1)
    {
      order: 4;
      grid-column: 1;
    }
    
    .grid-item:nth-child(2)
    {
      order: 3;
      grid-column: 2;
    }
    
    .grid-item:nth-child(3)
    {
      order: 2;
      grid-column: 2;
    }
    
    .grid-item:nth-child(4)
    {
      order: 1;
      grid-column: 4 ;
    }
    
    body
    {
      background-color: black;
    }
    <div id = 'grid-container'>
      <div class = 'grid-item'>1</div>
      <div class = 'grid-item'>2</div>
      <div class = 'grid-item'>3</div>
      <div class = 'grid-item'>4</div>
    </div>

    I am placing item2 and item3 at the same position but item2 is above because we first place item3 then item2 following the order property


    So there is no conflict between the properties and the browser will not run the order first. The browser will place each item one by one following the order property and for each item we look at the grid-* properties to know where to place it.

    #grid-container {
      display: grid;
      grid-template-columns: 100px 100px 100px 100px;
      grid-template-rows: 100px 50px;
    }
    
    .grid-item {
      color: white;
      background-color: darkblue;
      border: 1px solid white;
      width: 150%;
    }
    
    .grid-item:nth-child(1) {
      order: 2;
      grid-row: 1;
      grid-column: 1;
    }
    
    .grid-item:nth-child(2) {
      order: 1;
      grid-column: 2;
    }
    
    body {
      background-color: black;
    }
    <div id='grid-container'>
      <div class='grid-item'>1</div>
      <div class='grid-item'>2</div>
    </div>

    In the above, we first place item2 and then item1. I am explicitly creating an overlap using a big width to show than item1 is above because it's placed after even if both items aren't at the same place. Remove order and the item2 will overlap item1

    Take your example and create an overlap to see how items are stacked:

    #grid-container {
      display: grid;
      grid-template-columns: 100px 100px 100px 100px;
      grid-template-rows: 100px;
    }
    
    .grid-item {
      color: white;
      background-color: darkblue;
      border: 1px solid white;
      grid-row: 1 / 2;
      width: 120%;
    }
    
    .grid-item:nth-child(1) {
      order: 4;
      grid-column: 1 / 2;
      margin-top: 50px;
    }
    
    .grid-item:nth-child(2) {
      order: 3;
      grid-column: 2 / 3;
      margin-top: 30px;
    }
    
    .grid-item:nth-child(3) {
      order: 2;
      grid-column: 3 / 4;
      margin-top: 10px;
    }
    
    .grid-item:nth-child(4) {
      order: 1;
      grid-column: 4 / 5;
    }
    
    body {
      background-color: black;
    }
    <div id='grid-container'>
      <div class='grid-item'>1</div>
      <div class='grid-item'>2</div>
      <div class='grid-item'>3</div>
      <div class='grid-item'>4</div>
    </div>