Chapter 5 - Element Node Geome

5.1 Element node size, offsets, and scrolling overview

DOM nodes are parsed and painted into visual shapes when viewing html documents in a web browser. Nodes, mostly element nodes, have a corresponding visual representation made viewable/visual by browsers. To inspect and in some cases manipulate the visual representation and gemometry of nodes programatically a set of API"s exists and are specified in the CSSOM View Module. A subset of methods and properties found in this specification provide an API to determine the geometry (i.e. size & position using offset) of element nodes as well as hooks for manipulating scrollable nodes and getting values of scrolled nodes. This chapter breaks down these methods and properties.

Notes

Most of the properties (excluding scrollLeft & scrollTop) from the CSSOM View Module specification are read only and calculated each time they are accessed. In other words, the values are live

5.2 Getting an elements offsetTop and offsetLeft values relative to theoffsetParent

Using the properties offsetTop and offsetLeft we can get the offset pixel value of an element node from theoffsetParent. These element node properties give us the distance in pixels from an elements outside top and left border to the inside top and left border of the offsetParent. The value of the offsetParent is determined by searching the nearest ancestor elements for an element that has a CSS position value not equal to static. If none are found then the <body> element or what some refer to as the "document" (as opposed to the browser viewport) is the offsetParent value. If during the ancestral search a <td><th>, or <table>  element with a CSS position value of static is found then this becomes the value of offsetParent.

Lets verify that offsetTop and offsetLeft provide the values one might expect. The properties offsetLeftand offsetTop in the code below tell us that the <div> with an id of red is 60px"s from the top and left of theoffsetParent (i.e. the <body> element in this example).

live code: http://jsfiddle.net/domenlightenment/dj5h9

<!DOCTYPE html>
<html lang="en">
<head>
<style>
body{margin:0;}
#blue{height:100px;width:100px;background-color:blue;border:10px solid gray; padding:25px;margin:25px;}#red{height:50px;width:50px;background-color:red;border:10px solid gray;}
</style>
</head>
<body>

<div id="blue"><div id="red"></div></div>

<script>

var div = document.querySelector("#red"); console.log(div.offsetLeft); //logs 60console.log(div.offsetTop); //logs 60
console.log(div.offsetParent); //logs <body>

</script>
</body>
</html>

Examine the following image showing what the code visually show in browser to help aid your understanding of how the offsetLeft and offsetTop values are deteremined. The red <div> shown in the image is exactly 60 pixels from the offsetParent.

Notice I am measuring from the outside border of the red <div> element to the inside border of theoffsetParent (i.e. <body>).

As previously mentioned If I was to change the blue <div> in the above code to have a position of absolute this would alter the value of the offsetParent. In the code below, absolutely positioning the blue <div> will cause the values returned from offsetLeft and offsetTop to report an offset (i.e. 25px"s). This is because the offset parent is now the blue <div> and not the <body> .

live code: http://jsfiddle.net/domenlightenment/ft2ZQ

<!DOCTYPE html>
<html lang="en">
<head>
<style>
#blue{height:100px;width:100px;background-color:blue;border:10px solid gray; padding:25px;margin:25px;position:absolute;}
#red{height:50px;width:50px;background-color:red;border:10px solid gray;}
</style>
</head>
<body>

<div id="blue"><div id="red"></div></div>

<script>

var div = document.querySelector("#red"); console.log(div.offsetLeft); //logs 25console.log(div.offsetTop); //logs 25
console.log(div.offsetParent); //logs <div id="blue">

</script>
</body>
</html>

The image of the browser view shown below clarifies the new measurements returned from offsetLeft andoffsetTop when the offsetParent is the blue <div>.

Notes

Many of the browsers break the outside border to inside border measurement when the offsetParent is the  <body> and the<body> or <html> element has a visible margin, padding, or border value.

The offsetParentoffsetTop, and offsetLeft are extensions to the HTMLelement object.

5.3 Getting an elements top, right, bottom and left border edge offset relative to the viewport using getBoundingClientRect()

Using the getBoundingClientRect() method we can get the position of an elements outside border edges as its painted in the browser viewport relative to the top and left edge of the viewport. This means the left and right edge are measured from the outside border edge of an element to the left edge of the viewport. And the top and bottom edges are measured from the outside border edge of an element to the top edge of the viewport.

In the code below I create a 50px X 50px <div> with a 10px border and 100px margin. To get the distance in pixels from each border edge of the <div> I call the getBoundingClientRect() method on the <div> which returns an object containing a toprightbottom, and left property.

live code: http://jsfiddle.net/domenlightenment/A3RN9

<!DOCTYPE html>
<html lang="en">
<head>
<style>
body{margin:0;}div{height:50px;width:50px;background-color:red;border:10px solid gray;margin:100px;}</style>
</head>
<body>

<div></div>

<script>

var divEdges = document.querySelector("div").getBoundingClientRect(); console.log(divEdges.top, divEdges.right, divEdges.bottom, divEdges.left); //logs "100 170 170 100"

</script>
</body>
</html>

The image below shows the browser rendered view of the above code with some added measurement indicators to show exactly how getBoudingClientRect() is calculated.

The top outside border edge of the <div> element is 100px from the top edge of the viewport. The right outside border edge of the element <div> is 170px from the left edge of the viewport. The bottom outside border edge of the element <div> is 170px from the top edge of the viewport. And the left outside border edge of the element<div> is 100px from the left edge of the viewport.

5.4 Getting an elements size (border + padding + content) in the viewport

The getBoundingClientRect() returns an object with a top, right, bottom, and left property/value but also with a height and width property/value. The height and width properties indicate the size of the element where the total size is derived by adding the content of the div, its padding, and borders together.

In the code below I get the size of the <div> element in the DOM using getBoundingClientRect().

live code: http://jsfiddle.net/domenlightenment/PuXmL

<!DOCTYPE html>
<html lang="en">
<head><style>div{height:25px;width:25px;background-color:red;border:25px solid gray;padding:25px;}</style></head><body><div></div><script>var div = document.querySelector("div").getBoundingClientRect(); 
console.log(div.height, div.width); //logs "125 125"
//because 25px border + 25px padding + 25 content + 25 padding + 25 border = 125</script></body>
</html>

The exact same size values can also be found using from the offsetHeight and offsetWidth properties. In the code below I leverage these properties to get the same exact height and width values provided bygetBoundingClientRect().

live code: http://jsfiddle.net/domenlightenment/MSzL3

<!DOCTYPE html>
<html lang="en">
<head><style>div{height:25px;width:25px;background-color:red;border:25px solid gray;padding:25px;}</style></head><body><div></div><script>var div = document.querySelector("div"); 
console.log(div.offsetHeight, div.offsetWidth); //logs "125 125"
//because 25px border + 25px padding + 25 content + 25 padding + 25 border = 125</script></body>
</html>

5.5 Getting an elements size (padding + content) in the viewport excluding borders

The clientWidth and clientHeight properties return a total size of an element by adding together the content of the element and its padding excluding the border sizes. In the code below I use these two properties to get the height and width of an element including padding but excluding borders.

live code: http://jsfiddle.net/domenlightenment/bSrSb

<!DOCTYPE html>
<html lang="en">
<head><style>div{height:25px;width:25px;background-color:red;border:25px solid gray;padding:25px;}</style></head><body><div></div><script>var div = document.querySelector("div"); 
console.log(div.clientHeight, div.clientWidth); //logs "75 75" because 25px padding + 25 content + 25 padding = 75</script></body>
</html>

5.6 Getting topmost element in viewport at a specific point usingelementFromPoint()

Using elementFromPoint() it"s possible to get a reference to the topmost element in an html document at a specific point in the document. In the code example below I simply ask what is the topmost element 50 pixels from the top and left of the viewport. Since we have two *"s at that location the topmost (or if there is no z-index set the last one in document order) div is selected and returned.

live code: http://jsfiddle.net/domenlightenment/8ksS5

<!DOCTYPE html>
<html lang="en">
<head><style>div{height:50px;width:50px;background-color:red;position:absolute;top:50px;left:50px;}</style></head><body><div id="bottom"></div><div id="top"></div><script>console.log(document.elementFromPoint(50,50)); //logs <div id="top"></script></body>
</html>

5.7 Getting the size of the element being scrolled using scrollHeightand scrollWidth

The scrollHeight and scrollWidth properties simply give you the height and width of the node being scrolled. For example, open any HTML document that scrolls in a web browser and access these properties on the <html>(e.g. document.documentElement.scrollWidth) or <body> (e.g. document.body.scrollWidth) and you will get the total size of the HTML document being scrolled. Since we can apply, using CSS (i.e overflow:scroll), to elements lets look at a simpler code example. In the code below I make a <div> scroll a <p> element that is 1000px"s x 1000px"s. Accessing the scrollHeight and scrollWidth properties on the <div> will tell us that the element being scroll is 1000px"s x 1000px"s.

live code: http://jsfiddle.net/domenlightenment/9sZtZ

<!DOCTYPE html>
<html lang="en">
<head><style>
*{margin:0;padding:0;}div{height:100px;width:100px; overflow:auto;}p{height:1000px;width:1000px;background-color:red;}</style></head><body><div><p></p></div><script>var div = document.querySelector("div"); console.log(div.scrollHeight, div.scrollWidth); //logs "1000 1000"</script></body>
</html>

Notes

If you need to know the height and width of the node inside a scrollable area when the node is smaller than the viewport of the scrollable area don"t use scrollHeight and scrollWidth as this will give you the size of the viewport. If the node being scrolled is smaller than the scroll area then use clientHeight and clientWidth to determine the size of the node contained in the scrollable area.

5.8 Getting & Setting pixels scrolled from the top and left usingscrollTop and scrollLeft

The scrollTop and scrollLeft properties are read-write properties that return the pixels to the left or top that are not currently viewable in the scrollable viewport due to scrolling. In the code below I setup a <div> that scrolls a <p> element.

live code: http://jsfiddle.net/domenlightenment/DqZYH

<!DOCTYPE html>
<html lang="en">
<head><style>div{height:100px;width:100px;overflow:auto;}p{height:1000px;width:1000px;background-color:red;}</style></head><body><div><p></p></div><script>var div = document.querySelector("div"); div.scrollTop = 750;div.scrollLeft = 750;console.log(div.scrollTop,div.scrollLeft); //logs "750 750" </script></body>
</html>

I programatically scroll the <div> by setting the scrollTop and scrollLeft to 750. Then I get the current value of scrollTop and scrollLeft, which of course since we just set the value to 750 will return a value of 750. The 750 reports the number of pixels scroll and indicates 750 px"s to the left and top are not viewable in the viewport. If it helps just think of these properties as the pixel measurements of the content that is not shown in the viewport to the left or top.

5.9 Scrolling an element into view using scrollIntoView()

By selecting a node contained inside a node that is scrollable we can tell the selected node to scroll into view using the scrollIntoView() method. In the code below I select the fifth <p> element contained in the scrolling<div> and call scrollIntoView() on it.

live code: http://jsfiddle.net/domenlightenment/SyeFZ

<!DOCTYPE html>
<html lang="en">
<head><style>div{height:30px;width:30px; overflow:auto;}p{background-color:red;}</style></head><body><div><content><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p>            </content>        </div><script>
//select <p>5</p> and scroll that element into view, I pass children "4" because its a zero index array-like structuredocument.querySelector("content").children[4].scrollIntoView(true);    </script></body>
</html>

By passing the scrollIntoView() method a parameter of true I am telling the method to scroll to the top of the element being scrolled too. The true parameter is however not needed as this is the default action performed by the method. If you want to scroll align to the bottom of the element pass a parameter of false to thescrollIntoView() method.

文章导航