84

I'm working on a web app that shows a large grid of cards, the height of which is inherently variable.

In the interests of aesthetics, we were using jQuery's .matchHeight() to equalise the height of cards within each row.

The performance of that didn't scale well, so today I've been migrating to a flex-box based solution which is so much faster.

However, I've lost a behaviour - the content of the card header should be truncated with an ellipsis if it won't fit.

Goals:

  1. 3 columns
  2. Column widths vary to fill parent
  3. Constant spacing between columns
  4. Heights equalised within a row

How do I arrange for the container size to be respected and the text-overflow: ellipsis; and white-space: nowrap; to be honoured?

(No jQuery tag as we're moving away from that)

My solution in it's current form, which achieves all of my goals apart from the truncation:

https://codepen.io/anon/pen/QvqZYY

#container { 
                display: flex; 
                flex-direction: row; 
                flex-wrap: wrap; 
                
                justify-content: flex-start;    /* Bias cards to stack from left edge       */ 
                align-items: stretch;           /* Within a row, all cards the same height  */ 
                
                border: thin solid gray; 
            } 
            .card-wrapper { 
                width: 33.33%; 
                display: flex; 
                background: #e0e0ff; 
            } 
            .card { 
                flex-grow: 1; 
                margin: 7px; 
                display: flex; 
                flex-direction: column; 
                border: thin solid gray; 
                background: #e0ffff; 
            } 
            .card div { 
                border: thin solid gray; 
            } 
            .card div:nth-child(1) { 
                white-space: nowrap; 
                text-overflow: ellipsis; 
            } 
            .card div:nth-child(2) { 
                flex-grow: 2; 
            } 
<div id="container"> 
            <div class="card-wrapper"> 
                <div class="card"> 
                    <div>Title</div> 
                    <div>Multiline<br/>Body</div> 
                    <div>Footer</div> 
                </div> 
            </div> 
            <div class="card-wrapper"><div class="card"><div>Really long rambling title that pushes beyond the bounds of the container, unless your screen is really, really wide</div><div>Body</div><div>Footer</div></div></div> 
            <div class="card-wrapper"><div class="card"><div>Title</div><div>Body</div><div>Footer</div></div></div> 
            <div class="card-wrapper"><div class="card"><div>Title</div><div>Body</div><div>Footer</div></div></div> 
            <div class="card-wrapper"><div class="card"><div>Title</div><div>Body</div><div>Footer</div></div></div> 
        </div> 
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Chris
  • 3,445
  • 3
  • 22
  • 28

1 Answers1

200

An initial setting on flex items is min-width: auto. This means that a flex item, by default, cannot be smaller than the size of its content.

Therefore, text-overflow: ellipsis cannot work because a flex item will simply expand, rather than permit an overflow. (Scroll bars will not render either, for the same reason.)

To override this behavior, use min-width: 0 or overflow: hidden. More details.

#container {
  display: flex;
  flex-wrap: wrap;
  border: thin solid gray;
}

.card-wrapper {
  width: 33.33%;
  display: flex;
  background: #e0e0ff;
}

.card {
  flex-grow: 1;
  margin: 7px;
  display: flex;
  flex-direction: column;
  border: thin solid gray;
  background: #e0ffff;
  overflow: hidden;        /* NEW */
}

.card div {
  border: thin solid gray;
}

.card div:nth-child(1) {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;        /* NEW */
}

.card div:nth-child(2) {
  flex-grow: 2;
}
<div id="container">
  <div class="card-wrapper">
    <div class="card">
      <div>Title</div>
      <div>Multiline<br/>Body</div>
      <div>Footer</div>
    </div>
  </div>
  <div class="card-wrapper">
    <div class="card">
      <div>Really long rambling title that pushes beyond the bounds of the container, unless your screen is really, really wide</div>
      <div>Body</div>
      <div>Footer</div>
    </div>
  </div>
  <div class="card-wrapper">
    <div class="card">
      <div>Title</div>
      <div>Body</div>
      <div>Footer</div>
    </div>
  </div>
  <div class="card-wrapper">
    <div class="card">
      <div>Title</div>
      <div>Body</div>
      <div>Footer</div>
    </div>
  </div>
  <div class="card-wrapper">
    <div class="card">
      <div>Title</div>
      <div>Body</div>
      <div>Footer</div>
    </div>
  </div>
</div>
Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    No reason to pick one over the other in terms of the flex minimum sizing issue. But there is a difference in terms of general CSS. `min-width: 0` will allow the item to shrink, but the content can visibly overflow ([you can test this in your codepen](https://codepen.io/anon/pen/NjaEMK)) ... – Michael Benjamin May 05 '17 at 16:50
  • With `overflow: hidden` the same minimum sizing objective is achieved, but overflow content is hidden. Plus, [the `overflow` property is necessary for `text-overflow: ellipsis` to work](http://stackoverflow.com/a/33061059/3597276). – Michael Benjamin May 05 '17 at 16:52
  • 1
    Thanks for the clarification. `overflow: hidden;` it is then. – Chris May 05 '17 at 16:54
  • 12
    `min-width: 0` fixed my issue which was similar. I had placed `max-width: x` on my container so text overflow would work but that would push other items out of the container on responsive. `min-width: 0` prevented that :) Thanks! – pourmesomecode Mar 21 '18 at 10:46
  • 2
    Thank you for this. Was stuck for hours.. :) – ankitjain11 Aug 01 '19 at 11:38
  • There are some cases where you do want to have some content sticking out (for instance: `position: absolute` stuff) in which case the `min-width:0` solution is the only way to go – byteSlayer Dec 28 '20 at 19:24
  • 5
    `min-width: 0` on flex children is just what I was looking for. Makes text overflow work perfectly. Thanks! – camslice Jul 15 '21 at 12:13