Ruben
Ruben

Reputation: 3532

Align flexbox items horizontally with unwrappable variable-width item

I want to align three items in a flexbox like this. The context is that these are unknown-length (but wrappable) labels for an unknown-width (unwrappable) slider/row of buttons in a survey.

[L] [R] [variable width]

How do I align the top two items to the width of the lower/middle item without fixing the width of the container to the (in reality unknown width of the middle item)?

I considered putting left and right into another flexbox and using a column layout for the top container. I don't like that way, because I'd have to break with the true content order (left-middle-right), but I couldn't even make it work this way.

div {
  border: 1px dotted;
}

.container {
  display: flex;
  flex-wrap: wrap;
  width: 300px; /* I want to get rid of this */
}

.left {
  order: 1;
  flex: 1 0;
}

.right {
  order: 2;
  flex: 1 0;
  text-align: right;
}

.middle {
  order: 3;
  flex: 2 0 auto;
}
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    Some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right label may wrap if it's wider than 50%
  </div>
</div>

Upvotes: 2

Views: 927

Answers (5)

Vadim Ovchinnikov
Vadim Ovchinnikov

Reputation: 14022

The only pure CSS possibility to align items as you want is CSS Grid.

div {
  border: 1px dotted;
}

.container {
  display: inline-grid;
  grid-template-columns: min-content min-content;
}

.right {
  grid-column: 2;
  grid-row: 1;
}

.middle {
  grid-column: 1 / span 2;
  white-space: nowrap;
}
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    Some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right label may wrap if it's wider than 50%
  </div>
</div>

Also if you need IE10+ support it's easy to achieve:

div {
  border: 1px dotted;
}

.container {
  display: -ms-inline-grid;
  display: inline-grid;
  -ms-grid-columns: min-content min-content;
  grid-template-columns: min-content min-content;
}

.right {
  -ms-grid-column: 2;
  grid-column: 2;
  grid-row: 1;
}

.middle {
  -ms-grid-row: 2;
  -ms-grid-column-span: 2;
  grid-column: 1 / span 2;
  white-space: nowrap;
}
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    Some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right label may wrap if it's wider than 50%
  </div>
</div>

Upvotes: 1

Adam
Adam

Reputation: 1383

Use flex-basis: number% it works very well and supported by IE 10+, and you can choose your breaking point in media query selectors if you want.

check my code:

div {
  border: 1px dotted;
}

.container {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}

.left {
  flex-basis: 49.55%; /* change this to whatever you want */
}

.right {
  flex-basis: 49.55%; /* change this to whatever you want */
}

.middle {
  order: 3;
  flex-basis: 100%;
}
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    Some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right label may wrap if it's wider than 50%
  </div>
</div>

Upvotes: -1

Temani Afif
Temani Afif

Reputation: 273934

Here is an idea of solution without adding extra markup:

.container {
  display: inline-flex;
  flex-wrap: wrap;
  max-width: 100%;
  border: 1px solid;
  margin: 20px;
}

.left {
  order: 1;
  min-width: 0;
  width: 0.5px;
  white-space: nowrap;
}

.right {
  order: 2;
  min-width: 0;
  width: 0.5px;
  margin-left: auto;
  display: flex;
  justify-content: flex-end;
  white-space: nowrap;
}

.middle {
  order: 3;
  flex-basis: 100%
}
<div class="container">
  <div class="left">
    some left content
  </div>
  <div class="middle">
    So in my real example, there is some unknown-width unwrappable thing here. there is some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    some right content
  </div>
</div>
<div class="container">
  <div class="left">
    some left content
  </div>
  <div class="middle">
    So in my real example, there is some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right
  </div>
</div>
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    So in my real example, there is.
  </div>
  <div class="right">
    right
  </div>
</div>
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    So in my
  </div>
  <div class="right">
    right
  </div>
</div>

But if you are ok to slightly adjust the HTML you can try something like this:

.container {
  display: inline-flex;
  flex-direction: column;
  max-width: 100%;
  border: 1px solid;
  margin: 20px;
}

.sub {
  display: flex;
  justify-content: space-between;
}
<div class="container">
  <div class="sub">
    <div class="left">
      some left content
    </div>
    <div class="right">
      some right content
    </div>
  </div>
  <div class="middle">
    So in my real example, there is some unknown-width unwrappable thing here. there is some unknown-width unwrappable thing here.
  </div>
</div>
<div class="container">
  <div class="sub">
    <div class="left">
      some left content
    </div>
    <div class="right">
      some right content
    </div>
  </div>
  <div class="middle">
    So in my real example, there is some unk
  </div>
</div>
<div class="container">
  <div class="sub">
    <div class="left">
      left
    </div>
    <div class="right">
      right
    </div>
  </div>
  <div class="middle">
    So in my real example,
  </div>
</div>

Upvotes: 3

Richard Parnaby-King
Richard Parnaby-King

Reputation: 14892

I don't think flex can be configured like that. The effect you are looking for can be achieved using position:absolute on the left/right elements:

.container {
  position: relative;
  padding-top: 1em;
  display: inline-block;
}

.left,
.right {
  position: absolute;
  top: 0;
}

.left {
  left: 0;
}

.right {
  right: 0;
}

.middle {}
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    So in my real example, there is some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right
  </div>
</div>

Upvotes: 1

Mers
Mers

Reputation: 734

You could change the flex from auto to 100%, and add text-align: center to .middle, like so:

.container {
  display: flex;
  flex-wrap: wrap;
}

.left {
  order: 1;
  flex: 1 0;
}

.right {
  order: 2;
  flex: 1 0;
  text-align: right;
}

.middle {
  order: 3;
  flex: 2 0 100%; /* change this to 100% instead of auto */
  text-align: center; /* To center the text */
}
<div class="container">
  <div class="left">
    left
  </div>
  <div class="middle">
    So in my real example, there is some unknown-width unwrappable thing here.
  </div>
  <div class="right">
    right
  </div>
</div>

Upvotes: 0

Related Questions