CSS 100vh is too tall on mobile due to browser UI - css

What is the best way to solve this issue. Obviously all browsers on mobile have got a UI (address bar etc) at the top. This adds additional height to the viewport, so my website which is using 100vh is missing a section.
I'd assume different browsers have different sized viewports due to this, I could simply do something like height: calc(100vh - 50px) or what ever the height is, but it won't match up on all mobile browsers right?

Usually the 100vh height will account for the adjusted height, with is why you'll sometimes see mobile pages go funky when the browser's address bar slides down.
For browsers that don't account for the sliding bar within the vh unit: The height for the address bars will not be constant across the browsers, so I'd advise against appending -50px.
Try setting the height of the page (using javascript) with the window.innerheight property.
function resetHeight(){
// reset the body height to that of the inner browser
document.body.style.height = window.innerHeight + "px";
}
// reset the height whenever the window's resized
window.addEventListener("resize", resetHeight);
// called to initially set the height.
resetHeight();

The accepted answer didn't work for me. I had to make two adjustments:
use document.body.style.height instead of document.body.height
add 'px' to the end of window.innerHeight
document.body.style.height = ${window.innerHeight}px;

If the element is a direct child of body, you can achieve the desired effect with:
html, body {
height: 100%;
}
#screenheight {
height: 100%;
background-color: blue;
}
<div id="screenheight"></div>
<p>Random content after screenheight element.</p>

Use height: 100% which gives you the height after reducing the menu bar's height.
You can test the difference between 100vh and 100% by using document.getElementsByTagName('html')[0].scrollHeight on mobile browser.
For me (Chrome on Andriod), 100vh returns a higher value than 100%, which always giving me a vertical scrollbar, even if I haven't added anything in the html body.

In modern browsers, you can use the dvh unit, which refers to the dynamic viewport. For more information on these new units, see the relevant can I use and web.dev article.

A simple solution worth mentioning...
Continue to set the height of your element to 100vh, then just declare that element's max-height in js.
$('.top-hero-container').css('max-height', (window.innerHeight + "px"));
Now on page load, your element will be no larger than that declared max-height, so will display fine on mobile. It obviously doesn't account for resizing, but the load overhead is less.

Related

How to add explicit width and heights on image that changes sizes due to device, to disable layout shift in pages?

I am facing CLS problems and https://pagespeed.web.dev/ recommend me to set explicit width and heights on images, but i just don't understand how i suppose to do this. For example:
If i set width and height for mobile, problem will be actual for desktops and tablets.
I am using media queries for changing image sizes for different devices, but to fix CLS problems i need to add explicit width and heights on image to reduce any shifts on page
I am using dust templates
Any help will be appreciated, thanks
This Pagespeed Insights message is misleading, you are NOT required to set the width + height of your images using the HTML attributes, you can also use CSS.
Set a width + height in CSS: .your-image { width: 200px; height: 150px; }

CSS vh units inside an iframe

I'm trying to use CSS vh units inside of an iframe. I'm finding that they are scaled to the size of the iframe somehow. In other words, 100vh isn't the windowheight. It's set to the height of the iframe.
Does this seem right?
Is there a workaround?
I know this is an old question, but as people move toward the vh unit, this question will become much more common.
To clarify, here's an example of the problem. We have an HTML file that loads an iframe:
<!DOCTYPE html>
<html>
<head></head>
<style>
iframe {
height: 50vh;
width: 100%;
}
</style>
<body>
<iframe src="iframe.html"/>
</body>
</html>
And its iframe:
<!DOCTYPE html>
<html>
<head></head>
<style>
div {
height: 50vh;
width: 100%;
background: blue;
}
</style>
<body>
<div></div>
</body>
</html>
The important thing to note here is that both the iframe and the iframe's div element are designated as having a height of 50vh. The intended behaviour may be that the iframe honor the parent context's viewport height or width. Instead, the result looks like this:
That is, the height of the blue element is ~25% of the browser window, instead of the expected 50% (100% of the iframe). Although we may wish the iframe to respect the viewport of its parent, this example makes a good case for how unintuitive that may be, though it surely would make the v* units more valuable for content being iframe'd in. The problem has to do with how viewport height is determined.
From the spec:
The viewport-percentage lengths are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly.
Both an iframe and the browser window can be the initial containing block, as they are both valid viewports. A viewport is not limited to the browser window, but instead is defined as a window or other viewing area on the screen through which users consult a document.
An iframe creates a nested browsing context when inserted into a document, and thus is its own viewport.
So yes, this is the intended behaviour - and unfortunately there is no pure CSS workaround - however, www139 has provided an example of how this can be accomplished using JavaScript. The problem with this begins when many elements' size are controlled using v* units.
This is an excellent question. Sadly, I haven't been able to figure out a solution in CSS but I have been able to figure out a solution in JavaScript which I think is your best bet at the moment. Remember that the frames must be on the same domain for this to work.
Hope this helps. If this answer needs improvement, please comment below :-)
Solution in Theory (can't use here on SO because of frame origin issue):
window.addEventListener('load',function(){
initializeV();
function initializeV(){
//1% of the parent viewport width (same as 1vw):
var vw = window.parent.innerWidth/100;
//1% of the viewport height (same as 1vh):
var vh = window.parent.innerHeight/100;
//assign width and height to your v unit elements here
}
window.parent.addEventListener('resize',function(){
//when the browser window is resized; recalculate
initializeV();
});
});
Edit (Dec. 2018): In the comments, I was asked to supply an example. I can't do an exact example because the codepens on Stackoverflow load over a different frame origin than the page. However, I can mimic the effect. For practical applications, please reference the code snippet above. This snippet is meant merely to illustrate how it works.
Practical Application. Uses the concept explained above but without frame reference.
window.addEventListener('load',function(){
initializeV();
function initializeV(){
//note: I can't use window.parent becuase the code snippet loads on a different frame than the parent page. See the other snippet for a practical example. This snippet is meant to merely illustrate the effect.
//1% of the parent viewport width (same as 1vw):
var vw = window.innerWidth/100;
//1% of the viewport height (same as 1vh):
var vh = window.innerHeight/100;
//this is where the magic happens. Simply set width/height/whatever to a multiple of vw/vh and add 'px'. Dimensions must be in pixels since the vw/vh measurement is based on pixels.
document.getElementById('test').style.width = 30*vw+'px';
document.getElementById('test').style.height = 50*vh+'px';
//assign width and height to your v unit elements here
}
window.addEventListener('resize',function(){
//when the browser window is resized; recalculate
initializeV();
});
});
#test{
background:red;
}
<div id="test"></div>

How can I get angular-ui-bootstrap tabs to fill the remaining height

I have a plunker to show: http://plnkr.co/edit/nGjdvrG27jNpQ3QTulMr?p=preview
I want the green area to fill the remaining available height. I can set div height:100% and get almost I want, but that is less than desirable.
Is there a way to do this with css? Do I need to do some sort of resizing via js?
I've set the following classes to height: 100% and it seems to work now:
.tabset, .tab-content, .tab-pane, .tabbable {
height:100%;
}
Updated Plunker
if you use flexbox layout you can do it this way:
override the display property of the '.tab-content>.active' class. By default it is set to 'display: block'. It has to be set to 'display: flex'. Also modify the tab template.
See my solution:
Using flexbox layout with angular-ui tabs
The easiest way that I know is to set the height with vh units. They were introduced in CSS3
height: 100vh;
Updated plunker.
vh unit is setting the viewport height. I believe it's viewed as setting it to a % of the viewport, or visible screen. So simply changing 100% to 100vh gives you the desired outcome.
It seems like it's pretty widely used: http://caniuse.com/#search=vh. Just depends on who your audience base is I suppose.

Preventing relayout due to scrollbar

How can I prevent the body of the page being "pushed" to the left when a scrollbar appears due to ajax content?
I can of course set overflow:scroll to the body, but it wouldn't look nice.
I am using bootstrap, but I guess it is a general question.
overflow: overlay
Building on avrahamcool's answer, you can use the property overflow: overlay.
Behaves the same as auto, but with the scrollbars drawn on top of content instead of taking up space. Only supported in WebKit-based (e.g., Safari) and Blink-based (e.g., Chrome or Opera) browsers.
Source: MDN
This is great for when you need horizontally-scrolling content and don't want it to change size when scrollbars appear on hover.
Caveat: it is deprecated. Support is pretty much limited to Chromium, but that might go away in the future. See https://caniuse.com/css-overflow-overlay.
However, you can do a fallback of auto:
.container:hover {
overflow: auto; /* fallback */
overflow: overlay;
}
Demo: jsfiddle.net/NKJRZ/385/
Can I Use also has an interesting note:
This value is deprecated and related functionality being standardized as the scrollbar-gutter property.
However, you should check their link because browser support for this experimental feature is no better than overflow: overlay as of November 2021.
You can create a container that have a fixed width, and give the content the same width (same static width - not 100%).
that way, when the content overflows the parent, the scroll will not push the content but will flow above it.
using that, you can apply a cool way to scroll without pushing anything. by showing the scroll only when you hover the container.
Check out this simple Demo
EDIT:
Here I show the difference between setting static width, and %.
Well, the scrollbar will always push your content aside, there is really nothing you can do about that. What you can do is to always show to scrollbar for example:
html,body {
height:101%;
}
or
html {
overflow-y: scroll;
}
The best way to do this is assign value 'overlay' to overflow property. This works fine.
overflow-y: overlay;
In my case, I was getting an annoying pop event on my navbar whenever the scrollbar appears, but applying position fixed on my nav solved it for me.

Resizing a div using css/html, but there's a catch

A page I'm working on has a div that spans its width. Its height has to resize according to the browser window. Here's how I've got it so far:
#vid_window{
position:absolute;
float:left;
background-color:#000;
width:100%;
height:57%;
margin-left:auto;
margin-right:auto;
overflow:hidden;
}
At the bottom of the page is a 'menu' to play an assortment of videos in the above div, and the video, of course, will have to resize with the height of the div. The div is absolutely positioned, per the client. That's not a problem:
#vid{width:100%;height:100%:}
As it will fill #vid_window
Here's the problem: When the browser page resizes, it doesn't take long for the 'menu' to begin overlapping the vid window. I know I can reduce the percentage, but, I may not, per the client. They want the lion's share of the page to be able to display the video, but they, of course, don't want the menu to overlap the window or the vid.
Here's the question: Is there a way to have the vid_window and vid resize exponentially according to the browser window, such that if the window is fully expanded, the vid_window is at 57%, but if it's half-size, the vid_window would be, say, 30%?
Here's a link to the page, if you'd like:
page
From what you've described, it sounds like you'd be better off absolutely positioning the menu at the bottom, and using relative postioning on vid_window. With a little JavaScript you can resize it correctly, and it should resolve your overlap issue. If you're allowed to use it, you can make quick work of it with jQuery.
Like James says the best way I can think of for you to do this is set a class on the Div vid_window set the height % in the class and check the display window size to determine your optimal settings. Also I would probably set a min-height so that the page won't go below that height and for backwards compatibility look at Modernizr. http://www.modernizr.com/
------EDIT------
That the Header and footer will never be off of the page. One way to reduce the problems you are having is setting the height on the header and footer to percentages so that they will scale with the height of the body
html,body { height:99%; min-height: 100%; }
header { height:22%; min-height: 100px; }
#content { height: 56%; min-height: 200px; }
footer { height:21%; min-height: 100px; }
The min-height values can be whatever you think is appropriate for the smallest height you want to go. The percentage heights on the rest should auto scale you header footer and consequently your content. This will however force the footer to go off the page at a certain point (when all min widths are met and the browser window continues to shrink). I do think that this would be desirable and should meet your clients needs. If not then you are going to get into a very complicated javascript that is not always going to do the math just right because of how each browser handles padding and height calculations. On top of that if they disable javascript then it would never work.

Resources