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>
Related
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.
This probably was answered somewhere, but I can't find it :s
My question is about dynamic resizing of divs based in percentages.
Please look at code example below for the examples and possible solutions I made.
I ask if there is a better way to do resizing?
More detailed explanation:
Say I am writing a plugin that people can insert in their pages. (Imagine login form).
I go ahead and design the plugin's divs. I use media queries to achieve desired look for different devices. I work on a div straight inside of a 'body' element.
I use percentages for design (I like percentages). Say I set div to 80% width.
Now I give this plugin to the user. User goes ahead and puts the plugin's div inside of another
div that is 100px in width. Now everything looks awful. (80% of 100px is not a lot [80px]).
And of course I want user to put my plugin inside of whatever small-width divs that he have.
The solutions I saw so far to this problem was to create a holder div of certain width - say hardcode 300px. (ex - jQuery UI's Datepicker div; Meteor's login widget div). And then code to it always knowing the 300px width that I set before is not going to change.
But I don't know how good of a solution this is.
Moreover if I decide to go with hard-coding width, my plugin would need width of ~ 1000px. Because I want div to resize with media queries.
And if I go with hard-coding width (say holder div of 1000px width) and put it on a page, the page will have horizontal scrolling. And you cannot simply hide holder div (parent div) and have child to show at the same time. So this requires setting position:relative for holder (parent) div, putting it outside of window, and use same for child div - position:relative with same offset in opposite direction of parent offset.
I hope I am being clear so far and have not confused you!
A code example to illustrate what I am talking about:
http://jsbin.com/ifawez/18/edit
#cimmanon's comment cleared things out for me.
The problem is with lack of HTML/CSS "tools" available at the moment. Since responsiveness came into play fairly recently there are not a lot of CSS-native tools to accommodate changes in dimensions.
For instance media-queries exclusively work with width of window/document and not of other elements such as divs.
The solution I currently employ is using Javascript to determine width of a div and resize accordingly.
What I resize is the number of columns I want to display (I use Multi-Column module as suggested by cimmanon) which is pretty stable on webkit browsers. Since it is all done in Javascript (and jQuery's Sizzle) I keep an array of sizes like so:
var widthArray = [
{min:0, max:250, columns:1, secondary:false},
{min:251, max:350, columns:1, secondary:true },
{min:351, max:479, columns:1, secondary:true },
//more div sizes
];
// more code here
$(element).css({
"column-count": object.columns,
"-moz-column-count": object.columns,
"-webkit-column-count": object.columns
});
This is sort of like media-queries, but allows to work with width of html elements, not screen size alone.
Additionally I follow the way jQuery UI displays its components: using position relative/absolute.
.outer_div {
position: relative;
}
.inner_div_with_elements {
position: absolute;
z-index: 1010;
width: 99%;
float: left;
overflow: hidden;
...
}
.inner_components_displayable {
position: relative;
display: block;
}
.inner_components_hidden {
display: none;
}
So in Summary:
Media queries alone work with size of screen, and resizing of any inner element can be done in percentages to the screen size. They can be of huge help, but you turn into making your components work either with percentages based off screen, or specifying something like min-height and !important (as suggested by #Octavian)
Javascript manipulation of elements is currently easier, but is a costlier alternative (jQuery SIzzle is pretty slow)
A lot of libraries (ex. jQuery UI) use Javascript together with position relative/absolute to make sure their components/plug-ins will work nicely on all users' screen sizes.
I ended up combining position with javascript to emulate media-queries and multi-column design at the same time for responsiveness.
Thanks everyone who participated!
If I am reading this correctly, the main issue here is that it can potentially become too small based on where the code is located.
So why not just add a min-width property with !important? That way you can still base the size off of the parent container, but be sure that it doesn't get too small and ugly.
Potentially, you could even have a script to base the width off of the parent div and the min-width off of the screen size.
Is it possible to set a font size to a percentage of the container size? I have a list of items which have an image, a header and a description. The image resizes automatically as the user resizes the window. I would like the header font to do the same.
edit: Javascript/JQuery is fine.
In CSS3, there is the vw unit, which stands for 1/100 of the viewport width. For example,
h1 { font-size: 5.5vw; }
sets the heading font size to 5.5% of the viewport width.
However, this seems to work on IE 9 (Standards Mode) only so far. Moreover, IE 9 does not dynamically change the value of the unit when the browser window is resized, only on reload.
Just to expand on Tyler's answer, this is what javascript is meant for, though I'm tad sure you can achieve the same feat using CSS3 viewports, you will be better off using jQuery (it's usually in the cache of most browser's and always hosted on Google so no need to worry :)
If you have a css like this:
#body #mytext {
font-size: 50%;
}
you can dynamically resize in jQuery like this:
$(window).resize(function(){
$('#body #mytext').css('font-size',($(window).width()*0.5)+'px');
});
No, this can only be done in JavaScript.
Is jquery is an option?
Super easy if it is: fiddle
<div id="container">
<p>HELLO WORLD!</p>
</div>
<script>
$(document).ready(function() {
var sizeMe = ($('#container').height() / 100) * 90; /* 90% of container */
$('p').css('font-size', sizeMe);
};
</script>
I've done it with jquery in the past. Check out this article if it's of any interest to you. You can also use CSS to detect device width (not browser, and it's not supported in older browsers).
http://css-tricks.com/resolution-specific-stylesheets/
Any ideas for using max-height on a borderless/scrolless iFrame so if it ends up being too tall the browser doesn't render a giant black area to fill in the rest of the iFrame?
I've tried setting height="100%" and max-height="xx" but that doesn't seem to work.
Many Thanks!
Your use of height="100%", using the = operator, suggests you're trying to use in-line attributes. This can work, but usually works better with absolute measurements (so 700px rather than a percentage). max-height isn't a valid attribute, so far as I'm aware, of any element except in stylesheets, so I'd suggest that you use CSS:
iframe {
min-height: 200px; /* or whatever */
max-height: 500px; /* or whatever */
}
You can, if you must, also use in-line styles, which would yield <iframe src="..." style="min-height: 200px; max-height: 500px;">
Also, while you can use percentages, to give max-height: 80%, this does seem to require that the parent element has a defined height of its own (I'm not sure if it's all browsers, or just one or two, but either way it seems a reasonable expectation in order that the browser can work out what 80% actually is).
A good JavaScript based answer seems to be the first solution from:
https://www.geeksforgeeks.org/how-to-adjust-the-width-and-height-of-iframe-to-fit-with-content-in-it/
Resizes the iframe to suit the content. I've found that you have to manually add a bit extra for height... go figure, but seems to work.
Here's the full mark-up and JS that works for me based on that solution:
<iframe src="/app/index.html" style="width:100%;" frameborder="0" id="Iframe">
Oops, your browser doesn't get Iframes. Click Here to proceed.
</iframe>
<script>
// Adjust the iframe height to exactly as much as required by the content
var frame = document.getElementById("Iframe");
frame.onload = function() {
// add extra 50 pixels - in reality need just a bit more
frame.style.height = (50+frame.contentWindow.document.body.scrollHeight) + 'px';
// not sure if this is really required.
// set the width of the iframe as the width of the iframe content
frame.style.width = frame.contentWindow.document.body.scrollWidth+'px';
}
</script>
In my page there's only one image. Kind of 1500x3000 px.
In the printer, I need that this image's maximum width to be the width of the page, so I did: width 100% in the css, and it works.
But the height... the old bullshit of height 100% will never work. Because it always will be 100% of the parent container, then someone must have height defined. Or html or body.
So, my question is: make this image fit in one page.
Any ideas?
One way to do it would be to perform some calculations to find out what width would cause the length to be exactly one page, and then set your width in the CSS accordingly.
If I understand this right, could you do
.OnePageImage { height: 100%; width: 600px; }
Where 600px (the width) is the total width of the page. Then the image would fit on one page (albeit with some distortion potentially). You could also add a css page break style to a div before and after the image, which is done like this:
.break { page-break-after:always; }
Then the code would look like this:
<div class="break"></div>
<img src="[your image src]" class="OnePageImage" />
<div class="break"></div>
The only thing that limited the print output to a single page for me was setting the height in cm of a container element that wrapped the entire page, and also setting it's overflow to hidden. For some reason this didn't seem to work on the body element.
body > section {
padding:0 !important;
margin:0 !important;
height:25.7cm !important;
overflow:hidden !important;
}
Incidentally, I had hoped that setting page-break-inside to avoid on the body or the container element might have been the solution to limiting to a single print page but that doesn't seem to have any effect at all.
Ok sorry for putting the "solution" as a comment:
What I've ended up doing was assume that 99% of the clients (that's true) they use a single page size. So I put some warning in the print interface that will only work with the page size "X". too bad. but it's working out so far