76

I have the following layout in mind for a list. Each list item is represented by two columns. The second column should take up all available space, but it should be anchored to the right with its minimum size if the first column is taking up too much space. The first column should then show an ellipsis.

The problem is happening in that last case. When the first column consists of too much text, instead of showing an ellipsis, it stretches itself out of the flexbox causing an horizontal scrollbar to appear, and the second column is not anchored to the right.

I would like to have it rendered like this (mockup):

Expected rendering

How can I achieve that?

This is sample fiddle .

.container {
    display: -webkit-flex;
}

div {
    white-space: nowrap;
    text-overflow: ellipsis;
}

.container > div:last-child {
    -webkit-flex: 1;
    background: red;
}
<!-- a small first column; the second column is taking up space as expected -->
<div class="container">
    <div>foo barfoo bar</div>
    <div>foo bar</div>
</div>

<!-- a large first column; the first column is overflowing out of the flexbox container -->
<div class="container">
    <div>foo barfoo barfoo barfoo barfoo barfoo barfoo bar
    foo barfoo barfoo barfoo barfoo barfoo barfoo bar
    foo barfoo barfoo barfoo barfoo barfoo barfoo bar</div>
    <div>foo bar</div>
</div>
user
  • 23,260
  • 9
  • 113
  • 101
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • Related: http://stackoverflow.com/questions/19789263/prevent-css3-flex-shrink-from-crushing-content setting `flex-shrink` in my case was the solution. – greenoldman Jan 18 '15 at 21:24

7 Answers7

128

UPDATE

Adding code that works:

.container {
    display: -webkit-flex; 
}

.container>div:first-child{
    white-space:nowrap;
   -webkit-order:1;
   -webkit-flex: 0 1 auto; /*important*/
    text-overflow: ellipsis;
    overflow:hidden;
    min-width:0; /* new algorithm overrides the width calculation */
}

.container > div:last-child {
    -webkit-flex: 1;
    -webkit-order:2;
    background: red;
    -webkit-flex:1 0 auto; /*important*/
}
.container > div:first-child:hover{
    white-space:normal;
}
<div class="container">
    <div>foo barfoo bar</div>
    <div>foo bar</div>
</div>

<div class="container">
        <div>foo barfoo barfoo barfoo barfoo barfoo barfoo bar
        foo barfoo barfoo barfoo barfoo barfoo barfoo bar
        foo barfoo barfoo barfoo barfoo barfoo barfoo bar</div>
    <div>foo bar</div>
</div>
<div class="container">
    <div>foo barfoo bar</div>
    <div>foo bar</div>
</div>

<div class="container">
        <div>foo barfoo barfoo barfoo barfoo barfoo barfoo bar
        foo barfoo barfoo barfoo barfoo barfoo barfoo bar
        foo barfoo barfoo barfoo barfoo barfoo barfoo bar</div>
    <div>foo bar</div>
</div><div class="container">
    <div>foo barfoo bar</div>
    <div>foo bar</div>
</div>

Original answer / explanation.

W3C specification says, "By default, flex items won't shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the ‘min-width’ or ‘min-height’ property."

If we follow this line of reasoning, I believe the bug has been removed from Canary, not the other way round.

Check as soon as I put min-width to 0, it works in Canary.

So bug was in older implementations, and canary removes that bug.

This example is working in canary. http://jsfiddle.net/iamanubhavsaini/zWtBu/

I used Google Chrome Version 23.0.1245.0 canary.

matharden
  • 757
  • 6
  • 15
  • Perfect! Your solution works on both Chrome 21 and 23. – pimvdb Aug 26 '12 at 15:49
  • 24
    This is crazy. It took me a whole day to dig up this. Isn't flexbox supposed to be "non-hacky" solution to layout? Setting min-width to 0 to make flexbox work as I expected it looks hacky to me. Flexbox should be simpler and more straightforward. – Evgeni Petrov May 30 '13 at 12:56
  • did you manage to find a way to remove that extra white space after the ellipsis has been added? after the '...' there's a gap before the red 'foo bar'. – Vik Apr 23 '15 at 02:49
  • Thanks heaps mate, this just saved me so much time. – Keegan Lillo Aug 27 '15 at 21:31
  • 2
    Major 'aha!' moment reading this - `min-width: 0` makes perfect sense in the context of the minimum content size quoted above. Shame it's not at all obvious. Maybe I need to start printing W3C specs for bedtime reading... – Michael Mason Jun 09 '16 at 13:56
  • My "aha" was because someone else had added `* { min-width: 0; min-height: 0 }` to fix the very issue noted in this post, but by doing so had inadvertently screwed flex up across the whole of the site. Fun! – Matt Fletcher Aug 18 '17 at 12:00
  • I tried setting `overflow: hidden` also worked. – Daiwei Jan 05 '18 at 23:28
  • FWIW, using `white-space:nowrap;` was the offender which led me to this problem. Adding `min-width:0;` to the most immediate parent element solved the problem just as this answer described. – alphazwest Nov 03 '18 at 20:22
10

You can set the preferred size of the child by setting the third value of the flex property to auto, like so:

flex: 1 0 auto;

This is shorthand for setting the flex-basis property.

(Example)

As noted in the comments however, this doesn't seem to work in Chrome Canary, although I'm not sure why.

Marcus Stade
  • 4,724
  • 3
  • 33
  • 54
  • Is there a `min-width` value that is equal to the normal width of the element (i.e. so that the text just fits)? – pimvdb Aug 20 '12 at 23:08
  • In flexbox, `auto` should work like that according to the [spec](http://dev.w3.org/csswg/css3-flexbox/#min-auto) but I don't think there's any browser support for it yet. – Marcus Stade Aug 20 '12 at 23:18
  • I believe this [landed](http://trac.webkit.org/changeset/122508) in WebKit, and unfortunately your solution has broken in Chrome Canary (not sure if these are related to each other, though). The problem is that the red div *is* large enough to hold the text, but it's pushed away by the overflowing div. – pimvdb Aug 20 '12 at 23:21
  • I don't have Canary on this machine, but I found a solution that works without explicit min-width: http://jsfiddle.net/QCLjt/4/ -- Any chance you could give it a go? – Marcus Stade Aug 20 '12 at 23:32
  • It works like a charm on Chrome 21! But it has the same effect on Chrome 23. If Chrome 21 does what the spec says, then perhaps I should file a bug. – pimvdb Aug 20 '12 at 23:37
  • Hopefully someone smarter than me will be able to figure that one out :) – Marcus Stade Aug 20 '12 at 23:48
  • Edit the answer to reflect the discussion. Still no clue why it won't work in Canary unfortunately. – Marcus Stade Aug 20 '12 at 23:57
  • It's weird that in Chrome 21, the `-webkit-flex` shorthand accepts `auto` for the third item (and renders it correctly), while `-webkit-flex-basis` as a separate property isn't recognised yet. I'll see what other answers I might get, thanks for your time. – pimvdb Aug 21 '12 at 00:00
  • That answer actually helped with weird bug of Safari for iPhone 5/6 when block went off the borders of flex container – Zanshin13 Mar 23 '17 at 15:57
2

Update: This is not the answer. It solves different problem, and it was a step in finding the real answer. So I am keeping it for the historical reasons. Please don't vote on it.

I believe this is your answer: http://jsfiddle.net/iamanubhavsaini/zWtBu/2/

enter image description here

refer W3C

for the first element

-webkit-flex: 0 1 auto; /* important to note */

and for the second element

-webkit-flex:1 0 auto; /* important to note */

are the properties and values that do the trick.

Read more at http://www.w3.org/TR/2012/WD-css3-flexbox-20120612/#flex


and this is how you reverse the order: http://jsfiddle.net/iamanubhavsaini/zWtBu/3/

and this one with the predefined minimum width of the red-backgrounded-thingy: http://jsfiddle.net/iamanubhavsaini/zWtBu/1/

  • Thanks! Unfortunately this suffers from the same issue as the solution of @macke (i.e. it fails on Chrome 23). I'll see if it's a bug and whether/when it gets fixed. – pimvdb Aug 26 '12 at 14:19
0

Update: This is not the answer. It solves different problem, and it was a step in finding the real answer. So I am keeping it for the historical reasons. Please don't vote on it.

EDIT 2: This answer doesn't solve the problem. There is a subtle difference between target of the question and the answer.

First of all, text-overflow:ellipsis works with overflow:hidden. Actually, it works with anything other than overflow:visible .Ref

Then, iterate through:

http://jsfiddle.net/iamanubhavsaini/QCLjt/8/

Here, I have put overflow and max-width properties. max-width:60%; and overflow:hidden is what makes things appear as you intended, as hidden stops the text from displaying and 60% actually creates the box of definite size in case of too much text data.

Then, if you are really interested in flex box model here's how things pan out via -webkit-order.

http://jsfiddle.net/iamanubhavsaini/QCLjt/9/

--code--

<div class="container">
    <div>foo barfoo bar</div>
    <div>foo bar</div>
</div>

<div class="container">
        <div>foo barfoo barfoo barfoo barfoo barfoo barfoo bar
        foo barfoo barfoo barfoo barfoo barfoo barfoo bar
        foo barfoo barfoo barfoo barfoo barfoo barfoo bar</div>
    <div>foo bar</div>
</div>

​concerned CSS

.container {
    display: -webkit-flex;
}

div {
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow:hidden;
}
.container>div:first-child{
   -webkit-order:1;
        -webkit-flex: 1;
}
.container > div:last-child {
    -webkit-flex: 1;
    -webkit-order:2;
    background: red;
}

​-- There is no width and still it works. And this is what I see.

enter image description here

--after comment

-webkit-order:N; is the what we will be using after 2+ years instead of float:---; and many more hacks(if W3C stays on this course and also if every browser vendor follow)

here, order is 1 for the left div and 2 for the right div. thus, they are Left-Right.

http://jsfiddle.net/iamanubhavsaini/QCLjt/10/

same thing here, but only if you are looking for Right-Left, just change the order of the things as div>first-child { -webkit-order:2; } div>last-child{-webkit-order:1;}

NOTE: this -webkit-flex way of doing things obviously renders this code useless on other engines. For, reuse of code, on multiple browser engines floating should be used.

below are some JS examples; that doesn't answer the question -after comment

I think this answers your question and many more to come, there are some other ways and different solutions but not exactly the solution for this question. http://jsfiddle.net/iamanubhavsaini/vtaY8/1/ http://jsfiddle.net/iamanubhavsaini/9z3Qr/3/ http://jsfiddle.net/iamanubhavsaini/33v8g/4/ http://jsfiddle.net/iamanubhavsaini/33v8g/1/

  • My system setup: Win 7, Chrome 21.0.1180.83 m. –  Aug 26 '12 at 05:13
  • I appreciate your input but it does not answer my question. You're setting explicit widths which of course is not difficult. I did set `overflow: hidden`, and `-webkit-order` does not change anything in your fiddle. Your last fiddle doesn't use flexbox at all; it even uses JavaScript. I'm sorry but this is basically some generic flexbox explanation which I was not after. – pimvdb Aug 26 '12 at 09:47
  • really? where can you see WIDTH in http://jsfiddle.net/iamanubhavsaini/QCLjt/9/ –  Aug 26 '12 at 13:02
  • That's not the rendering I'm after. Please read my question and look at the mockup screenshot, thanks. – pimvdb Aug 26 '12 at 13:36
0

for mozilla you should add "min-width: 1px;"

goksel
  • 4,450
  • 3
  • 42
  • 51
0

This example really helped me: http://jsfiddle.net/laukstein/LLNsV/

container {
    display: -webkit-flex;
    -webkit-flex-direction: row;
    padding: 0;
    white-space: nowrap;
}

.container>div {
    overflow: hidden;
    display: inline-block;
    -webkit-flex: 1;
    min-width: 0;
    text-overflow: ellipsis;
    -moz-box-sizing: border-box;
         box-sizing: border-box;
}
Con Antonakos
  • 1,735
  • 20
  • 23
-4

You should make the container position: relative and the child position: absolute.

Radu Brehar
  • 155
  • 2
  • 7