I need to dynamically build a table to hold some data.
I've followed the usual approach of using divs with display: table, display: table-row and display: table-cell:
.tab {
display: table;
height:100%;
width: 200px;
}
.row {
height: 100%;
display: table-row;
}
.elem {
border: 1px solid black;
vertical-align: top;
display: table-cell;
height:100%;
background: blue;
}
.content {
height: 100%;
background: greenyellow;
}
<div class="tab">
<div class="row">
<div class="elem">
<div class="content">
Content
</div>
</div>
<div class="elem">
<div class="content">
Longer content that will need to wrap around eventually you know and don't you hate it when things don't end as you expect them octopus
</div>
</div>
</div>
</div>
Or view on Jsfiddle.
In most browsers I get the expected output:
However, in IE8 (and possibly later versions, I haven't tested later versions), I get the following:
The height: 100% set on the div surrounding "Content" is ignored.
According to CanIUse, IE8 should offer full support for the related display properties.
I've looked through a number of similar questions on SO without finding a working solution: most solutions either rely on Javascript (which I'm looking to avoid), use a fixed height (ibid previous) or don't work on IE8.
Unfortunately, the effect of percentage values for height on display: table-row and display: table-cell elements is undefined according to the spec:
CSS 2.1 does not define how the height of table cells and table rows is calculated when their height is specified using percentage values.
So while a browser may claim to offer full support for table layout, certain aspects such as percentage heights may not be consistently implemented across all browsers because there is no correct behavior. You could try raising an issue on Microsoft Connect in hopes that they will change the behavior to be interoperable, but in the meantime you will need to find a different workaround (and even then you can't guarantee the behavior will remain interoperable, even in other browsers).
To make matters worse, I just tested and this affects all versions of IE up to and including 11, which means an IE-specific hack will fall short here. If you need to use a CSS table layout, as evidenced by the fact that you need to support IE8, then a pure CSS workaround is probably not feasible.
For Internet Explorer 8-10 table-cells with height: 100%; have to be wrapped by table-row with height: 100%;.
Html for IE should be like:
table > table-row > table-cell
While other browsers will work properly with
table > table-row
or
table > table-cell
[edit] I reviewed the question again, and noticed You want to set 100% height not to the table-cells, but on the content inside it.
solution 1: So for Internet Explorer content-height is related to closest element with height set in absolute units, such as pixels, em's, if you want to use % height, you may also need to set 100% height on all parent elements, this will be html and body.
working example
solution 2: Simply add
.content {
padding-bottom: 9999px;
margin-bottom: -9999px;
}
.elem {
overflow: hidden;
}
You don't need to set height on Any of the parent elements in this case.
working example.
Hope this helps.
Related
Struggling to find the right title that isn't just a mixture of "help" and "what, CSS, why?!" so hopefully a couple of you geniuses will find this...!
I have two columns. Each of them has a full-width div inside it which contains a logo. The images are quite different shapes, one being a square and one being a more panoramic aspect ratio. To achieve a balanced look, the images are set to a max-width of 50% and a max-height of 100%. Flexbox is used to center the images both horizontally and vertically.
They look perfectly fine.
// working before wrapping images with links
section.working {
div.flex {
display: flex;
justify-content: center;
align-items: center;
img {
max-width: 50%;
max-height: 100%;
}
}
}
And then I needed to add links.
https://codepen.io/lenoz/pen/VwZyeOG
This is the problem reduced to its most simple, in that the bottom row was the original code I was using to get the perfect layout, and the top row shows what happens when the images were wrapped in tags to make them links. Some points of note:
colours added just to help distinguish boundaries a little - useful for detecting when the link (red background) is no longer constricted to the size of the image inside it (as it ideally should be)
the two columns are separate in the code and not part of a shared container - i.e. one cannot inform the height of the other (want to fix this with CSS not JS)
I should mention that of course there was no way adding links would just work - the <a> tags come in between the flex container and the flex item, so obviously they will mess with the layout.
Much appreciated if you can help me find a CSS solution.
Still here? Read on if you want some more info on my attempts to fix, with a side portion of Chrome weirdness.
It should also go without saying I've spent ages fiddling with this, so here's another link showing some of my efforts that have gotten close: https://codepen.io/lenoz/pen/pozpjVq
The top row (section.help) is my latest attempt, but is a bit of a mess simply because I stopped half way, having suffered frustration sufficient to lead to me making this post.
The middle row, which I'm calling section.weirdness, actually seemed to be a solution for a hot minute. If you're using Chrome, like I am, when you look at the Codepen link you may see nothing on these blue blocks?
But try removing the display: flex attribute from div.flex and, if your Chrome is like my Chrome, you'll see this:
Now, add that same display: flex attribute back on the same div.flex selector and you'll see that suddenly the blue blocks are not blank:
How strange is that? Browser rendering bug or what?
Now find the max-width or max-height attributes on div.image, toggle one of those off and then on again and you'll see that everything suddenly looks right again:
Somehow, without changing any CSS other than toggling it, we've gone from no links showing up at all, to them showing up and looking perfect. You can see how I'd managed to confuse myself into thinking I had got it working!
Just add style="display: contents" to your anchors
"display: contents" causes an element's children to appear as if they were direct children of the element's parent, ignoring the element itself
<div>
<a style="display: contents" href="#">
<img src="https://via.placeholder.com/1000x300.png" />
</a>
</div>
Here's a simple solution:
I've changed the columns to be flex contexts but retained an inner div to serve as the 50% width constraint. When the imgs are allowed to set their own height explicitly all the other constraints around them flow into place without much fuss, and because the anchors don't have any layout rules, they manage to avoid having any clickable areas outside their image.
With the same max-height on the images, they'll match in the same way as your .working class as long as their containers are the same width.
section {
width: 800px;
display: flex;
}
.column {
background-color: blue;
margin: 5px;
width: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.column > div {
max-width: 50%;
}
img {
display: block; /* get rid of bottom gap */
max-width: 100%;
max-height: 80px;
}
<section>
<div class="column">
<div>
<a href="#">
<img src="https://via.placeholder.com/500x500.png" />
</a>
</div>
</div>
<div class="column">
<div>
<a href="#">
<img src="https://via.placeholder.com/1000x300.png" />
</a>
</div>
</div>
</section>
Try adding this to your Codepen example:
.flex > a {
flex: 0 0 50%;
height: 100%;
display: flex;
}
div.flex a > img {
max-width: 100% !important;
max-height: 100% !important;
margin: auto;
}
Any immediate child of a container with display: flex is flex item. To prevent that item from growing or shrinking we must set flex-grow and flex-shrink properties to 0. In my case I used flex: 0 0 50% shorthand for that. That last value of 50% is from your initial image max-width property. That + height:100% will make sure that <a> behaves like images in your original example.
Now the fun part: use display: flex again on <a> to make the image flex item again. Since <a> is already properly sized we can set max-width and max-height to `00% to fill available space.
Using margin: auto is a neat trick to center both horizontally and vertically flex child inside of flex container (works only when there is one child).
sidenote: I used important to override specificity without changing markup but I would advise against it and put new CSS class on both a and img.
UPDATE
working fork (Chrome only): https://codepen.io/teodragovic/pen/wvwpWbx?editors=1100
section.broken {
.flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
a {
max-width: 50%;
max-height: 100%;
}
img {
max-width: 100%;
max-height: 100%;
display: block;
}
}
I have some code which currently renders properly on Chrome Stable. I have received reports of the code working incorrectly on Beta and Dev and I am able to reproduce the issue on Canary. I found this PSA which appears related to my issue. So, I am working under the assumption this is a change to more closely follow spec rather than a bug.
My software only targets Google Chrome. So, a robust solution is not necessarily needed although it would be nice to have backwards compatibility.
The setup is:
Parent element has display:flex, flex-direction: column and has max-height applied to it.
A deep descendant of the parent exceeds the max-height
And the behavior change is:
On stable, max-height is enforced and child does not break out.
On canary, max-height is disregarded and child breaks out.
I am able to prevent the child from breaking out by applying max-height to the inner element. However, this is not desirable because I would need to reduce the value for max-height by the height of footer which isn't easily done in a non-contrived example.
The following code snippet highlights my issue:
.outer {
display: flex;
flex-direction: column;
max-height: 410px;
}
.inner {
display: flex;
flex-direction: column;
}
.content {
width: 200px;
height: 500px;
background-color: green;
}
.footer {
height: 20px;
width: 200px;
background-color: red;
}
<div class='outer'>
<div class='inner'>
<div class='content'>
</div>
</div>
<div class='footer'>
</div>
</div>
Here is a screenshot of how this renders on Chrome Canary (left) vs Chrome Stable (right):
Is anyone able to tell me how to adjust this code such that inner + footer respect the max-height value of outer?
I believe I understand the issue, but I will build upon this answer more as I learn more about the solution.
This issue was introduced due to resolution of this bug filed against Chromium. The spec indicates that the default value of a flex container should be min-height: auto where as currently it is min-height: 0.
A specific comment addresses the fact that this is a breaking change against all production websites and references a suggested change:
https://code.google.com/p/chromium/issues/detail?id=426898#c17
The change is:
In case this patch breaks any website or chrome UI, the fix is likely
to add:
min-width: 0;
min-height: 0;
Applying min-height: 0 to .inner resulted in a layout consistent with what I currently see on stable.
Using the display:table and display:table-row CSS attributes, I want my content to fill the remaining available height of a div. In case the content exceeds the available height, I want a scrollbar to be shown.
Here's the fiddle: http://jsfiddle.net/3HYJx/2/
The behaviour as shown in Google Chrome and Safari is the one I'm trying to achieve. However, Firefox and Opera show it differently. Haven't tried IE yet, but fearing the worst.
Why is this behaviour so different? And even better: how can I achieve what I want (as shown in Chrome) in every browser?
Thanks a lot in advance.
Chrome and Safari:
Firefox and Opera:
Using the table display properties, you could overcome the firefox problem by wrapping two more elements around the text of the scrolling section, so you have three:
the outer one is a table-row container that fills the rest of the table
inside which we have a relatively positioned container with height and width set to 100%, and with set vertical scrolling overflow-y:scroll;
the innermost container is absolutely with height and width also set to 100%
So here I just quickly added two div containers around your content paragraph (you could probably found a more appropriate set of containers according to your needs, but this will do for the illustration):
<div id="wrapper">
<h2 id="date">Date</h2>
<h1 id="title">A title ...</h1>
<div id="contentbox-outer">
<div id="contentbox-inner">
<p id="content">The content ...</p>
</div>
</div>
</div>
And your whole CSS has to be modified. Your original selectors, with slight modifications:
#wrapper {
position:absolute;
display: table;
table-layout:fixed;
background-color:black;
padding:10px;
width: 250px;
height:350px;
border-spacing:20px;
}
#date {
display: table-row;
font-weight: normal;
font-size: 25px;
background-color:yellow;
}
#title {
display: table-row;
font-weight: normal;
font-size: 40px;
line-height:90%;
background-color:blue;
}
note that the table-row and table elements take now speciffinc styling for tables, like the border-spacing property that sets spacing between the table rows, and this you can now combine with the padding property of the table for the appearance you want.
And the styling for the added containers would be something like this (first is still based on your styling, the last two are the additional - inner ones):
#contentbox-outer {
display: table-row;
font-size: 12pt;
width: 100%;
height:90% !important;
text-align: justify;
background-color:red;
overflow-y: scroll;
}
#contentbox-inner {
position:relative;
height:100%;
width:100%;
overflow-y:scroll;
}
#content {
position:absolute;
height:100%;
width:100%
}
I also updated your fiddle for a quick check:
http://jsfiddle.net/3HYJx/7/
Edit: This works in browsers like Firefox, Chrome, Safari, but for example not in Opera cause height: 100% does not get rendered in documents in strict mode. So with a little more research I found out that you can get it to work in quirks mode, here is a test html - the above code but in a quirks mode document. Thanks for giving me a reason to learn that, it's good to know =)
Working fiddle: http://jsfiddle.net/3HYJx/3/
The problem is height:90% !important; you have set on #content.
You have fixed heights set on #wrapper, #date and #title.
If you set a fixed height on #content (since you have everything else with fixed height, so this won't be a problem) you will get the expected result in FireFox too.
I'm currently redesigning my website from a table layout to CSS. I'm having some problems with what seemed like a very simple task.
The site is simple. A box in the middle of the screen that contains several links.
The old site used <td valign="center"> to center all the links in the box. CSS seems to have no equivalent. I've been centering elements using negative margins like so:
div {
height: 200px;
position: absolute;
top: 50%;
margin-top: -100px;
}
This works fine when you know exactly how big the element you're centering is, but I need to be able to center the links without knowing how much vertical size the links take up. I just want the aligning in the box to act like text-align: center. Only vertically too.
Current website designed with tables
Current progress on the CSS version
You have 4, possibly 5 solutions one added to the bottom since it's a combination of different css from your original and js to set height:
Use a table cell and center it's content vertically
Use display: table-cell; vertical-align: middle; as css for your div
Update margin-top every time the div's height changes via javascript
Use css3 flexbox (you need to use vendor-specific extensions so it won't work on some older browsers)
Simple example using old-style flexbox - chrome version - add a wrapper div and set it's styling to this:
#wrapper { display: -webkit-box; -webkit-box-align: center; }
#wrapper > div { margin: auto; }
fiddle for this http://jsfiddle.net/gK7YU/
New style flexbox - also chrome version, you'll have to add the other vendor prefixes as well as the version without any prefixes in the final product.
#wrapper { display: -webkit-flex; }
#wrapper > div { margin: auto; }
fiddle for this: http://jsfiddle.net/LeHRD/
The fiddles contain a few more css properties so you can see what is happening easily.
Oh, sorry, you don't need the wrapper div, you can just center vertically any content with flexbox... well, anyway the solution I proposed can be combined with display: table-cell; so it works in older browsers as well.
You can also use absolute positioning with specified height jsfiddle.net/N28AU/1
#wrapper { possition:relative }
#wrapper > div { position:absolute;top:0;right:0;bottom:0;left:0;margin: auto;}
you can calculate height from the contained elements and update it via js if you want to avoid negative margins.
I've been to your website and copied the html here.
You can do this:
<style>
#box{
display: table;
}
#box > div {
display: table-cell;
vertical-align: middle;
}
</style>
<!-- Your html part -->
<div id="box">
<div>
Link A
Link B
Link C
Link D
</div>
</div>
You must wrapped a div element inside #box because display: table-cell property won't work properly if you don't have a wrapper element that is set to display: table.
Your example here: jsfiddle
Does anyone know I can make min-height work with the latest browsers? I am using CSS tables and it seems to ignore min-height.
<div style="background-color: red; display: table; min-height: 100px;">
abc
</div>
Fiddle
When using tables, height essentially is min-height, as tables always stretch. Just get rid of the "min-" and it will work as you expect.
Use height: 1px; on the table or any value. Basically you need to give table some height to make it work with min-height. Having only min-height won't work on tables on firefox.
Solution for Firefox
Add height to unlock setting the min-height
div {
display: table;
width: 100%;
height: 0;
min-height: 100px;
}
The number in height can be any other real value less or equal to min-height for making it work as expected.
Whenever you are using display:table; or any deeper property like display:table-cell; consider using height instead of min-height. As in tables height = min-height considering the auto-span feature in them.