jQuery window resize issue - height/width calculation - javascript

The issue is as such - I'm using jQuery to set the height of a container. I am using the plugin bgStretcher 3.1.2 to stretch an image to the dimensions of this container. In screenshot 1 the container I am reffering to is the area occupied y the brick wall image.
The problem arises when you resize the browser, every 2nd time the resize fires the calculations for height/width are off by 15px (I have no idea where this number comes from), creating a gap to the right and bottom of the container as visible in Screenshot 2. This screenshot also includes the console readings of the height of the container as returned by Jquery, indicating the issue. So when you resize the container jitters like hell and potentially ends up with the aforementioned gap.
I believe there is some sort of conflict happening between my code and the plugin as they're both bound to window resize.
This is the simple bit of code I'm using on my end:
win.resize(function() {
console.log(win.height());
conH = win.height()-68;
wrapper.css({
height: conH+"px"
})
}).resize();

function init_heght(element) {
var y = $(window).height();
$(element).css('height', y);
};
init_heght('#section-left-menu');

Related

Detecting VH on mobile in js and returning it's current value

My issue is a hack for a dubious mobile browser discrepancy between the 100vh and the area hidden behind the mobile browser bars. This is a problem for any page where a full screen effect is desired.
The hack detects the difference between the VH and the actual visible viewport. However the simple js in the first code example appears to be detecting it backwards. So if the browser bar is overlaid the value should be 75 but is instead 0 -- likewise when the the browser is large it should return 0 but instead returns -75.
This can be reproduced simply by testing an iPhone with the 'develop' tool in Safari on google.com and entering this in the console.
document.documentElement.clientHeight - window.innerHeight
This seems to compute the shorter browser height with the top offset to compensate for the browser bar as being offset by 0 and the tall browser height where the browser bar is no longer covering the top of the page at -75px. This, to me, appears to be very wrong and should be 75 and 0 respectively. The below example is how I think it should work to properly offset the body tag to position elements with absolute positioning.
function fixIt(){
var offset = (document.documentElement.clientHeight - window.innerHeight);
document.body.style.marginTop = offset;
}
fixIt(); // run on resize
My extra super hacky solution it to offset the body by 75px by default and to assign the old value on vertical resize. (so when the browser bars hide, instead of 75px offset, use previous offset of 0 and save the 75px offset for the next resize). The works in Mobile Chrome and Mobile Safari, but for instance, if the link is opened in facebook where there is no browser bar and no resize events, it is offset by 75px permanently. This code is obviously insane and should be banished into the nothing.
var offset;
var oldOffset = 75px;
function fixIt(oldOffset){
offset = (document.documentElement.clientHeight - window.innerHeight);
document.body.style.marginTop = oldOffset;
oldOffset = offset;
return oldOffset;
}
fixIt(oldOffset); // run on resize
As an aside, or for further reading, here's a big complaint blog on the issue. https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html I agree with the browser vendors that VH should be constant (because the reflow would be obnoxious for everything besides the actual body height) but for the top level elements like body and html tags on mobile this behavior appears to be wrong and it makes no semantic sense, plus these computed numbers appear backwards, further making this issue headache inducing.
What other solutions are out there?

How do I move the background image of a DIV based on the scrollbar movement?

I have been looking into parallax effects for vertical scrolling on my web page, and after some research, I'm not sure that what I want to do is technically a parallax effect.
From what I've seen, most parallax effects assume you want to be able to scroll indefinitely with many background images rolling by, or with huge images that repeat.
What I want to do is have the background of two DIVs be filled with a background image as the scroll bar reaches the bottom of the page. Note that I do not want the background images to stretch. I'm assuming to get the effect I want that these images would have a vertical height bigger than most people's viewport, and then their vertical position would change. When the user's scrollbar is at the top, a certain amount of the background is visible, and then it moves vertically to fill the background space as the user scrolls down.
Please see the image below for a visual explanation of the effect I hope to acheive:
The height of the veiwport will vary depending on the length of content inside the inner DIV.
My trouble is that if what I am trying to do is not exactly a parallax effect, then I don't know what else to call it, and my attempts to search by describing it keep landing me back at pages offering tutorials on parallax effects. So I've been stumped by a lack of terminology.
If someone could direct me to how I can control the vertical position of the background depending on the scrollbar position, that would be much appreciated. If this can be done with just CSS that would be great, but I'm assuming some Javascript would be required. A jQuery solution would also work for me.
Update:
After searching using the terms provided in comments, I've got the background image in the outer DIV to almost do what I want with the following code:
$(window).scroll(function () {
var yPos = $("#outerDiv").height() - ($("#outerDIV").height() * ($(window).scrollTop() / $(window).height()));
document.getElementById('outerDIV').style.backgroundPosition="0px " + yPos + "px";
});
It moves the background image in the right direction relative to the scrolling, but what it lacks is constraining that motion to within the viewport. Getting the right proportions based on the viewport and DIV sizes is proving to be just a little beyond my mathematical abilities.
For your requirement, you have to use a jquery parallax plugin to guide this activity, my best suggest it to use a Superscollorama and play with the elements as your wish...
As far as your question, Try this example,
controller.addTween(
'#examples-background',
(new TimelineLite())
.append([
TweenMax.fromTo($('#parallax-it-left'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 -54px)"}}),
TweenMax.fromTo($('#parallax-it-right'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 54px)"}})
]),
1000 // scroll duration of tween
);
You serial vice change as far as your wish...
Try practice this plugin, hope that works for you...
http://johnpolacek.github.io/superscrollorama/
Thanks...
Turns out what I want to acheive is possible with no special plugins, just some carefully thought out math. I did use a little jQuery syntax, but I don't think it's strictly necessary.
The code below has copious notes, so hopefully it's largely explanatory. In summary, you just need to find the position of the background image when the scroll would be at the top, and the position it would be if the scroll bar was at the bottom, and then you can use the percentage of the scrollbar's movement to work out where you are between those two points. It's a little tricker than just that, of course, in that you have to account for the difference between the total height of the scroll bar and where your DIV appears on the page and a few other adjustments, but the details of what I did are below.
What I've done here is just for the "outer DIV" that I described in my question. To get a background to move like the "inner DIV" I described, you'd have to modify the code, presumeably by reversing a few parameters. I haven't done that yet, but it seems like a straightforward task.
Hope others find this code useful. If anyone has suggestions on how it can be made more efficient or better, please let me know.
function moveBG(){
// imageHeight is not the total height of the image,
// it's the vertical amount you want to ensure remains visible no matter what.
var imageHeight = 300;
// Get the maximum amount within the DIV that the BG can move vertically.
var maxYPos = $("#outerDIV").height() - imageHeight;
// Get the amount of vertical distance from the top of the document to
// to the top of the DIV.
var headerHeight = document.getElementById("outerDIV").offsetTop;
// Calculate the BG Y position for when the scrollbar is at the very top.
var bgTopPos = $(window).height() - headerHeight - imageHeight;
// I don't want the image to wander outside of the DIV, so ensure it never
// goes below zero.
if (bgTopPos < 0)
{
bgTopPos = 0;
}
// Calculate the BG Y position when the scrollbar is at the very top.
var bgBottomPos = $(document).height() - $(window).height() - headerHeight;
// To prevent the BG image from getting cut off at the top, make sure
// its position never exceeds the maximum distance from the top of the DIV.
if (bgBottomPos > maxYPos)
{
bgBottomPos = maxYPos;
}
// Subtract the top position from the bottom, and you have the spread
// the BG will travel.
var totalYSpan = bgBottomPos - bgTopPos;
// Get the scrollbar position as a "percentage". Note I simply left it as a
// value between 0 and 1 instead of converting to a "true" percentage between
// 0 and 100, 'cause we don't need that in this situation.
var scrollPercent = ($(window).scrollTop() / ( $(document).height() - $(window).height()));
// The percentage of spread is added to the top position, and voila!
// You have your Y position for the BG image.
var bgYPos = bgTopPos + (Math.round(totalYSpan * scrollPercent));
// Apply it to the DIV.
document.getElementById('outerDIV').style.backgroundPosition="0px " + bgYPos + "px";
}
// Place the BG image correctly when opening the page.
$(document).ready(function() {
moveBG();
});
// Make it update when the scrollbar moves.
$(window).scroll(function () {
moveBG();
});

jQuery/JS, iOS 4 and $(document).height() problems

I've run into an odd issue with what appears to be various versions of Webkit browsers. I'm trying to position an element on the center of the screen and to do the calculations, I need to get various dimensions, specifically the height of the body and the height of the screen. In jQuery I've been using:
var bodyHeight = $('body').height();
var screenHeight = $(window).height();
My page is typically much taller than the actual viewport, so when I 'alert' those variables, bodyHeight should end up being large, while screenHeight should remain constant (height of the browser viewport).
This is true in
- Firefox
- Chrome 15 (whoa! When did Chrome get to version 15?)
- Safari on iOS5
This is NOT working in:
- Safari on iOS4
- Safari 5.0.4
On the latter two, $(window).height(); always returns the same value as $('body').height()
Thinking it was perhaps a jQuery issue, I swapped out the window height for window.outerHeight but that, too, does the same thing, making me think this is actually some sort of webkit problem.
Has anyone ran into this and know of a way around this issue?
To complicate things, I can't seem to replicate this in isolation. For instance: http://jsbin.com/omogap/3 works fine.
I've determined it's not a CSS issue, so perhaps there's other JS wreaking havoc on this particular browser I need to find.
I've been fighting with this for a very long time (because of bug of my plugin) and I've found the way how to get proper height of window in Mobile Safari.
It works correctly no matter what zoom level is without subtracting height of screen with predefined height of status bars (which might change in future). And it works with iOS6 fullscreen mode.
Some tests (on iPhone with screen size 320x480, in landscape mode):
// Returns height of the screen including all toolbars
// Requires detection of orientation. (320px for our test)
window.orientation === 0 ? screen.height : screen.width
// Returns height of the visible area
// It decreases if you zoom in
window.innerHeight
// Returns height of screen minus all toolbars
// The problem is that it always subtracts it with height of the browser bar, no matter if it present or not
// In fullscreen mode it always returns 320px.
// Doesn't change when zoom level is changed.
document.documentElement.clientHeight
Here is how height is detected:
var getIOSWindowHeight = function() {
// Get zoom level of mobile Safari
// Note, that such zoom detection might not work correctly in other browsers
// We use width, instead of height, because there are no vertical toolbars :)
var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
// window.innerHeight returns height of the visible area.
// We multiply it by zoom and get out real height.
return window.innerHeight * zoomLevel;
};
// You can also get height of the toolbars that are currently displayed
var getHeightOfIOSToolbars = function() {
var tH = (window.orientation === 0 ? screen.height : screen.width) - getIOSWindowHeight();
return tH > 1 ? tH : 0;
};
Such technique has only one con: it's not pixel perfect when page is zoomed in (because window.innerHeight always returns rounded value). It also returns incorrect value when you zoom in near top bar.
One year passed since you asked this question, but anyway hope this helps! :)
I had a similar problem. It had to do with 2 thing:
Box-sizing CSS3 property:
In the .height() jQuery documentation I found this:
Note that .height() will always return the content height, regardless of the value of the CSS box-sizing property. As of jQuery 1.8, this may require retrieving the CSS height plus box-sizing property and then subtracting any potential border and padding on each element when the element has box-sizing: border-box. To avoid this penalty, use .css( "height" ) rather than .height().
This may apply to $('body').height().
Document ready vs Window.load
$(document).ready() is run when the DOM is ready for JS but it's possible that images haven't finished loading yet. Using $(window).load() fixed my problem. Read more.
I hope this helps.
It is 2015, we are at iOS 8 now. iOS 9 is already around the corner. And the issue is still with us. Sigh.
I have implemented a cross-browser solution for the window size in jQuery.documentSize. It stays clear of any kind of browser sniffing and has been heavily unit-tested. Here's how it works:
Call $.windowHeight() for the height of the visual viewport. That is the height of the area you actually see in the viewport at the current zoom level, in CSS pixels.
Call $.windowHeight( { viewport: "layout" } ) for the height of the layout viewport. That is the height which the visible area would have at 1:1 zoom - the "original window height".
Just pick the appropriate viewport for your task, and you are done.
Behind the scenes, the calculation roughly follows the procedure outlined in the answer by #DmitrySemenov. I have written about the steps involved elsewhere on SO. Check it out if you are interested, or have a look at the source code.
Try this :
var screenHeight = (typeof window.outerHeight != 'undefined')?Math.max(window.outerHeight, $(window).height()):$(window).height()
A cross browser solution is set that by jQuery
Use this property:
$(window).height()
This return a int value that represents the size of visible screen height of browser in pixels.

Using Javascript to resize a div to screen height causes flickering when shrinking the browser window

The Background:
I tried to solve the StackOverflow question yet another HTML/CSS layout challenge - full height sidebar with sticky footer on my own using jQuery. Because the sidebar in my case may be longer than the main content it matches the case of comment 8128008. That makes it impossible to have a sidebar longer than the main content and having a sticky footer without getting problems when shrinking the browser window.
The status quo:
I have a html page with a div, which is automatically stretched to fill the screen. So if there is empty space below the element, I stretch it downwards:
But if the browser viewport is smaller than the div itself, no stretching is done but the scrollbar shows up:
I've attached jQuery to the window's resize event to resize the div, if the browser window is not to small and remove any resizing in the other case. This is done by checking if the viewport is higher or smaller than the document. If the viewport is smaller than the document, it seems like the content is larger than the browser window, why no resizing is done; in the other case we resize the div to fill the page.
if ($(document).height() > $(window).height()) {
// Scrolling needed, page content extends browser window
// --> No need to resize the div
// --> Custom height is removed
// [...]
} else {
// Window is larger than the page content
// --> Div is resized using jQuery:
$('#div').height($(window).height());
}
The Problem:
Up to now, everything runs well. But if I shrink the browser window, there are cases, where the div should be resized but the document is larger than the window's height, why my script assumes, that no resizing is needed and the div's resizing is removed.
The point is actually, that if I check the document's height using Firebug after the bug appeared, the height has just the value is was meant to have. So I thought, the document's height is set with a little delay. I tried to run the resize code delayed a bit but it did not help.
I have set up a demonstration on jsFiddle. Just shrink the browser window slowly and you'll see the div "flickering". Also you can watch the console.log() output and you will notice, that in the case of "flickering" the document's height and the window's height are different instead of being equal.
I've noticed this behavior in Firefox 7, IE 9, Chrome 10 and Safari 5.1. Can you confirm it?
Do you know if there is a fix? Or is the approach totally wrong? Please help me.
Ok -- wiping my old answer and replacing...
Here's your problem:
You are taking and comparing window and document height, without first taking into consideration the order of events here..
Window loads
Div grows to window height
Window shrinks
Document height remains at div height
Window height is less than div height
At this point, the previously set height of the div is keeping document height greater than the window height, and this logic is misinterpreted:
"Scrolling needed, no need to extend the sidebar" fires, erroneously
Hence the twitch.
To prevent it, just resize your div along with the window before making the comparison:
(function () {
var resizeContentWrapper = function () {
console.group('resizing');
var target = {
content: $('#resizeme')
};
//resize target content to window size, assuming that last time around it was set to document height, and might be pushing document height beyond window after resize
//TODO: for performance, insert flags to only do this if the window is shrinking, and the div has already been resized
target.content.css('height', $(window).height());
var height = {
document: $(document).height(),
window: $(window).height()
};
console.log('height: ', height);
if (height.document > height.window) {
// Scrolling needed, no need to externd the sidebar
target.content.css('height', '');
console.info('custom height removed');
} else {
// Set the new content height
height['content'] = height.window;
target.content.css('height', height['content']);
console.log('new height: ', height);
}
console.groupEnd();
}
resizeContentWrapper();
$(window).bind('resize orientationchange', resizeContentWrapper);
})(jQuery);
Per pmvdb's comment, i renamed your $$ to "target"
$(window).bind('resize',function(){
$("#resizeme").css("height","");
if($("#resizeme").outerHeight() < $(window).height()){
$("#resizeme").height($(window).height());
$("body").css("overflow-y","hidden");
}else{
$("body").css("overflow-y","scroll");
}
});
Maybe I am misunderstanding the problem, but why are you using Javascript? This seems like a layout (CSS) issue. My solution without JS: http://jsfiddle.net/2yKgQ/27/

How do I easily find the distance between a point on the page and the bottom of the browser window using JavaScript?

A view in my web app has a table which may be extremely long, so I wrapped it in a div with overflow: auto; max-height: 400px; so users can scroll through it while keeping the other controls on the page visible.
I want to use a bit of JavaScript to dynamically adjust the max-height CSS property so the div stretches to the bottom of the browser window. How can I determine this value? jQuery solutions are fine.
The table doesn't start at the top of the page, so I can't just set the height to 100%.
Something like this would work I think:
var topOfDiv = $('#divID').offset().top;
var bottomOfVisibleWindow = $(window).height();
$('#divID').css('max-height', bottomOfVisibleWindow - topOfDiv - 100);
I had a very similar problem, except in my case I had a dynamic pop-up element (a jQuery UI Multiselect widget), to which I wanted to apply a max-height so that it never went below the bottom of the page. Using offset().top on the target element wasn't enough, because that returns the x coordinate relative to the document, and not the vertical scroll-position of the page.
So if the user scrolls down the page, the offset().top won't provide an accurate description of where they are relative to the bottom of the window - you'll need to determine the scroll position of the page.
var scrollPosition = $('body').scrollTop();
var elementOffset = $('#element').offset().top;
var elementDistance = (elementOffset - scrollPosition);
var windowHeight = $(window).height();
$('#element').css({'max-height': windowHeight - elementDistance});
window.innerHeight gives you the visible height of the entire window. I did something almost identical recently so I'm pretty sure that's what you need. :) Let me know, though.
EDIT: You'll still need the Y-value of the overflowed div which you can get by document.getElementById("some_div_id").offsetHeight, seeing that .style.top won't give you a result unless it has been specifically set to a point via CSS. .offsetHeight should give you the correct 'top' value.
Then it's just a matter of setting the size of the table to the window height, minus the 'top' value of the div, minus whatever arbitrary wiggle room you want for other content.
something like max-height: 100%, but not to forget the html and body height 100%.

Categories