The Curious Case of the Giant Scrollbar

Recently I fixed bug 439269 (“AMO theme has unnecessary scrollbar at the bottom”) and thought it was an interesting bug for a few reasons.

To summarize the issue, for no apparent reason in right-to-left languages a really long scrollbar would appear at the bottom of the window.

Screenshot of scrollbar

Even though there was a scrollbar, when you scrolled all the way to the left, nothing was there. Another reason this was odd was the scrollbar only appeared in right-to-left (RTL) languages. Inspecting the page via Firebug didn’t give any clues as to what was causing the issue as there was no element hidden somewhere onscreen. Finally, to make things even weirder, the scrollbar only appeared when JavaScript was turned on.

After some thought, I had a feeling that we might be using absolute positioning to position an element to the left and above the page offscreen, which is quite common. In a RTL page, however, left is does not move an element outside a page’s boundaries. So the result is you get a scrollbar.

So what’s a web developer to do? Firebug to the rescue! I popped it open and started typing some JavaScript into the console to find an element that seemed really far offscreen:

var nodes = document.getElementsByTagName("*");

for(var i=0; i < nodes.length;i++) {
    var node = nodes[i];
    if(node.offsetLeft < -500) {
        console.log(node);
    }
}

And Firebug’s console spit out:

<ul id="cat-list">

Ah-ha! Now I was getting somewhere. A quick search through our CSS files for ‘#cat-list’ found an interesting line of code:

#categories.collapsed #cat-list {
    position: absolute;
    left: -999em;
    top: -999em;
}

And when JavaScript is turned on, the class ‘collapsed’ is added to the parent node #categories. In RTL mode this creates a huge scrollbar because -999em to the left of the page is a valid location that a user can scroll to. The solution?

.html-rtl #categories.collapsed #cat-list {
    position: absolute;
    left: 999em;
    top: -999em;
}

On any pages that are RTL, we add the class ‘html-rtl’ to the body tag in order to change the layout for RTL languages. This fixes the issue by moving the category list offscreen to the right, which is outside the page in RTL mode.

Things to remember:

  • Firebug is your friend
  • The DOM is a live document you can inspect, utilize this feature
  • Be careful with positioning with sites that are LTR and RTL

9 responses

  1. Daniel Einspanjer wrote on :

    Why do you need to use an absolute offscreen position for that collapsed list of categories? It seems like a display:none would be easier?

  2. Simon wrote on :

    Out of curiosity, why use off-screen positioning to hide the element? Wouldn’t it be simpler to use visibility:hidden or display:none instead?

  3. Robin wrote on :

    Ah, interesting issue. Will have to bear that in mind should I do any RTL sites.

  4. Dan wrote on :

    Or since you’re already moving it off the top 999px, just have it left: 0px;

    Unless there exists a bottom to top language, then we have a problem. ;P

    I personally hide stuff with display: none; instead of moving it offscreen. Might be some reason whoever made that opted not to do it that way…

  5. Noel Grandin wrote on :

    Wouldn’t a position of
    { left: 0em; top:-999em; }
    move the element off-screen no-matter the language orientation?

  6. Neil Rashbrook wrote on :

    This only raises more questions… why move the element at all? If as I’m assuming it’s for perf reasons, why not just move the element off the top only?

  7. rdoherty wrote on :

    Good questions:

    @Daniel
    display:none; hides the content from screen readers, which is not a good experience because most screen readers do not detect the DOM changing, which it does when the list expands. So blind or visually impaired users would never ‘see’ the category list.

    @Simon:
    visibility:hidden; leaves elements in the document flow, so it could affect other element’s display even when hidden.

    @Dan & Noel
    top: -999em would get it offscreen, but there is a slight possibility that the element you are moving could have a width wide enough to cause a scrollbar. Especially if you are using a standard class of ‘.hidden’ for multiple elements.

  8. confiq wrote on :

    –edit–
    Hi rdoherty!
    As one that writes lot of RTL sites i found this bug frustrating.
    Unfortunately i put display: none if i don’t have access to external JS (ex. facebook connect) but most of cases i resolve as you did…
    Instead of left: 999em i write right: 999em;…

    regards

  9. Andrew Mason wrote on :

    I ran across the same issue when working on a localisation project. A simple fix is to use:

    overflow: hidden;

    …on the parent element to clip the child off.

    Bonus tip: The same trick of setting overflow: hidden; on the parent element prevents the focus dashed outline from stretching across the page when using image replacement technique with links.