0

I have a grid layout with two rows:

  1. A header and
  2. a content section which sometimes has two columns, and sometimes has only one.

Basically your typical header with content layout, except I want to dynamically turn off the right column sometimes.

  • The height of the header must be determined by its content. OK: grid-template-rows: min-content auto;
  • The header must span the one or both columns. But this fails. I've tried the following approaches:

This will only work when there is one column. If there are two columns, this row won't span over them.

.header {
  grid-row-start: 1;
  grid-column-start: 1;
  grid-column-end: auto;
}

Same as

.header {
  grid-row-start: 1;
  grid-column: 1 / span auto;
}

This will only work when there is two columns. It creates a place on the screen for a second column, even when there isn't one.

.header {
  grid-row-start: 1;
  grid-column: 1 / span 2;
}
  • Finally, I'm a bit puzzled by the fact that the two columns aren't the same width. Probably related to auto-fill, but can't really get my head around that, is there a solution for that?

This is the code:

.header {
  grid-row-start: 1;
  grid-column-start: 1;
  grid-column-end: auto;
}

.left {
  grid-row-start: 2;
  grid-column-start: 1;
  grid-column-end: 1;
}

.right {
  grid-row-start: 2;
  grid-column-start: 2;
  grid-column-end: 2;
}

.wrapper {
    height: 100%;
    width: 100%;

    display: grid;
    grid-gap: 10px;
    grid-column: 1 / -1;
    grid-template-rows: min-content auto;
}
<div style="height: 300px;">
    <div class="wrapper">
        <div class="header" style="background-color:#006;">
            HEADER
        </div>
        <div class="left" style="background-color:#600;">
            LEFT
            Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.
        </div>
        <div
            class="right"
            v-if="true"
            style="background-color:#060;">
            RIGHT
        </div>
    </div>
</div>

Result looks like:

enter image description here

svenema
  • 1,766
  • 2
  • 23
  • 45
  • 2
    Two things: `grid-template-columns: repeat(auto-fill, 1fr);` is invalid. You can't *auto-fill* with fractional sizes. If that's fixed, simply `grid-column: 1 / -1` on the header would make it fill the row. – Yoshi Oct 21 '20 at 08:37
  • Thanks for that, however, the result is the same in that the column width seems to be related to the content. Grid, especially, should be layout-first, right? – svenema Oct 21 '20 at 08:46
  • 1
    The columns aren't the same size, because your `grid-template-columns` directive is completely ignored due to it being invalid. Make it (for example) `grid-template-columns: 1fr 1fr` and you'll have two equal columns. I understand that this isn't what you want with regards to conditionally adding a column, but for that you'll need another solution. It's definitely not `repeat(auto-fill, 1fr)`. – Yoshi Oct 21 '20 at 08:54

1 Answers1

2

As I wrote in my comments, the problem is repeat(auto-fill, 1fr). This is invalid. A simple fix would be to settle for two columns each 1fr and conditionally have the main column (e.g. if it's the last child) span both.

For example (using grid-template):

.wrapper {
    height: 100%;
    width: 100%;
    color: white;

    display: grid;
    grid-template:
        "header header" min-content
        "main   aside" auto / 1fr 1fr;
    grid-gap: 10px;
}

.header {
    grid-area: header;
    background-color: #006;
}

.left {
    grid-area: main;
    background-color: #600;
}

.left:last-child {
    grid-column: 1 / -1;
}

.right {
    grid-area: aside;
    background-color:#060;
}
<h4>With two columns</h4>

<div style="height: 300px;">
    <div class="wrapper">
        <div class="header">HEADER</div>
        <div class="left">LEFT</div>
        <div class="right">RIGHT</div>
    </div>
</div>

<h4>Only one column</h4>

<div style="height: 300px;">
    <div class="wrapper">
        <div class="header">HEADER</div>
        <div class="left">LEFT</div>
    </div>
</div>

Or if you do not want to use grid-template, this will work too:

.wrapper {
    height: 100%;
    width: 100%;
    color: white;

    display: grid;
    grid-auto-columns: 1fr;
    grid-template-rows: min-content auto;
    grid-gap: 10px;
}

.header {
    grid-column: 1 / 3;
    background-color: #006;
}

.left {
    grid-column: 1 / 2;
    background-color: #600;
}

.left:last-child {
    grid-column: 1 / 3;
}

.right {
    grid-column: 2 / 3;
    background-color:#060;
}
<h4>With two columns</h4>

<div style="height: 300px;">
    <div class="wrapper">
        <div class="header">HEADER</div>
        <div class="left">LEFT</div>
        <div class="right">RIGHT</div>
    </div>
</div>

<h4>Only one column</h4>

<div style="height: 300px;">
    <div class="wrapper">
        <div class="header">HEADER</div>
        <div class="left">LEFT</div>
    </div>
</div>
Yoshi
  • 54,081
  • 14
  • 89
  • 103
  • Works brilliantly, and very elegant. Take-aways here: Use grid-auto-columns, and if I'm not mistaken, the grid-column-end, is "not inclusive", ie. 3 means up to 2, not including 3. Many thanks. – svenema Oct 21 '20 at 09:58
  • @svenema Be careful here. *inclusive* is not the right thought here. The values refer to grid tracks. Those are numbered by default, but can be named. E.g. `grid-template-columns: [start] 1fr 1fr 1fr [some-track] 200px [end]` and `grid-column: start / some-track`. – Yoshi Oct 21 '20 at 10:02
  • for our understanding, 3 refers to (vertical, in this case) track 3, right? We did not use any named tracks here, in which case grid-column: 1 / 3; should be read as columns 1 to 2, but not 3. Correct? – svenema Oct 21 '20 at 10:27
  • @svenema I'm sorry, I actually used the wrong name. It should be *line* instead of *track*. It's the *thing* where your tracks (be it in columns or rows) come together. When you use `grid-column/row`, the values refer to those grid lines. For a better explanation, check: https://css-tricks.com/snippets/css/complete-guide-grid/ – Yoshi Oct 21 '20 at 10:53