Nested flexboxes: IE11 doesn't respect max-width: 100% - css

I'm working on a two column layout. Both columns will display an iframe, the width of both will be defined as inline-style / be set in the CMS. If the iframe is smaller than the column, it should center vertically. If its bigger than the column, it should shrink to the max width of the column, which is nearly 50% wide.
(Yes, this could probably be done without using flexbox twice. But I'm not interested in such answers, because I simplified the example and the use case.)
Example:
http://jsbin.com/logifu/2/
HTML:
<div class="content">
<div class="col">
<div class="media-wrapper">
<iframe src="http://www.jsbin.com/blog" frameborder="0" scrolling="no" style="width: 2000px; height: 2000px"></iframe>
</div>
</div>
<div class="col">
<div class="media-wrapper">
<iframe src="http://www.jsbin.com/blog" frameborder="0" scrolling="no" style="width:200px"></iframe>
</div>
</div>
</div>
SCSS:
.content {
display: flex;
justify-content: center;
flex-flow: row wrap;
}
.col {
display: flex;
justify-content: center;
align-items: flex-start;
flex: 1;
height: 100%;
min-width: 0; // this fixes the issue in FF 34
+ .col {
margin-left: 40px;
}
}
.media-wrapper {
box-sizing: border-box;
max-width: 100%;
padding: 15px;
background: lightblue;
}
iframe {
display: block;
margin: 0 auto;
max-width: 100%;
overflow: hidden;
}
This works as expected in Chrome 39. In Firefox 33 and in IE 10 this works, too. (I'm lazy, so I didn't add the IE10-flexbox syntax in the fiddle.)
In the new FF34 it behaved the same as in IE11, but this could be fixed with max-width: 100%. See How can I get FF 33.x Flexbox behavior in FF 34.x? for further explanation.
Unfortunately, this fix does not affect IE11. So how do I prevent IE11 displaying the iframe larger than the column? And why is this happening; is this a bug or is this another flexbox-feature that was reintroduced as mentioned in the linked question?

Ok, I found a way to prevent this in IE11: max-width: calc( 100% - 0.1px );. Therefore the max-width gets calculated and interpreted in pixel and not in percent, but is nearly 100%. So visually everything looks as expected.
Does anyone know a better solution or an explanation for this problem?

Related

Is it possible to round values in css? Or, how to solve half/sub-pixels on % translated layouts?

I have a curious problem. I built a flex/grid fullscreen responsive interface. I used % values. It works fine, but sometimes, randomly, by resizing the window a 1 px line appears between item (horizontal, vertical, or both). I think maybe that's because, using % values and being the elements liquid, the items size is not always perfect-pixel. Look:
How could I avoid that, still maintaining a responsive layout?
I managed to somewhat good by very little scaling the inner elements (images and rollover layers) like scale(1.005), but still it was not always perfect. The problem is that browsers can't round element sizes on fullscreen layouts, or something like that, don't know.
Just a little abstraction of my original code, just to add context. It's a 3 cols flex layout where 1 col is 50% width (the third one is off screen > the overall behaves like a 3 panels 'slideshow'). The second column, itself contains the grid on the picture:
/* HTML */
<div class="sections-list">
<div class="section column-1"></div>
<div class="section column-2">
<div class="grid">
<button type="button">a</button>
<button type="button">b</button>
<button type="button">c</button>
<button type="button">d</button>
</div>
</div>
<div class="section column-3"></div>
</div>
/* SCSS */
.sections-list{
display: flex;
justify-content: flex-start;
min-height: 100vh;
translateX(-50%);
}
.section{
flex-grow:1;
min-width: 50%;
box-sizing:border-box;
min-height: 100vh;
}
.grid{
display: grid;
height: 100%;
grid-template:
"a b" 50%
"c d" 50%
/ 50% 50%;
button{
display: block;
position: relative;
overflow: hidden;
padding: 0;
min-width: none;
max-width: none;
height: auto;
&:nth-child(1){ grid-area: a; }
&:nth-child(2){ grid-area: b; }
&:nth-child(3){ grid-area: c; }
&:nth-child(4){ grid-area: d; }
}
}
So, it turns out the problem was caused by the 50% translation on the main element. That caused half pixels when window.width was odd.
The solution to me was to recalculate and round the translation using a little javascript, css --properties and a fallback for legacy browsers. Here's some simplified code (and please look to the original's code too):
:root{
--half-window: -50%;
}
.sections-list{
display: flex;
justify-content: flex-start;
min-height: 100vh;
transform: translatex(-50%); // legacy
transform: translatex(var(--half-window));
}
then:
function round_half_window(){
document.documentElement.style.setProperty('--half-window', -Math.round($(window).width()/2) + 'px');
}
$window.resize(_.debounce(function(){ round_half_window(); },500));
round_half_window();

How set full screen width background on fixed width element?

I have simple structure of element container of dynamic height and fixed width (Markup below). On one hand the element's background should span the whole window width, on the other the children's size must be limited by the container (Desired layout below). The number of children and their sizes (which are equal on the image only for simplicity) are dynamic.
Is that possible without adding extra container? I want to avoid achieving the desired element content width by setting width on the children, because their number is dynamic and the size relationships become complicated to write unless their total width is already limited by container's width.
Here's a pen to experiment;
Markup
<div class="container">
<div class="child">
<div class="child">
...
</div>
.container {
width: <fixed-width>px;
}
Desired layout (the whitespace between children and container is irrelevant)
One route we can take to solve this is by using viewport width on the parent container padding, to force the children into a box that is only 500px wide (as per your codepen).
The important thing to remember when doing this is that box-sizing:border-box; will need to be set on the container, otherwise the padding goes ballistic.
We do this by using calc, vw and padding.
padding: 20px calc(50vw - /*half of container width*/);
Here's the full expanded code of your container on the linked codepen:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
html {
overflow-y:scroll; /* fixes potential calculation errors caused by scroll bar - thanks to Roberts comment */
}
Here's a working version of the codepen, and for the sake of keeping all my eggs in one basket, here's an expandable code snippet:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
.child {
flex: 1 0 auto;
width: 100px;
height: 100%;
background-color: #ff4444;
}
.child+.child {
margin-left: 20px;
}
<div class="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
I will finish off by pointing out that if someone else has a better solution, you may want to look at that for time being instead as there is some issues with using vw inside calc on older versions of Chrome and Safari.
EDIT:
As noted in the comments by Vadim and Robert there are a few things that can cause some snags.
Firstly, assuming you are working with a bare minimum template (i.e. no normalize/reset.css), your body will most probably still have the inherent margins that would mess with this kind of layout. You can fix this with:
body {
margin:0;
}
Secondly, depending on your OS (Yes I'm looking at you Microsoft!) your scrollbars can push your content to the side whilst simultaneously still being included in the calculation for vw.
We can fix this one of two way. The first being an adjustment on the padding calculation to include the scrollbar side, but you would have to write a script to ensure that scrollbar is actually present, and scrollbars differ in sizes (I.E -> 17px, Edge -> 12px).
The other alternative would be to use a custom content scroller, which would do a full overflow:hidden; over the content, thereby removing the scroll bar, before implementing it's own version of a scrollbar (which generally lies on top of the content with a position:fixed;) it.
Using vw and flex we can center the child elements and achieve exactly what you require. I have written a JSfiddle where you can check it out.
Basically what I have done is created a container with display set to flex. Using margin property of the first child element, I have centered all of the other child divs and then the regular properties were added to other divs.
Here's the code
body{
margin: 0;
padding: 0;
}
#container{
display: flex;
width: 100vw;
height: 40vw;
background-color: #333333;
align-items: center;
}
.child{
width: 4vw;
height: 80%;
background-color: red;
margin-right: 10vw;
}
.child:first-child{
margin-left: 28vw;
}
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

Flexbox overflowing container height in IE11

Firstly, let me say that unfortunately I do have to support IE11 still and I don't believe this is a duplicate question, although I have found a few that were kinda similar.
I have a simple modal window which contains 3 flexible components in a column, header, footer and main.
The plan is that the outer box should grow as the content grows, until it is 80% of the height of the screen, at which point the middle section of the modal which is set to overflow-y:auto should get a scrollbar and the main modal will not get any taller.
Here is my markup
<div class="modal-wrapper">
<div class="modal">
<div class="modal-header">Header</div>
<div class="modal-main">
<div>Content goes here, could get very long</div>
</div>
<div class="modal-footer">Footer</div>
</div>
</div>
Fairly standard stuff. The modal is set to flex and the header and footer are fixed height. The middle section is set to grow and shrink as necessary. The main thing is that the .modal should never overflow the .modal-wrapper.
I have a jsfiddle set up and it's tested in Chrome, Firefox, Safari and iOS and it's working fine if you drag the bottom right box height up and down you'll see how it is supposed to behave. IE11 though is a mess.
https://jsfiddle.net/jonhobbs/sf6untnt/3/
Now, I have a feeling it may be related to the min-height bug here:
https://connect.microsoft.com/IE/feedback/details/802625/min-height-and-flexbox-flex-direction-column-dont-work-together-in-ie-10-11-preview
but I'm not convinced it's exactly that bug because none of the workarounds for that bug seem to work (e.g. using min-height:1px instead of 0, wrapping in another flexbox etc).
Hopefully somebody on SO can take a look at the jsfiddle and see an obvious problem
Maybe if you make it a flex child and use flex:0 1 80%; , it should fixe your trouble with IE :
example
html, body{
height: 100%;
display:flex;
flex-flow:column;
}
.modal-wrapper{
display: flex;
flex-direction: column;
width: 70%;
margin: 0 auto;
flex:0 1 80%;/* IE gets it , because the flow is column */
max-height:80%;/* others such as FF gets it */
background: white;
}
.modal{
display: flex;
flex-glow: 1;/* doesn't exist */
flex/*-shrink*/: 1; /* good enough */
flex-direction: column;
min-height: 1px;
}
.modal-main{
flex: 1;/* good enough */
min-height: 1px;
overflow-y: auto;
padding: 20px;
}
.modal-header, .modal-footer{
flex-grow: 0;
flex-shrink: 0;
height: 60px;
color: white;
line-height: 60px;
text-align: center;
background: dodgerblue;
}
<div class="modal-wrapper">
<div class="modal">
<div class="modal-header">Header</div>
<div class="modal-main">
<div>This content could get very long so I'm going to put a big long div in it</div>
<div style=" width:100px; height:1000px; background-color:red; opacity:0.1;"></div>
</div>
<div class="modal-footer">Footer</div>
</div>
</div>
https://jsfiddle.net/sf6untnt/7/

Vertically and horizontally centering container and content in container

I am trying to vertically and horizontally center a container, and the content inside using CSS.
The markup looks like this:
<div id="container">
<img src="..someimage.jpg">
<img src="..someverticaldivider">
<form action="action.php">
<input type="text">
.... (other inputs)
</form>
</div>
I need the end result to look like this:
So far, my css looks like this:
#content{
position:absolute;
width: 900px;
left:50%;
top:50%;
height:300px;
margin-top:-150px;
margin-left: -450px;
}
That works fine and if I add a border to #content, I can easily see that it is indeed centered horizontally and vertically.
The problem I am facing is that I do not know the size of the content inside #content. I need to be able to align those elements 2 images and 1 form horizontally and vertically. I have checked out this site for vertically centering, but the problem is that I do not know the size of my content, and the content is not only text.
What is the best way to do this with support for older browsers (IE7 and up)?
You can do it with display:table-cell
fiddle
html
<div id="a">
<div id="b">hello<br/>world</div>
</div>
css
#a {
display: table;
width: 100%;
height: 100%;
}
#b {
text-align:center;
vertical-align: middle;
display: table-cell;
}
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
edit 1
And here is the the final result of the jury
This centers also the content inside the box vertically (image, vertical ruler, form)
http://jsfiddle.net/HerrSerker/TuPvF/13/
I'm trying to give an authoritative answer to this.
Maybe this won't work in mobile browsing (smart phones, iPad etc.). Could anyone check?
Use display: table and display: table-cell in modern browsers which support them to make use of the vertical-align which works with them.
Use positioning with relative measures in some old IE browsers
http://jsfiddle.net/HerrSerker/TuPvF/
<!-- HTML -->
<div class="table">
<div class="cell">
<div class="inner">
<div class="align">
<img src="//lorempixel.com/200/300">
</div>
<div class="align">
<img src="//lorempixel.com/200/200">
</div>
</div>
</div>
</div>
/* all css rules prepended by a hash sign (#) are specifically for IE 7 and below */
html, body {
/* w3c dropped height percentage in some css2 or so version
* if you don't know the heights of ALL the parent element up to the root.
* So give ALL parents a known height
* CAVE: If mobile browsing is important check, if this does not affect scrolling and zooming
*/
height: 100%;
}
.table{
/* modern browsers support display: table
* use this for an easy vertical alignment
*/
height: 100%;
width: 100%;
display: table;
/* check if you want absolute positioning */
position: absolute;
/* if you don't want absolute positioning, uncomment the next line and comment the previous line out */
/* #position: relative */
}
.table > .cell {
/* modern browsers support display: table-cell
* use this for an easy vertical alignment
* You don't need table-row
*/
display: table-cell;
vertical-align: middle;
text-align: center;
/* this is again for lte IE7 */
#position: absolute;
/* 50% is half of the containing element (.table here) */
#top: 50%;
#width: 100%;
}
.cell > .inner {
text-align: left;
display: inline-block;
/* triggers hasLayout in IE 6+7 */
#zoom: 1;
/* if IE 6+7 element have hasLayout, display: inline behaves as display: inline-block. Strange, huh? */
#display: inline;
#position: relative;
/* here the 50% are the half of the .cell element */
#top: -50%;
}
.cell > .inner > .align {
vertical-align: middle;
display: inline-block;
#zoom: 1;
#display: inline;
}
.inner {
border: 1px solid gold;
padding: 10px;
white-space: nowrap;
}
Could you give a little more info, like why you don't know how big content is? It seems like you want CSS to dynamically change the formatting based on the content you're loading. I don't think that's something CSS is built to do. Javascript would be straight-forward and probably the simplest, but you could do it server-side with something like PHP.
If you give us a little bit more information about the context in which this is being implemented, we'll be able to offer more specific advice about what ways could be used to implement this.

css vertical centering

how could i vertically center a <div> within a <div> ?
my code so far:
<div style="height:322px;overflow:auto;">
<div style="border: Solid 1px #999999;padding:5px;">
</div>
</div>
i have tried "top:50%;" and "vertical-align:middle;" without success
EDIT: okay so it's been discussed a lot. and i've maybe started another mini flame war. but for argument sake, how would i do it with a table then? i've used css for everything else so far so it's not like i'm not trying to employ "good practices".
EDIT: the inner div does not have a fixed height
In short, you're stuffed. More on this in a recent question I asked Can you do this HTML layout without using tables? Basically the CSS fanatics need to get a grip and realize there's simply some things you can't do (or can't do well) without tables.
This anti-table hysteria is nothing short of ridiculous.
Table cells handle vertical centering really well and are backwards compatible as far as you could possibly care about. They also handle side-by-side content way better than floats, relative/absolute positioning or any of the other CSS type methods.
Joel coined (or at least popularized) the term "architect astronauts" in Don't Let Architecture Astronauts Scare You. Well, in that same vein I think the term "CSS Astronaut" (or "CSS Space Cadet") is equally appropriate.
CSS is an incredibly useful tool but it also has some pretty serious limitations. My favourite ishow numbered lists may only appear as "3." but not "3)" or "(3)" (at least prior to CSS3 generated content--or is it CSS2.1? Either way it's not widely supported). What an oversight.
But bigger than that is vertical centering and side-by-side layout. These two areas are still a huge problem for pure CSS. Another poster decided the relative positioning combined with negative margin heights was the way to go. How is that any better than:
<html>
<head>
<title>Layout</title>
<style type="text/css">
#outer { height: 200px; border: 1px solid black; width: 600px; background-color: #DDD; }
#inner { width: 150px; border: 1px solid red; background: yellow; margin: auto; line-height: 100%; }
</style>
</head>
<body>
<table>
<tr>
<td id="outer">
<div id="inner">Inner</div>
</td>
</tr>
</table>
</body>
</html>
which will work everywhere, everytime.
Here is an article on vertical centering in CSS. To achieve a similar thing they use three nested divs with relative+absolute+relative positioning just to get vertical centering. I'm sorry but whoever wrote that--and anyone who thinks that's a good diea--has simply lost the plot.
A counterargument is given in Tables vs CSS: CSS Trolls begone. The proof really is in the pudding. The vast majority of the top 20 (Alexa) sites still use tables for layout. With good reason.
So decide for yourself: do you want your site to work and spend less time getting it to work? Or do you want to be a CSS Astronaut?
It's non-trivial, there can be caveats, and it's not something CSS handles well at this point.
It is however quite widely discussed and googleable. This is a good example.
Whatever you do, please don't fallback to tables.
Edit: this is ridiculous, the following works perfectly well in a strict doc without resorting to table markup:
<style type="text/css">
.outer {height: 322px; overflow: hidden; position: relative;}
*|html .outer {display: table; position: static;}
.middle {position: absolute; top: 50%;}
*|html .middle {display: table-cell; vertical-align: middle; position: static;}
.inner {position: relative; top: -50%; overflow: auto;}
*|html .inner {position: static; max-height: 322px;}
</style>
<!--[if IE]>
<style>
.inner {height: expression(Math.min(this.scrollHeight,322)+'px'); width: 100%;} /* for explorer only */
</style>
<![endif]-->
<div class="outer">
<div class="middle">
<div class="inner">
Any text any height
</div>
</div>
</div>
I like this solution best. It is for IE8+, and is easy to understand.
<style>
/* Can be any width and height */
.block {
height:500px;
text-align: center;
}
/* The ghost, nudged to maintain perfect centering */
.block:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
margin-right: -0.25em; /* Adjusts for spacing */
}
/* The element to be centered, can be any width or height */
.centered {
display: inline-block;
vertical-align: middle;
width: 300px;
}
</style>
<div class="block"><div class="centered">Centered Content</div></div>
top: 50%; should work. you need to put margin-top to negative half of the height or it will start in the middle. Therefore, you need the height of the inner div. You also probably need position:relative;
Something like this for you inner div.
position:relative;
top: 50%;
height:80px;
margin-top: -40px; /*set to a negative number 1/2 of your height*/
Not very neat working with negative sizes (what does it even mean?) but maybe the easiest way.
<div style="display: table; height: 400px; #position: relative; overflow: hidden;">
<div style=" #position: absolute; #top: 50%;display: table-cell; vertical-align: middle;">
<div style=" #position: relative; #top: -50%">
vertically centered
</div>
</div>
</div>
more information
Two techniques of many
Browser compatibility of the following has been tested in IE only. Modern browsers should handle these no problem.
#1 - Absolute and auto margin
Compatibility: IE 8 +
The combination of top, right, bottom, left and margin: auto centers the div vertically and horizontally.
The width and height are needed, but can be percentages
Can also be applied to an inner div with the parent set position: relative
Note: A max-width and max-height instead of a percentage height is possible IE 9 +. IE 8 requires a height.
html,
body {
height: 100%;
}
.outer {
background: #ff8f00;
height: 50%;
width: 50%;
margin: auto;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
<div class="outer"></div>
#2 - Flexbox
Compatibility: IE 11. See here for other browser support.
Using Flexbox and flexible vw and vh lengths
body {
margin: 0;
}
.outer {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.inner {
width: 50vw;
height: 50vh;
background: #ff8f00;
}
<div class="outer">
<div class="inner">
</div>
</div>
Do you absolutely need to do this with css? The above link looks pretty good, but you could get a result using javasctipt/jquery - determine the height of the innter div and adjust the margin.padding accordingly. Something similar to: (jquery)
var gap = ( $('the-outer-div').height() - $('the-inner-div').height() ) /2;
$('the-inner-div').css( "margin-top" , gap );
A table isn't necessary if you're willing to use the flexbox display model.
E.g.
<div style="height: 322px; width: 200px; display: flex; background: gray;">
<div style="border: Solid 1px #999999; padding:5px; margin: auto;">
This text would be both vertically AND horizontally centered, if it's inner height and width were less than the parent's height and width.
</div>
</div>
If you just want vertical centering use the rule "margin: auto 0;" in the child div.
p.s. You'll have to prefix your use of flexbox if you want cross-browser compatibility (e.g. "display: -webkit-flexbox;")
The display: flex property works especially well for centering, both vertically and horizontally. For vertical centering, add the properties display: flex and justify-content: center to the container.
Try line-height

Resources