skip to Main Content

What I’m trying to achieve:
I have a card element that has an image on the left, with a number of rows on the right. With grid, it might look something like this:

.container>* {
  border: 1px solid black;
}

.container {
  display: grid;
  grid-template-columns: [first] 70px [second] 1fr;
  grid-template-rows: 1fr 25% 25% 25% [lastRow];
  height: 70px;
  width: 220px;
  grid-template-areas: "date title" "date location" "date notes" "date links";
}

.title {
  grid-area: title;
  overflow: hidden;
}

.location {
  grid-area: location;
}

.notes {
  grid-area: notes;
}

.links {
  grid-area: links;
}

.date {
  grid-area: date;
}
<div class='container'>
  <div class='title'>Title that is super long and we are going to have a problem fitting it</div>
  <div class='location'>location</div>
  <div class='notes'>notes</div>
  <div class='links'>links</div>
  <div class='date'>date</div>
</div>

There are a few conditions: some of the the rows might not be present (only title is guaranteed), and title might be super long. Overflow is okay, but if rows are missing below title, I would like it to take up as much of that space as possible, while still allowing overflow to work. Ideally, all of the other rows below would go to the bottom (to give title as much space as possible), but I’m able to manage that on the server side by changing which areas the lines go to (but I would rather not change the css because there are multiple of these cards on the page).
Also, if all rows are present, they should take up the same amount of height.

Question: Is this possible with just css?

What I’ve tried:
I tried adding grid-row-end:lastRow; to the .title class, but while this helped me achieve the spacing effect, it broke overflow, as the element now thought that it had all of the space available to it up until the end of the card, so text appeared positioned behind other elements.

I also tried doing this through flex. This was actually the closest I got, but I wasn’t able to figure out how to get the flex-grow parameter to adjust the title row to take up more space when an element was missing (see my attempt below, and note what happens if you remove everything inside one of the divs with item2 or item3).
I set the flex-grow to be 1 for all elements, since they need to be the same when they’re all present, but set it to 0 for empty elements. This deletes them, but spreads the height between remaining items equally, but I want all of that extra height to go to the title element. I also couldn’t figure out if I could achieve this with flex-basis.

p {
  margin: 0;
  padding-left: 1%;
  padding-right: 1%;
  text-align: center;
  max-height: 100%;
}

.title {
  overflow: hidden;
}

.container {
  display: flex;
  border: 1px solid red;
  flex-direction: column;
  height: 150px;
  width: 80px;
}

.container>* {
  flex: 1 1;
  border: 1px solid #000;
  display: flex;
  justify-content: center;
  align-items: center;
}

.container> :first-child {
  flex: 1 1;
}

.container> :empty {
  flex-grow: 0;
  border: 0px;
  padding: 0px;
}
<div class="container">
  <div class="title">
    <p>item1 a really long piece of text that doesn't fit into our container at all</p>
  </div>
  <div>
    <p>item2</p>
  </div>
  <div>
    <p>item3</p>
  </div>
</div>

2

Answers


  1. Declaring a value for flex-basis in the flex shorthand is optional. When omitted, flex-basis is given 0 (replacing the default value "auto".)

    Going with the Flexbox example, you can use the :has() pseudo-class to declare flex-basis: auto on the child elements when there are empty child elements.

    Can I use :has()? currently shows 87.03% support. (It’s not enabled by default in Firefox, but that’s less than 3% of users.)

    I also want to point out that the :empty element must be completely empty with no whitespace, linebreaks, etc.

    .container:has(> :empty) > * {
      flex-basis: auto;
    }
    
    p {
      margin: 0;
      padding: 0 1%;
      text-align: center;
      max-height: 100%;
    }
    
    .title {
      flex-grow: 1;
      overflow: hidden;
    }
    
    .container {
      display: flex;
      border: 1px solid red;
      flex-direction: column;
      height: 150px;
      width: 80px;
    }
    
    .container > * {
      display: flex;
      flex: 1 1;
      justify-content: center;
      align-items: center;
      border: 1px solid;
    }
    
    .container > :empty {
      flex-grow: 0;
      border: 0;
    }
    
    .container:has(> :empty) > * {
      flex-basis: auto;
    }
    <div class="container">
      <div class="title">
        <p>row1 a really long piece of text that doesn't fit into our container at all</p>
      </div>
      <div>
        <p>row2</p>
      </div>
      <div>
        <p>row3</p>
      </div>
      <div>
        <p>row4</p>
      </div>
    </div>
    
    <hr>
    
    <div class="container">
      <div class="title">
        <p>row1 a really long piece of text that doesn't fit into our container at all</p>
      </div>
      <div>
        <p>row2</p>
      </div>
      <div></div>
      <div>
        <p>row4</p>
      </div>
    </div>
    
    <hr>
    
    <div class="container">
      <div class="title">
        <p>row1 a really long piece of text that doesn't fit into our container at all</p>
      </div>
      <div></div>
      <div>
        <p>row3</p>
      </div>
      <div></div>
    </div>
    Login or Signup to reply.
  2. I have simplified your CSS, and make some use of nth-child.

    This way we can make the rows of the grid dynamic, and probably solve the problem:

    .container > * {
      border: 1px solid black;
    }
    
    .container {
      display: grid;
      grid-template-columns: 70px 1fr;
      grid-template-rows: 1fr;
      grid-auto-rows: 25%;
      height: 70px;
      width: 220px;
      margin-top: 5px;
    }
    
    .title {
      overflow: hidden;
    }
    
    .title, .location, .notes, .links {
      grid-column: 2;
    }
    
    .date {
      grid-column: 1;
      grid-row-start: 1;
    }
    
    .date:nth-child(5) {
      grid-row-end: 5;
      background-color: lightblue;
    }
    
    .date:nth-child(4) {
      grid-row-end: 4;
      background-color: lightgreen;
    }
    
    .date:nth-child(3) {
      grid-row-end: 3;
      background-color: lightyellow;
    }
    
    .date:nth-child(2) {
      grid-row-end: 2;
      background-color: coral;
    }
    <div class='container'>
      <div class='title'>Title that is super long and we are going to have a problem fitting it</div>
      <div class='location'>location</div>
      <div class='notes'>notes</div>
      <div class='links'>links</div>
      <div class='date'>date</div>
    </div>
    
    <div class='container'>
      <div class='title'>Title that is super long and we are going to have a problem fitting it</div>
      <div class='location'>location</div>
      <div class='links'>links</div>
      <div class='date'>date</div>
    </div>
    
    <div class='container'>
      <div class='title'>Title that is super long and we are going to have a problem fitting it</div>
      <div class='location'>location</div>
      <div class='date'>date</div>
    </div> 
    
    <div class='container'>
      <div class='title'>Title that is super long and we are going to have a problem fitting it</div>
      <div class='date'>date</div>
    </div> 
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search