Search code examples
htmlcssflexboxcss-grid

How do I style three divs as two columns with either flex or css-grid?


Goal

I want two divs (title and description) in column 1 with one div (button) in column 2 (see Layout Goal for a visual example using table markup). The button should be vertically aligned to the center of the first column if that column grows taller than column 2. I only want to use CSS to create the layout--either css-grid or flexbox, and I do not want to inherit any of the grid styling from the outer grid.

What I Have Tried

I have tried a variety of css-grid and flex layouts, and none of them worked. I could not figure out flexbox because I could never find a layout that was similar to my end goal, but it felt like it may be what I need. The closest I was able to get was using css-grid, but the second column would either grow (grid-row: 1/3) too much, making the whole column the button, or the button would not center vertically.

Samples

.outer-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: 24px;
  row-gap: 24px;
}

.container {
  padding: 24px;
  border: 1px solid black;
}

.title {
  font-weight: bold;
  font-size: 1.2em;
  margin-bottom: 12px;
}

.button {
  display: inline-block;
  padding: 12px;
  background-color: lightgray;
  border: 1px solid darkgray;
}


/* flex/grid properties */

.container {

}

.title,
.description {

}

.button {

}
<div class="outer-grid">
  <div class="container">
    <div class="title">Title of Element</div>
    <div class="description">This is the description of the element.</div>
    <a class="button">Button</a>
  </div>
  <div class="container">
    <div class="title">Title of Element</div>
    <div class="description">This is the description of the element.</div>
    <a class="button">Button</a>
  </div>
</div>


Solution

  • For those finding this question and wanting an answer, here is the solution using CSS grid layout by defining template areas.

    CSS to Add

    .container {
      display: grid;
      grid-template-columns: 1fr max-content;
      grid-template-rows: fit-content(100%);
      grid-template-areas:
        "title button"
        "description button";
      column-gap: 24px;
    
      /* center grid content top-to-bottom */
      align-content: center;
      align-items: center;
    }
    
    .title {
      grid-area: title;  
    }
    
    .description {
      grid-area: description;
    }
    
    .button {
      grid-area: button;
      align-self: center;
    }
    

    Solution Demo

    I tossed in an "even-height" solution as well for good measure. This makes all boxes across all rows the same height. This add-on is applied to the parent container (.outer-grid).

    .outer-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      column-gap: 24px;
      row-gap: 24px;
    
      /* makes height even across all rows */
      grid-auto-rows: 1fr;
    }
    
    .container {
      padding: 24px;
      border: 1px solid black;
    }
    
    .title {
      font-weight: bold;
      font-size: 1.2em;
      margin-bottom: 12px;
    }
    
    .button {
      display: inline-block;
      padding: 12px;
      background-color: lightgray;
      border: 1px solid darkgray;
    }
    
    
    /* grid layout */
    
    .container {
      display: grid;
      grid-template-columns: 1fr max-content;
      grid-template-rows: fit-content(100%);
      grid-template-areas:
        "title button"
        "description button";
      column-gap: 24px;
    
      /* center grid content top-to-bottom */
      align-content: center;
      align-items: center;
    }
    
    .title {
      grid-area: title;  
    }
    
    .description {
      grid-area: description;
    }
    
    .button {
      grid-area: button;
      align-self: center;
    }
    <div class="outer-grid">
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">This is the description of the element.</div>
        <a class="button">Button</a>
      </div>
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">This is the description of the element with a bit longer of a sentence so that it wraps.</div>
        <a class="button">Button</a>
      </div>
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">This is the description of the element with an even longer, more complex sentence--one that should be more interesting but is not.</div>
        <a class="button">Button</a>
      </div>
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">Short description.</div>
        <a class="button">Button</a>
      </div>
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">This could be Lorem Ipsum filler text, but why use filler text when you can write your own?</div>
        <a class="button">Button</a>
      </div>
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">Which of the 118 elements is this? Specificity is key--whether in CSS or language.</div>
        <a class="button">Clarify</a>
      </div>
      <div class="container">
        <div class="title">Title of Element</div>
        <div class="description">It's the end of the examples as we know it, and I feel fine.</div>
        <a class="button">Button</a>
      </div>
    </div>