Memahami offsetWidth, clientWidth, scrollWidth dan -Height, masing-masing

385

Ada beberapa pertanyaan tentang StackOverflow tentang offsetWidth / clientWidth / scrollWidth (dan -Height, masing-masing), tetapi tidak ada yang memberikan penjelasan komprehensif tentang nilai-nilai tersebut.

Juga, ada beberapa sumber di web yang memberikan informasi yang membingungkan atau salah.

Bisakah Anda memberikan penjelasan lengkap termasuk beberapa petunjuk visual? Juga, bagaimana nilai-nilai itu dapat digunakan untuk menghitung lebar bilah gulir?

pengguna123444555621
sumber

Jawaban:

869

Model kotak CSS agak rumit, terutama dalam hal menggulir konten. Sementara browser menggunakan nilai-nilai dari CSS Anda untuk menggambar kotak, menentukan semua dimensi menggunakan JS tidak lurus jika Anda hanya memiliki CSS.

Itu sebabnya setiap elemen memiliki enam sifat DOM untuk kenyamanan Anda: offsetWidth, offsetHeight, clientWidth, clientHeight, scrollWidthdan scrollHeight. Ini adalah atribut read-only yang mewakili tata letak visual saat ini, dan semuanya adalah integer (sehingga mungkin mengalami kesalahan pembulatan).

Mari kita telusuri secara terperinci:

  • offsetWidth, offsetHeight: Ukuran kotak visual yang mencakup semua batas. Dapat dihitung dengan menambahkan width/ heightdan paddings dan borders, jika elemen memilikidisplay: block
  • clientWidth, clientHeight: Bagian visual dari konten kotak, tidak termasuk batas atau bilah gulir, tetapi termasuk padding. Tidak dapat dihitung langsung dari CSS, tergantung pada ukuran bilah gulir sistem.
  • scrollWidth, scrollHeight: Ukuran semua konten kotak, termasuk bagian yang saat ini disembunyikan di luar area gulir. Tidak bisa dihitung langsung dari CSS, tergantung kontennya.

Kotak Model CSS2

Cobalah: jsFiddle


Karena offsetWidthmemperhitungkan lebar bilah gulir, kami dapat menggunakannya untuk menghitung lebar bilah gulir melalui rumus

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

Sayangnya, kami mungkin mendapatkan kesalahan pembulatan, karena offsetWidthdan clientWidthselalu bilangan bulat, sedangkan ukuran sebenarnya mungkin fraksional dengan tingkat zoom selain 1.

Perhatikan bahwa ini

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

tidak tidak bekerja andal di Chrome, karena Chrome kembali widthdengan scrollbar sudah dikurangi. (Juga, Chrome membuat paddingBottom ke bagian bawah konten gulir, sementara browser lain tidak)

pengguna123444555621
sumber
27
Untuk mereka yang mencari granularity yang lebih baik daripada integer, gunakan element.getBoundingClientRect()(lihat catatan di developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )
Anson Kao
1
Perhatikan bahwa tergantung pada tata letak Anda, scrollWidth dan scrollHeight dapat sangat berguna untuk mendapatkan ukuran elemen pseudo Anda :: before dan :: after.
David
Juga, akan bermanfaat untuk menjelaskan bagaimana kaitannya dengan naturalWidthdannaturalHeight
YakovL
mengapa scrollHeighttermasuk padding-bottomtetapi scrollWidthtidak termasukpadding-right
JunGor
clientWidthuntuk document.documentElement.clientWidthberbeda karena tampaknya untuk menyertakan padding, borders, danmargin
Drenai
50

Saya membuat versi yang lebih komprehensif dan lebih bersih yang mungkin berguna bagi beberapa orang untuk mengingat nama mana yang sesuai dengan nilai mana. Saya menggunakan kode warna Chrome Dev Tool dan label disusun secara simetris untuk mengambil analogi lebih cepat:

masukkan deskripsi gambar di sini

  • Catatan 1: clientLeftjuga termasuk lebar bilah gulir vertikal jika arah teks diatur ke kanan ke kiri (karena bilah ditampilkan ke kiri dalam kasus itu)

  • Catatan 2: garis terluar mewakili induk yang diposisikan terdekat (elemen yang positionpropertinya diatur ke nilai yang berbeda dari staticatau initial). Dengan demikian, jika wadah langsung bukan elemen yang diposisikan , maka garis tidak mewakili wadah pertama dalam hierarki tetapi elemen lain yang lebih tinggi dalam hierarki. Jika tidak ditemukan induk yang diposisikan , browser akan menggunakan elemen htmlatau bodysebagai referensi


Semoga seseorang menemukan itu berguna, hanya 2 sen saya;)

Lual
sumber
30

Jika Anda ingin menggunakan scrollWidth untuk mendapatkan WIDTH / HEIGHT KONTEN "NYATA" (karena kontennya bisa LEBIH BESAR daripada lebar / tinggi-kotak yang ditentukan css) scrollWidth / Height sangat TIDAK DAPAT DIANDALKAN karena beberapa browser tampaknya "PINDAHKAN" paddingRIGHT & paddingBOTTOM jika kontennya terlalu besar. Mereka kemudian menempatkan bantalan di KANAN / BOTTOM dari "konten terlalu luas / tinggi" (lihat gambar di bawah).

==> Karena itu untuk mendapatkan WIDTH KONTEN NYATA di beberapa browser Anda harus mengurangi KEDUA bantalan dari scrollwidth dan di beberapa browser Anda hanya perlu mengurangi KIRI Padding.

Saya menemukan solusi untuk ini dan ingin menambahkan ini sebagai komentar, tetapi tidak diizinkan. Jadi saya mengambil gambar dan membuatnya sedikit lebih jelas dalam hal "paddings yang dipindahkan" dan "scrollWidth yang tidak dapat diandalkan". Di BIRU AREA Anda menemukan solusi saya tentang cara mendapatkan "KONTEN WIDTH" NYATA!

Semoga ini bisa membantu membuat segalanya lebih jelas!

masukkan deskripsi gambar di sini

Manny_user3297459
sumber
13

Ada artikel bagus tentang MDN yang menjelaskan teori di balik konsep-konsep tersebut: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

Ini juga menjelaskan perbedaan konseptual yang penting antara lebar / tinggi boundingClientRect vs offsetWidth / offsetHeight.

Kemudian, untuk membuktikan teorinya benar atau salah, Anda perlu beberapa tes. Itulah yang saya lakukan di sini: https://github.com/lingtalfi/dimensions-cheatsheet

Ini pengujian untuk chrome53, ff49, safari9, edge13 dan ie11.

Hasil tes membuktikan bahwa teorinya secara umum benar. Untuk pengujian, saya membuat 3 div yang masing-masing berisi 10 paragraf lorem ipsum. Beberapa css diterapkan pada mereka:

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

Dan inilah hasilnya:

  • div1

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetTinggi: 330 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 530 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.tinggi: 330 (chrome53, ff49, safari9, edge13, ie11)

    • clientWidth: 505 (chrome53, ff49, safari9)

    • clientWidth: 508 (edge13)
    • clientWidth: 503 (ie11)
    • clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)

    • scrollLebar: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • scrollTinggi: 916 (chrome53, safari9)
    • scrollTinggi: 954 (ff49)
    • scrollTinggi: 922 (edge13, ie11)
  • div2

    • offsetWidth: 500 (chrome53, ff49, safari9, edge13, ie11)
    • offsetTinggi: 300 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 500 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.tinggi: 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)

    • scrollLebar: 475 (chrome53, safari9, ff49)

    • scrollWidth: 478 (edge13)
    • scrollWidth: 473 (ie11)
    • scrollTinggi: 916 (chrome53, safari9)
    • scrollTinggi: 954 (ff49)
    • scrollTinggi: 922 (edge13, ie11)
  • div3

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetTinggi: 330 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 265 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.tinggi: 165 (chrome53, ff49, safari9, edge13, ie11)
    • clientWidth: 505 (chrome53, ff49, safari9)
    • clientWidth: 508 (edge13)
    • clientWidth: 503 (ie11)
    • clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)

    • scrollLebar: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • scrollTinggi: 916 (chrome53, safari9)
    • scrollTinggi: 954 (ff49)
    • scrollTinggi: 922 (edge13, ie11)

Jadi, terlepas dari nilai tinggi boundingClientRect (299,9999694824219, bukan yang diharapkan 300) di edge13 dan ie11, hasilnya mengkonfirmasi bahwa teori di balik ini bekerja.

Dari sini, inilah definisi saya tentang konsep-konsep itu:

  • offsetWidth / offsetHeight: dimensi kotak batas tata letak
  • boundingClientRect: dimensi kotak batas render
  • clientWidth / clientHeight: dimensi bagian yang terlihat dari kotak padding tata letak (tidak termasuk bilah gulir)
  • scrollWidth / scrollHeight: dimensi kotak padding tata letak jika tidak dibatasi oleh scroll bar

Catatan: lebar bilah gulir vertikal default adalah 12px di edge13, 15px di chrome53, ff49 dan safari9, dan 17px di ie11 (dilakukan dengan pengukuran di photoshop dari tangkapan layar, dan terbukti benar dengan hasil pengujian).

Namun, dalam beberapa kasus, mungkin aplikasi Anda tidak menggunakan lebar bilah gulir vertikal bawaan.

Jadi, mengingat definisi konsep-konsep tersebut, lebar bilah gulir vertikal harus sama dengan (dalam kode pseudo):

  • dimensi tata letak: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • dimensi render: boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

Catatan, jika Anda tidak memahami tata letak vs render, harap baca artikel mdn.

Juga, jika Anda memiliki browser lain (atau jika Anda ingin melihat hasil tes sendiri), Anda dapat melihat halaman pengujian saya di sini: http://codepen.io/lingtalfi/pen/BLdBdL

ling
sumber