Flexbox on table doesn't work in Firefox - html

Using flexbox to control the layout of a table works in webkit browsers but in Firefox, <td>s only render as wide as their own content.
Demonstration:
http://codepen.io/afraser/pen/wMgbzr?editors=010
* {
box-sizing: border-box;
}
table {
border: 1px solid #ddd;
width: 100%;
}
tbody {
background: #fff;
}
tr {
display: flex;
}
td:first-child {
flex: 1 1 80%;
background: mistyrose;
}
td:nth-child(2) {
flex: 0 0 10%;
background: Aquamarine;
}
td:nth-child(3) {
flex: 0 0 10%;
background: pink;
}
<table>
<tbody>
<tr>
<td>Ted</td>
<td>1</td>
<td>100%</td>
</tr>
<tr>
<td>Turd Ferguson</td>
<td>2</td>
<td>65%</td>
</tr>
<tr>
<td>Hingle McKringleberry</td>
<td>3</td>
<td>99%</td>
</tr>
</tbody>
</table>
I tried several variations on this including:
Using flex-grow, flex-shrink, and flex-basis individually.
Using pixels for the flex-basis instead of percents.
Using table-layout: fixed.
I see nothing documenting this here: https://github.com/philipwalton/flexbugs and have come up dry elsewhere. Does anyone know what's going on?

That's because, according to CSS tables, anonymous table objects should be generated when tabular elements are not children of a table:
According to the Flexbox Last Call Working Draft, it was that anonymous table what became the flex item, not the table cells:
Some values of display trigger the creation of anonymous boxes
around the original box. It’s the outermost box—the direct child of
the flex container box—that becomes a flex item. For
example, given two contiguous child elements with display: table-cell, the anonymous table wrapper box generated around
them [CSS21] becomes the flex item.
Since the table cells were not flex items, they ignored the flex property. It would apply to the anonymous table, but CSS selectors can't select anonymous elements.
However, Chrome disagreed with the spec and decided to blockify the table cells instead.
Then the CSS working group decided to standardize Chrome's behavior:
If you have a flex container and you put two table cells in it, they
won't become flex items independently. They'll wrap in an anonymous
table and that will be flex.
However, Chrome had implemented it so that each item is independently
a flex item. [...] So it turns the table cells into blocks.
I've seen at least one presentation at a conference where they took
advantage of this to create fallback behavior for a flex. [...] If you're
not trying to trigger fallback, I don't know why you'd put a bunch of
table cells in flex and get it wrapped in anonymous stuff. [...]
RESOLVED: Just blockify the children of flex and grid containers.
Don't do anonymous box fix-up
The first Flexbox Candidate Recommendation was published with that new resolution:
Some values of display normally trigger the creation of
anonymous boxes around the original box. If such a box is a flex
item, it is blockified first, and so anonymous box creation will
not happen. For example, two contiguous flex items with
display: table-cell will become two separate display: block flex items, instead of being wrapped into a single
anonymous table.
And then Firefox implemented the new behavior starting at version 47 (bug 1185140).
For older versions, you can style the cells as blocks manually:
.flex-container > td {
display: block;
}
* {
box-sizing: border-box;
}
table{
border: 1px solid #ddd;
width: 100%;
}
tbody {
background: #fff;
}
tr {
display: flex;
}
td {
display: block;
}
td:first-child {
flex: 1 1 80%;
background: mistyrose;
}
td:nth-child(2){
flex: 0 0 10%;
background: Aquamarine;
}
td:nth-child(3){
flex: 0 0 10%;
background: pink;
}
<table>
<tbody>
<tr>
<td>Ted</td>
<td>1</td>
<td>100%</td>
</tr>
<tr>
<td>Turd Ferguson</td>
<td>2</td>
<td>65%</td>
</tr>
<tr>
<td>Hingle McKringleberry</td>
<td>3</td>
<td>99%</td>
</tr>
</tbody>
</table>

I believe the issue involves the default display value of your flex items.
If you override it with display: flex the layout should work as intended across browsers.
Make the following adjustments:
td:first-child { display: flex; }
td:nth-child(2) { display: flex; }
td:nth-child(3) { display: flex; }
Revised Codepen
My first thought was to make sure each td had the proper display value applied – something along the lines of display: flex-item. However, flex-item doesn't exist, so I used display: flex.
EDIT
The solution above stands. This edit pertains to the explanation.
On examination of the spec, it appears that flex items don't even have a default display value. Basically, once you make the parent a flex container, the children become flex items, and accept flex properties, regardless of any display rule applied. Hence, a default display rule is not necessary.
In this case, it seems that having to declare display: flex on the flex items is a quirk necessary to get Firefox and IE to work.

Related

A way to have table-rows with height 0 and overflow hidden?

I know it should not be possible, but maybe there's some new quirk... Take a look:
https://jsfiddle.net/1hnxzyux/4/
So I'm using display:table, table-cell and table-row.
I was previously able to get a row to zero height if it doesn't contain anything or if it contains a display:none element, but on the fiddle you can see I've tried to hide the first row/cell by setting height:0 and overflow:hidden on all the elements, including a .box inside the cell, and it really doesn't work.
Please especially test on Safari, because it has some more problems than Firefox and Chrome.
Any way to get rid of the height and hide contents?
EDIT 1: for now, I've found out that IF using a real html table and adding table-layout:fixed to it along with setting some width for it, as for the official specs (and some other posts here in SO) the overflow property does work.
Though, it seems it doesn't work/apply to, css-tables, and I need css-tables.
EDIT 2: Thanks to #zer00ne I updated the fiddle and found that it --would-- work by setting font-size:0 both to td and input field. Though, it's not what I'm currently looking for, since I have to animate the field position and must be fully functional itself. Anyway, these 2 edits can be helpful for other people.
After about one week of searching for a solution, the answer is:
no, it's still not possible. At least, it's not possible in a reliable and versatile way. It's only possible in ways that somewhat limit elements or future actions.
If one doesn't strictly need css-tables (like me in this specific case), you can successfully mimic the same behaviour in 2 ways:
use real tables, apply table-layout:fixed and a width to the table (doesn't matter the unit, can be percentage, for ex.). Than just height:0/oveflow:hidden as usual.
use flexbox. It's the css construct that, with the right rules applied, can better approximate the table behaviour.
Hope it helps
You shouldn't set height of a row. Just place div tag inside each td and put your content in div but not in td directly. The height of row will be equal to height of its content. Set height and overflow for div element and set 0 in top and bottom padding of td. And of course you can use transition for height of div.
$(function() {
$('button').on('click', toggleColumn);
});
function toggleColumn() {
$('div').toggleClass('rollup');
}
table {
border-collapse: collapse;
}
td {
padding-top: 0;
padding-bottom: 0;
border: 1px solid black;
}
div {
background-color: yellow;
height: 40px;
padding-top: 10px;
padding-bottom: 10px;
overflow: hidden;
transition: 2s all;
}
div.rollup {
height: 0;
padding-top: 0;
padding-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>toggle</button>
<table>
<tr>
<td><div>Column 1</div></td>
<td><div>Column 2</div></td>
<td><div>Column 3</div></td>
<td><div>Column 4</div></td>
</tr>
</table>
If you are simply out after making the first row "invisible", you should simply be able to use CSS's :first-of-type like such:
/* Hide the first occurance of the 'tr' class */
.tr:first-of-type {
display: none;
}
Other than that, I'm not sure why you wouldn't be able to do something like this, alternatively? (a bit like the method you had attempted):
HTML
<div class="tr hidden">
<div class="td">
My Content
</div>
</div>
CSS
.hidden {
display: none;
}
Last but not least, may I ask why you are creating a "handmade" table using div's, instead of HTML's designated table?
You can animate opening a table row with HTML tables using this css:
tr.info td {
transition: all 0.5s ease;
}
tr.info.hide td {
line-height: 0;
padding-top: 0;
padding-bottom: 0;
overflow: hidden;
opacity: 0;
}
Remove the vertical padding which causes the apparent "minimum height" (thanks Andrey Shaforostov). Set opacity 0 to make the text appear as the row grows - smoother effect than using font-size. No need for inner div's - just add/remove the "hide" class on the table row.

CSS Right Side Overflows Left Side

I'm outputting a list of file names with total views (tally) beside them.
I'm trying to get the tally to overflow the file name.
..So with a file / tally list like:
ejs-2015-participants-list 125,000
koh-hammertown-pics 20
slaughterhouse-co-summer-run 100
..I'm trying to get the result of:
ejs-2015-participan...125,000
koh-hammertown-pics 20
slaughterhouse-co-summe...100
The HTML / CSS (html5 / css3) has a structure like:
<style>
.box {width:200px;}
.box span {float:left;}
.box div {float:right;}
</style>
<div class="box">
<span>ejs-2015-participants-list</span><div>125,000</div>
<span>koh-hammertown-pics</span><div>20</div>
<span>slaughterhouse-co-summer-run</span><div>100</div>
</div>
I'm not particular about the elements used other than 'box' is repeated so it needs to be a class. If the structure won't work or you'd rather use another selector in your example, feel free. The solution does need to validate and work in consortium compliant browsers (not worried about IE).
I've tried various inline and block level elements with various style including:
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
Nothings working though - any ideas?
Tables would make the left side the same length for all rows.
You can totally get the effect you're looking for using flexbox (and for broader browser support fall back to a table solution). The idea here is that the price is the full width of its text, say "$500", and the rest of the space is filled by the item name, which has the three rules text-oveflow, overflow, and white-space that you mentioned.
Codepen:
http://codepen.io/tholex/pen/wKQPEV
HTML:
<div class="item">
<div class="name">Delicious Bagels</div>
<div class="price">$500</div>
</div>
CSS:
.row {
display: flex;
}
.name {
flex-grow: 1;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.price {}
So I used a table for this, since it helps with alignment of the data and is semantically correct. No need to mess with floats.
The trick is really in the CSS. Set a max width, text-overflow of ellipsis, and don't allow word break. The actual ellipsis trick doesn't need to be in a table - any block level element can handle it.
Here's the codepen: http://codepen.io/anon/pen/bVQYWJ
CSS
.table td {
text-align: right;
}
.table th {
text-align: left;
}
.table th {
display: inline-block;
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
HTML
<table class="table">
<tr>
<th>ejs-2015-participants-list</th>
<td>125,000</td>
</tr>
<tr>
<th>koh-hammertown-pics</th>
<td>20</td>
</tr>
<tr>
<th>slaughterhouse-co-summer-run</th>
<td>100</td>
</tr>
</table>
The simple answer is your .box is too small to contain the div so it drops down. One solution is to make it wider but you have other problems.
Your span is an inline element while the div is block level. I don't know why you do it that way but you should probably contain those two inside their own div so one doesn't overflow into the other.
<div class="box">
<div>
<span> stuff </span><div>125,000</div>
</div>
...
Though it seems to me you should turn the div with the number into a span also. Then everything is inline.

No matter what I do, I can't get the table elements to touch

So I'm designing an org chart based on the table element and I have a problem. I'm using <hr> elements to create the connectors; however, I can't get the dead space inbetween elements to go away. I've spent the last hour trying to figure out how the hell to get it to work and I just can't seem to figure it out.
I've included a picture to show:
The other issue is more of a question I haven't really looked into but figured I'd ask anyway. How can I lock the height of my table items. I've locked the width just fine but I can't seem to lock the height to 70px.
And here is some choice code:
<table class="orgchart" cellspacing="0" cellpadding="0">
<tr>
<td></td><td></td><td></td><td></td><td></td><td></td><td class="item">Director</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="divider"><td></td><td></td><td></td><td></td><td></td><td></td><td><hr width="1" size="20"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
<td></td><td></td><td></td><td></td><td></td><td class="item">Assistant to the Director</td><td></td><td class="item">Deputy Director</td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
And the CSS:
.orgchart td {
width: 70px;
height: 70px;
text-align: center;
overflow: hidden;
white-space: no-wrap;
}
.divider td {
height: 20px;
}
.item {
border: 2px solid black;
}
And here is the CodePen: http://codepen.io/jacob_johnson/pen/GpEjmm?editors=110
There's a margin all the way around the <hr>. Remove the top and bottom margins from the <hr>. All browsers apply default styling to elements, though not always the same. As a result you will see reset and normalize stylesheets used to improve visual consistency and development pains.
Updated Codepen with CSS below added.
hr {
margin: 0 auto;
}
If I was doing this project I would find a simple grid framework to layout with DIVs or more than likely I would create this chart as an inline SVG.

Center bottom row cells inside table

Yes, this is table-based layout. It's legacy so I may or may not be able to rip out the table, nonetheless I want to understand how table alignment works anyway, hence this arguably abhorrent question.
Say I have a 3x3 table with the values 1, 2, 3, ..., 8. It ends at 8, so the last row only has 2 elements in it. I want those centered.
HTML:
<table>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>4</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td></tr>
</table>
I would like the CSS rule tr { text-align: center } to work, but I think there's some sort of table structure rule trumping what text align would do in this case, so some other style property maybe I have to cancel.
Fiddle, including a bunch of CSS that doesn't do what I want: http://jsfiddle.net/sdqtg7kr/
If you want those bottom td elements to respect text-align: center, you could change the display of the elements from table-cell to inline-block.
Updated Example
td {
border-color: red;
border-style: solid;
border-width: thin;
display: inline-block;
}

Control order of vertically stacked elements using only CSS Flexbox

I'm trying to use the CSS Flexible Box Layout Module to control the order that elements are rendered. Here's some sample HTML (and fiddle):
<div id='outer-container'>
<div id='blue-objects' class='object-container'>
<p>In here we have a number of blue things.</p>
<p>The amount of content could be very small, or very large.</p>
</div>
<div id='green-objects' class='object-container'>
<p>This is very similar to the blue objects block, in that the amount of content is unknown at design-time, and it could be very small or very large.</p>
<p>It could be a complicated, nested set of child objects, although in this example there is nothing more than two <p> elements.</p>
</div>
</div>
/* Started with a columnar layout as given by the Flexplorer: http://bennettfeely.com/flexplorer/ */
.outer-container {
display: -webkit-flex;
display: flex;
-webkit-flex-flow: column wrap;
flex-flow: column wrap;
}
.object-container {
-webkit-flex: 1 auto;
flex: 1 auto;
border: 1px dotted black;
padding: 0 10px;
margin: 10px;
}
#blue-objects {
order: 2;
font-weight: bold;
}
#green-objects {
order: 1;
font-style: italic;
}
My goal is to be able to use pure CSS to control the order the #blue-objects and #green-objects elements appear. All I've been able to accomplish so far is control the horizontal sort order.
The spec describes the order property as follows:
A flex container lays out its content in order-modified document
order, starting from the lowest numbered ordinal group and going up.
I would have thought this would mean that the #green-objects would appear before #blue-objects, because of the order values being 1 and 2, respectively... but it's not working in Chrome 36, Firefox 31, or IE 11.
According to caniuse.com, flexbox has good support in modern browsers. What am I doing wrong? How can I control the order of a vertically stacked set of elements using the CSS Flexible Box Layout module? Help with this fiddle would be greatly appreciated.
You should call #outer-container and not .outer-container in CSS file. Then the flex model will be triggered.
To only put blue objects last, then just apply: order:1; to it and nothing to others:
DEMO
Order defaut value is 0.