1

I'm trying to understand the CSS grid. My layout consist of two menus (red), one on each side of a main content box in the middle (blue).

When the screen becomes smaller and there is not enough space for 3 columns, I want the second (right) side menu to appear right under the first (left) one.

enter image description here

Consider the height of main content and the side menus as random values, as the height will change depending on how much content/menu items is in them. Solution should work regardless of height.

My current layout almost works, except that the second menu appears under the end of the main content, and not right after the first menu. How can I solve this?

.main-container {
  width: 100%;
  height: 100%;
}

@media only screen and (min-width: 400px) {
  .main-container {
    display: grid;
    grid-gap: 20px;
    grid-template-columns: 40px 80px 40px;
    justify-content: center;
  }
}

@media only screen and (max-width: 400px) {
  .main-container {
    display: grid;
    grid-gap: 20px;
    grid-template-columns: 40px 80px;
    justify-content: center;
  }
}

.side-menu {
  width: 100%;
  height: 50px;
  background-color: red;
}

.main-content {
  width: 100%;
  height: 300px;
  background-color: blue;
}
<div class="main-container">
  <div class="side-menu"></div>
  <div class="main-content"></div>
  <div class="side-menu"></div>
</div>

Like the title states "CSS grid layout" i don't want to use js.

2 Answers 2

2

You haven't defined any rows in the grid:

.main-container {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 40px 80px 40px;
  justify-content: center;
}

Therefore, all rows are implicit, meaning they are created automatically to accommodate items.

The sizing function for implicit rows is grid-auto-rows and its default value is auto. This means that rows take the size of the content.

You've set the size of your grid items:

.side-menu {
  height: 50px;
}

.main-content {
  height: 300px;
}

So the .main-content, being the taller of the grid items, sets the height of the row:

enter image description here

As you can see, you have a grid container with one row.

Then your media query kicks in for smaller screens:

@media ( max-width: 400px ) {
  .main-container {
    grid-template-columns: 40px 80px;
  }
}

The new grid-template-columns rule alters the grid from three to two columns.

This forces the grid to create a second implicit row to accommodate the second .side-menu, whose column has been removed.

enter image description here

In short, a second row exists under the first row. The first row is 300px tall. This results in a wide vertical gap between the first and second menus.


One Possible Solution

Use multiple smaller rows and make your items span across them. The

The code below renders like this:

enter image description here

.main-container {
    display: grid;
    grid-template-columns: 40px 80px 40px;
    grid-auto-rows: 10px;  /* new */
    grid-column-gap: 20px; /* adjusted */
}

.side-menu:first-child {
  /* height: 50px; */
  grid-column: 1;
  grid-row: span 5;
}

.side-menu:last-child {
  /* height: 50px; */
  grid-column: 3;
  grid-row: span 5;
}

.main-content {
  /* height: 300px; */
  grid-column: 2;
  grid-row: span 30;
}

@media ( max-width: 400px ) {
  .main-container {
    grid-template-columns: 40px 80px;
  }
  .side-menu:last-child {
    grid-column: 1;
    grid-row: 7 / span 5;
  } 
}

.main-content { background-color: blue; }
.side-menu    { background-color: red;  }
<div class="main-container">
  <div class="side-menu"></div>
  <div class="main-content"></div>
  <div class="side-menu"></div>
</div>

codepen demo

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for you answer. But this is again a solution that is based on fixed heights values. I wont be able to know the height of either the side menus or the main content. I will update my question to be even more specific.
I understand what you're saying, and your question was clear. But if you want to use Grid CSS, and don't want grid items to automatically wrap to new rows (with the potential to create unsightly gaps) this is what you need to do.
1

In media screen you can set up 2 rows to do the job Also i suggest to use "fr" instead of pixels in grid layout.

You can find a nice guide here https://css-tricks.com/snippets/css/complete-guide-grid/

.main-container {
      width: 100%;
      height: 100%;
    }

    @media only screen and (min-width: 400px) {
      .main-container {
        display: grid;
        grid-gap: 20px;
        grid-template-columns: 40px 80px 40px;
        grid-template-rows: 40px;
        justify-content: center;
        grid-auto-flow: rows;
      }
      .side-menu:nth-child(odd) {
      width: 100%;
      height: 50px;
      background-color: red;
        grid-column: 1;
      }

      .side-menu:nth-child(even) {
      width: 100%;
      height: 50px;
      background-color: red;
        grid-column: 3;
      }
    }

    @media only screen and (max-width: 400px) {
      .main-container {
        display: grid;
        grid-gap: 20px;
        grid-template-columns: 40px 80px;
        grid-auto-rows: 40px;
        justify-content: center;
      }

      .side-menu {
      width: 100%;
      height: 50px;
      background-color: red;
        grid-column: 1;
      }
    }


    .main-content {
      width: 100%;
      height: 300px;
      background-color: blue;
    }
<div class="main-container">
  <div class="side-menu"></div>
  <div class="main-content"></div>
  <div class="side-menu"></div>
</div>

5 Comments

This is getting very close. However, in a scenario where one of the side menus suddenly have more menu items, this wont work anymore. or... the css would have to be updated to match the new height. e.i. not very responsive/dynamic unfortunately. I have updated the question to include this information.
Now it works, at least for mobile. I've set the .side-menu to auto-rows (it generate as many rows as your elements) and in column 1. You should give us info about the final result you want to achieve in desktop version. Please consider to edit your html, i think .side-menu elements has to be consecutive
side-menu:nth-child(even) does not hit the second side menu as it is number 3 (odd) so it is never in column 3. Change to: side-menu:nth-child(3) and it works better. But still has a problem with grid-auto-rows set to a fixed value. That makes the side menus forced to have a fixed height. Ideally they should be responsive so that can contain more/less menu items and expand in height, without overlapping each other.
codepen.io/anon/pen/aRoMzJ this is a little cleaner and closer to a solution, still not independent of heights unfortunately
Try to set a content for the side-menu, you can try with flex also but i suggest to create a side-menu as a container for each menu. You can find an interesting guide about flexbox <css-tricks.com/snippets/css/a-guide-to-flexbox>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.