scrollTop inconsistencies when (zoom < 1) - javascript

This is my first SO question, so please forgive any question faux-pas!
I have two containers on my HTML DOM that float:left. Each has content that must be perfectly aligned with the other. The left container (A) has overflow-y:hidden while the right container (B) has overflow-y:scroll. I use an onscroll callback to set the scroll position of container A like such:
A.scrollTop = B.scrollTop;
This works great in 99% of use-cases... until a client zooms below 100%. When zoom is below this level, rows in one container are sometimes 1 pixel off from those in the other. My first guess is that this is a rounding issue, but I can't figure out where I can find values that I could use to build an algorithm to predict when & how the error will occur. In addition, both containers have exactly the same height, and their content is of identical height as well, so I'd expect any rounding errors to be the same for each of them!
I've created a jsFiddle demonstrating the behavior here. (I've used divs in this example, but other elements exhibit the same behavior) (I'm testing in chrome)
Can anyone explain why these two containers exhibit different behaviors when setting scrollTop to the same value? Also, given that browser-zoom detection is difficult at best
(discussion here) does anyone know an efficient way to identify and correct for this issue?

Looks like scaling problem, not sure.
Forcing scrollTop might help.
JSFiddle demo here.
$('#b').on('scroll', function () {
var top = $(this).scrollTop();
if (top != $('#a').scrollTop()) {
$('#a').scrollTop(top);
$(this).scrollTop(top);
}
});

Update: I just revisited this question to see if there were any changes in Chrome's handling of this datapoint... lo and behold, Chrome now returns a floating point value for scrollTop!
Problem solved!

Related

element.scrollTop has different behavior across browsers while setting a very large value

I want to scroll to bottom without triggering layout/reflow.
So I tried to set a fixed large number(Number.MAX_SAFE_INTEGER or 1000000000000000) to scrollTop, which caused different behavior across browsers:
Firefox(59.02)/Safari(11.1): scroll to top
Chrome(66.0.3359.139): scroll to bottom
Here's the Example.
Is this a bug or there's something I went wrong...?
Instead you can try with scrollTop to the calculated height of the page.
It is simpler and straight forward.
Steps to follow
1. Find the height of the document / any container div
var containerHeight= $("#box").height();
scrollTop with containerHeight.
document.querySelector('#box').scrollTop = containerHeight;
This will surely work with any behaviour mismatch.
This could be caused by the different max values for elements across browsers. For instance, in Chrome the limit is 33554428px. A complete list was given here: What's the maximum pixel value of CSS width and height properties?

Dealing with scroll bars and jquery .width() method

jQuery's .width() method doesn't seem to account for scroll bars. This is problematic for me, since I'd like to set the width of some children to equal the width of their parent. I used jQuery similar to the following:
$('#contentDiv').width($('#containerDiv').width())
In this example, #contentDiv is the element I'd like to size, and I want to set it to have the width of #containerDiv, which is its parent element. My problem is that this cuts off the side of #contentDiv, as seen in this fiddle.
In my actual code, I have several elements that I'm sizing with jQuery, which all need to fit in the scrollable div, so just setting the css of #contentDiv to 100% is not an option. What's the best way of dealing with scroll bar widths of divs in jQuery?
The best solution I found while working around this solution is this:
http://chris-spittles.co.uk/?p=531
jQuery is all powerful and everything but sometimes a small dash of native JS is all you need to render pixel perfect pages... I hope you will find this solution helpful!
UPDATED:
None of the jQuery width-finding methods account for the scroll bar. In my original example, using .innerWidth(true) LOOKS like it works, but only because it returns and object, which causes width to fail and the inner contents size themselves to fit in the available space, because the example wasn't very good. However, it's possible to write a function to compute the available space in a div with a scroll bar in it, which can then be used to position the contents as you wish.
To write that function, I took advantage of the fact that, when a div is appended to a div with a scroll bar in it, it takes up the full available width (i.e. the inner width of the parent minus the width of the scroll bar).
The function looks like this:
function noScrollWidth(div){
var measureDiv = $('<div id="measureDiv">');
div.append(measureDiv);
var width = measureDiv.outerWidth();
measureDiv.remove();
return width
};
I then use this to size my content div:
$('#contentDiv').width(noScrollWidth($('#containerDiv')));
Working fiddle.
Try this:
$('#contentDiv').width($('#containerDiv')[0].clientWidth)
For more information about that solution, see this StackOverflow answer.
Another approach I'd try is setting both elements' box-sizing property to 'border-box', and see whether setting your contentDiv's width to 100% then works the way you want.
Now that fewer projects worry about crufty old browsers anymore, 'border-box' can make things easier to work with. Be sure to test multiple browsers on multiple platforms, though, because I'm not sure they all handle scrollbars the same way.

How to improve JS scroll performance?

I'm working on revamping my website, and the new one can be found on http://beta.namanyayg.com/
There are mainly two things related to scroll on the site:
To check on which 'page' the user is on, by calculating the top offset and scroll position, then adding a class to the page.
To smooth scroll on menu click.
I've written code for both, but there is a lot of lag.
The first one almost always results in lagging. The second one, as a result, lags too. I have included a boolean to check if it's smooth scrolling and disabled the normal scroll events then, but there's not much change.
Do you have any advice on how to improve performance so there is no (or at least, less) lag? Thank you in advance! :)
...Or is it not related to JS at all? I've optimized everything else...
EDIT: Unminified JS at http://beta.namanyayg.com/js/main.js
If you are using underscore, it has an awesome _.debounce function that is excellent for this sort of thing.
To check how much the user has scrolled from the top of the page (i.e. on which 'page' he is at the moment) can be achieved with:
$(window).scroll(function () {
var scrollAmount = $(window).scrollTop(); // in pixels
if(scrollAmount > SOME_AMOUNT)
{
// add required css class
}
});
To scroll smoothly, to some id for example, you could use:
$("html, body").animate({ scrollTop: $("#someID").scrollTop() }, 1000);
These are both jQuery solutions, so you should have jquery library included. There is also a nice jQuery plugin called waypoints that performs these calculations. It might prove useful to you and it has some other nice features and examples.
I have the same problem. I have a scrollable div with thousands of smaller divs. Every time I call scrollTop to get the scroll-position or set it, it sometimes waits at least 1 second.
I read these slides: http://www.slideshare.net/nzakas/high-performance-javascript-2011 (especially slides 138-139) and now I realize that every call to scrollTop, even as a getter, makes javascript relayout the page. This is most likely the cause of delay, but unfortunately I have not found a solution yet, as in a way to call scrollTop without causing relayouts.
Note: I've only been testing on Chrome.
Also read 'Browsers are smart' section of this article: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
I've found an easy solution to the lag with getting scrollTop, just call it inside a scroll-handler and save the result in a variable.
for example in jQuery:
var scrollPos = 0,
element = $('.class');
element.scroll(function(){
scrollPos = element.scrollTop();
});
For the second problem, setting the scrollTop, I reduced the amount of DOM elements by only showing the visible elements. In your case make sure only the visible page(s) are added to the DOM. when scrolling to the next page, in the scroll handler remove the top one (use jQuery .detach) and append the next one to the DOM.

Implementing weighted flexible layout with CSS

Please take a look at this jsFiddle and press the only button to fill the list up. As you can see DIV elements inside the list are resized to fill the parent contained. This code does exactly what I want to do, but I think the way I implement this is too complex for such a seemingly simple task. Here is the code for the algorithm to assign height to inner elements:
fill = function() {
//Loop through all elements once to get total weight
var totalWeight = 0;
var totalHeight = $("#container").height() - 15; //need a little extra empty space at the buttom
$(".list").each(function(i) {
totalWeight += parseInt($(this).attr('weight'));
totalHeight -= parseInt($(this).css('margin'));
});
//Loop though the element a second time to set the relative height
$(".list").each(function(i) {
var element = $(this);
element.css("height", (element.attr("weight") / totalWeight) * totalHeight);
});
}
My question is, is the best we can do? Are there any other - hopefully faster or more elegant -- ways to achieve this functionality with reasonable cross-browser compatibility? I need to support newer Firefox, Chrome, and Safari only. I was reading about flex-box here and looking at its promising specs, but it does not look like flex-box can do weighted flexible layout consistently across browsers. If I am wrong, please show me a simple example of how this could be achieved.
This type of weighted flexible linear layout is not uncommon, for example it is available in Android SDK as one of the layout options. What is the recommended way to resize elements to fill their parent container, relative to a weight value assigned to them? A pure CSS solution would be wonderful, if at all possible.
Just a quick look over it, after about 30 mins googling. I may do a demo but don't really hav much time.
Have you looked here
html5rocks
coding.smashmag...
tutsplus
umarr
w3c
benfrain
There are some good examples on the 6th one
edit:
I was looking thought the firefox developer section on their website and found
developer.mozilla...
I also found another example with a download!!
github..
this might give you some direction for firefox and the rest should be in the other links I have provided

javascript getelementbyid ... how to 'get' the "html" variable

function allowscroll()
{
if (screen.width<1200){document.getElementById('html').style.cssText='overflow-x: scroll !important;';};
}
<body onLoad="allowscroll();">
hi there, the above code works for any element, e.g. subbing "html" for "wrapper", but how is it possible to edit the css applied to html? Basically, because of overflow:hidden not inheriting in ie7 - which causes a big empty righthand margin and horizontal scrollbar (only in ie7, ie 8 compatibilty), ive set the css to
html {overflow-x:hidden;}
this is the only way to fix it without losing necessary functionality, e.g. overflowed graphics visibilty.
and this is all well and good, however, lower screen resolutions need the horizontal scroll just to see all of the page itself, so I'm attempting to restore the horizontal scrollbar for those users - and restore the big right margin for anyone who happens to be, for example ie7 1024 by 768 - I can live with that (unless anyone happens to have a superdupa solution).
document.getElementById('html').style.cssText='overflow-x: scroll !important;';
So the above code works for editing the CSS of any element, but not the CSS of the html.
I've also tried:
function allowscroll()
{
if (screen.width<1200){document.getElementByName('html').style.cssText='overflow-x: scroll !important;';};
}
and
function allowscroll()
{
if (screen.width<1200){window.style.cssText='overflow-x: scroll !important;';};
}
I would really appreciate any help, - if it helps in seeing the solution, the link where this applies is: delight design, basically, its how to take out:
html {overflow-x:hidden;}
from the css when in lower screen resolutions...
many thanks
Will
There are a bunch of different ways to get the html element:
document.documentElement
document.getElementsByTagName('html')[0]
document.body.parentNode
But in all honesty, there must be a better way. I don't have time right now to track down what exactly happened here, but from what I can tell, adding position:relative to whatever needs the overflow might help.
Try document.getElementsByTagName("html")[0]
Note I just edited the answer as getElementsByTagName returns an array. You want the first element in that array.
Just use the documentElement:
document.documentElement
It has full browser suport.

Categories