Posted at 12/28/2010 4:27:52 AM
In Web sites that use centered layouts, like mine, the page
content seems to jump from left to right when navigating between
some pages, or expanding content on a page. This happens because
some pages are taller than other, causing the vertical scrollbar be
present only in some cases. Because the vertical scrollbar takes
some space on the page, the centered layout is shifted a few
pixels. The screenshots below illustrate this issue. The top one is
from a page with no scrollbar. The bottom one is from the same site
but has a scrollbar. Notice that, although the content is centered
on both pages, the bottom content is shifted to the left relative
to the top content.


I don't like this behavior and will show a method for fixing
it.
After some research, I found that the usual fix is to ensure
that the vertical scrollbar is always visible. This is done using
the overflow-y css property. While this prevents the jumping
content, the downside is that the vertical scrollbar is always
visible, even when there is no content to scroll to. I think we can
do better.
My approach is to use javascript to reposition the content of
the page while taking into account the visibility of the scrollbar.
For that, we need to know if the scrollbar is visible and its
width. If it is visible, we can adjust the position of the content.
Note: I am using jQuery, but it is easy to convert the code to pure
javascript if needed.
There is no direct way of knowing the size of the scrollbar and
whether it is visible. The trick is to disable the scrollbar using
overflow:hidden, measure the width of the body element, re-enable
the scrollbar using overflow:auto and measure the width of the body
element again. The difference between the measured widths is the
width of the scrollbar. If the difference is zero, then the
scrollbar is not visible at that moment.
// This script fixes the shift that occurs in a centered layout when the page grows and forces scrollbars to appear.
$(function () {
var body = $("body");
var previousWidth = null;
// Function that applies padding to the body to adjust its position.
var resizeBody = function () {
var currentWidth = body.width();
if (currentWidth != previousWidth) {
previousWidth = currentWidth;
// Measure the scrollbar size
body.css("overflow", "hidden");
var scrollBarWidth = body.width() - currentWidth;
body.css("overflow", "auto");
body.css("margin-left", scrollBarWidth + "px");
}
};
// setInterval is required because the resize event is not fired when a scrollbar appears or disappears.
setInterval(resizeBody, 100);
resizeBody();
});