20

I'm making a page with a vertical menu using display: flex;. I want the menu's width to fit snuggly around a few buttons, without having to use a fixed width.

However, I also want the menu box to have a status message, which can have quite a long text. I'd like this status-div to have the width of the menu, while not forcing the menu container to grow its width. Instead, the status-div should grow its height and wrap the text.

Explaining this in words is pretty difficult, so I suggest you checkout out this fiddle: http://jsfiddle.net/bXL3q/

Note the difference when setting .statusmessage to display: none;.

Any ideas, or is what I'm trying to do not feasible? ..should it be?


What I've tried:

  • width: 100% fails, obviously it just assumes the parent width
  • width: -webkit-min-content sort of works, but it makes the element too narrow
  • flex-basis and flex-grow affect the height of the element, and do nothing to affect the width
  • position: absolute will solve the width issues, but now I have no way to define the height of the status-div.. (for the purpose of forcing a scroll bar in windows with small height - instead it will just flow over the button elements)

body {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  flex-flow: row nowrap;
  align-items: stretch;
}

.page {
  flex-grow: 1;
  background-color: yellow;
}

.menu {
  background-color: red;
  height: 100%;
  display: flex;
  flex-flow: column nowrap;
}

.somechildren {
  white-space: nowrap;
  background-color: green;
  border: 1px solid black;
}

.menu>* {
  flex-shrink: 0;
}

.separate {
  flex-grow: 1;
}

.statusmessage {
  background-color: magenta;
  align-self: flex-end;
  /*display: none;*/
}
<div class=menu>
  <div class=somechildren>I'd like the menu's</div>
  <div class=somechildren>width to fit nicely</div>
  <div class=somechildren>around these children</div>

  <div class=separate></div>

  <div class=statusmessage>
    While forcing this status message to wrap and grow its height, without affecting the width of the container.
  </div>
</div>
<div class=page>
  The page
</div>
Brett DeWoody
  • 59,771
  • 29
  • 135
  • 184
Thoronwen
  • 574
  • 1
  • 5
  • 13

3 Answers3

33

You were almost there with width. What you need to do is set width and min-width (demo):

.statusmessage {
 width:0; /* Collapses .statusmessage so it doesn't affect column width */
 min-width:100%; /* Expands .statusmessage to width of column */
}

The width can be (and probably should be) set to a value other than 0. It should just be the minimum width of the column or smaller. So use a value that works for you.

I've tested this on Chrome and Firefox and seems to work in both. Now, is it supposed to work? I'm not sure, I haven't read into the spec that much (it could be undefined). Make sure to test in all browsers you need it to work in. (And check the spec to see if this behavior is undefined/incorrect.)

0b10011
  • 18,397
  • 4
  • 65
  • 86
  • 2
    Thats.. amazing :P The statusmessage's width is used to calculate the width of the parent, and afterwards the min-width of 100% is applied. Effectively, the width acts as a minimum width in case the other elements are small, and the min-width property defines the 'real' width. – Thoronwen Jul 31 '14 at 07:26
  • 1
    Chrome 36, Firefox 31 and IE 11 are all playing ball. Cheers! – Thoronwen Jul 31 '14 at 07:29
  • 1
    Derp, our special friend IE11 is not playing ball after all. I'll max-width for IE specifically. – Thoronwen Jul 31 '14 at 10:00
  • 1
    Man you saved me today. This sound like an awfully good and weird trick. – Minh Nghĩa Aug 25 '22 at 04:01
3

width: 0; min-width: 100%; didn't work for me.

Instead, I set

position: relative;

on the flex child and wrapped its contents in an inner div with

position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;

This prevents the contents from contributing to the flex container size while still matching the cross-axis size determined by the rest of the flex children.

CletusW
  • 3,890
  • 1
  • 27
  • 42
  • Wrapping the flex child's content in an inner div worked for me, without changing styling. Thank you. (`width: 0; min-width: 100%;` didn't work for me, either) – Matt Kleinsmith Jan 27 '23 at 04:01
1

For me, the issue was that the default value of align-items is stretch. So the items stretch out the cross axis by default.

You can either set align-items: flex-start or align-self: flex-start for the single flex child.

The visual here is quite illustrative.

kuzdogan
  • 554
  • 7
  • 13