Element Positions



The CSS position property specifies the positioning method used for an element. The default value of most elements is static, which renders elements in order in the document flow. Other allowed values include relative, absolute, fixed, and inherit.

The position of an element is determined by its top/left or bottom/right properties. The top property is the vertical distance from the origin; the positive direction is downward. The left property is the horizontal distance from the origin; the positive direction is rightward. The bottom property is the vertical distance from the origin; the positive direction is upward. The right property is the horizontal distance from the origin; the positive direction is leftward.

An element with position: absolute is placed relative to the first parent element with a position setting other than static. Absolutely positioned elements can stack together. The z-index property is used to define the stack order. An element with a greater z-index will stack on top of an element with a lower z-index. The default z-index is the element's defined order in the document; the lately-defined element has a greater z-index.

The following example uses position: absolute with the top, left, and z-index properties. Clicking anywhere in the document can change the position of the "message 1" element. Clicking one of the div elements can increase its z-index.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type">
        <style type="text/css">
            #message1 {
                color: #ffffff;
                background-color: #ff0000;
                border-width: 10px;
                border-color: black;
                border-style: solid;
                width: 100px;
                height: 50px;
                padding: 50px;
                margin: 10px;
                position: absolute;
                top: 50px;
                left: 50px;
                z-index: 0;                
            }
            #message2 {
                color: #ffffff;
                background-color: #ff0000;
                border-width: 10px;
                border-color: black;
                border-style: solid;
                width: 100px;
                height: 50px;
                padding: 50px;
                margin: 10px;
                position: absolute;
                top: 150px;
                left: 150px;
                z-index: 0;                
            }
        </style>
        <script type="text/javascript">
            window.onload = function(event) {
                var message1 = document.getElementById('message1');
                var message2 = document.getElementById('message2');
                
                document.onclick = function(event) {
                    event = event || window.event;
                    message1.style.left = event.clientX + 'px';
                    message1.style.top = event.clientY + 'px';
                };
                
                function stopPropagation(event) {
                    if(event) {
                        event.stopPropagation();
                    }
                    else {
                        window.event.cancelBubble = true;
                    }
                }
                
                message1.onclick = function(event) {
                    this.style.zIndex = 1;
                    message2.style.zIndex = 0;
                    stopPropagation(event);
                };
                
                message2.onclick = function(event) {
                    this.style.zIndex = 1;
                    message1.style.zIndex = 0;
                    stopPropagation(event);
                };
            };
        </script>        
    </head>
    <body>
        <div id="message1">message 1</div>
        <div id="message2">message 2</div>
    </body>
</html>

An element with position: relative is placed relative to its normal position. The relative position is defined using top/left or bottom/right. For example, if an element's normal position is 100px * 50px and its position is relative, setting top: 20px and left: 30px will position the element in (100 + 20) * (50 + 30) = 120px * 80px.

A fixed positioned element is placed relative to the browser view-port. For example, if you want to keep an element positioned in 100px * 50px of the view-port after scrolling the document, you can set position: fixed. Then, the top/left or bottom/right settings are relative to the view-port. Internet Explorer 6 browser doesn't support the fixed value; Internet Explorer 7 and 8 support this setting only if a <!DOCTYPE> is specified.

To get the exact position of an element, we should figure out the element's offsetParent. The offsetParent isn't the direct parent of an element; it returns the first positioned parent element in the DOM hierarchy.

Every element has the offsetTop and offsetLeft properties. They represent the distances from the upper left corner of the offsetParent element's outer border. The following example demonstrates how to calculate the exact position of an element in the simple layout.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type">
        <style type="text/css">
            #container {
                color: #ffffff;
                background-color: #ff0000;
                border-width: 10px;
                border-color: black;
                border-style: solid;
                width: 100px;
                height: 50px;
                padding: 50px;
                position: absolute;
                top: 50px;
                left: 50px;
            }
            #message {
                position: static;
                top: 20px;
                left: 20px;
            }
        </style>
        <script type="text/javascript">
            window.onload = function(event) {
                function offset(element) {
                    var x = 0;
                    var y = 0;
                    while(element) {
                        x += element.offsetLeft;
                        y += element.offsetTop;
                        element = element.offsetParent;
                    }
                    return { 
                        x: x, 
                        y: y, 
                        toString: function() {
                            return '(' + this.x + ', ' + this.y + ')';
                        }
                    };
                }
                
                document.onclick = function(event) {
                    event = event || window.event;
                    var container = document.getElementById('container');
                    container.style.left = event.clientX + 'px';
                    container.style.top = event.clientY + 'px';
                    var message = document.getElementById('message');
                    var console = document.getElementById('console');
                    console.innerHTML = offset(message);
                };                
            };
        </script>        
    </head>
    <body>
        <div id="container"><span id="message">This is a message<span></div>
        <span id="console"></span>
    </body>
</html>

One example which requires the exact position of an element is the search box suggestions. You need to know the search box's position, and then show the suggested keywords below the search box. The following example is a simple demonstration:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN">
<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type">
        <style type="text/css">
            #container {
                color: #ffffff;
                background-color: #ff0000;
                height: 50px;
                position: absolute;
                top: -100px;
                left:-100px;
            }
        </style>
        <script type="text/javascript">
            window.onload = function(event) {
                function offset(element) {
                    var x = 0;
                    var y = 0;
                    while(element) {
                        x += element.offsetLeft;
                        y += element.offsetTop;
                        element = element.offsetParent;
                    }
                    return { 
                        x: x, 
                        y: y, 
                        toString: function() {
                            return '(' + this.x + ', ' + this.y + ')';
                        }
                    };
                }
                var input = document.getElementById('search');
                var search = offset(input);
                var container = document.getElementById('container');
                container.style.left = search.x + 'px';
                container.style.top = search.y + input.offsetHeight + 'px';
                container.style.width = input.offsetWidth + 'px';
            };
        </script>        
    </head>
    <body>
        <div id="container">This is a message</div>
        <hr>
        Search: <input id="search" type="text">
    </body>
</html>

Unfortunately, the offsetParent property has the problem of browser compatibility. In Firefox, the offsetParent property of an absolute or fixed positioned element returns the body element. The offsetParent property of a static or relative positioned element returns the first positioned parent element. But, the offsetParent property of a relative positioned element returns different elements in different versions of Internet Explorer.

Besides, getting the exact position of an element will becomes more complex in a more complex layout. For example, the CSS overflow property may set a scroll bar, but the offset amount doesn't consider the scroll bar position. If you set the CSS overflow property, you should take the scroll bar into consideration. For example:
function offset(element) {
    var x = 0;
    var y = 0;
    for(var e = element; e; e = e.offsetParent) {
        x += e.offsetLeft;
        y += e.offsetTop;
    }

    // consider a scroll bar's offset
    for(var e = element.parentNode; e && e != document.body; e = e.parentNode) {
        if(e.scrollLeft) {
            x -= e.scrollLeft;
        }
        if(e.scrollTop) {
            y -= e.scrollTop;
        }
    }

    return {
        x: x,
        y: y,
        toString: function() {
            return '(' + this.x + ', ' + this.y + ')';
        }
    };
}