Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating navbar with CSS grid

Tags:

html

css

css-grid

I'm creating a navbar made with CSS grid.

I decided making it with grid so I can re-arrange the sections (items) without modifying the html (just modify the CSS).

Then I created the grid with 3 areas: logo, menus, toggler.

And I added a bit of gap so each items won't stick together.

enter image description here

So far so good, until I tried to remove one/some sections, the gap still there even if the section was gone.

Then I tried to remove the gap and replace with a margin to each section. But the margin won't collapse at the beginning/ending of the grid. It behave differently than on regular block element.

I know it's more practical using a flexbox rather than a grid, but I prefer the grid because the section can be re-arranged without modifying the html. It's possible to move the logo at the top or somewhere else. Something impossible with flex.

Anyone can solve my grid-gap problem? Or maybe you've a different approach for creating the navbar?

See my sandbox:

.navbar {
  background: pink;
  display: grid;
  grid-template-rows: auto;
  grid-template-columns: max-content auto max-content;
  grid-template-areas: "logo menus toggler";
  justify-items: stretch;
  align-items: stretch;
  column-gap: 20px;
}

.logo {
  background: green;
  grid-area: logo;
  width: 60px;
}

.menus {
  background: lightsalmon;
  grid-area: menus;
  display: flex;
  flex-direction: row;
  justify-content: start;
}

.menus * {
  padding: 5px;
}

.toggler {
  background: lightskyblue;
  grid-area: toggler;
}
<p>navbar with complete sections:</p>
<nav class="navbar">
  <div class="logo">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler">
    X
  </div>
</nav>

<hr>

<p>navbar without logo:</p>
<nav class="navbar">
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler">
    X
  </div>
</nav>

<hr>

<p>navbar without toggler:</p>
<nav class="navbar">
  <div class="logo">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
</nav>
like image 508
Heyyy Marco Avatar asked Apr 19 '21 01:04

Heyyy Marco


3 Answers

In such case, you can rely on implicit columns. You only define one explicit column and you create new ones only when the elements are there. You can easily swap the positions with issue too

.navbar {
  background: pink;
  display: grid;
  grid-template-rows: auto;
  grid-template-columns: 1fr; /* only column intially */
  grid-auto-flow:dense;
  justify-items: stretch;
  align-items: stretch;
  column-gap: 20px;
}

.logo {
  background: green;
  width: 60px;
  grid-column:-3; /* create an implicit one at the beginning */
}

.menus {
  background: lightsalmon;
  display: flex;
  flex-direction: row;
  justify-content: start;
  grid-column: 1; /* take the explicit one */
}

.menus * {
  padding: 5px;
}

.toggler {
  background: lightskyblue;
  grid-column:2; /* create an implicit one at the end */
}
<p>navbar with complete sections:</p>
<nav class="navbar">
  <div class="logo">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler">
    X
  </div>
</nav>

<hr>

<p>navbar without logo:</p>
<nav class="navbar">
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler">
    X
  </div>
</nav>

<hr>

<p>navbar without toggler:</p>
<nav class="navbar">
  <div class="logo">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
</nav>

<hr>
<p>navbar without toggler and log at the end </p>
<nav class="navbar">
  <div class="logo" style="grid-column:2">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
</nav>

<hr>

<p>navbar without logo and toogler at the beginning </p>
<nav class="navbar">
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler" style="grid-column:-3">
    X
  </div>
</nav>
like image 200
Temani Afif Avatar answered Nov 15 '22 08:11

Temani Afif


Instead of column-gap: 20px; in this case you can try this:

nav > div:not(:first-child){
  margin-left:20px;
}

It adds margin for first level divs and it excludes the first div from selection.

.navbar {
  background: pink;
  display: grid;
  grid-template-rows: auto;
  grid-template-columns: max-content auto max-content;
  grid-template-areas: "logo menus toggler";
  justify-items: stretch;
  align-items: stretch;
}

nav > div:not(:first-child){
  margin-left:20px;
}

.logo {
  background: green;
  grid-area: logo;
  width: 60px;
}

.menus {
  background: lightsalmon;
  grid-area: menus;
  display: flex;
  flex-direction: row;
  justify-content: start;
}

.menus * {
  padding: 5px;
}

.toggler {
  background: lightskyblue;
  grid-area: toggler;
}
<p>navbar with complete sections:</p>
<nav class="navbar">
  <div class="logo">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler">
    X
  </div>
</nav>

<hr>

<p>navbar without logo:</p>
<nav class="navbar">
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
  <div class="toggler">
    X
  </div>
</nav>

<hr>

<p>navbar without toggler:</p>
<nav class="navbar">
  <div class="logo">
    LoGo
  </div>
  <div class="menus">
    <div>menu-1</div>
    <div>menu-2</div>
    <div>menu-3</div>
  </div>
</nav>
like image 25
Masoud Keshavarz Avatar answered Nov 15 '22 09:11

Masoud Keshavarz


This can absolutely be done with grid, and you're completely right about the strengths of grid being able to seemingly re-arrange html elements. I think the issue is that your column gap applies in all three cases since it is a part of your navbar class

.navbar {
    column-gap: 20px;
}

In the example below I created two grid-area containers using the same class. I applied the column-gap to the top container, but not the bottom container.

I also used justify-self: end for the blue div on the left to show you that there is no gap between columns, although you can also use the chrome dev tools to see that the top grid has gaps, while the bottom does not.

.container {
  display: grid;
  grid-template-areas: "left center right";
  margin-bottom: 40px;
}
.top {
  column-gap: 20px;
}
.bottom{
  column-gap: 0;
}

.d1 {
  grid-area: left;
  background: red;
}

.d2 {
  grid-area: center;
  background: red;
}

.d3 {
  grid-area: right;
  background: red;
}

.d4 {
  grid-area: left;
  background: blue;
  justify-self: end;
}

.d5 {
  grid-area: center;
  background: blue;
}

.d1,
.d2,
.d3,
.d4,
.d5 {
  width: 200px;
  height: 50px;
}
<div class="container top">
  <div class="d1"></div>
  <div class="d2"></div>
  <div class="d3"></div>
</div>

<div class="container bottom">
  <div class="d4"></div>
  <div class="d5"></div>
</div>
like image 36
ssbrear Avatar answered Nov 15 '22 07:11

ssbrear