avatar

Derek Zeng

A programmer

Solving cross browser scrolling issue

by coderek

An interesting task I was assigned recently was to fix the app in RTL mode.

Our app is an react app built using webpack. When it's working in the RTL mode, the react app will be under <body dir='rtl'>. When coding the styles, I need to take that into consideration.

The first approach I did was to apply override when it's in [dir=rtl]. This incurs least change to our project. Since we are using scss, I just need to put every overriding styles under [dir=rtl]. What are the things I need to change? Followings are some examples:

  • margin left/right if they are not equal; same for paddings
  • text-align/vertical-align
  • float
  • left/right for positioned elements

I need to change the value that is left oriented to right oriented, vice versa. Moreover, I have to revert the original to default style. One such example is:

div.cell {
    border: 1px solid black;

    &:last-child {
        border-right: none;
    }
}

// when overriding I have to do two things
body[dir=rtl] {
    div.cell:last-child {
        border-right: 1px solid black;
        border-left: none;
    }
}

Obviously it's tedious and time-consuming to change. I figured I must not be the first who had this problem. There should be a 'rtl css' library that generate this things for you.

Like I said, rtlcss shows up as the first entry in the google search. I have to put it into webpack's postcss plugin that we are using. It turns out even better; people have already built this postcss plugin.

Now I only need to make sure the body has [dir=ltr] when it's in normal mode, and [dir=rtl] when it's in right to left mode. Otherwise, everything works like a charm!

Ok, not exactly everything. Those things that has styles hardcoded into scripts will not benefit from the generated css. Also things related to scrolling.

Scrolling is problematic because browsers have different implementations on how to interpres scrollleft when it's in the [dir=rtl] mode.

So scrolling has cross browser issues. Just like the f**king IE. I found out the issues by building a simplest scrolling example and run it in all the browsers.

<!DOCTYPE html>
<html>
<head>
  <title>JS Bin</title>
  <style>
    .container {
      width: 400px;
      overflow-x: hidden;
      border: 1px solid black;
    }
  </style>
</head>
<body dir=rtl>
  <div class="container">
    <table>
      <tr>
        <td>11111111111111</td>
        <td>22222222222222</td>
        <td>33333333333333</td>
        <td>44444444444444</td>
        <td>55555555555555</td>
      </tr>
    </table>
  </div>
  <script>
    let container = document.querySelector('.container');
    container.scrollLeft = 100;
  </script>
</body>
</html>

I've found that in chrome: the scrollLeft behaves the same way as it's in non rtl mode. The scrollLeft still account for the distance that the origin x of the content is on the left side of the container.

In IE, it's different. The scrollLeft is like inverted like its content. That means, I do not need to change the value of scrollLeft in rtl mode. This is pretty good.

In Firefox, it's almost like in IE while you have to put a negative sign to the value in rtl mode. This is exactly like it's stated on mozilla website:

Note that if the element's direction of the element is rtl (right-to-left) then scrollLeft is 0 when the scrollbar is at its rightmost position (at start of the scrolled content) and then increasingly negative as you scroll towards the end of the content.

The bottom of the page shows that Chrome is the only known compliant browser however, in my test is not true.

It's interesting to note that how little the browser vendors care about the standards in the a11y world. I'm pretty sure I can find many more such things.

So to solve my problem. I use an abstract value called scrollAmount to denote the scrolling. It's a positive value between 0 and max scrollable amount. Only when it's time to set element.scrollLeft I derive the scrollLeft from scrollAmount by looking at the browser type.

This way, I can assume browser consistency in all other places.

(End of article)