javascript - incorrect viewport size - javascript

I'm try to get the browser viewport size.
When the page initially loads (in jQuery(function() { .. });) , both these show the correct value (eg: 560):
console.log($(window).height());
console.log(document.documentElement.clientHeight);
But later when I do the same thing, it shows the height of the whole docoument (eg: 11675).
There's a lot of HTML and JS and it would take a while to figure out what's going on, I was just wondering, did anyone see anything like this, if so, what can cause it and how can I get the correct size of the viewport? All google hits show that's the correct way to retrieve the value.
Note: I'm using chrome.

I recently bumped into the same problem in one of my projects. I didn't have time to dig and isolate this weird bug, and I ended up using this function (adapted from this answer) to correctly get the viewport dimensions :
var getViewportSize = (function(){
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0];
return function(){
return {
w : Math.max(w.innerWidth || e.clientWidth || g.clientWidth, app.config.minWidth),
h : Math.max(w.innerHeight|| e.clientHeight|| g.clientHeight, app.config.minHeight)
};
}
})();
From what I've tested, jQuery returned the incorrect size when the console or some other browser extension/toolbar was occupying some of the viewport space.
Hope this helps, but I'm also curious and trying to figure this one out, because it's hard to think that a mature lib such as jQuery 2.0 has these kind of bugs.

Related

Optimize animation with javascript assigning value

I am building an animation with lots of effects and animation in a website. I am trying to optimize the efficiency of those animations since some of them are a little complex to low CPU/RAM devices. The animations are not smooth as I want as you can see here https://www.empresasite.com.br
So I realize in many parts of my code I do this:
var x = 38; //this value changes every 50ms
document.getElementById("a").style.left = document.getElementById("b").style.left = document.getElementById("c").style.left = document.getElementById("d").style.left = document.getElementById("e").style.left = x + "px";
Actually it's a simplification above, I run the code above with at least 13 elements a = b = c = d .... m = x; and at least with 4 properties (left, height, box-shadow and background-color).
So I was wondering if there is any better alternative to assign the same value to multiple elements/objects at once?
Maybe the code below would be faster? I used it but I didnt see a significant improvement in animation, maybe I should have seen it?
var x = 38;
x = x + "px";
document.getElementById("a").style.left = x;
document.getElementById("b").style.left = x;
document.getElementById("c").style.left = x;
document.getElementById("d").style.left = x;
document.getElementById("e").style.left = x;
I think the code above should be faster right? I say this cause every element updates its own property (left) retrieving the value from "x". In the first example I gave MAYBE javascript is assigning the value of the previous element in the chain of "=" sign so it has to assign "x" to the first element then assign the value of the first element to the second... go on.
Do you know exactly what jquery does when I use this:
$(".elements").css({left:x});
Does it use some optimization?
You could increase performance no-end by using translate instead of modifying position.
Using the jQuery variation you asked will not make any difference, as you are still modifying position left.
After playing around with most of the javascript benchmarking tools online I came up to this conclusion:
1) Jquery is the faster method of all native js solutions I used. Maybe Jquery uses some sort of optimization when you apply the same property to lots of elements at once! So you should rely on $(".class").css("left",x) to apply the x value to left property for hundreds of elements and it will be the faster solution;
2) The second solution is apply x individually TO EACH element. Example:
var x = 38;
document.getElementById("a").style.left = x;
document.getElementById("b").style.left = x;
3) The worst solution was actually the one I was using in the website that I was facing not smooth animations. So avoid this:
document.getElementById("a").style.left = document.getElementById("b").style.left = ... = ... = x;
The difference from the 1st solution to the 3rd is really noticeable. You can check it in the links below (pay special attention to the animation at the top):
1) https://www.empresasite.com.br/?q=principal&before -> this is using the 3rd solution
2) https://www.empresasite.com.br/?q=principal -> this is using the 1st solution
In a computer with lots of resources you may not see a difference but if you run this in a computer with 4GB of RAM or less you will see a big impact!
Hope this helps anyone that does not have smooth animations!

Modify FireFox extension: If (scrollbar exists) var - 30 else var -14

Hello fellow code people :)
I am a frontend web developer and as such in need of constant knowledge of the actual viewport size in order to see where in responsive designing breakpoints start and end.
I know FF's own 'test window size' function, but came across a very handy extension: FireSizer.
the extension has one itsy bitsy drawback: It gives back the window-size including FF's borders and scrollbar. I need the viewport-size though. So I need the extension hacked, but dont't know enough javaScript to do so. Maybe someone is willing to help em out here?
I would love the extension to actually look for the scrollbar, and subtract from the width
a) 14 if no scrollbar present or
b) 30 if scrollbar present
I found of what I think is the right place to alter the code:
//
// Update the status bar panel with the current window size
//
function FiresizerUpdateStatus() {
var width = window.outerWidth + ''; // <- Think code needs to be edited here
var height = window.outerHeight + '';
document.getElementById("firesizer-statuspanel").label = width + 'x' + height;
}
Thanks for any effort!
AO
#Chen Asraf:
Well thank you very much. I didn't know there was an element to call the document-width. I changed the code to the following, and that did the trick (also when compared to FF's own 'Responsive Design View mode', which is spot on, its off by 2px - which i subtract from clientWidth.)
function FiresizerUpdateStatus() {
var width = window.outerWidth + ''; // changed this line to:
var width = document.documentElement.clientWidth-2 + '';
var height = window.outerHeight + '';
document.getElementById("firesizer-statuspanel").label = width + 'M' + height;
}
Thanks
AO
Possible duplicate of Get the browser viewport dimensions with JavaScript
Seems like you can get the window's inner dimensions by using:
// My window is maximized; screen is 1366x768
alert(document.documentElement.clientWidth);
// ^ returns 1349 (17 missing pixels because of scrollbar)
alert(document.documentElement.clientHeight);
// ^ returns 643 (125 pixels missing because of start bar & Chrome toolbars)
You can then compare the following with whatever else you need (for example, compare client width with window width to find if the difference is big enough to be a scrollbar - just experiment with the sizes)

Detecting if the browser window is moved with JavaScript?

This is for a demo... and i was just curious, can you detect if the window has been moved? Like if you move Firefox/Chrome/IE around your monitor? I doubt it, but I wanted to see since you can check for resize and focus/blurred windows.
I can only think of this (heavy) work-around, where you check if window.screenX and window.screenY have changed every x milliseconds
var oldX = window.screenX,
oldY = window.screenY;
var interval = setInterval(function(){
if(oldX != window.screenX || oldY != window.screenY){
console.log('moved!');
} else {
console.log('not moved!');
}
oldX = window.screenX;
oldY = window.screenY;
}, 500);
Though I would not recommend this -- it might be slow and I'm not sure if screenX and screenY are supported by all browsers
A potentially more optimised version of this is to only check for window movement when outside of the window combined with Harmen's answer:
var interval;
window.addEventListener("mouseout", function(evt){
if (evt.toElement === null && evt.relatedTarget === null) {
//if outside the window...
if (console) console.log("out");
interval = setInterval(function () {
//do something with evt.screenX/evt.screenY
}, 250);
} else {
//if inside the window...
if (console) console.log("in");
clearInterval(interval);
}
});
If using jQuery, it may normalise screenX/Y in this case so it's worth running a few tests on that. Jquery would use this format instead of addEventListener:
$(window).on('mouseout', function () {});
If you are moving the window in Windows OS via alt + Space, and find that windows resizes are ignored, I would recommend adding an extra level of detection via keypress events.
Re the first answer: I use the 'poll window position' in production code. It's a very lightweight thing to do. Asking for a couple of object properties twice a second is not going to slow anything down. Cross-browser window position is given by:
function get_window_x_pos()
{
var winx;
if(window.screenX)
winx=window.screenX;
else if(window.screenLeft)
winx=window.screenLeft;
return winx;
}
and similarly for vertical position. In my code I use this to fire an AJAX event off to the server to store position and size of the window so next time it will open where it was the last time (I'm probably moving to HTML5 local storage soon.) One little wrinkle you might want to cover is not generating spurious updates while the window is being dragged. The way to handle this is to register when the window has been moved for the first time and only trigger an update when two subsequent polls of window position return the same value. A further complication is for windows which allow resizing from all sides. If the left or top side are dragged, the DOM will give you a resize event, but the nominal window position will have altered as well.
Unfortunately not. The DOM is only notified about window sizes, cursor positions, "focus" and "blur", etc; anything that affects drawing. Since moving a window doesn't necessarily require any of the contents to be "redrawn" (in a Javascript/Html engine sort of sense), the DOM, therefore, doesn't need to know about it.
Sadly, no. Although I did find this page that claims there is such a thing. I tested that in IE, Chrome, and FireFox, no luck.

How can I get the scrollbar position with JavaScript?

I'm trying to detect the position of the browser's scrollbar with JavaScript to decide where in the page the current view is.
My guess is that I have to detect where the thumb on the track is, and then the height of the thumb as a percentage of the total height of the track. Am I over-complicating it, or does JavaScript offer an easier solution than that? What would some code look like?
You can use element.scrollTop and element.scrollLeft to get the vertical and horizontal offset, respectively, that has been scrolled. element can be document.body if you care about the whole page. You can compare it to element.offsetHeight and element.offsetWidth (again, element may be the body) if you need percentages.
I did this for a <div> on Chrome.
element.scrollTop - is the pixels hidden in top due to the scroll. With no scroll its value is 0.
element.scrollHeight - is the pixels of the whole div.
element.clientHeight - is the pixels that you see in your browser.
var a = element.scrollTop;
will be the position.
var b = element.scrollHeight - element.clientHeight;
will be the maximum value for scrollTop.
var c = a / b;
will be the percent of scroll [from 0 to 1].
document.getScroll = function() {
if (window.pageYOffset != undefined) {
return [pageXOffset, pageYOffset];
} else {
var sx, sy, d = document,
r = d.documentElement,
b = d.body;
sx = r.scrollLeft || b.scrollLeft || 0;
sy = r.scrollTop || b.scrollTop || 0;
return [sx, sy];
}
}
returns an array with two integers- [scrollLeft, scrollTop]
It's like this :)
window.addEventListener("scroll", (event) => {
let scroll = this.scrollY;
console.log(scroll)
});
Answer for 2018:
The best way to do things like that is to use the Intersection Observer API.
The Intersection Observer API provides a way to asynchronously observe
changes in the intersection of a target element with an ancestor
element or with a top-level document's viewport.
Historically, detecting visibility of an element, or the relative
visibility of two elements in relation to each other, has been a
difficult task for which solutions have been unreliable and prone to
causing the browser and the sites the user is accessing to become
sluggish. Unfortunately, as the web has matured, the need for this
kind of information has grown. Intersection information is needed for
many reasons, such as:
Lazy-loading of images or other content as a page is scrolled.
Implementing "infinite scrolling" web sites, where more and more content is loaded and rendered as you scroll, so that the user doesn't
have to flip through pages.
Reporting of visibility of advertisements in order to calculate ad revenues.
Deciding whether or not to perform tasks or animation processes based on whether or not the user will see the result.
Implementing intersection detection in the past involved event
handlers and loops calling methods like
Element.getBoundingClientRect() to build up the needed information for
every element affected. Since all this code runs on the main thread,
even one of these can cause performance problems. When a site is
loaded with these tests, things can get downright ugly.
See the following code example:
var options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
var observer = new IntersectionObserver(callback, options);
var target = document.querySelector('#listItem');
observer.observe(target);
Most modern browsers support the IntersectionObserver, but you should use the polyfill for backward-compatibility.
If you care for the whole page, you can use this:
document.body.getBoundingClientRect().top
Snippets
The read-only scrollY property of the Window interface returns the
number of pixels that the document is currently scrolled vertically.
window.addEventListener('scroll', function(){console.log(this.scrollY)})
html{height:5000px}
Shorter version using anonymous arrow function (ES6) and avoiding the use of this
window.addEventListener('scroll', () => console.log(scrollY))
html{height:5000px}
Here is the other way to get the scroll position:
const getScrollPosition = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
If you are using jQuery there is a perfect function for you: .scrollTop()
doc here -> http://api.jquery.com/scrollTop/
note: you can use this function to retrieve OR set the position.
see also: http://api.jquery.com/?s=scroll
I think the following function can help to have scroll coordinate values:
const getScrollCoordinate = (el = window) => ({
x: el.pageXOffset || el.scrollLeft,
y: el.pageYOffset || el.scrollTop,
});
I got this idea from this answer with a little change.

Javascript execution order issues with Dojo

Before I ask my question, here's the offending code:
var coords = dojo.coords(g);
g.style.left = coords.x + "px";
g.style.top = coords.y + "px";
g.style.position = "absolute";
Now imagine that g is a relatively positioned element with an x position of 70 and a y position of 30. If I comment out the last line of the above code, that's what dojo.coords(g) gives me. But as soon as I add the last line, dojo.coords(g) returns an x position of 18, which is where the element would be if it were absolutely positioned. It seems to me that the call to dojo.coords() shouldn't be affected by code below it, but it is.
I'm also seeing the same problem with dojo.require() where if I call it directly before the function call that it's loading, I get an undefined error for that given function.
I'm testing in Firefox 3, but I also am noticing similar problems in Safari 3. Any ideas?
It is not the Dojo quirk but the way browsers work. Basically it may take some time for DOM to reflect your changes and reposition elements, or even change the layout. That's why you see what you see.
Another reason may be in the parent of your element. dojo.coords() returns the position relative to the viewport. If you pass "true" as the second value, it will return the position relative to the document root. Assigning top/left directly and changing position to "absolute" makes the element positioned relatively to its parent, if it was positioned too (absolute, relative, or fixed), or to the document root. It is a subtle difference, but sometimes it bites people. Relevant references: Containing Block, MSDN: position Attribute, Google doctype: position.
PS: personally I rely on Dojo to set left/top hoping it'll do the right thing working around browser quirks, and I set the position first:
var coords = dojo.coords(g);
g.style.position = "absolute";
dojo.marginBox(g, {l: coords.x, t: coords.y});
I still would love someone to explain why this works, but here's a solution:
var coords = dojo.coords(g);
g.style.left = coords.x + "px";
g.style.top = coords.y + "px";
setTimeout(function(h) {
h.style.position = "absolute";
}, 0, g);
Cheers
sorry to not respond your question, (because I do not know dojo) but unless coords.x and coords.y returns a string, there is an error in your function,
g.style.left = coords.x + "px";
g.style.top = coords.y + "px";
You need to pass always a string to style, so add these also:
g.style.left = parseInt(coords.x) + "px";
g.style.top = parseInt(coords.y) + "px";
You would be surprised how many times this kind of error got my head spinning. About the answer, sorry, but I can't help you.
Good luck!
Edited:
Oh, if I understood, I can help you now.. well, since I do not know dojo, I can point out to you a javascript similar that will do what you want.
g.offsetTop
and
g.offsetLeft
Will give you the coords from the position of the element. Try them out and see if it works..

Categories

Resources