Home>

1. Correctly understand offsetwidth, clientwidth, scrollwidth and corresponding height attributes

Assume that the horizontal and vertical scroll bars of an element are all dragged to the end.The corresponding ranges of properties such as offsetwidth, clientwidth, scrollwidth are shown in the following figure:

1) offsetwidth and offsettheight correspond to the width and height of the box model,These two values ​​are consistent with the dimensions we see when we use chrome to review elements:

2) scrollwidth, corresponding to scrollheight is the width and height of the scroll area, but does not include the width of the scroll bar! The scroll area consists of padding and content.

3) clientwidth and clientheight correspond to the width and height of the part of the box model after removing the border,Does not include the width of the scroll bar.

4) For any dom element, you can quickly get the offsetwidth, clientwidth, scrollwidh and related height attributes through the following APIs:

//dome is a dom html element object

dome.scrollwidth

dome.scrollheight

dome.clientwidth

dome.clientheight

dome.offsetwidth

dome.offsetheight

//dome is a dom html element object

dome.scrollwidth

dome.scrollheight

dome.clientwidth

dome.clientheight

dome.offsetwidth

dome.offsetheight

5) These attributes have almost no compatibility issues on modern browsers including pc and mobile,Can be used with confidence. If i want to know the detailed compatibility rules,You can refer to the following two articles:

w3c dom compatibility – css object model view

cssom view mode cssom-view-module related finishing and introduction

The following tests are performed on the above related attributes of ordinary HTML elements, HTML root elements and body elements.In order to verify the previous conclusions,Summarize some tips and tricks that can be used directly in the actual coding process.The reason to distinguish ordinary HTML elements, HTML root elements and body elements is because of the previous theory,There will be some weirdness in the html root element and the body element,Need to be handled with care.

Note:

1. To reduce space,Test posted code is not complete code,But does not affect learning references,In addition, the test results given in the article are obtained under chrome (version:45.0).In case of differences in test results,The test results of ie9, ie10, ie11, firefox (version:42.0) and opera (version:34.0) will also be given.No difference will be explained in the test results,Do not consider ie8 and below.

2. safari will not be tested due to equipment limitations.In addition it is the same as the chrome kernel,The reliability of standards support is not much worse.

3. Older versions of chrome, firefox, opera cannot be tested due to device limitations.However, considering the degree of browser support for standards,These three browsers started to be quite standard in w3c standards in very early versions.In addition, these browsers are updated faster.The mainstream versions of these browsers on the market are also relatively new.

4. Since ie8 and below are not considered, and html5 is now used for html5, the case of document.compatmode="backcompat" is not considered.But although the backcompat mode is derived from ie6 browsers,But for chrome, firefox, etc. document.compatmode="backcompat" also exists, such as this web page,You open it with chrome, and print document.compatmode in the console, you will find that its value is also backcompat (the reason is related to the use of html4.0 dtd on this page, if you change to html4.01 dtd will not be in chrome And firefox):

You can learn more about compatmode through the following resources:

Test 1. Verify the offsetwidth, clientwidth, scrollwidth and related height attributes of common html elements (non-body and html root elements):

<style type="text/css">
  html,  body {
    margin:0;
  }
  body {
    padding:100px;
  }
  .box {
    overflow:scroll;
    width:400px;
    height:300px;
    padding:20px;
    border:10px solid #000;
    margin:0 auto;
    box-sizing:content-box;
  }
  .box-2 {
    border:1px solid #000;
  }
</style>
<body>
  <div>
    <div>...</div>
  </div>
</body>
<script type="text/javascript">
var boxe=document.queryselectorall (". box") [0];
console.log ("scrollwidth:" + boxe.scrollwidth);
console.log ("scrollheight:" + boxe.scrollheight);
console.log ("clientwidth:" + boxe.clientwidth);
console.log ("clientheight:" + boxe.clientheight);
console.log ("offsetwidth:" + boxe.offsetwidth);
console.log ("offsetheight:" + boxe.offsetheight);
</script>
<styletype="text/css">
  html,  body {
    margin:0;
  }
  body {
    padding:100px;
  }
  .box {
    overflow:scroll;
    width:400px;
    height:300px;
    padding:20px;
    border:10px solid #000;
    margin:0 auto;
    box-sizing:content-box;
  }
  .box-2 {
    border:1px solid #000;
  }
</style>
<body>
  <divclass="box">
    <divclass="box-2">...</div>
  </div>
</body>
<scripttype="text/javascript">
var boxe=document.queryselectorall (". box") [0];
console.log ("scrollwidth:" + boxe.scrollwidth);
console.log ("scrollheight:" + boxe.scrollheight);
console.log ("clientwidth:" + boxe.clientwidth);
console.log ("clientheight:" + boxe.clientheight);
console.log ("offsetwidth:" + boxe.offsetwidth);
console.log ("offsetheight:" + boxe.offsetheight);
</script>

In this example,The box element has a width of 400 * 300, a padding of 20px and a border of 10px. The corresponding box model in chrome:

js execution results:

From the box model and js execution results:

1) The offsetwidth and offsettheight are exactly the same as the size seen by the chrome review element;

2) clientwidth and clientheight are equal to offsetwidth and offseteth minus the corresponding border (20px up and down, 20px left and right) and the value of the scroll bar width (the scroll bar width is 17px under chrome)

3) As the scrollwidth does not occur laterally,At the same time, due to overflow:scroll, scrollwidth is the same as clientwidth, but does not include the width of the scroll bar.This also validates the previously proposed conclusions;

4) For scrollheight, in this example,It is actually equal to the top and bottom padding (40px total) + the offseteth (1370px) of div.box-2, div.box-2:

5) There is also a css worth noting for the above tests.It is box-sizing. In the above code, box-sizing is set to content-box. If you change it to border-box, the result is similar.Because offsetwidth, clientwidth and scrollwidth will not change.

6) The results of other browsers are consistent with the conclusions of 1-5.

Test two, verify the offset client scroll width and height attributes of the html root element and the body element:

<style type="text/css">
  html,  body {
    margin:0;
  }
  body {
    border:10px solid #d4d2d2;
  }
  .box {
    overflow:scroll;
    width:400px;
    height:300px;
    padding:20px;
    border:10px solid #000;
    margin:0 auto;
    box-sizing:content-box;
  }
  .box-2 {
    border:1px solid #000;
  }
</style>
<body>
  <div>
    <div>...</div>
  </div>
  <div>
    <div>...</div>
  </div>
  <div>
    <div>...</div>
  </div>
  <div>
    <div>...</div>
  </div>
</body>
<script>
console.log ("doce.scrollwidth:" + document.documentelement.scrollwidth);
console.log ("scrollheight:" + document.documentelement.scrollheight);
console.log ("doce.clientwidth:" + document.documentelement.clientwidth);
console.log ("doce.clientheight:" + document.documentelement.clientheight);
console.log ("doce.offsetwidth:" + document.documentelement.offsetwidth);
console.log ("doce.offsetheight:" + document.documentelement.offsetheight);
console.log ("");
console.log ("body.scrollwidth:" + document.body.scrollwidth);
console.log ("body.scrollheight:" + document.body.scrollheight);
console.log ("body.clientwidth:" + document.body.clientwidth);
console.log ("body.clientheight:" + document.body.clientheight);
console.log ("body.offsetwidth:" + document.body.offsetwidth);
console.log ("body.offsetheight:" + document.body.offsetheight);
</script>
<styletype="text/css">
  html,  body {
    margin:0;
  }
  body {
    border:10px solid #d4d2d2;
  }
  .box {
    overflow:scroll;
    width:400px;
    height:300px;
    padding:20px;
    border:10px solid #000;
    margin:0 auto;
    box-sizing:content-box;
  }
  .box-2 {
    border:1px solid #000;
  }
</style>
<body>
  <divclass="box">
    <divclass="box-2">...</div>
  </div>
  <divclass="box">
    <divclass="box-2">...</div>
  </div>
  <divclass="box">
    <divclass="box-2">...</div>
  </div>
  <divclass="box">
    <divclass="box-2">...</div>
  </div>
</body>
<script>
console.log ("doce.scrollwidth:" + document.documentelement.scrollwidth);
console.log ("scrollheight:" + document.documentelement.scrollheight);
console.log ("doce.clientwidth:" + document.documentelement.clientwidth);
console.log ("doce.clientheight:" + document.documentelement.clientheight);
console.log ("doce.offsetwidth:" + document.documentelement.offsetwidth);
console.log ("doce.offsetheight:" + document.documentelement.offsetheight);
console.log ("");
console.log ("body.scrollwidth:" + document.body.scrollwidth);
console.log ("body.scrollheight:" + document.body.scrollheight);
console.log ("body.clientwidth:" + document.body.clientwidth);
console.log ("body.clientheight:" + document.body.clientheight);
console.log ("body.offsetwidth:" + document.body.offsetwidth);
console.log ("body.offsetheight:" + document.body.offsetheight);
</script>

In this example,There are 4 box elements in the next body (the total height is 360 * 4=1440px). The width of the body is adaptive.The body also has a border of 10px. The results are as follows:

From this result you can see:

1) Due to the 10px border of the body element,So clientwidth is 20px less than offsetwidth, which is consistent with the theory mentioned earlier.But it is incredible that the scrollwidth/scrollheight of the body is actually equal to its offsetwidth/offsetheight, and the scrollwidth/scrollheight is the width and height of the scroll area of ​​the element,Under the scope chart given earlier,The scrollwidth/scrollheight of the body should be less than its offsetwidth/offsetheight;

2) The scrollwidth and scrollheight of doce should be equal to the offsetwidth and offsetetheight of the body element. From the running result,This is consistent,But the clientwidth of doce turned out to be equal to its offsetwidth. According to the range chart,doce's clientwidth should be equal to offsetwidth minus the width of the scroll bar.

The results of other browsers are also significantly different from chrome:

ie11:

1) There is no problem with the body element under chrome under ie11

2) The HTML root element under ie11 also has a similar problem with chrome

ie10, ie9:

1) There is no problem with the body element under chrome under ie10,9

2) The root element of html under ie10, 9 does not have similar problems with chrome

firefox:Consistent with ie11.

opera:consistent with chrome running results,It may be because my version of opera uses the same webkit kernel as chrome.

It seems that ie9 and ie10 are the most normal,It's a bit difficult to understand,Searching the web for a long time,No relevant information was found to explain these differences, In the end, we can only take bold assumptions.Guess a few reasons that could explain these problems:

1) First, the overall scrolling of the web page,Unlike the scrolling of ordinary html elements,Ordinary html elements are themselves scrolling objects, But for web pages,The scroll object is not necessarily the HTML root or body element. Because when the body content is empty,The height of the body is 0, and the height of the html root element is also 0. If you add overflow:scroll css to html or body at this time, you will see that the scroll bar still appears on the right and bottom of the browser window.So for the overall scrolling of the web page,In theory, the scroll object should be a window, not an html element or a body element! But this is not the case.As far as the browsers tested:

For ie10 and ie9, the scroll object is the root HTML element, so the offset of their root HTML element will include the width of the scroll bar;

For other browsers,The scroll object is a window, so the offset of their html root element does not include the width of the scroll bar.

2) Second, when common elements scroll,Scrolling content=its content area + its padding area. When the web page is scrolled as a whole,The scrolling content should be the html root element! But this is not the case.As far as the browsers tested:

For ie9, ie10, ie11, firefox, their scroll area is the html root element, so the scrollwidth and scrollheight of their documentelement always represent the size of the entire scroll area of ​​the web page!

For chrome and opera, their scroll object is the body element, so the scrollwidth and scrollheight of their body always represent the size of the entire scrolling area of ​​the web page!

3) Third, the browser always describes documentelement.clientwidth and documentelement.clientheight as the size of the visible area of ​​the webpage without the scroll bar.It has nothing to do with the content of the web page!

These inferences are not unreasonable,Take the scroll object and scroll area:If i want to use js to scroll the page to a certain location,Without using window.scrollto,It must be handled with document.body.scrolltop=xxx, but setting document.documentelement.scrolltop is invalid, indicating that the overall scroll area of ​​chrome is determined by the scroll area of ​​the body;In ie11 and Firefox, if i want to use js to scroll the page to a certain position,Without using window.scrollto,It must be handled with document.documentelement.scrolltop=xxx. Setting document.body.scrolltop has no effect, indicating that the overall scrolling area of ​​ie11 and Firefox is determined by the scrolling area of ​​the HTML root element.

2. Use js to accurately get the size of the dom object

Common scenarios are:

1) Get the size of the visible area of ​​the entire web page,Excluding scroll bar

2) Get the size of the entire web page,Include invisible scroll area

3) Get the size of an ordinary html element

4) Determine whether the scroll bar appears on the element or web page

5) Calculate the width of the scroll bar

The following describes these five scenarios one by one.The following code does not consider ie8 and below, and does not consider html4. In addition, please pay attention to the setting of the viewport to ensure that the visual viewport and the layout viewport coincide on mobile devices.

1) How to get the size of the visible area of ​​the entire web page,Excluding scroll bar

document.documentelement.clientwidth;
document.documentelement.clientheight;
document.documentelement.clientwidth;
document.documentelement.clientheight;

2) How to get the size of the entire web page,Include invisible scroll area

function pagewidth () {
  var doc=document.documentelement,    body=document.body;
  if (doc.clientwidth == window.innerwidth) {
    return doc ["clientwidth"];
  }
  return math.max (
    body ["scrollwidth"], doc ["scrollwidth"],    body ["offsetwidth"], doc ["clientwidth"]
  );
}
function pageheight () {
  var doc=document.documentelement,    body=document.body;
  if (doc.clientheight == window.innerheight) {
    return doc ["clientheight"];
  }
  return math.max (
    body ["scrollheight"], doc ["scrollheight"],    body ["offsetheight"], doc ["clientheight"]
  );
}
function pagewidth () {
  var doc=document.documentelement,    body=document.body;
  if (doc.clientwidth == window.innerwidth) {
    return doc ["clientwidth"];
  }
  return math.max (
    body ["scrollwidth"], doc ["scrollwidth"],    body ["offsetwidth"], doc ["clientwidth"]
  );
}
function pageheight () {
  var doc=document.documentelement,    body=document.body;
  if (doc.clientheight == window.innerheight) {
    return doc ["clientheight"];
  }
  return math.max (
    body ["scrollheight"], doc ["scrollheight"],    body ["offsetheight"], doc ["clientheight"]
  );
}

The window.innerwidth and window.innerheight that appear above are used to obtain the width and height of the visible area of ​​the webpage including the scroll bar, respectively.This is also a good compatibility method,However, from the actual development situation,We need more viewable areas that do not include scrollbars,So it was not introduced separately before.In addition, there is a compatibility test about these two attributes in the ppk blog given earlier.Can understand.

3) How to get the size of an ordinary html element

Simple method:

doce.offsetwidth;
doce.offsetheight;
doce.offsetwidth;
doce.offsetheight;

Use getboundingclientrect:

var obj=doce.getboundingclientrect (),  elemwidth,  elemheight;
if (obj) {
  if (obj.width) {
    elemwidth=obj.width;
    elemheight=obj.height;
  } else {
    elemwidth=obj.right-obj.left;
    elemheight=obj.bottom-obj.top;
  }
} else {
  elemwidth=doce.offsetwidth;
  elemheight=doce.offsetheight;
}
var obj=doce.getboundingclientrect (),  elemwidth,  elemheight;
if (obj) {
  if (obj.width) {
    elemwidth=obj.width;
    elemheight=obj.height;
  } else {
    elemwidth=obj.right-obj.left;
    elemheight=obj.bottom-obj.top;
  }
} else {
  elemwidth=doce.offsetwidth;
  elemheight=doce.offsetheight;
}

getboundingclientrect will be introduced in detail in the next article along with other location-dependent dom attributes.

4) Determine whether the scroll bar appears on the element or web page

function scrollbarstate (elem) {
  var doce=document.documentelement,    body=document.body;
  if (! elem || elem === document || elem === doce || elem === body) {
    return {
      scrollbarx:doce.clientheight window.innerheight,      scrollbary:doce.clientwidth window.innerwidth
    }
  }
  if (typeof (element) == "function"&! (elem instanceof (element) ||! body.contains (elem))) {
    return {
      scrollbarx:false,      scrollbary:false
    };
  }
  var elemstyle=elem.style,    overflowstyle={
      hidden:elemstyle.overflow == "hidden",      hiddenx:elemstyle.overflowx == "hidden",      hiddeny:elemstyle.overflowy == "hidden",      scroll:elemstyle.overflow == "scroll",      scrollx:elemstyle.overflowx == "scroll",      scrolly:elemstyle.overflowy == "scroll"
    };
  return {
    scrollbarx:overflowstyle.scroll || overflowstyle.scrollx || (! overflowstyle.hidden&! overflowstyle.hiddenx&&elem.clientwidth elem.scrollwidth),    scrollbary:overflowstyle.scroll || overflowstyle.scrolly || (! overflowstyle.hidden&&! overflowstyle.hiddeny&&elem.clientheight elem.scrollheight)
  };
}
function scrollbarstate (elem) {
  var doce=document.documentelement,    body=document.body;
  if (! elem || elem === document || elem === doce || elem === body) {
    return {
      scrollbarx:doce.clientheight window.innerheight,      scrollbary:doce.clientwidth window.innerwidth
    }
  }
  if (typeof (element) == "function"&! (eleminstanceof (element) ||! body.contains (elem))) {
    return {
      scrollbarx:false,      scrollbary:false
    };
  }
  var elemstyle=elem.style,    overflowstyle={
      hidden:elemstyle.overflow == "hidden",      hiddenx:elemstyle.overflowx == "hidden",      hiddeny:elemstyle.overflowy == "hidden",      scroll:elemstyle.overflow == "scroll",      scrollx:elemstyle.overflowx == "scroll",      scrolly:elemstyle.overflowy == "scroll"
    };
  return {
    scrollbarx:overflowstyle.scroll || overflowstyle.scrollx || (! overflowstyle.hidden&! overflowstyle.hiddenx&&elem.clientwidth elem.scrollwidth),    scrollbary:overflowstyle.scroll || overflowstyle.scrolly || (! overflowstyle.hidden&&! overflowstyle.hiddeny&&elem.clientheight elem.scrollheight)
  };
}

When the overflow in the x or y direction is scroll, the scrollbarx in that direction is true, indicating that a scroll bar appears.

5) Calculate the width of the scroll bar

function scrollbarwidth () {
  var doce=document.documentelement,    body=document.body,    e=document.createelement ("div");
  e.style.csstext="position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll;";
  body.appendchild (e);
  var _scrollbarwidth=e.offsetwidth-e.clientwidth
  body.removechild (e);
  return _scrollbarwidth;
}
function scrollbarwidth () {
  var doce=document.documentelement,    body=document.body,    e=document.createelement ("div");
  e.style.csstext="position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll;";
  body.appendchild (e);
  var _scrollbarwidth=e.offsetwidth-e.clientwidth
  body.removechild (e);
  return _scrollbarwidth;
}
  • Previous Overview of desktop suspended memory app based on Android
  • Next How to draw a "Christmas tree" in C
  • Trends