|
home / bulletins / 9 / page 5
dir="rtl" Implementation Notes
As we worked through the various HM behavior problems that we saw
in pages where directionality was set specifically to rtl, we discovered a number
of cross-browser JavaScript/DOM quirks that may be of interest to all DHTML developers.
Those quirks are the subject of the next two pages, and we'll divide 'em up by major
browsers.
dir="rtl" in Internet Explorer
By far, the greater number of dir landmines sent our
way was presented in Internet Explorer for Windows, version 5.0 or later (IE5 Mac
doesn't seem to support rtl mode documents at all; nor does IE4 or earlier
on Windows platforms). Some of the problems we encoutered in this particular browser
were the result of coding assumptions on our part that probably shouldn't have
happened, while others were the result of some unique positioning behaviors on
the part of Internet Explorer.
x positioning not based on left of canvas
The biggest Internet Explorer difference in a page where
directionality is set to rtl is that the x/y positioning of the page
is altered so that position (0,0) is not the top left corner of the
browser canvas. Instead, (0,0) is the top left corner of the
browser window, when the browser window is fully scrolled to the
right (or there is no horizontal scrollbar for the page). In other
words, a left pixel position of 0 is located at a distance of
clientWidth less than the right edge
of the browser document.
This is not an easy point to visualize, so let's see if a simple graphic
will help:

In the above graphic, we've opened an HTML document that renders wider than
the width of our current browser window. In this scenario, with dir="rtl"
in effect, Internet Explorer's default behavior is to move the vertical scroll
bar to the left of the page, and then immediately "scroll" the page all the way
to the right when initially displaying it. The net effect, then, is that the
initial browser window is displayed with pixel position 0 in the top left corner
of the screen, and in order to see the remaining portion of the document (to
the left of the browser window), you must use the horizontal scrollbar.
Note that when the page is scrolled to the left, the left pixel positions
become negative. Or, in other words, objects can be positioned in the area to
the left of the initial browser window by setting negative left positions. However,
if the browser window is resized, then position 0,0 is altered as described
above--so that it's always positioned at:
(the right edge of the document) -
(the width of the browser window)
This latter point is important. If you need to know
what the offset between the left edge of the document and the actual pixel position
0 is (we'll revisit this in a moment), you'll need to refresh your calculation
each time the window is resized (or simply retrieve it dynamically every time).
Finally, note that this pixel positioning logic only applies when the document
itself is wider than than the browser window. When the browser window is equal
to or wider than the document, (i.e., when there is no need for horizontal
scrolling) then pixel positioning on the document behaves as you would expect
it to.
All this is well and good; but doesn't effect HierMenus directly, since all
of our absolute pixel positions for permanently displayed menus are specified
as simple x/y positions. And since the page content itself is right-aligned
when dir="rtl", having the pixel positions be based on the right edge
of the document allows the objects to appear within the user's default browser
window--where they would expect them to appear. But understanding this
scheme will help you understand the following points:
scrollLeft doesn't match pixel layout of page
In conjunction with the above, you might expect that the
canvas's scrollLeft property (the property used by Internet Explorer to
note the offset of the horizontal scrollbar) would initially be 0, to match
the 0,0 pixel position of the left side of the window; and as you scroll
the page to the left, scrollLeft would take on negative numbers.
And, in fact, this is the behavior in IE 5.0.
In IE 5.5+, scrollLeft is never a negative number,
and is initially set to whatever the distance is between the left
edge of the canvas and the left edge of the browser window. As you scroll
the page to the left, scrollLeft is gradually decremented until
it reaches 0, the left edge of the document. We suspect Microsoft made this
change between 5.0 and 5.5 to honor their documented scrollLeft
behavior, which explicitly states that scrollLeft cannot be a
negative number. In fact, specifically setting scrollLeft to a
negative number results in it being automatically set to 0, a behavior
that occurs in IE 5.0 as well (in IE 5.0, scrollLeft can have
a negative number as the result of horizontal scrolling, but you cannot
assign it a negative number). Microsoft's documentation for the
scrollLeft parameter can be found
here.
Perhaps the most common use of scrollLeft--and the use that is problematic
for us in HierMenus--is to add it to the position of the mouse to arrive at
a true x position for the mouse on the document, regardless of where the
page is scrolled (in IE, the event.clientX property represents the
position of the mouse in the window, not necessarily the x position of the mouse
in relationship to the document). To determine what the mouse position is in
Internet Explorer as it relates to the document, we might use this
calculation:
var mouse_x_position =
document.documentElement.scrollLeft + event.clientX;
When dir="rtl" is used in IE5.5+ this calculation won't work; since
scrollLeft is not necessarily in sync with the left x position of the
document. Therefore, when these two conditions (IE5.5+ and dir="rtl")
are true, we must subtract the horizontal offset--the distance between the
left edge of the document and the left edge of the browser window--from the
scrollLeft property to arrive at the position of the mouse as it
relates to the actual document itself. Translated into HM code, our
(abbreviated) adjustment looks like this:
var mouse_x_position =
HM_Canvas.scrollLeft + event.clientX;
if (HM_IE&&!HM_IE50W&&HM_f_RTLCheck())
mouse_x_position-=
(HM_Canvas.scrollWidth-HM_Canvas.clientWidth);
where HM_IE50W is a new sniffing variable we set up to tell us
if the browser in question is IE5.0 Windows and HM_f_RTLCheck is
a new function that tells us if the browser document is currently
rendering in rtl mode:
// 5.3
function HM_f_RTLCheck() {
if(HM_IE5M) return false;
var TempElement=HM_MenusTarget.document.body;
while(!TempElement.dir&&TempElement.parentNode)
TempElement=TempElement.parentNode;
return ((typeof(TempElement.dir)=="string")&&
(/^rtl$/i.test(TempElement.dir)))
? true : false;
}
Note that simply referring to the offsetLeft property of the canvas will
not be valid, since it is always zero (it is the outermost container and therefore
its left pixel offset should be zero). And using the document.body.offsetLeft
property directly would only be valid in pages where IE is running in standards
mode.
Initial positioning of menus
When initially creating menus, we've always positioned them offscreen
(way offscreen) so as to avoid a quirk in Internet Explorer where the initial
horizontal/vertical scrollbars are expanded unnecessarily to make room for the menus
(which are initially hidden and can't be seen anyways). Browsers do not expand their
documents upwards or to the left of the initial browser window to accommodate these
offscreen menus, making it an effective workaround.
When dir="rtl" in Internet Explorer, the positions
to the left of the initial browser window (as described above), are actually negative
pixel positions and therefore the browser will expand the canvas to accommodate them.
This is not what we want, since the width of the document is then initially set to
be much wider than it should. Therefore, when rtl mode is in effect, we'll
create the menus at pixel position 0, instead of a left pixel position.
HM scrollParent and scrollbar inconsistencies
The automatic right-alignment of elements when in rtl mode
in Internet Explorer caused some confusion with our internal elements, especially the
scrollParent element and the individual scrollbars of scrolling menus.
Specifically, in the past we've created these elements without an explicit left pixel
position, assuming it would be 0 in all cases. Not true in Internet Explorer, where
we found that both the scrollParent and scrollbars tended to drift slightly
to the right or left of 0, causing some strange menu displays. To correct the problem
we simply removed our original assumption and explicitly set the initial left pixel
position of the newly created elements to 0px.
Similarly, with horizontal menus we never bothered to specifically
adjust the width of scrollParent elements when we changed the
width of the horizontal menus themselves. This resulted in horizontal menus where the
menu border appeared in the proper dimensions, but the menu content--i.e., the
individual menu items--were positioned as if the first menu item was in the rightmost
slot of the menu. A picture's worth a thousand words:

In HM 5.3, we correct this bug by ensuring that the scrollParent
width is always set when its corresponding menu's width is set. This HM bug affected all
rtl capable browsers, not just Internet Explorer.
On page 6 we continue discussing rtl mode
issues.
      
[previous] [next]
|