It is possible to position elements with JavaScript. A simple example of such positioning is a tooltip which follows mouse.
This section describes how to get/calculate coordinates of elements and their position.
Prerequisite: CSS box model
The CSS box model is painted below:

It is described in the CSS Box model specification.
Knowing it’s components is a preliminary knowledge to going any further.
Example document
The example document is at tutorial/browser/dom/metric.html.
Before you continue reading, it would be a good idea to open it.
We’ll use the following box in demonstrations:
<div id="example"> ## Introduction The contents. </div>
The box is positioned absolutely, has borders, paddings, margins, and so scrollbar:
#example {
position: absolute;
width: 300px;
height: 200px;
left: 160px;
top: 160px;
padding: 20px;
margin: 20px;
overflow: auto;
border: 25px solid #F0E68C;
}
The CSS picture:

Box metrics
- CSS
width/height - Size of the content area, which lies inside the padding. CSS properties can be set using
element.styleproperty and retrieved usinggetComputedStyle()/currentStyle. Read more in the article Styles and classes, getComputedStyle.
Next we’ll learn more about other times of width and height available in JavaScript.
All JavaScript metrics are in pixels and don’t have 'px' at the end.
clientWidth/HeightscrollWidth/Height-
Content area width and height including the scrolled out part.
scrollHeight = 723- full height with scrollable areascrollWidth = 324- full width with scrollable area
scrollWidth/Heightis same asclientWidth/Height, but includes full scrollable area.The following code changes the vertical size of an
elementto show all contents:
element.style.height = element.scrollHeight+'px'
scrollTop/scrollLeft- Size of scrolled out part: vertical and horizontal. The value is always in pixels.
The picture below illustrates
scrollHeightandscrollTopfor a vertically scrollable box.
scrollLeft/scrollTop are writeableUnlike other properties, which are read-only, you can change
scrollLeft/scrollTop, and the browser scrolls the element.In standards mode, the scroll of the document is in
document.documentElement. The following code scrolls the document 10px down: offsetWidth/Height- Outer box width/height, full size with borders, but without margins.
offsetWidth = 390- outer box widthoffsetHeight = 290- outer box height
This is how the box looks from outside.
clientTop/Left- The indent of client area from box outer corner.
In other words, the width of top/left border in pixels.
clientLeft = 25- left border widthclientTop = 25- top border width

There are two exceptions to the general border-width meaning:
-
In case of a right-to-left document (arabic, hebrew), the
clientLeftproperty also includes the width of a right scrollbar. - In IE<8 and IE8 compat. mode:
document.documentElement(ordocument.bodyif in quirksmode) is shifted a bit from left-upper corner of the document. There is no border, butdocument.body.clientLeft/clientTopis not zero (usually 2) in this case.
offsetParent,offsetLeft/Top- Properties
offsetLeftandoffsetTopreflect a relative shift of an element from itsoffsetParent.The
offsetParentis the parent element in the sense of layout. For example, if an element is positioned absolutely, theoffsetParentis not it’s DOM parent, but a nearest positioned element (orBODY).The full rule for
offsetParent:- For static positioning - the nearest table cell or
BODY(in standards mode). - For other types of positioning - a closest positioned element.

- For static positioning - the nearest table cell or
Size of the client area: content area with paddings, but without scrollbars.

The sizes can be calculated as:
clientWidth = 300(width) + 40(paddings) - 16(scrollbar) = 324 clientHeight = 200(height) + 40(paddings) = 240
If there is no padding, and the box is scrollable, clientWidth/Height show the real content area size:

On the picture above, CSS width is with the scrollbar. You can’t actually insert something of 300px in the box. The real available width is clientWidth.
JavaScript coordinates and sizes are set for attached and displayed elements only.
They equal 0 for elements with display:none or out of DOM. The offsetParent is also null for such elements.
We could use this to check if an elem is hidden:
function isHidden(elem) return !elem.offsetWidth && !elem.offsetHeight }
- Works even if parent element has
display:none. - Works for all elements except
TR, on which it bugs in some browsers. But usually we check other elements thanTR, so it’s ok. - Doesn’t work if the element has
visibility:hiddenor is positioned off-screen. Empty elements will also be hidden.
Practice
There was a green-bordered div in the text:
A programmer John of your team wrote the code to shift the div to right-top with position: absolute:
var div = document.getElementById('moving-div')
div.style.position = 'absolute'
div.style.right = div.style.top = 0
Naturally, the text after DIV shifted up:
Enhance the code, make the text keep it’s place even after the DIV is shifted.
Hint: Create a helper DIV with the same size as the green-bordered DIV and insert it in the document. This is called making a placeholder.
Should be like this (placeholder got background for demo purposes):
The source document: tutorial/browser/dom/replaceDiv/2.html.
P.S… Do it without any additional CSS.
What we need is to create a div with same height and insert it instead of the moving one.
var div = document.getElementById('moving-div')
var placeHolder = document.createElement('div')
placeHolder.style.height = div.offsetHeight + 'px'
offsetHeightis outer box height includig borders, but margins are not counted.'px'is required for CSS property.
But we’re not done yet. The placeHolder doesn’t have a margin, so the text will shift.
Let’s use JavaScript to copy the margin:
var div = document.getElementById('moving-div')
var placeHolder = document.createElement('div')
placeHolder.style.height = div.offsetHeight + 'px'
// IE || other browser
var computedStyle = div.currentStyle || getComputedStyle(div, null)
placeHolder.style.marginTop = computedStyle.marginTop // full prop name
placeHolder.style.marginBottom = computedStyle.marginBottom
Full property name marginTop is used. It guarantees that for any combination of margin-top, margin-bottom, margin, the computed value is correct.
The final result (see SCRIPT):
<!DOCTYPE HTML>
<html>
<head>
<style>
#moving-div {
border: 5px groove green;
padding: 5px;
margin: 10px;
background-color: yellow;
}
</style>
</head>
<body>
Before Before Before
<div id="moving-div">
Text Text Text<br>
Text Text Text<br>
</div>
After After After
<script>
var div = document.getElementById('moving-div')
var placeHolder = document.createElement('div')
placeHolder.style.height = div.offsetHeight + 'px'
var computedStyle = div.currentStyle || getComputedStyle(div, null)
placeHolder.style.marginTop = computedStyle.marginTop // full prop name
placeHolder.style.marginBottom = computedStyle.marginBottom
// highlight it for demo purposes
placeHolder.style.backgroundColor = '#C0C0C0'
document.body.insertBefore(placeHolder, div)
div.style.position = 'absolute'
div.style.right = div.style.top = 0
</script>
</body>
</html>
Place a ball in the center of the field.
Source:
Use JavaScript to place the ball in the center:
The source document: tutorial/browser/dom/ball-source/index.html.
The field has no padding. So, it’s width and height are clientWidth/Height.
The center is (clientWidth/2, clientHeight/2).
If we set ball.style.left/top of the ball to the center, then the left-upper corner of the ball will be at the center, not the ball itself:
var ball = document.getElementById('ball')
var field = document.getElementById('field')
ball.style.left = Math.round(field.clientWidth / 2)+'px'
ball.style.top = Math.round(field.clientHeight / 2)+'px'
To align the center of the ball against the field center, we need to shift the ball. Half of it’s width left, half of it’s height up.
var ball = document.getElementById('ball')
var field = document.getElementById('field')
ball.style.left = Math.round(field.clientWidth/2 - ball.offsetWidth/2)+'px'
ball.style.top = Math.round(field.clientHeight/2 - ball.offsetHeight/2)+'px'
Unfortunately, there will be a bug, because IMG has no width/height:
<img src="ball.gif" id="ball">
Width/height of an image is unknown to the browser until it loads, if not set explicitly. So, we’ll have ball.offsetWidth = 0.
A reasonable fix is to provide width/height:
<img src="ball.gif" width="40" height="40" id="ball">
Now we’re done.
Full solution code: tutorial/browser/dom/ball/index.html
P.S. Using offsetHeight/offsetWidth instead of clientHeight/clientWidth would be wrong, because positioning takes place inside the borders.
Summary
There are following properties:
clientWidth/clientHeight- width/height of the visible in-border area (can be called a client area.
The client area includes padding and doesn’t include scrollbars.clientLeft/clientTop- left/top border width or, more generally, a shift of the client area from the top-left corner of the box.
Also used in IE, becausedocument.bodymay be shifted there.scrollWidth/scrollHeight- width/height of the scrollable in-border area. Includes padding. Doesn’t include scrollbars.scrollLeft/scrollTop- the width/height of the scrolled out part of the document, starting from the top-left corner.offsetWidth/offsetHeight- the “outer” width/height of the box as seen from outside, excluding margins.offsetParent- the nearest table-cell, body for static positioning or the nearest positioned element for other positioning types.offsetLeft/offsetTop- the position in pixels of top-left corner of the box related to it’soffsetParent.
The summarizing picture for all properties except scrolls:
