ทำความเข้าใจกับ offsetWidth, clientWidth, scrollWidth และ -Height ตามลำดับ


385

มีคำถามหลายข้อเกี่ยวกับ StackOverflow เกี่ยวกับ offsetWidth / clientWidth / scrollWidth (และ -Height ตามลำดับ) แต่ไม่มีใครให้คำอธิบายที่ครอบคลุมเกี่ยวกับค่าเหล่านั้น

นอกจากนี้ยังมีหลายแหล่งบนเว็บที่ให้ข้อมูลที่สับสนหรือไม่ถูกต้อง

คุณสามารถให้คำอธิบายที่สมบูรณ์รวมถึงคำแนะนำที่มองเห็นได้บ้างไหม? นอกจากนี้ค่าเหล่านั้นสามารถใช้ในการคำนวณความกว้างของแถบเลื่อนได้อย่างไร?

คำตอบ:


868

CSS box model ค่อนข้างซับซ้อนโดยเฉพาะเมื่อพูดถึงการเลื่อนเนื้อหา ในขณะที่เบราว์เซอร์ใช้ค่าจาก CSS ของคุณเพื่อวาดกล่องการกำหนดมิติทั้งหมดโดยใช้ JS จะไม่ส่งต่อหากคุณมี CSS เท่านั้น

นั่นเป็นเหตุผลที่แต่ละองค์ประกอบมีคุณสมบัติหก DOM เพื่อความสะดวกสบายของคุณ: offsetWidth, offsetHeight, clientWidth, clientHeight, และscrollWidth scrollHeightเหล่านี้เป็นคุณลักษณะแบบอ่านอย่างเดียวที่แสดงเค้าโครงภาพปัจจุบันและทั้งหมดเป็นจำนวนเต็ม (อาจมีข้อผิดพลาดในการปัดเศษ)

มาดูรายละเอียดกันดีกว่า:

  • offsetWidth, offsetHeight: ขนาดของกล่องภาพที่ใส่เส้นขอบทั้งหมด สามารถคำนวณได้โดยการเพิ่มwidth/ heightและ paddings และเส้นขอบถ้าองค์ประกอบมีdisplay: block
  • clientWidth, clientHeight: ส่วนที่มองเห็นได้ของเนื้อหากล่องไม่รวมถึงเส้นขอบหรือแถบเลื่อน แต่รวมถึงการขยาย ไม่สามารถคำนวณได้โดยตรงจาก CSS ขึ้นอยู่กับขนาดแถบเลื่อนของระบบ
  • scrollWidth, scrollHeight: ขนาดของเนื้อหาทั้งหมดของกล่องรวมถึงชิ้นส่วนที่ถูกซ่อนอยู่นอกพื้นที่เลื่อน ไม่สามารถคำนวณได้โดยตรงจาก CSS ขึ้นอยู่กับเนื้อหา

รูปแบบกล่อง CSS2

ลองใช้: jsFiddle


เนื่องจากoffsetWidthคำนึงถึงความกว้างของแถบเลื่อนเราจึงสามารถใช้เพื่อคำนวณความกว้างของแถบเลื่อนผ่านสูตร

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

น่าเสียดายที่เราอาจได้รับข้อผิดพลาดในการปัดเศษเนื่องจากoffsetWidthและclientWidthเป็นจำนวนเต็มเสมอในขณะที่ขนาดที่แท้จริงอาจเป็นเศษส่วนด้วยระดับการซูมอื่นที่ไม่ใช่ 1

สังเกตว่าอันนี้

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

ไม่สามารถทำงานได้อย่างน่าเชื่อถือใน Chrome เนื่องจาก Chrome กลับมาwidthพร้อมกับแถบเลื่อนที่ถูกระงับ (นอกจากนี้ Chrome ยังแสดงผล padding ด้านล่างของเนื้อหาการเลื่อนในขณะที่เบราว์เซอร์อื่นไม่ได้ทำ)


27
สำหรับผู้ที่มองหาความละเอียดที่ละเอียดกว่าจำนวนเต็มให้ใช้element.getBoundingClientRect()(ดูหมายเหตุที่developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )
Anson Kao

1
โปรดทราบว่าขึ้นอยู่กับเลย์เอาต์ของคุณ scrollWidth และ scrollHeight นั้นมีประโยชน์จริง ๆ ในการรับขนาดของอิลิเมนต์หลอกของคุณ :: ก่อนและ :: หลัง
David

นอกจากนี้จะเป็นประโยชน์ในการอธิบายว่าสิ่งเหล่านั้นเกี่ยวข้องกับอย่างไรnaturalWidthและnaturalHeight
YakovL

เหตุใดจึงscrollHeightรวมถึงpadding-bottomแต่scrollWidthไม่รวมpadding-right
JunGor

clientWidthสำหรับdocument.documentElement.clientWidthความแตกต่างกันอย่างที่ดูเหมือนว่าจะรวมpadding, bordersและmargin
Drenai

49

ฉันสร้างเวอร์ชันที่ครอบคลุมและสะอาดกว่าซึ่งบางคนอาจพบว่ามีประโยชน์สำหรับการจดจำชื่อที่สอดคล้องกับค่าใด ฉันใช้โค้ดสีและป้ายกำกับของ Chrome Dev Tool มีการจัดระบบแบบสมมาตรเพื่อรับการเปรียบเทียบได้เร็วขึ้น:

ป้อนคำอธิบายรูปภาพที่นี่

  • หมายเหตุ 1: clientLeftรวมถึงความกว้างของแถบเลื่อนแนวตั้งหากทิศทางของข้อความถูกตั้งค่าเป็นจากขวาไปซ้าย (เนื่องจากแถบจะแสดงทางด้านซ้ายในกรณีนั้น)

  • หมายเหตุ 2: สายนอกสุดหมายถึงที่อยู่ใกล้ตำแหน่งผู้ปกครอง (องค์ประกอบที่มีpositionการตั้งค่าคุณสมบัติที่แตกต่างกันมูลค่ากว่า staticหรือinitial) ดังนั้นหากคอนเทนเนอร์โดยตรงไม่ได้เป็น องค์ประกอบในตำแหน่งดังนั้นบรรทัดจะไม่แสดงคอนเทนเนอร์แรกในลำดับชั้น แต่เป็นอีกองค์ประกอบหนึ่งที่สูงกว่าในลำดับชั้น ถ้าไม่มี ตำแหน่งผู้ปกครองพบว่าเบราว์เซอร์จะใช้htmlหรือbody องค์ประกอบเป็นข้อมูลอ้างอิง


หวังว่าใครบางคนพบว่ามันมีประโยชน์เพียง 2 เซ็นต์ของฉัน;)


30

หากคุณต้องการใช้ scrollWidth เพื่อรับเนื้อหา"จริง" ที่มีความ กว้าง / สูง (เนื่องจากเนื้อหาอาจมีขนาดใหญ่กว่าความกว้าง / ความสูงที่กำหนดโดย CSS- cs ) scrollWidth / Height นั้นไม่น่าเชื่อถือเนื่องจากเบราว์เซอร์บางตัวดูเหมือน "MOVE" paddingRIGHT & paddingBOTTOM หากเนื้อหามีขนาดใหญ่ จากนั้นพวกเขาวางช่องว่างที่ RIGHT / BOTTOM ของ "เนื้อหาที่กว้าง / สูงเกินไป" (ดูรูปด้านล่าง)

==>ดังนั้นในการรับเนื้อหาความจริงในเบราว์เซอร์บางตัวคุณต้องย่อขยายแพ็ดย่อยทั้งสองจากสวิทช์แบนด์และในเบราว์เซอร์บางตัวคุณจะต้องย่อส่วนรองซ้ายเล็กน้อย

ฉันพบวิธีแก้ปัญหาสำหรับเรื่องนี้และต้องการเพิ่มสิ่งนี้เป็นความคิดเห็น แต่ไม่ได้รับอนุญาต ดังนั้นฉันจึงถ่ายภาพและทำให้มันชัดเจนขึ้นเล็กน้อยในเรื่องของ "ช่องว่างเลื่อน" และ "scrollWidth ที่ไม่น่าเชื่อถือ" ในพื้นที่สีน้ำเงินคุณพบทางออกของฉันเกี่ยวกับวิธีรับเนื้อหา "จริง"!

หวังว่านี่จะช่วยทำให้สิ่งต่าง ๆ ชัดเจนยิ่งขึ้น!

ป้อนคำอธิบายรูปภาพที่นี่


13

มีบทความที่ดีเกี่ยวกับ MDN ที่อธิบายทฤษฎีเบื้องหลังแนวคิดเหล่านั้น: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

นอกจากนี้ยังอธิบายถึงความแตกต่างทางแนวคิดที่สำคัญระหว่าง boundingClientRect's width / height เทียบกับ offsetWidth / offsetHeight

จากนั้นเพื่อพิสูจน์ทฤษฎีว่าถูกหรือผิดคุณต้องมีการทดสอบ นั่นคือสิ่งที่ฉันทำที่นี่: https://github.com/lingtalfi/dimensions-cheatsheet

มันคือการทดสอบสำหรับ chrome53, ff49, safari9, edge13 และ ie11

ผลการทดสอบพิสูจน์ว่าทฤษฎีนั้นถูกต้อง สำหรับการทดสอบฉันสร้าง divs 3 อันที่มี 10 lorem ipsum ย่อหน้าแต่ละอัน 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)

    • ลูกค้ากว้าง: 505 (chrome53, ff49, safari9)

    • ลูกค้ากว้าง: 508 (edge13)
    • ลูกค้ากว้าง: 503 (ie11)
    • ลูกค้าความสูง: 320 (chrome53, ff49, safari9, edge13, ie11)

    • scrollWidth: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • เลื่อนความสูง: 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)
    • ลูกค้ากว้าง: 475 (chrome53, ff49, safari9)
    • ลูกค้ากว้าง: 478 (edge13)
    • ลูกค้ากว้าง: 473 (ie11)
    • ลูกค้าความสูง: 290 (chrome53, ff49, safari9, edge13, ie11)

    • scrollWidth: 475 (chrome53, safari9, ff49)

    • scrollWidth: 478 (edge13)
    • scrollWidth: 473 (ie11)
    • เลื่อนความสูง: 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)
    • ลูกค้ากว้าง: 505 (chrome53, ff49, safari9)
    • ลูกค้ากว้าง: 508 (edge13)
    • ลูกค้ากว้าง: 503 (ie11)
    • ลูกค้าความสูง: 320 (chrome53, ff49, safari9, edge13, ie11)

    • scrollWidth: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • เลื่อนความสูง: 916 (chrome53, safari9)
    • scrollHeight: 954 (ff49)
    • scrollHeight: 922 (edge13, ie11)

ดังนั้นนอกเหนือจากค่าความสูงของ boundingClientRect (299.9999694824219 แทนที่จะเป็น 300) ใน edge13 และ ie11 ผลลัพธ์ยืนยันว่าทฤษฎีเบื้องหลังการทำงานนี้

นี่คือคำจำกัดความของแนวคิดเหล่านี้ของฉัน:

  • offsetWidth / offsetHeight: ขนาดของกล่องเส้นขอบเค้าโครง
  • boundingClientRect: ขนาดของกล่องเส้นขอบการเรนเดอร์
  • clientWidth / clientHeight: ขนาดของส่วนที่มองเห็นได้ของกล่องแพ็คเก็ตเค้าโครง (ยกเว้นแถบเลื่อน)
  • scrollWidth / scrollHeight: ขนาดของช่องว่างภายในของเค้าโครงหากไม่มีการ จำกัด โดยแถบเลื่อน

หมายเหตุ: ความกว้างของแถบเลื่อนแนวตั้งเริ่มต้นคือ 12px ใน edge13, 15px ใน chrome53, ff49 และ safari9 และ 17px ใน ie11 (ทำโดยการวัดใน photoshop จากภาพหน้าจอและพิสูจน์จากผลการทดสอบ)

อย่างไรก็ตามในบางกรณีแอปของคุณอาจไม่ได้ใช้ความกว้างของแถบเลื่อนแนวตั้งเริ่มต้น

ดังนั้นตามคำจำกัดความของแนวคิดเหล่านั้นความกว้างของแถบเลื่อนแนวตั้งควรเท่ากับ (ในโค้ดหลอก):

  • มิติโครงร่าง: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • มิติการเรนเดอร์: boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

หมายเหตุหากคุณไม่เข้าใจเค้าโครงและการแสดงผลโปรดอ่านบทความ mdn

นอกจากนี้หากคุณมีเบราว์เซอร์อื่น (หรือหากคุณต้องการดูผลลัพธ์ของการทดสอบด้วยตัวคุณเอง) คุณสามารถดูหน้าทดสอบของฉันได้ที่นี่: http://codepen.io/lingtalfi/pen/BLdBdL

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.