13.6 Centering an Element on Top of Another Element

NN 6, IE 5

13.6.1 Problem

You want to position an element so that it is vertically and horizontally centered in front of an element in the main document flow.

13.6.2 Solution

The following centerOnElement( ) function takes two arguments: the ID of the main document element and ID of the positioned element to be placed there. The function is compatible with browsers that support W3C DOM element reference syntax:

function centerOnElement(baseElemID, posElemID) {
    baseElem = document.getElementById(baseElemID);
    posElem = document.getElementById(posElemID);
    var offsetTrail = baseElem;
    var offsetLeft = 0;
    var offsetTop = 0;
    // account for IE 6 CSS compatibility mode
    while (offsetTrail) {
        offsetLeft += offsetTrail.offsetLeft;
        offsetTop += offsetTrail.offsetTop;
        offsetTrail = offsetTrail.offsetParent;
    if (navigator.userAgent.indexOf("Mac") != -1 && 
        typeof document.body.leftMargin != "undefined") {
        offsetLeft += document.body.leftMargin;
        offsetTop += document.body.topMargin;
    posElem.style.left = offsetLeft + parseInt(baseElem.offsetWidth/2) - 
        parseInt(posElem.offsetWidth/2) + "px"
    posElem.style.top = offsetTop + parseInt(baseElem.offsetHeight/2) -
        parseInt(posElem.offsetHeight/2)+ "px"

13.6.3 Discussion

As simple as this operation may sound in theory, the code that accomplishes it must compensate for a variety of compatibility issues affecting various versions and compatibility modes of Internet Explorer. Another key point that makes this function generalizable is that it bases its measurements on the rendered dimensions of both the static and positioned elements. If the elements contain content that flows (such as text), the dimensions will likely differ with browser window size and, in some browsers, font preferences that aren't overridden by document style sheets. This function reads the rendered dimensions before calculating sizes and locations.

The first part of the calculations obtains the absolute position of the base element, wherever it may render in the document. This is an iterative process that accumulates the offsetLeft and offsetTop measures of the base element and any elements that report in as offset parent elements. For many browsers, the base element's offset measures are sufficient. But IE 6 for Windows in CSS-compatibility mode needs to add the offset parent's dimensions to get accurate coordinates. Looping through the offsetParent trail takes care of the problem.

Next is an adjustment for an anomaly that affects IE for the Mac. In that browser, the absolute location of an element in the main document is impacted by the left and top margins of the body element. Unfortunately, there is no guarantee that this adjustment will either work or be needed in future versions of IE for the Mac. Future versions may or may not correct this anomaly, making it too hazardous to branch for a specific numbered version of IE at this time. It's something to watch out for in future IE/Mac releases.

With the absolute location of the base element in hand, the final calculations establish the coordinates of the positioned element. To arrive at the value along any one axis, the inset dimension is calculated by subtracting half the size of the positioned element from half the size of the base element. Adding that difference to the absolute coordinate of the base element provides the absolute coordinate of the centered, positioned element.

You must also take into account the possibility that the user might resize the browser window in such a way that the flow of the base content changesalong with the position of the underlying element. Because there is no inherent connection between the elements (as there is with nested relative- and absolute-positioned elements, as in Recipe 13.2), you need to provide an onresize event handler for the window (typically embedded as an attribute of the <body> tag) that reinvokes the centering function. If multiple positioned elements are centered on multiple base elements, the onresize event handler can invoke a function that makes repeated calls to centerOnElement( ), each with the necessary pair of arguments.

Bear in mind that the offset properties used in the centerOnElement( ) function are not part of the W3C DOM. But nothing in DOM Level 2 provides the kind of vital information needed for this kind of operation (and many other positioning tasks). Although the properties were Microsoft inventions (first used in IE 4), Mozilla-based browsers also implement them. Thus, the function works perfectly well in Netscape 6 and later.

13.6.4 See Also

Recipe 11.13 for IE 6 CSS-compatibility issues and how to govern which mode the browser follows.