web-dev-qa-db-ja.com

OffsetWidth、clientWidth、scrollWidth、および-Heightをそれぞれ理解する

StackOverflowにはoffsetWidth/clientWidth/scrollWidth(およびそれぞれ-Height)に関していくつかの質問がありますが、それらの値が何であるかについての包括的な説明はありません。

また、ウェブ上には紛らわしい情報や不正確な情報を記載しているものがいくつかあります。

いくつかの視覚的なヒントを含む完全な説明をしてもらえますか?また、スクロールバーの幅を計算するためにこれらの値をどのように使用できますか?

326

CSSボックスモデルは、特にコンテンツのスクロールに関してはかなり複雑です。ブラウザはCSSの値を使用してボックスを描画しますが、CSSのみを使用している場合、JSを使用してすべての寸法を決定するのは簡単ではありません。

そのため、各要素にはoffsetWidthoffsetHeightclientWidthclientHeightscrollWidth、およびscrollHeightという6つのDOMプロパティがあります。これらは現在の視覚的レイアウトを表す読み取り専用の属性であり、それらはすべてintegersです(したがって、丸め誤差が生じる可能性があります)。

それらを詳しく見ていきましょう。

  • offsetWidthoffsetHeight:すべての境界線を含むビジュアルボックスのサイズ。要素にdisplay: blockがある場合、width/heightとパディングとボーダーを追加することで計算できます
  • clientWidthclientHeight:ボックスのコンテンツの視覚的な部分。境界線やスクロールバーは含まれませんが、パディングが含まれます。 CSSから直接計算することはできません。システムのスクロールバーのサイズによって異なります。
  • scrollWidthscrollHeight:スクロール領域の外側に現在非表示になっている部分を含む、ボックスのすべてのコンテンツのサイズ。コンテンツによって異なりますが、CSSから直接計算することはできません。

CSS2 Box Model

試してみてください: jsFiddle


offsetWidthはスクロールバーの幅を考慮するため、これを使用して、式を介してスクロールバーの幅を計算できます。

scrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidth

残念ながら、offsetWidthclientWidthは常に整数であり、ズームレベルが1以外の場合、実際のサイズは小数になることがあるため、丸めエラーが発生する可能性があります。

これに注意してください

scrollbarWidth = getComputedStyle().width + getComputedStyle().paddingLeft + getComputedStyle().paddingRight - clientWidth

Chromeはwidthを返すため、Chromeではnotは確実に動作しますが、スクロールバーはすでに減算されています。 (また、ChromeはpaddingBottomをスクロールコンテンツの下部にレンダリングしますが、他のブラウザーはレンダリングしません)

789

どの名前がどの値に対応するのかを覚えておくと便利な場合がある、より包括的でクリーンなバージョンを作成しました。私はChrome Dev Toolのカラーコードを使い、ラベルは対称的に構成されています。

enter image description here

  • 注1:テキストの方向が右から左に設定されている場合、clientLeftには垂直スクロールバーの幅も含まれます(その場合、バーは左に表示されるため)。

  • 注意2:最も外側の行は最も近い位置付けparent(positionプロパティがstaticまたはinitialとは異なる値に設定されている要素)を表します。したがって、直接コンテナが位置要素ではない場合、その行は階層の最初のコンテナではなく、階層の上位にある別の要素を表しません。位置parentが見つからない場合、ブラウザはhtmlまたはbody要素を参照として使用します。


誰かがそれが便利だと思うことを願っています、ちょうど私の2セント;)

36
Lual

ScrollWidthを使用して "REAL" コンテンツの幅/高さ を取得する場合(CSS定義の幅/高さボックスよりも大きくなる可能性があるため) scrollWidth内容が大きい場合、ブラウザによってはpaddingRIGHTおよびpaddingBOTTOMが「移動」されるように見えるため、/ Heightは非常に信頼できません 。それからそれらは「余りに広い/高い内容」の右/下にパディングを置く(下記の図を見なさい)。

==> したがって、ブラウザによってはREAL CONTENT WIDTHを得るためにスクロール幅からBOTHパディングを引く必要があり、ブラウザによってはLEFTパディングを引くだけでよい場合があります。

これに対する解決策を見つけ、これをコメントとして追加したいのですが、許可されませんでした。そこで私は写真を撮り、「移動されたパディング」と「信頼できないscrollWidth」に関してそれをもう少し明確にしました。 BLUE AREAには、 "REAL" CONTENT WIDTHを取得する方法に関する私の解決策があります。

これが物事をさらに明確にするのに役立つことを願っています!

enter image description here

29

これらの概念の背後にある理論を説明するMDNに関する良い記事があります: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Det​​ermining_the_dimensions_of_elements

また、boundingClientRectの幅/高さとoffsetWidth/offsetHeightの間の概念上の重要な違いについても説明します。

それから、その理論が正しいか間違っているかを証明するために、いくつかのテストが必要です。それが私がここでしたことです: https://github.com/lingtalfi/dimensions-cheatsheet

それはchrome53、ff49、safari9、Edge13そしてie11をテストしています。

テストの結果は、理論が一般的に正しいことを証明しています。テストのために、それぞれ10個のloremイプサム段落を含む3個のdivを作成しました。いくつかのCSSがそれらに適用されました:

.div1{
    width: 500px;
    height: 300px;
    padding: 10px;
    border: 5px solid black;
    overflow: auto;
}
.div2{
    width: 500px;
    height: 300px;
    padding: 10px;
    border: 5px solid black;
    box-sizing: border-box;
    overflow: auto;
}

.div3{
    width: 500px;
    height: 300px;
    padding: 10px;
    border: 5px solid black;
    overflow: auto;
    transform: scale(0.5);
}

そして、これが結果です。

  • div1

    • offsetWidth:530(chrome53、ff49、safari9、Edge13、ie11)
    • offsetHeight:330(chrome53、ff49、safari9、Edge13、ie11)
    • bcr.width:530(chrome53、ff49、safari9、Edge13、ie11)
    • bcr.height:330(chrome53、ff49、safari9、Edge13、ie11)

    • clientWidth:505(chrome53、ff49、safari9)

    • clientWidth:508(Edge13)
    • clientWidth:503(ie11)
    • clientHeight:320(chrome53、ff49、safari9、Edge13、ie11)

    • scrollWidth:505(chrome53、safari9、ff49)

    • scrollWidth:508(Edge13)
    • scrollWidth:503(ie11)
    • scrollHeight:916(chrome53、safari9)
    • scrollHeight:954(ff49)
    • scrollHeight:922(Edge13、ie11)
  • div2

    • offsetWidth:500(chrome53、ff49、safari9、Edge13、ie11)
    • offsetHeight:300(chrome53、ff49、safari9、Edge13、ie11)
    • bcr.width:500(chrome53、ff49、safari9、Edge13、ie11)
    • bcr.height:300(chrome53、ff49、safari9)
    • bcr.height:299.9999694824219(Edge13、ie11)
    • clientWidth:475(chrome53、ff49、safari9)
    • clientWidth:478(Edge13)
    • clientWidth:473(ie11)
    • clientHeight:290(chrome53、ff49、safari9、Edge13、ie11)

    • scrollWidth:475(chrome53、safari9、ff49)

    • scrollWidth:478(Edge13)
    • scrollWidth:473(すなわち11)
    • scrollHeight:916(chrome53、safari9)
    • scrollHeight:954(ff49)
    • scrollHeight:922(Edge13、ie11)
  • div3

    • offsetWidth:530(chrome53、ff49、safari9、Edge13、ie11)
    • offsetHeight:330(chrome53、ff49、safari9、Edge13、ie11)
    • bcr.width:265(chrome53、ff49、safari9、Edge13、ie11)
    • bcr.height:165(chrome53、ff49、safari9、Edge13、ie11)
    • clientWidth:505(chrome53、ff49、safari9)
    • clientWidth:508(Edge13)
    • clientWidth:503(ie11)
    • clientHeight:320(chrome53、ff49、safari9、Edge13、ie11)

    • scrollWidth:505(chrome53、safari9、ff49)

    • scrollWidth:508(Edge13)
    • scrollWidth:503(ie11)
    • scrollHeight:916(chrome53、safari9)
    • scrollHeight:954(ff49)
    • scrollHeight:922(Edge13、ie11)

したがって、Edge13とie11のboundingClientRectの高さの値(予想される300ではなく299.9999694824219)とは別に、この結果の裏にある理論が機能することが確認されました。

そこから、これらの概念の私の定義は次のとおりです。

  • offsetWidth/offsetHeight:レイアウト枠ボックスの寸法
  • boundingClientRect:レンダリングボーダーボックスの寸法
  • clientWidth/clientHeight:レイアウトパディングボックスの表示部分の寸法(スクロールバーを除く)
  • scrollWidth/scrollHeight:スクロールバーに制約されていない場合のレイアウトパディングボックスの寸法

注:デフォルトの垂直スクロールバーの幅は、Edge13では12px、chrome53、ff49およびsafari9では15px、ie11では17pxです(スクリーンショットからのフォトショップでの測定によって行われ、テストの結果によって正しく証明されています)。

ただし、場合によっては、アプリがデフォルトの垂直スクロールバーの幅を使用していない可能性があります。

したがって、これらの概念の定義を考えると、垂直スクロールバーの幅は(疑似コードで)に等しいはずです。

  • レイアウト寸法:offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • レンダリング寸法:boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

注意してください、あなたがレイアウト対レンダリングを理解していないならば、mdn記事を読んでください。

また、あなたが他のブラウザを持っているなら(あるいはあなた自身でテストの結果を見たいのなら)、あなたはここに私のテストページを見ることができます: http://codepen.io/lingtalfi/pen/BLdBdL

12
ling