Robert Koritnik
Robert Koritnik

Reputation: 104999

CSS flexbox with single container and differently sized items

I'm trying to implement a flex box of the following scenario outlined by this positioning

+----+----------+----+
|   1|2>        |  <3|
+----+----------+----+
|   4|5              |
|   v|v              |
+----+               |
     |               |
+----+------+--------+
|7>         |      <6|
+-----------+--------+

Explanation

The problem

The main problem is that all of the items are within the same flex container. Therefore I have problems wrapping them (breaking the line) at the right point i.e. items should wrap after item 3, while items 2 and 3 have to stretch over the whole line, so item 3 can display content completely to the right of itself.

Here a working JSFiddle with inital HTML and CSS that you can work on.

Some ideas

Maybe just for idea that crossed my mind. One could use two additional items in flexbox container by using :before and :after and giving them proper order. This way one could simulate some additional content to get required results.

If there were flex groups it would be much easier because one could change flex-direction to column and group several items together:1&2&3, 4&5 and 6&7 and position them in row within flex group with proper widths.

Upvotes: 1

Views: 4251

Answers (3)

Robert Koritnik
Robert Koritnik

Reputation: 104999

Solution

This solution I've now come up with using some ideas of @Jan's answer and realising that all browsers that support flexbox also support calc CSS function. And based on this I was able to make flexbox container flexible and keep items within break at points I require.

Jan's answer solved my layout assuming that all item widths are relative to container, yet items #1 and #3 have fixed widths. All of the others are flexible according to layout.

I'm just adding the most important CSS that defines flex item widths on a flexible container. I'll refer to .itemX as a selector of flex item X where X is element number. So these selectors are just pseudo code for easier understanding. Adjust accordingly:

.itemAll {
    flex-grow: 1;
}

.item1,
.item4 {
    flex-grow: 0;
    flex-basis: @FixedWidth; /* i.e. 25px */
}

.item2,
.item3 {
    flex-basis: calc((100% - @FixedWidth)/2);
}

.item5 {
    flex-basis: calc(100% - @FixedWidth);
}

.item6,
.item7 {
    flex-basis: 50%;
}

As we can see from my modified JSFiddle example this actually works. Try resizing results panel width and you'll see that all flex items except #1 and #4 adjust their width according to container and always keep their layout as defined.

Upvotes: 0

Oriol
Oriol

Reputation: 287950

Effectively, you can use pseudo-elements to achieve this:

main::before, main::after {
    content: '';        /* Enable pseudo-elements */
    margin-right: 100%; /* Force line break */
}
main::before {
    order: 4;           /* Place it before .i4 */
}
main::after {
    order: 5;           /* Place it after .i5 */
}

main {
  width: 200px;
  display: flex;
  flex-flow: row wrap;
  border: 1px solid #ccc;
  resize: horizontal;
  overflow: auto;
}
main::before, main::after {
  content: '';
  margin-right: 100%;
}
main::before {
  order: 4;
}
main::after {
  order: 5;
}
.i2, .i3, .i5, .i6, .i7 {
  flex-grow: 1;
}
.i5 {
  width: 0;
}
section {
  border: 1px solid #eee;
}
.i1, .i4 {
  width: 50px;
  text-align: right;
}
.i7 {
  text-align: right;
  order: 6;
}
.i1 { order: 1; }
.i2 { order: 2; }
.i3 { order: 3; }
.i4 { order: 4; }
.i5 { order: 5; }
.i6 { order: 7; }
.i7 { order: 6; }
<main>
  <section class="i1">1</section>
  <section class="i2">2</section>
  <section class="i3">3</section>
  <section class="i4">4</section>
  <section class="i5">This one has much more content than the rest.</section>
  <section class="i6">6</section>
  <section class="i7">7</section>
</main>

Upvotes: 1

Jan
Jan

Reputation: 1414

I managed to achieve the desired result by using flex-basis. When the items 1, 2, 3 and 4 all have a basis of 26%, the 4th item does not fit in the first row anymore. The same thing can be applied to the second row.

Then flex-grow can be applied to items 2, 3, 5, 6 and 7 to fill the remaining space in each row.

Finally align-self the 4th item, so it does not use the same height as item 5.

Updated JSFiddle: http://jsfiddle.net/ojmghu3t/2/

Update: Of course you can also specify px with flex-basis. But then it is harder to produce a break at the correct position.

Here is the JSFiddle with fixed values for item 1 and 4: http://jsfiddle.net/ojmghu3t/4/

Upvotes: 1

Related Questions