Safari: Vh Units Applied to Parent Element Doesn't Allow 100% Height in Child

Safari: VH units applied to parent element doesn't allow 100% height in child?

This is a known bug with vh and vw in Safari. You can fix it by setting height: inherit on the inner element:

.inner {
height: inherit;
}

http://jsfiddle.net/24hZQ/47/

safari: height:100% not executing

In the #signup-login-forms form, changing height:100%to height:inherit solved the problem. This allows me to keep the height of #signup-login-forms measured in vh.

Child inside parent with min-height: 100% not inheriting height

This is a reported webkit (chrome/safari) bug, children of parents with min-height can't inherit the height property: https://bugs.webkit.org/show_bug.cgi?id=26559

Apparently Firefox is affected too (can't test in IE at the moment)

Possible workaround:

  • add position:relative to #containment
  • add position:absolute to #containment-shadow-left

The bug doesn't show when the inner element has absolute positioning.

See http://jsfiddle.net/xrebB/

Edit on April 10, 2014

Since I'm currently working on a project for which I really need parent containers with min-height, and child elements inheriting the height of the container, I did some more research.

First: I'm not so sure anymore whether the current browser behaviour really is a bug. CSS2.1 specs say:

The percentage is calculated with respect to the height of the
generated box's containing block. If the height of the containing
block is not specified explicitly (i.e., it depends on content
height), and this element is not absolutely positioned, the value
computes to 'auto'.

If I put a min-height on my container, I'm not explicitly specifying its height - so my element should get an auto height. And that's exactly what Webkit - and all other browsers - do.

Second, the workaround I found:

If I set my container element to display:table with height:inherit it acts exactly the same way as if I'd give it a min-height of 100%. And - more importantly - if I set the child element to display:table-cell it will perfectly inherit the height of the container element - whether it's 100% or more.

Full CSS:

html, body {
height: 100%;
margin: 0;
}

#container {
background: green;
display: table;
height: inherit;
width: 100%;
}

#content {
background: red;
display: table-cell;
}

The markup:

<div id="container">
<div id="content">
<p>content</p>
</div>
</div>

See http://jsfiddle.net/xrebB/54/.

Prevent child element from stretching parent: portable solution for both Chrome & Safari?

Here is a simplified example (I removed a couple elements from your code just to make it easier to read). The scroll element needs two things: a parent with overflow:hidden, and an ancestor with a height property (can't be auto). Then to center the non-overflowing content, just use flexbox on the parent, and margin:auto on the content element.

*** UPDATE

A better explanation of what is going on with your code:

  1. You want to center a content block while making the parent hide its overflow if any.
  2. For overflow to work it needs a parent with a height otherwise it will not know where to cut off the content.
  3. To vertically center the content box within the available space, set the parent to display:flex.
  4. The important part: the content block has to be centered using margin:auto otherwise when there is overflow, it will remain centered with its top and bottom parts being cut-off by the parent's overflow:hidden.

body,
html {
margin: 0;
padding: 0;
height: 100%;
}

.page {
/* Set height for overflow element ancestor */
height: 100%;
max-height: 100vh;
display: flex;
background: blue;
justify-content: center;
}

.central-column {
flex-basis: 100%;
max-width: 90%;
display: flex;
flex-direction: column;
height: 100%;
}

.topbar {
height: 20%;
flex-shrink: 0;
background: red;
}

.cardbar {
flex-grow: 1;
display: flex;
/* Parent of the scroll element hide overflow */
overflow: hidden;
}

.cardtable {
padding: 20px;
background: white;
display: flex;
flex-basis: 100%;
}

.card {
background: cyan;
padding: 30px;
/* Margin auto to center the content */
margin: auto;
text-align: center;
}

.bottombar {
height: 20%;
flex-shrink: 0;
background: red;
}
<div class="page">
<div class="central-column">
<div class="topbar">
</div>
<div class="cardbar">
<div class="cardtable">
<div class="card">
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
</div>
</div>
<div class="bottombar"></div>
</div>
</div>

CSS3 100vh not constant in mobile browser

Unfortunately this is intentional…

This is a well know issue (at least in safari mobile), which is intentional, as it prevents other problems. Benjamin Poulain replied to a webkit bug:

This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)

The base problem is this: the visible area changes dynamically as you scroll. If we update the CSS viewport height accordingly, we need to update the layout during the scroll. Not only that looks like shit, but doing that at 60 FPS is practically impossible in most pages (60 FPS is the baseline framerate on iOS).

It is hard to show you the “looks like shit” part, but imagine as you scroll, the contents moves and what you want on screen is continuously shifting.

Dynamically updating the height was not working, we had a few choices: drop viewport units on iOS, match the document size like before iOS 8, use the small view size, use the large view size.

From the data we had, using the larger view size was the best compromise. Most website using viewport units were looking great most of the time.

Nicolas Hoizey has researched this quite a bit: https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html

No fix planned

At this point, there is not much you can do except refrain from using viewport height on mobile devices. Chrome changed to this as well in 2016:

  • https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/BK0oHURgmJ4
  • https://developers.google.com/web/updates/2016/12/url-bar-resizing

Safari height 100% element inside a max-height element

This issue happens due to a reported bug in Webkit:

Bug 26559 - When a block's height is determined by min-height/max-height, children with percentage heights are sized incorrectly

This seems to be fixed for Chrome by now, but not for Safari.

The only non-JavaScript workaround that worked for me, is using an absolute positioning on the parent element:

div {     
position: absolute;
}

Demo

Try before buy

height:100% works in Chrome but not in Safari

Your flex container (.flex-box) has a defined height of 500px.

Your splitter (.handle-inner) has a defined height of 100%.

However, .handle, which exists between them, does not have a defined height. Safari sees this as a missing link, which it considers a violation of the spec, which essentially says:

The parent of an element with a percentage height must have a defined height and it must be with the height property. Otherwise, the element with a percentage height must default to height: auto (content height).

Therefore, you need to add height: 100% to .handle.


Also, in your body element, you not only have your .flex-box element, but you also have a nav element with height: 250px. Depending on how a browser handles the overflow (250px + 100%), this may cause your splitter element to disappear off-screen, which is happening in Safari.

To avoid that problem, make these adjustments to your code:

 * { box-sizing: border-box; }   /* include borders and padding in width
and height calculations */

.flex-box { height: calc(100% - 250px); } /* compensate for nav height */

revised demo


Also, being that body is a column-direction flex container, you can also use flex properties (such as flex: 1 on .flex-box) to consume remaining space. You may not even need percentage heights. See my answer here for details.

revised demo

Each section must have at least 100% height

You can also make section 100% height with js

$(window).on("resize", function () {  var fullHeight = $(window).height();  $('section').height(fullHeight);}).resize();
.s-one {  background: blue;}
.s-two { background: green;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><section class="s-one"></section><section class="s-two"></section>


Related Topics



Leave a reply



Submit