2

I have a simple CSS Grid Layout with three columns. I need to have the first row's background stretch across the entire track, yet align the child elements at inner grid lines, like a standard navbar aligned with the content following it. I'm using the following code, but can accomplish only one of my requirements at a time (either have the background color stretch across, moving child elements to the left, or have the child elements in the right position, but failing to have the background color run across):

body {
  display: grid;
  grid-template: 
           "nav   nav   nav" 
           " .  content  . "
}

nav {
  background-color: lightblue;
  grid-area: nav;
}

nav ul {
  display: flex;
  list-style: none;
}

main {
  grid-area: content;
}
<nav>
  <ul>
    <li>item 1</li>
    <li>item 2</li>
  </ul>
</nav>

<main>
  <h1>content</h1>
</main>

As far as I understand, I can only place immediate child elements of a grid container when using CSS Grid Layout. In other words, I can place nav but not nav ul. Presumably, CSS Grid Layout Module Level 2 will lift this restriction, and make this embarrassingly trivial. But I need a solution that works today.

How would I go about this, given the following restrictions:

  • A solution must be CSS-only (no JavaScript or frameworks).
  • It must be maintainable, e.g. if I decide to change the first column's width, I do not want to change two (or more) pieces of code.
  • A solution need not be generic; I really just need to span a single solid color across a row, in case that makes a difference.

Update:

Reading the answers I realize, that my wording was too sloppy. What I asked for did not coincide with what I meant to ask. I'm looking for a CSS Grid Layout based solution replicating the following 'traditional' implementation:

nav {
  background-color: lightblue;
}

.container {
  margin: auto;
  width: 80vw;
}
<nav>
  <div class="container">
    <a>item</a>
    <a>item</a>
  </div>
</nav>

<main>
  <div class="container">
    <p>content</p>
  </div>
</main>

I need the background color of the navigation bar to cover the entire width of the parent element, but have the actual content of <nav> and <main> be left-aligned at the same horizontal position.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • something like this: https://stackoverflow.com/a/53554204/8620333 ? – Temani Afif Dec 15 '19 at 11:31
  • @tem: That seems to always cover the entire viewport width, so this only works, if the layout uses up the entire viewport width as well. I'll be using this for now, but it doesn't quite cover my use case. – IInspectable Dec 15 '19 at 12:15

2 Answers2

2

Notice how your main element, an HTML5 semantically-meaningful container, eliminates the need for a div container, which was common prior to HTML5.

<!-- valid and efficient structure -->
<main>
  <h1>content</h1>
</main>

<!-- valid but inefficient structure -->
<main>
  <div>
     <h1>content</h1>
  </div>
</main>

Why aren't you applying this same principle to your navigation bar?

With the HTML5 nav tag available, why use list items?

Instead of this:

<nav>
   <ul>
      <li>item 1</li>
      <li>item 2</li>
   </ul>
</nav>

Just do this:

<nav>
   <a>item 1</a>
   <a>item 2</a>
</nav>

This offers you at least three benefits:

  1. a clean and semantically-meaningful element,
  2. an HTML structure that falls within the scope of Grid's parent-child relationship, and
  3. with one nested grid, that occupies the same space as the parent grid, you can align your items along grid lines.

body {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-areas: " nav nav nav " 
                       " . content . "
}

nav {
  grid-area: nav;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  background-color: lightblue;
}

main {
  grid-area: content;
}
<nav>
  <a>item 1</a>
  <a>item 2</a>
  <a>item 3</a>
</nav>

<main>
  <h1>content</h1>
</main>

There are other ways to achieve your layout, and the code concept above could be applied to your original HTML structure (just add another nested grid). I'm just putting this forward as one hopefully useful method.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • That was insightful, thanks. I did not realize, that I could use ` – IInspectable Dec 16 '19 at 10:39
  • Then you may need to wait for implementation of the [subgrid feature](https://stackoverflow.com/q/47929369/3597276). – Michael Benjamin Dec 16 '19 at 11:48
1

Your problem comes from having your grid styles on the body tag. Move them down to the individual sections you want to format:

main,
header ul.menu {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

main .content {
  grid-column: 2/3;
}

header ul.menu {
  list-style: none;
  padding: 0;
  margin: 0;
  background-color: lightblue;
}

header ul.menu li {
   margin: 1em;
}

header ul.menu li:not(:first-child){
   margin-left: 0;
}
<header>
  <nav>
    <ul class="menu">
      <li>item 1</li>
      <li>item 2</li>
    </ul>
  </nav>
</header>

<main>
  <div class="content">
    <h1>content</h1>
  </div>
</main>
symlink
  • 11,984
  • 7
  • 29
  • 50
  • This doesn't align the items along the inner grid lines, as specified. It just spreads them out across the row. – Michael Benjamin Dec 15 '19 at 17:25
  • Yes. This is the same concept as in my answer: *Moving the grid closer to the items.* Except I didn't remove the top-level grid because I don't know if it's needed for other purposes. – Michael Benjamin Dec 15 '19 at 17:58
  • @Michael_B It's close. If you look again at yours, you are nesting two grids, which causes your items to not line up exactly. – symlink Dec 15 '19 at 18:09
  • Thanks for pointing that out. The problem wasn't the nested grid. It was top-level grid columns set (by default) to `auto`, and nested grid columns set (by me) to `1fr`. I fixed it. It all lines up now. – Michael Benjamin Dec 15 '19 at 19:09
  • @Michael_B You're welcome. I still don't recommend nesting grids with the same layout as doing things like common formatting of children creates a telescope effect. – symlink Dec 15 '19 at 19:21