6

I have been reading through the CSS Grid tutorial at CSS Tricks, but one basic aspect confused me a bit.

There seems to be two ways of deciding how many cells a grid item spans:

  1. grid-template-area using names given to grid items with the grid-area property
  2. Using grid-column-start/end and grid-row-start/end

Looking at my test code below, it seems the sizes of the grid items are decided in the following order (where values to the left overwrites values to the right):

grid-row/column-start/end > grid-template-area > Size of items themselves

Question

  1. Is my above order generally correct?
  2. Is there a preferred way (1 or 2 above), of specifying the size of the grid items (i.e. how many cells they span)?

Code

.container {
  display: grid;
  border: 1px solid green;
  grid-template-columns: 120px 120px 120px;
  grid-template-rows: 120px 120px 120px;
  grid-template-areas: "item-1 item-1 item-2" "item-3 item-4 item-4" "item-5 item-6 .";
}

.item-1 {
  border: 1px solid blue !important;
  grid-area: item-1;
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 1;
}

.item-2 {
  grid-area: item-2;
}

.item-3 {
  grid-area: item-3;
}

.item-4 {
  grid-area: item-4;
}

.item-5 {
  grid-area: item-5;
}

.item-6 {
  grid-area: item-6;
}

.box {
  border: 1px solid red;
  display: flex;
  align-items: center;
  text-align: center;
  justify-content: center;
}
<div class="container">
  <div class="item-1 box">Box1</div>
  <div class="item-2 box">Box2</div>
  <div class="item-3 box">Box3</div>
  <div class="item-4 box">Box4</div>
  <div class="item-5 box">Box5</div>
  <div class="item-6 box">Box6</div>
</div>
Magnus
  • 6,791
  • 8
  • 53
  • 84
  • note that grid-area is the shorthand for the all the other (grid-.-start grid-.-end) https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area – Temani Afif Mar 17 '19 at 23:51
  • Hey @TemaniAfif . According to the guide it is either `name`, or what you refer to: "`grid-area`: Gives an item a name so that it can be referenced by a template created with the `grid-template-areas` property. Alternatively, this property can be used as an even shorter shorthand for `grid-row-start` + `grid-column-start` + `grid-row-end` + `grid-column-end`. In my question I use it as the former. – Magnus Mar 17 '19 at 23:55
  • @TemaniAfif from MDN: "The grid-area property can also be set to a which acts as a name for the area, which can then be placed using grid-template-areas." – Magnus Mar 17 '19 at 23:58

2 Answers2

7

With the grid-template-areas property you are limited to rectangular grid areas.

With the grid-column-* and grid-row-* properties you have more flexibility.


With grid-template-areas you can create grid areas only within the explicit grid.

With grid-column-* and grid-row-* you can go outside the explicit grid, creating grid areas in the implicit grid.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Thank you, Michael. I read your other post on implicit vs. explicit grid, solid information. Related follow-up question: Is it only possible for an implicit grid to appear, when the explicit grid is smaller than the container. In tests i ran just now, it seemed like the implicit tracks were contained by the container. – Magnus Mar 18 '19 at 01:00
  • 1
    Grid tracks (explicit and implicit) exist inside the container. The container must expand to accommodate new tracks. Implicit rows and columns represent the grid container adding new tracks within itself to accommodate grid areas placed outside the explicit grid. – Michael Benjamin Mar 18 '19 at 02:16
4

There seems to be two ways of deciding how many cells a grid item spans:

To be more precise there are 3 ways to place items. From the specification:

The contents of the grid container are organized into individual grid items (analogous to flex items), which are then assigned to predefined areas in the grid. They can be explicitly placed using coordinates through the grid-placement properties or implicitly placed into empty areas using auto-placement. §8 Placing Grid Items

So either you consider area, coordinate or you leave the job to the browser for the auto placement. Basically you can use only one way.

Note that grid-area is the shorthand property for the explicit placement which can also be replace by grid-row-start; grid-column-star; grid-row-end; grid-column-end;

Here is a simple example to illustrate:

.grid {
  display:inline-grid;
  grid-template-areas:
    "a b"
    "c d";
  grid-gap:20px;
  border:1px solid;
}
span {
  width:50px;
  height:50px;
  background:red;
}
.one > span {
  grid-area:a;
  grid-row-start:1;
  grid-row-end:3;
  grid-column-start:1;
  grid-column-end:3;
}
.two > span {
  grid-row-start:1;
  grid-row-end:3;
  grid-column-start:1;
  grid-column-end:3;
  grid-area:a;
}
<div class="grid one">
  <span></span>
</div>

<div class="grid two">
  <span></span>
</div>

You can clearly see that we have a different result because of the order. This is logical since we are overriding properties. There isn't any order but only one configuration will be considered for your item.

You can inspect the second element and you will have the computed value like this:

enter image description here

You will not find a property called grid-area like you won't find a property called background, margin, border etc because all will get replaced by the longhand notation.


Considering the size, you should make the difference between the size of the tracks and the size of the items. In the previous example we didn't define any explicit size so the item width/height will also define the size of the track.

You can explicitely set the track sizes using different properties like grid-template-columns grid-template-rows and you will notice that grid item size will not always follow the size of the tracks and we may have overflow:

.grid {
  display:inline-grid;
  grid-template-columns:150px 150px;
  grid-template-areas:
    "a b"
    "c d";
  grid-gap:20px;
  border:1px solid;
}
span {
  width:50px;
  height:50px;
  background:red;
  grid-area:a;
}
.one > span {
  width:400px;
}
.two > span {
  width:100%;
}

.three > span {
  width:200%;
}
<div class="grid one">
  <span></span>
</div>

<div class="grid two">
  <span></span>
</div>

<div class="grid three">
  <span></span>
</div>

We have defined the track size to be 150px and if the item with is bigger we simply have an overflow. You will also notice how percetange will behave since the track will be the containing block of the grid item and not the grid container.

Using dev tools you can clearly see the tracks:

enter image description here

If for example you consider 1fr unit or auto then the width of the element will be used to define the sizes:

.grid {
  display:inline-grid;
  grid-template-columns:1fr 150px;
  grid-template-areas:
    "a b"
    "c d";
  grid-gap:20px;
  border:1px solid;
}
span {
  width:50px;
  height:50px;
  background:red;
  grid-area:a;
}
.one > span {
  width:400px;
}
<div class="grid one">
  <span></span>
</div>

enter image description here

So we can identify 4 cases 1:

  1. item size not defined and track size not defined: The content of each item will be used to define the item and the track size.
  2. item size not defined and track size defined: The item will be stretched to fill the track size (we may have overflow depending on the content of the item).
  3. item size defined and track size defined: There is no size relation between both, we simply place the item inside the track. We can either have overflow or empty space inside the track.
  4. item size defined and track size not defined: The item size will dictate the track size. Depending on the cases, it will not define it but it will be considered in the caclulation. (ex here: https://stackoverflow.com/a/54639430/8620333)

1: this is very simplifed to make think more clear. The sizing algorithm is more complex.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Very helpful, my friend. One point: In your `fr` scenario, it is not actually the `fr` which dictates that the track fits the item. Instead it is the `inline-grid` that makes the container the same size as its content. All `fr` does, is to look at the size of your container, remove all non-flexible items (in your case 150+20), then make column one a fraction of whats left (in your case the fraction is 1/1, i.e. 100%). Result can be seen by changing `inline-grid` to `grid`, in your example. – Magnus Mar 18 '19 at 01:20
  • Your point about `grid-area` being a shorthand property answered my question. It then just comes back to order within the css block, as you say. Note: My original assumption that item width and height was of the lowest priority, was wrong. In fact, item width and height trumps all css grid properties. An item will not span any grid cells if we fix the item width and height. Once set, the item will not change its size. – Magnus Mar 18 '19 at 01:51
  • One thing that is a bit more complex, is your first example with the two red squares, each with a fixed height and width. We know the `inline` part of the `display` property is what keeps the container from stretching the full width of its parent containing block. What is more difficult to understand, is the fact that the track height becomes the height of the item, ONLY when using a template. Basically, the other rows then become 0 in height, and the 20px gap at the bottom is kept..... 1/2 – Magnus Mar 18 '19 at 01:59
  • .... When applying individual item grid properties, the height of each row becomes equal, in total covering the height of the item. I have no idea why the two differs. I guess in the template scenario, we are informing the browser that there will in fact be two rows. It just does not show the second row because there is not enough items. In the other scenario (no template), the browser somehow assumes that there will be two rows and two columns, then shrink total container height to match height of item, and makes each row equally tall. – Magnus Mar 18 '19 at 02:05
  • Ahh, the browser infers the number of rows from the `grid-row-end` property. Ok, I think I understand it all now. PS: Just to point out one thing you probably already know, but in your first example with the two squares, the only reason the two paint differently on the screen is due to the grid gap (as in the second scenario it goes by the template). In the first scenario it infers the number of rows based on your individual item properties, then sets an equal height on each row (and width on each column if you keep the grid set to `inline-grid`). – Magnus Mar 18 '19 at 02:11
  • Lastly, there is a missing 4th size case: 4) Item size defined, track size not defined. This is what applies to your first example with two squares. I have typed up the answer on my computer, but it is too long to post here. In summary, it varies with `inline-grid` vs `grid`, and whether you place items with `named areas` (i.e. `template-areas`) or do `line-based` placement. – Magnus Mar 18 '19 at 02:38
  • 1
    @Magnus you almost got it. the only difference between `grid` and `inline-grid` is the shrink-to-fit behavior. So the grid will take full width then 1fr will be a fraction from the remaining space after removing 150px and one gap. For the inline-grid 1fr will be the minimum size required to place the item (this is the difference) because 1fr is minmax(auto,1fr). So for the inline-grid the auto is doing the job. Make your element to have `grid-column:1/-1` and see the difference. In this case you will make it contained in the 1fr and the 150px. – Temani Afif Mar 18 '19 at 07:09
  • 1
    @Magnus in the first example, since I didn't define any track size and there is no item in the `b`, `c`, `d` they will be empty BUT you will see the gap and you will see that `b` will have width:0 but the same height as `a` and `c` `d` height:0 and same width as `a` (because it's a grid). When I placed my element in all the gird I cover also the gap and again the shrink-to-fit plays here and since there is no size set, by default all of them (`a` `b` `c` `d`) will have the same width/height. The one needed to contain our element – Temani Afif Mar 18 '19 at 07:12
  • 1
    @Magnus Yes forget the 4th case (I was about to sleep :p) I will edit my answer ... and basically like you said, the size of the track will be based on the item and I have used inline-grid to show this. If we consider `grid` it will be different because the full width will be considered in the calulation that's why I considered `inline` to make thing easier to understand and as I said at the bottom, it's more complex in reality ... here is another question where I detailed the calculation in case of `grid` where we don't set track size https://stackoverflow.com/a/54639430/8620333 (4th case) – Temani Afif Mar 18 '19 at 07:20
  • 1
    @Magnus here is also another example to better understand the `fr` especially the fact that it's equal to `minmax(auto,1fr)` : https://stackoverflow.com/a/54129099/8620333 – Temani Afif Mar 18 '19 at 07:27