Search code examples
csscss-grid

Align child elements at inner grid lines


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.


Solution

  • 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.