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
Declaring a value for
flex-basis
in theflex
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 declareflex-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.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: