ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript の位置とサイズ (1) size_javascript スキルに関連する DOM 属性の正しい理解と使用

JavaScript の位置とサイズ (1) size_javascript スキルに関連する DOM 属性の正しい理解と使用

WBOY
WBOYオリジナル
2016-05-16 15:23:141311ブラウズ

Web 開発では、要素のサイズと位置を計算するという問題が避けられません。このような問題を解決する方法は、DOM が提供するいくつかの API と互換性処理を組み合わせて使用​​することです。 . 説明します。最初の記事として、この記事では DOM が提供するサイズに関連する DOM 属性を紹介し、いくつかの互換性処理方法を提供し、一般的なシナリオに基づいてこれらの属性を正しく使用する方法を説明します。

1. offsetWidth、clientWidth、scrollWidth、および対応する高さ属性を正しく理解する

ある要素の水平スクロールバーと垂直スクロールバーが最後までドラッグされたと仮定すると、offsetWidth、clientWidth、scrollWidth などの属性の対応範囲は以下のようになります。

1) offsetWidth と offsetHeight はボックス モデルの幅と高さに対応します。これら 2 つの値は、クロムを使用して要素を検査するときに表示されるサイズと一致しています。

2)scrollWidth は、scrollHeight に対応し、スクロール領域の幅と高さですが、スクロール バーの幅は含まれません。スクロール領域はパディングとコンテンツで構成されます。

3) clientWidth、clientHeightは、スクロールバーの幅を除いた、境界線を削除した後のボックスモデルの領域の幅と高さに対応します。

4) すべての DOM 要素は、次の API を通じて offsetWidth、clientWidth、scrollWidh、および関連する高さの属性を迅速に取得できます:

//domE は DOM Html 要素オブジェクトです

domE.scrollWidth

domE.scrollHeight
domE.clientWidth
domE.clientHeight
domE.offsetWidth
domE.offsetHeight
//domE は DOM Html 要素オブジェクトです
domE.scrollWidth
domE.scrollHeight
domE.clientWidth
domE.clientHeight
domE.offsetWidth
domE.offsetHeight

5) これらの属性は、PC やモバイルを含む最新のブラウザーでは互換性の問題がほとんどなく、安心して使用できます。詳しい互換性ルールを知りたい場合は、次の 2 つの記事を参照してください:

W3C DOM 互換性 – CSS オブジェクト モデル ビュー

cssom ビューモード cssom-view-module のコンパイルと導入

通常の HTML 要素、HTML ルート要素、および body 要素の上記の関連属性は、以前の結論を検証し、実際のコーディング プロセスで直接使用できる経験上のテクニックを要約するために 1 つずつテストされます。通常の html 要素、html ルート要素、および body 要素を区別する必要があるのは、前述の理論によるものです。html ルート要素と body 要素には注意が必要です。

注:

1. テスト用に掲載したコードは長さを減らすため完全なコードではありませんが、学習の参考には影響しません。また、記事内のテスト結果はすべて Chrome 上で実行したものです。 (バージョン: 45.0) のテスト結果に差異がある場合は、IE9、IE10、IE11、Firefox (バージョン: 42.0)、および Opera (バージョン: 34.0) のテスト結果も表示されます。これらは IE8 以前のテスト結果で説明されますが、考慮されません。

2. Safari はデバイスの制限によりテストされていません。また、Chrome カーネルと同じであり、標準サポートの信頼性も大きく異なります。

3. chrome、firefox、opera の古いバージョンは、デバイスの制限によりテストできません。ただし、ブラウザーの標準サポートを考慮すると、これら 3 つのブラウザーはすべて非常に初期のバージョンで W3C 標準をサポートし始めました。これらのブラウザは比較的定期的に更新され、市場にあるこれらのブラウザの主流バージョンも比較的新しいものです。

4. IE8 以下は考慮されず、html は html5 を使用するため、

document.compatMode = 'BackCompat' の場合は考慮されません。ただし、BackCompat モードは IE6 ブラウザーで導入されていますが、document.compatMode = 'BackCompat' は、chrome、firefox などにも存在します。たとえば、次の Web ページを chrome で開き、コンソールで document.compatMode を印刷すると、その値も BackCompat であることがわかります (理由は、ページが html4.0 の dtd を使用しているという事実に関連しています。html4.01 の dtd に変更すると、この状況は chrome と Firefox では発生しません)。

http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/refs/compatModeCompat.htm

compatMode について詳しくは、次のリソースを参照してください:

https://developer.mozilla.org/zh-CN/docs/Web/API/Document/compatMode

https://msdn.microsoft.com/en-us/library/ms533687(VS.85).aspx

http://www.cnblogs.com/uedt/archive/2010/09/21/1832402.html

テスト 1. 通常の HTML 要素 (非 body および HTML ルート要素) の offsetWidth、clientWidth、scrollWidth および関連する高さの属性を確認します:

<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 class="box">
    <div class="box-2">...</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>

この例では、ボックス要素の幅と高さは 400*300、パディングは 20 ピクセル、境界線は 10 ピクセルです。クロム上の対応するボックス モデルは次のとおりです。

js の実行結果:

ボックスモデルと js の実行結果から、次のことがわかります。

1) offsetWidth と offsetHeight は、Chrome で要素を検査するときに表示されるサイズとまったく同じです。

2) clientWidth と clientHeight は、それぞれ offsetWidth と offsetHeight から対応する境界線 (上下合計 20 ピクセル、左右合計 20 ピクセル) とスクロール バーの幅 (クロム下のスクロール バーの幅は 17 ピクセル) を引いたものと等しくなります。 );

3)scrollWidth の場合、水平方向のオーバーフローは発生しません。オーバーフローのため、scrollWidth は clientWidth と同じですが、スクロール バーの幅は含まれません。これは、以前に提案された結論も検証します。

4) この例では、scrollHeight は、実際には div.box-2、div.box-2 の上下のパディング (合計 40 ピクセル) + offsetHeight(1370 ピクセル) に等しくなります。

5) 上記のテストでは、box-sizing というもう 1 つの CSS に注目してください。上記のコードでは、box-sizing を content-box に変更すると、結果は次のようになります。 offsetWidth と clientWidth は同じなので、scrollWidth に対応する領域は変更されません。

6) 他のブラウザの結果は、結論 1 ~ 5 と一致しています。

テスト 2. HTML ルート要素と body 要素の関連するオフセット クライアント スクロール幅と高さの属性を確認します:

<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 class="box">
    <div class="box-2">...</div>
  </div>
  <div class="box">
    <div class="box-2">...</div>
  </div>
  <div class="box">
    <div class="box-2">...</div>
  </div>
  <div class="box">
    <div class="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>
<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>

この例では、本文の下に 4 つのボックス要素があります (合計の高さは 360 * 4 = 1440px)。本文の幅は調整可能で、本文にも 10 ピクセルの境界線があります。実行結果は次のとおりです。

この結果からわかるように:

1) body 要素の境界線が 10 ピクセルであるため、clientWidth は offsetWidth より 20 ピクセル小さくなります。これは上記の理論と一致しますが、驚くべきことに、body のスクロール幅/スクロール高さは実際には等しいということです。 offsetWidth/offsetHeight、scrollWidth /scrollHeight は、要素のスクロール領域の幅と高さです。上記の範囲図によれば、本文のスクロール幅/スクロール高さは、そのオフセット幅/オフセット高さよりも小さい必要があります。

2) docEのscrollWidthとscrollHeightはbody要素のoffsetWidthとoffsetHeightに等しいはずですが、これは一貫していますが、範囲によればdocEのclientWidthは実際にはそのoffsetWidthに等しいです。図では、docE の clientWidth は、offsetWidth からスクロール バーの幅を引いたものとなります。

他のブラウザの実行結果も Chrome とはかなり異なります:

IE11:

1) IE11 での body 要素には chrome での body 要素の問題はありません

2) IE11 の HTML ルート要素にも、Chrome と同様の問題があります

IE10、IE9:

1) IE10 および 9 の body 要素には、chrome の body 要素の問題はありません

2) IE10 および 9 の HTML ルート要素には、Chrome と同様の問題はありません

firefox: 実行結果は IE11 と一致します。

opera: 実行結果は chrome の結果と一致しています。これは、私のバージョンの opera が chrome と同じ Webkit カーネルを使用しているためかもしれません。

IE9 と IE10 が最も標準的なようです。ネットで長時間検索しても、これらの違いを説明する関連情報は見つかりませんでした。これらの問題の理由をいくつか考えてみましょう:

1) まず、Web ページ全体のスクロールは、通常の HTML 要素のスクロールとは異なります。通常の HTML 要素自体がスクロール オブジェクトですが、Web ページの場合、スクロール オブジェクトは HTML のルート要素である必要はありません。またはボディ要素。本文のコンテンツが空の場合、本文の高さは 0 になり、HTML のルート要素の高さも 0 になるためです。このとき、HTML または本文に overflow:scroll CSS を追加すると、スクロールが表示されることがわかります。バーは依然としてブラウザ ウィンドウの右側に表示されるため、Web ページ全体のスクロールでは、理論上、スクロール オブジェクトは HTML 要素や body 要素ではなくウィンドウである必要があります。しかし、テストしたブラウザの限りではそうではありません:

IE10 および IE9 の場合、スクロール オブジェクトは HTML ルート要素であるため、HTML ルート要素のオフセットにはスクロール バーの幅が含まれます。

他のブラウザの場合、スクロール オブジェクトはウィンドウであるため、HTML ルート要素のオフセットにはスクロール バーの幅は含まれません。

2) 次に、通常の要素がスクロールするとき、スクロールするコンテンツ = そのコンテンツ領域 + そのパディング領域になります。Web ページ全体がスクロールする場合、スクロールするコンテンツは HTML ルート要素である必要があります。しかし、テストしたブラウザの限りでは、これは実際には当てはまりません:

IE9、IE10、IE11、Firefox の場合、スクロール領域は HTML ルート要素であるため、documentElement のスクロール幅とスクロール高さは常に Web ページのスクロール領域全体のサイズを表します。

chrome と opera の場合、スクロール オブジェクトは body 要素であるため、body のスクロール幅とスクロール高さは常に Web ページのスクロール領域全体のサイズを表します。

3) 第三に、ブラウザは常に documentElement.clientWidth と documentElement.clientHeight を、スクロール バーを除いた Web ページの表示領域のサイズとして記述します。これは Web ページのコンテンツとは何の関係もありません。

上記の推論は不合理ではありません。スクロール オブジェクトとスクロール領域を例にとります。Chrome でページを特定の位置までスクロールするために js を使用したい場合は、ドキュメントを使用せずに window.scrollTo を使用する必要があります。 body.scrollTop = xxx を処理し、documentElement.scrollTop の設定が無効であることを示します。これは、Chrome の全体のスクロール領域が本文のスクロール領域によって決定されることを示し、js を使用して処理を実行する場合。 IE11 および Firefox でページを特定の位置までスクロールするには、window.scrollTo を使用せずに document.documentElement.scrollTop = xxx を使用する必要があります。これは、IE11 および Firefox のスクロール領域全体が無効であることを示します。 HTML ルート要素のスクロール領域によって決まります。

2. JS を使用して DOM オブジェクトのサイズを正確に取得します

一般的なシナリオは次のとおりです:

1) スクロールバーを除く、Web ページ全体の表示領域のサイズを取得します

2) 非表示のスクロール領域を含む Web ページ全体のサイズを取得します

3) 通常の HTML 要素のサイズを取得します

4) スクロール バーが要素または Web ページに表示されるかどうかを決定します

5) スクロールバーの幅を計算します

下面针对这5个场景一一说明,以下代码均 不考虑IE8及以下,不考虑html4 ,另外请注意viewport的设置,要保证在移动设备上visual viewport与layout viewport重合。

1)如何获取整个网页的可视区域的大小,不包括滚动条

document.documentElement.clientWidth;
document.documentElement.clientHeight;
document.documentElement.clientWidth;
document.documentElement.clientHeight;

2)如何获取整个网页的大小,包括不可见的滚动区域

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"]
  );
}

以上出现的window.innerWidth和window.innerHeight分别用来获取网页包括滚动条的可视区域的宽高,这也是一个兼容性不错的方法,不过从实际开发情况来看,我们需要不包括滚动条的可视区域更多一些,所以在前面没有单独介绍。另外在之前给出的PPK的博客中也有关于这两个属性的兼容性测试,可以去了解。

3)如何获取一个普通html元素的大小

简单方法:

docE.offsetWidth;
docE.offsetHeight;
docE.offsetWidth;
docE.offsetHeight;

利用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将在下篇文章中跟其它与位置有关的DOM属性一起再详细介绍。

4 )判断元素或网页有无出现滚动条

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)
  };
}

当x或y方向的overflow为scroll的时候,该方向的scrollbarX为true,表示出现滚动条。

5)计算滚动条的宽度

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;
}

以上就是本文的全部内容,希望能对您有所帮助:)另外本文第二部分提供的代码,是根据个人思考和经验总结出的一些方法,在兼容性方面可能还有未考虑到的地方, 如果您有遇到其它不兼容的情况或者有更好的代码,还请不吝赐教 ,欢迎您的指导。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。