CSS グリッドレイアウトでの自動配置

この記事は翻訳が完了していません。 この記事の翻訳にご協力ください

CSS グリッドレイアウト仕様書には、作成したグリッド上にアイテムを正確に配置する機能に加えて、グリッドを作成したときに子アイテムの一部またはすべてを配置しなかった場合の動作を制御するルールが含まれています。一連のアイテムでグリッドを作成することで、最も簡単な方法で自動配置を確認することができます。アイテムに配置情報を与えない場合、アイテムはグリッド上の各セルに1つずつ配置されます。

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
}
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>

自動配置の既定のルール

上記の例でわかるように、グリッドを作成すると、すべての子アイテムが各グリッドセルに1つずつ配置されます。既定のフローでは、行ごとにアイテムを配置します。グリッドは、それぞれのアイテムを1行目のそれぞれのセルに配置します。 grid-template-rows プロパティを使用して追加の行を作成した場合は、グリッドはこれらの行にアイテムを配置し続けます。明示的なグリッドにすべてのアイテムを配置するのに十分な行がない場合は、新たに暗黙の行が作成されます。

暗黙のグリッド内での行の大きさ

暗黙のグリッドで自動的に作成される行の既定値は、大きさが自動になっています。これは、あふれることなく、それらに追加されたコンテンツを含むことを意味します。

しかし、grid-auto-rowsプロパティを使用することで、これらの行の大きさを制御することができます。例えば、全ての作成された行を100ピクセルの高さにするには、次のように使います:

<div class="wrapper">
    <div>One</div>
    <div>Two</div>
    <div>Three</div>
    <div>Four</div>
    <div>Five</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
  grid-auto-rows: 100px;
}

You can use minmax() in your value for grid-auto-rows enabling the creation of rows that are a minimum size but then grow to fit content if it is taller.

<div class="wrapper">
     <div>One</div>
     <div>Two</div>
     <div>Three</div>
     <div>Four
     <br>This cell   
     <br>Has extra   
     <br>content.   
     <br>Max is auto 
     <br>so the row expands.
     </div>
     <div>Five</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
  grid-auto-rows: minmax(100px, auto);
}

You can also pass in a track listing, this will repeat. The following track listing will create an initial implicit row track as 100 pixels and a second as 200px. This will continue for as long as content is added to the implicit grid.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
   <div>Six</div>
   <div>Seven</div>
   <div>Eight</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
  grid-auto-rows: 100px 200px;
}

Auto-placement by column

You can also ask grid to auto-place items by column. Using the property grid-auto-flow with a value of column. In this case grid will add items in rows that you have defined using grid-template-rows. When it fills up a column it will move onto the next explicit column, or create a new column track in the implicit grid. As with implicit row tracks, these column tracks will be auto sized. You can control the size of implicit column tracks with grid-auto-columns, this works in the same way as grid-auto-rows.

In this next example I have created a grid with three row tracks of 200 pixels height. I am auto-placing by column and the columns created will be a column width of 300 pixels, then a column width of 100 pixels until there are enough column tracks to hold all of the items.

.wrapper {
    display: grid;
    grid-template-rows: repeat(3, 200px);
    grid-gap: 10px;
    grid-auto-flow: column;
    grid-auto-columns: 300px 100px;
}
<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
   <div>Six</div>
   <div>Seven</div>
   <div>Eight</div>
</div>

The order of auto placed items

A grid can contain a mixture of items. Some of the items may have a position on the grid, but others may be auto-placed. This can be helpful, if you have a document order that reflects the order in which items sit on the grid you may not need to write CSS rules to place absolutely everything. The specification contains a long section detailing the Grid item placement algorithm, however for most of us we just need to remember a few simple rules for our items.

Order modified document order

Grid places items that have not been given a grid position in what is described in the specification as “order modified document order”. This means that if you have used the order property at all, the items will be placed by that order, not their DOM order. Otherwise they will stay by default in the order that they are entered in the document source.

Items with placement properties

The first thing grid will do is place any items that have a position. In the example below I have 12 grid items. Item 2 and item 5 have been placed using line based placement on the grid. You can see how those items are placed and the other items then auto-place in the spaces. The auto-placed items will place themselves before the placed items in DOM order, they don’t start after the position of a placed item that comes before them.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
   <div>Six</div>
   <div>Seven</div>
   <div>Eight</div>
   <div>Nine</div>
   <div>Ten</div>
   <div>Eleven</div>
   <div>Twelve</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  grid-gap: 10px;
}
 .wrapper div:nth-child(2) {
   grid-column: 3;
   grid-row: 2 / 4;
 }
 .wrapper div:nth-child(5) {
   grid-column: 1 / 3;
   grid-row: 1 / 3;
}

Deal with items that span tracks

You can use placement properties while still taking advantage of auto-placement. In this next example I have added to the layout by setting odd items to span two tracks both for rows and columns. I do this with the grid-column-end and grid-row-end properties and setting the value of this to span 2. What this means is that the start line of the item will be set by auto-placement, and the end line will span two tracks.

You can see how this then leaves gaps in the grid, as for the auto-placed items if grid comes across an item that doesn’t fit into a track, it will move to the next row until it finds a space the item can fit in.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
   <div>Six</div>
   <div>Seven</div>
   <div>Eight</div>
   <div>Nine</div>
   <div>Ten</div>
   <div>Eleven</div>
   <div>Twelve</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  grid-gap: 10px;
}
.wrapper div:nth-child(4n+1) {
  grid-column-end: span 2;
  grid-row-end: span 2;
  background-color: #ffa94d;
}
 .wrapper div:nth-child(2) {
   grid-column: 3;
   grid-row: 2 / 4;
 }
 .wrapper div:nth-child(5) {
   grid-column: 1 / 3;
   grid-row: 1 / 3;
}

Filling in the gaps

So far, other than items we have specifically placed, grid is always progressing forward and keeping items in DOM order. This is generally what you want, if you are laying out a form for example you wouldn’t want the labels and fields to become jumbled up in order to fill in some gap. However sometimes, we are laying things out that don’t have a logical order and we would like to create a layout that doesn’t have gaps in it.

To do this, add the property grid-auto-flow with a value of dense to the container. This is the same property you use to change the flow order to column, so if you were working in columns you would add both values grid-auto-flow: column dense.

Having done this, grid will now backfill the gaps, as it moves through the grid it leaves gaps as before, but then if it finds an item that will fit in a previous gap it will pick it up and take it out of DOM order to place it in the gap. As with any other reordering in grid this does not change the logical order. Tab order for example, will still follow the document order. We will take a look at the potential accessibility issues of Grid Layout in a later guide, but you should take care when creating this disconnect between the visual order and display order.

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
   <div>Six</div>
   <div>Seven</div>
   <div>Eight</div>
   <div>Nine</div>
   <div>Ten</div>
   <div>Eleven</div>
   <div>Twelve</div>
</div>
.wrapper div:nth-child(4n+1) {
  grid-column-end: span 2;
  grid-row-end: span 2;
  background-color: #ffa94d;
}
 .wrapper div:nth-child(2) {
   grid-column: 3;
   grid-row: 2 / 4;
 }
 .wrapper div:nth-child(5) {
   grid-column: 1 / 3;
   grid-row: 1 / 3;
}
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  grid-gap: 10px;
  grid-auto-flow: dense;
}

Anonymous grid items

There is a mention in the specification of anonymous grid items. These are created if you have a string of text inside your grid container, that is not wrapped in any other element. In the example below we have three grid items, assuming you had set the parent with a class of grid to display: grid. The first is an anonymous item as it has no enclosing markup, this item will always be dealt with via the auto-placement rules. The other two are grid items enclosed in a div, they might be auto-placed or you could place these with a positioning method onto your grid.

<div class="grid">
  I am a string and will become an anonymous item
  <div>A grid item</div>
  <div>A grid item</div>
</div>

Anonymous items are always auto-placed because there is no way to target them. Therefore if you have some unwrapped text for some reason in your grid, be aware that it might show up somewhere unexpected as it will be auto-placed according to the auto-placement rules.

Use cases for auto-placement

Auto-placement is useful whenever you have a collection of items. That could be items that do not have a logical order such as a gallery of photos, or product listing. In that case you might choose to use the dense packing mode to fill in any holes in your grid. In my image gallery example I have some landscape and some portrait images. I have set landscape images – with a class of landscape to span two column tracks. I then use grid-auto-flow: dense to create a densely packed grid.

.wrapper {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    grid-gap: 10px;
    grid-auto-flow: dense;
    list-style: none;
    margin: 1em auto;
    padding: 0;
    max-width: 800px;
}
.wrapper li {
    border: 1px solid #ccc;
}
.wrapper li.landscape {
    grid-column-end: span 2;
}
.wrapper li img {
   display: block;
   object-fit: cover;
   width: 100%;
   height: 100%;
}
<ul class="wrapper">
   <li><img src="https://placehold.it/200x300" alt="placeholder"></li>
   <li class="landscape"><img src="https://placehold.it/350x200" alt="placeholder"></li>
   <li class="landscape"><img src="https://placehold.it/350x200" alt="placeholder"></li>
   <li class="landscape"><img src="https://placehold.it/350x200" alt="placeholder"></li>
   <li><img src="https://placehold.it/200x300" alt="placeholder"></li>
   <li><img src="https://placehold.it/200x300" alt="placeholder"></li>
   <li class="landscape"><img src="https://placehold.it/350x200" alt="placeholder"></li>
   <li><img src="https://placehold.it/200x300" alt="placeholder"></li>
   <li><img src="https://placehold.it/200x300" alt="placeholder"></li>
   <li><img src="https://placehold.it/200x300" alt="placeholder"></li>
</ul>

Auto-placement can also help you lay out interface items which do have logical order. An example is the definition list in this next example. Definition lists are an interesting challenge to style as they are flat, there is nothing wrapping the groups of dt and dd items. In my example I am allowing auto-placement to place the items, however I have classes that start a dt in column 1, and dd in column 2, this ensure that terms go on one side and definitions on the other - no matter how many of each we have.

<div class="wrapper">
   <dl>
       <dt>Mammals</dt>
       <dd>Cat</dd>
       <dd>Dog</dd>
       <dd>Mouse</dd>
       <dt>Fish</dt>
       <dd>Guppy</dd>
       <dt>Birds</dt>
       <dd>Pied Wagtail</dd>
       <dd>Owl</dd>
   </dl>
</div>
dl {
  display: grid;
  grid-template-columns: auto 1fr;
  max-width: 300px;
  margin: 1em;
  line-height: 1.4;
}
dt {
  grid-column: 1;
  font-weight: bold;
}
dd {
   grid-column: 2;
 }

What can’t we do with auto-placement (yet)?

There are a couple of things that often come up as questions. Currently we can’t do things like target every other cell of the grid with our items. A related issue may have already come to mind if you followed the last guide about named lines on the grid. It would be to define a rule that said “auto-place items against the next line named “n”, and grid would then skip other lines.There is an issue raised about this on the CSSWG GitHub repository, and you would be welcome to add your own use cases to this.

It may be that you come up with your own use cases for auto-placement or any other part of grid layout. If you do, raise them as issues or add to an existing issue that could solve your use case. This will help to make future versions of the specification better.