Is detecting scrollbar presence with jQuery still difficult? - javascript

I know that detecting scrollbar presence is supposed to be one of those elusive things that we should all have to suffer through. What I've read so far is that you can't really detect scrollbar presence, only use hints in the DOM to know if they may be present, and it can't be done in less than 30 lines of code.
This sounds a little impossible to me now that we're in 2010. Does jQuery have a cross-browser reliable solution that takes care of this and works at least most of the time? Any help please, I'm pulling my hair, half of it is already on the floor.

Probably not as elegant as you were hoping for but this is an adequate adaption from a script I recently wrote to calculate viewport height.
Logically you'd want to call this function on document ready and window resize.
It also deals with inconsistencies that you'd encounter in Opera (line 2) and IE7 (line 6).
function scrollbar() {
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
if (jQuery.browser.msie) {
if(parseInt(jQuery.browser.version) == 7) {
viewportHeight -= 3;
}
}
if(viewportHeight <= $('#wrapper').height()) {
return true;
} else {
return false;
}
}

Related

virtual scroll wrong display in IE missing rows

i have this script for virtual scroll and for some reason after about 68500 rows it breaks in Internet Explorer 11,but works in FF and Chrome...
https://jsfiddle.net/dLq2284r/5/
at the end you can see the rows overlap .., but only after over 65k rows
i think something is wrong here:
positionPage: function(inPage)
t is getting quite big :) over 1535274
so i think setting a css top : 1535274px; or more is the problem, but i might be wrong :D
positionPage: function(inPage) {
var pn = inPage.pageNum;
if (this.fixedHeight) {
t = pn * this.rowHeight * this.pageSize;
} else {
if (this.pageTops[pn]) {
t = this.pageTops[pn];
} else {
var n = 0, t = 0;
while (n < pn) {
t += this.getPageHeight(n);
n++;
}
}
}
var t0 = inPage.style[this.horiz ? 'left' : 'top'].slice(0, -2);
// update pageTops cache
this.pageTops[pn] = t;
this.pageTops[pn+1] = t + this.getPageHeight(pn);
// set the page's top
inPage.style[this.horiz ? 'left' : 'top'] = t + 'px';
if (t0) {
return t0 - t;
}
}
I have tried everything... any help, hints or anything will be appreciated.
I use this for a database with over 90k rows and i would love it to work on IE for at least 100k rows.
Also don't suggest frameworks or anything else, i have tried them all
Thanks
IE has a long way to go before can compete with other browsers .. So to answer my own question, based on #Sam Segers comment and my research it seems that after a specific height IE has a height miscalculation, based on
Determine Maximum Possible DIV Height
IE can handle about 10M pixels, but after about 1.5M it is not accurate, for example my element had a style top: 1535274px; and the browser was adding the content at 1534484px, so 790px higher, and my js stop working after that point. And since until that height everything was ok i concluded that my script is doing it's job.
I just added a warning in my script to let the IE users know that after that height results are not accurate and to use another browser.
Thank you for your help

Self-written rollout animation stuttering in Firefox

some time ago I started to write some code in JavaScript to learn it a little bit. I picked a rollin/rollout animation as 'project'. (I know about JQuery's slideDown/slideUp, but I wanted to work with pure JavaScript.)
I finished my effect, and the result looks pretty good in all major browsers except Firefox (tested versions 22.x to the latest (25.0.1)). In Firefox, the rolling (in and out) stutters while it rolls smoothly in Chrome, Opera, and Internet Explorer.
The general approach is (unsurprisingly) to have an element's style.height (or width) attribute increased/decreased several times by some pixels over a given time. To avoid calculating sizes every time the effect takes place, I calculate them one time and place them in an array (first item (0 + stepSize), last item wanted height/width). The decrease of the element's height is done by this function:
var verticalRollInWorker = function(step) {
if (step > 0) {
$(btt).style.height = stepSizes[step - 1];
setTimeout(function() { verticalRollInWorker(step - 1); }, delay);
} else {
$(btt).style.display = "none";
$(btt).style.height = 0;
// Enable roll out effect:
stateChange(false);
if (afterFullRollIn != null) {
afterFullRollIn();
}
}
}
In the particular example, I'm using 20 steps over 400ms. The step sizes in the array are rounded to integers, that's why the last step just sets 0 - to handle rounding differences.
(For convenience, I wrote my own $(element) helper, there's no JQuery involved here.)
I tested Firefox without Add-Ons, no difference.
I highly appreciate any help you can provide :)
One problem that I noticed in the above code is that you used $(btt). So, every 20s when the function is iterated, the browser needs to obtain the jQuery object. You could rather store it into a variable say 'var BTT=$(btt);' and use this BTT. Fetching jQuery object is a time consuming task.
Since you are using setTimeout(), the function will be executed every 20ms regardless of the completion of the current execution, this may also cause a drag. As Dagg Nabbit said, you could use setInterval() instad of setTimeout.
Another possible reason might be browser-reflow. I made a personalised scrollbar, and found browser reflow was noticeably greater in my FF than Chrome or IE. This depends on the size of the element, DOM tree depth, overflow property, and more...
And again use this code and see if it is fixed. reduces the subtraction into 1 code.
var BTT=$(btt).get(0);
var verticalRollInWorker = function(step) {
if (step > 0) {
step--;
BTT.style.height = stepSizes[step];
setTimeout(function() { verticalRollInWorker(step); }, delay);
}
else {
BTT.style.display = "none";
BTT.style.height = 0;
// Enable roll out effect:
stateChange(false);
if (afterFullRollIn != null) {
afterFullRollIn();
}
}
}
Further Comments can be made only after seeing a live example.
Regards.

Javascript: Overcoming standards mode differences

The problem I am having is with this code:
function scrollLeft() {
document.body.scrollLeft -= scrollSpeed;
}
It works perfectly in Chrome and Safari but in IE and Firefox it is doing nothing. I have narrowed this down to the fact that in Firefox and IE standards mode they accept document.documentElement.scrollLeft instead of document.body.scrollLeftand my page is being rendered in standards mode.
Please note that I run this script at an interval of 10ms so I can't afford to have a large clunky detection script running each time this function needs to perform.
Does anyone know a cross browser way or an extremely light way of overcoming this? I am using the jQuery library in this script but Firefox and IE aren't recognising $('body').scrollLeft() either and I'm not sure why that is.
KISS: use scrollBy
window.scrollBy( -scrollSpeed, 0 )
Use the logical or operator to fall back.
document[body || documentElement].scrollLeft -= scrollSpeed
This is very quick, so very little overhead for you.
For bonus points do this instead
scrollLeft = (function () {
var docEl = document[body || documentElement];
return function () {
docEl.scrollLeft -= scrollSpeed;
};
})();
This only finds the relevant element reference once and closes over the temporary variable that holds it.

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.

Most efficient way to determine if an HTML element is in the viewport?

I'm currently using prototype, with some code like:
function in_viewport(foo) {
var offset = foo.viewportOffset().top;
var viewportHeight = document.viewport.getHeight();
if (offset > (0 - foo.getHeight()) && offset < viewportHeight) {
return true;
} else {
return false;
}
}
Is there a faster/easier/more-efficient/better way of doing this?
With various JavaScript libraries like Dojo you can get pretty specific and cross browser compatible code that you can use to do this. It still wont look much prettier than what you have there. If you're doing it from scratch it gets much more complex as you have browser quirks, browser version quirks, have to deal with scrolling, etc.

Categories

Resources