1

I am trying to build a responsive navigation bar with CSS Grid layout that spans across the viewport width, but the inner items should be centred and aligned with other container elements on the page.

The result that I want is displayed in the code below, however, I don't feel that this is an elegant solution as I used 2 separate <div> elements stacked on top of each other.

One <div> is for having the items centred and the second <div> is to cover the background-color across the viewport width.


Is there a better way of doing this using the CSS Grid layout?

[EDIT] I am looking for a way to make the technique reusable on multiple elements.


Please expand the code snippet to full page so the layout appears correctly

.container {
  display: grid;
  grid-template-columns: 1fr repeat(4, minmax(min-content, 150px)) 1fr;
  border: 2px solid black;
  height: 100vh;
}

.nav {
  grid-area: 1 / 2 / 1 / span 4;
  height: 50px;
  background-color: grey;
  border: 1px solid red;
  position: relative;
}

.nav-underlay {
  background-color: grey;
  grid-area: 1 / 1 / 1 / span 7;
  height: 50px;
}

.content {
  grid-area: 2 / 2 / 2 / span 4;
  height: 200px;
  background-color: grey;
  border: 1px solid red;
}
<body class="container">
  <div class="nav">this box should stay aligned with the content box</div>
  <div class="nav-underlay"></div>
  <div class="content">Content box</div>
</body>
Lenny86
  • 120
  • 1
  • 9

1 Answers1

2

Since the background area you're looking to expand is for decorative purposes only (i.e., you're not using that area to convey content), then you can use CSS pseudo-elements instead of an actual HTML element.

Pseudo-elements become grid items when applied to a grid container (read more).

.container {
  display: grid;
  grid-template-columns: 1fr repeat(4, minmax(min-content, 150px)) 1fr;
  border: 2px solid black;
  height: 100vh;
}

.nav {
  grid-area: 1 / 2 / 2 / span 4;
  height: 50px;
  background-color: grey;
  border: 1px solid red;
  position: relative;
}

.container::before {
  grid-area: 1 / 1 / 2 / 2;
  content: "";
  background-color: grey;
  height: 50px;
}

.container::after {
  grid-area: 1 / -1 / 2 / -2;
  background-color: grey;
  height: 50px;
  content: "";
}

.content {
  grid-area: 2 / 2 / 2 / span 4;
  height: 200px;
  background-color: grey;
  border: 1px solid red;
}
<body class="container">
  <div class="nav">this box should stay aligned with the content box</div>
  <div class="content">Content box</div>
</body>

jsFiddle demo

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • This is a nice and clean solution and it answers my original question. If I wanted to add another element(eg. a banner) that would need to span across the viewport width in a similar fashion like the navigation bar, I could only apply the `::after` and `::before` pseudo-elements once? Is there a way to make this technique reusable on multiple elements? – Lenny86 Nov 02 '18 at 13:29
  • 1
    Hi @Michael_B, any idea for this one : https://stackoverflow.com/questions/53119276/extra-space-when-center-elements-using-flexbox ? – Temani Afif Nov 02 '18 at 22:11
  • 1
    @Lenny86, it would be tricky at this point, since pseudo-elements are considered children of their container. So, like you said, this can only be done once in a grid container. Ideally, you would be able to apply the pseudo-elements to grid items, and have the pseudo-elements respect the primary container's lines. That capability (`display: subgrid`) is in the works, but not available yet. https://stackoverflow.com/q/47929369/3597276 – Michael Benjamin Nov 03 '18 at 11:33