Javascript: Overcoming standards mode differences - javascript

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.

Related

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.

IE9 Javascript slower than IE8 - that's weird!

I'm having difficulty in explaining why the following code runs slower in IE9 than IE8!
Here's some test code that runs smoothly in about half a second in (latest) FF/Chrome/Safari on OS X, WinXP, and Win7 plus IE7 & 8 on WinXP (for simplicity I removed the tweak that makes it work in IE6).
For some reason I can't explain, it's awful in IE9, slow and clunky. Reducing the time for the setTimeout makes it a bit quicker but no less jerky.
I've tried removing and benchmarking a number of what might be the choke points (Math.min for example ... all with no change.
I'm stumped ... can anyone please point me in the right direction?... preferably one that does not require browser-sniffing?
Here's the test code ...
<div id = 'panel' class='noShow' style='background-color: #aaa;'>
<div id = 'wrapper' class='slideWrapper'>
<p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p><p>xxxxxxxxxxx</p>
</div>
</div>
<script type = 'text/javaScript'>
var e = document.getElementById('panel');
var w = document.getElementById('wrapper');
w.style.overflow = 'hidden';
w.style.height = '1px';
var sh = w.scrollHeight;
show();
function show()
{
setTimeout(function()
{
w.style.height = Math.min(sh, (w.offsetHeight + Math.ceil(sh/15))) + 'px';
if(
(w.offsetHeight < sh)
)
{
show(e);
}
else
{
w.style.height = 'auto';
}
}, 20);
}
</script>
IE9 defaults to software rendering on VMware Virtual Machines (as of 7/8/2011) there is supposed to be a hotfix released in the near future but no timeline is given per this blog post.
Are you running the 64 bit version of IE 9 or the 32 bit version? The 64 bit version is not running Chakra which is the optimized JavaScript engine from the 32 bit version
There are always odd performance variations when running in a virtualized environment. The selection of drivers and how the software offloads the processing will have an impact. Have you tried updating the drivers on your system?

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.

Is detecting scrollbar presence with jQuery still difficult?

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;
}
}

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