16

I'm trying to convert old layout based on tables and JS to the new Flexbox with backward compatibility by keeping the tables for old browsers (specifically IE8, IE9 and Opera 10+).

The problem is that there is no display:flex-item to override the old style of display:table-cell.

I've tried various definitions like display:inherit, display:initial but none is able to reset the display definition to work correctly as flex-item.

<!-- HTML user list -->
<div class="userDetails layout">
    <div class="picture"><img src="..."></div>
    <div class="details">username, email, etc.</div>
</div>

/* CSS Table Layout */
.layout { display: table; width: 100%; }
.layout > .picture { display: table-cell; width: 30%; }
.layout > .details { display: table-cell; width: auto; }

/* CSS Flexbox - ignored by browsers that does not support it */
/* just an example - should use all versions for best compatibility */
.layout { display: flex; }
.layout > .picture { display: ???; flex: 0 1 30%; }
.layout > .details { display: ???; flex: 1 1 auto; }

Whatever I set in display for the .details it does not work as flex-item and does not grow to fill the remaining space.

Any idea how to override this without using JS to detect browser version and switch the styles?

I've tried googling for solution but most of the results are just general articles about Flexbox; only similar is this test which simply does not solve the backward compatility.

UPDATE 1: This is a JSFiddle demo of a pure Flexbox and Flexbox combined with table layout. If you resize the result window, the pure layout shrinks differently than the bottom one that combine table and Flexbox. Note: in Chrome this works correctly, try it in Firefox, IE, Safari, etc.

UPDATE 2: Safari works correctly with prefixed definitions... updated JSFiddle demo

3 Answers 3

15

As Danield has mentioned, all children of a flex container (designated by display: flex or display: inline-flex) are automatically made flex items. There is no display property for a flex item; instead, you set it to some other value depending on how you want the children of the flex item to be laid out. If browsers are recognizing display: flex-item, then they probably have some weird non-standard implementation of "flexbox", because that value has never existed in any incarnation of the Flexbox spec (and I have no idea what exactly it would correspond to if it did).

The initial value of display is inline, so display: initial is equivalent to display: inline. See this answer. What you're trying to do is reset the elements to whatever their default display is as given by browsers. You will need to know this value in advance; for div elements it's display: block.

Unfortunately, this will override the existing table-cell declaration in all browsers, for obvious reasons. In that case, you might as well just stick with the table layout if it already works for you, if you need to support browsers that don't support flexbox.

1
  • Your right, on normal page setting flex-items to block or inline works correctly. Unfortunatelly it seems my page layout is so messed up that the browser is so confused it does not work how to correctly layout it. I'll have to redesign whole page to use only the flexbox :( .
    – Radek Pech
    Commented Nov 26, 2014 at 11:49
5

There is no display:flex-item because once you set display:flex on a container element, the children are automatically flex items.

Here is a demo to show that the display:table-cell on the children does not effect the functionality of the flex properties on the children

Edit: For Firefox and IE if you add the rule display:flex after the display:table-cell rule then the display:table-cell on the children does not effect the functionality of the flex properties on the children

/* flex layout with display:table falllback */

.layout {
  display: table; /* falllback */
  width: 100%; /* falllback */
  display: flex;
}

.layout > .picture {
  display: table-cell; /* falllback */
  width: 30%; /* falllback */
  display:flex; /* to make FF and IE happy */
  flex: 0 1 30%;
  background: tomato;
}

.layout > .details {
  display: table-cell; /* falllback */
  width: auto; /* falllback */
  display:flex; /* to make FF and IE happy */
  flex: 1 1 auto;
  background: aqua;
}
<div class="layout">
  <div class="picture">
    <img src="...">
  </div>
  <div class="details">username, email, etc.</div>
</div>

5
  • No, it seems to work because under normal situation flex-item and table-cell works the same, but if you get into an extreme condition (e.g. small screen) the flex-items starts working differently than the table-cells. Try this demo: jsfiddle.net/nothrem/do525ff3/1 and make the result window too narrow - upper layout (pure flexbox) shrinks differently than the bottom one (table-cells inside flexbox).
    – Radek Pech
    Commented Nov 26, 2014 at 10:14
  • WHich browser are you using - to me they look the same even on a narrow width screen
    – Danield
    Commented Nov 26, 2014 at 10:17
  • In Chrome it works correctly, but FF, IE and Safari are broken. (Updated in initial comment)
    – Radek Pech
    Commented Nov 26, 2014 at 10:19
  • @RadekPech - Interestingly enough if you add the rule display:flex after the display:table-cell rule for the flex items it seems to work in other browsers as well. cssdeck.com/labs/bctqezgs
    – Danield
    Commented Nov 26, 2014 at 10:28
  • Using flexbox helps - browsers probably expect the flex-items to be both flex-item and inner flexbox, but it breaks the inner layout because the items inside the table-cell turn into flex-item itself. You need to wrap the content of the old table-cells into another element to keep their layout untouched. Not convenient but still the best solution. Final demo: jsfiddle.net/nothrem/do525ff3/4
    – Radek Pech
    Commented Nov 26, 2014 at 11:00
1
.child {
  flex-shrink: 0;
}

add flex-shrink property to prevent shrinking more than its content

Not the answer you're looking for? Browse other questions tagged or ask your own question.