ตรวจสอบว่าองค์ประกอบ HTML มีแถบเลื่อนหรือไม่


113

วิธีใดที่เร็วที่สุดในการตรวจสอบว่าองค์ประกอบมีแถบเลื่อนหรือไม่

สิ่งหนึ่งที่แน่นอนคือการตรวจสอบว่าองค์ประกอบมีขนาดใหญ่กว่าวิวพอร์ตหรือไม่ซึ่งสามารถทำได้อย่างง่ายดายโดยตรวจสอบค่าทั้งสองนี้:

el.scrollHeight > el.offsetHeight || el.scrollWidth > el.offsetWidth

แต่นั่นไม่ได้หมายความว่ามันมีแถบเลื่อนด้วย (ดังนั้นมนุษย์จึงสามารถเลื่อนได้)

คำถาม

ฉันจะตรวจสอบแถบเลื่อนในเบราว์เซอร์1 แบบไขว้และ2จาวาสคริปต์เท่านั้น (เช่นเดียวกับที่ไม่มี jQuery ) ได้อย่างไร

Javascript เท่านั้นเพราะฉันต้องการค่าใช้จ่ายที่น้อยที่สุดเพราะฉันต้องการเขียนตัวกรองตัวเลือก jQuery ที่รวดเร็วมาก

// check for specific scrollbars
$(":scrollable(x/y/both)")

// check for ANY scrollbar
$(":scrollable")

ฉันคิดว่าฉันต้องตรวจสอบการoverflowตั้งค่าสไตล์ แต่ฉันจะทำได้อย่างไรในเบราว์เซอร์ข้าม?

แก้ไขเพิ่มเติม

overflowการตั้งค่าสไตล์ไม่เพียง การตรวจสอบว่าองค์ประกอบมีแถบเลื่อนนั้นไม่สำคัญเท่าที่ควร สูตรแรกที่ฉันเขียนไว้ข้างต้นใช้งานได้ดีเมื่อองค์ประกอบไม่มีเส้นขอบ แต่เมื่อเป็นเช่นนั้น (โดยเฉพาะอย่างยิ่งเมื่อเส้นขอบมีความกว้างมาก) offsetมิติอาจใหญ่กว่าscrollมิติ แต่องค์ประกอบยังสามารถเลื่อนได้ เราต้องลบเส้นขอบจากoffsetมิติข้อมูลเพื่อให้ได้วิวพอร์ตที่เลื่อนได้จริงขององค์ประกอบและเปรียบเทียบกับscrollมิติ

สำหรับการอ้างอิงในอนาคต

:scrollablejQuery selector filter รวมอยู่ใน.scrollintoview()ปลั๊กอิน jQuery ของฉัน รหัสที่สมบูรณ์สามารถพบได้ในโพสต์บล็อกของฉันหากใครต้องการ แม้ว่าจะไม่ได้ให้รหัสของ Soumya ในการแก้ปัญหาจริงก็ช่วยแก้ปัญหาได้มาก มันชี้ให้ฉันไปในทิศทางที่ถูกต้อง

คำตอบ:


118

ฉันพบสิ่งนี้เมื่อสองสามสัปดาห์ก่อน มันได้ผลสำหรับฉัน

var div = document.getElementById('container_div_id');

var hasHorizontalScrollbar = div.scrollWidth > div.clientWidth;
var hasVerticalScrollbar = div.scrollHeight > div.clientHeight;

/* you'll get true/false */

12
เห็นได้ชัดว่าคุณมีตัวอย่างที่เรียบง่าย จะเกิดอะไรขึ้นถ้าภาชนะของคุณoverflow:hiddenตั้งไว้? มีเนื้อหาส่วนเกิน แต่ยังไม่สามารถเลื่อนได้ ปัญหาก็ไม่ง่ายอย่างที่คิด
Robert Koritnik

8
นี่อาจไม่ใช่วิธีแก้ปัญหาที่ได้รับการยอมรับ แต่ก็ใช้ได้ผลสำหรับฉัน ฉันไม่แน่ใจว่าทำไมคุณถึงเลื่อนมันถ้ามันถูกซ่อนไว้
vol7ron

นี่อาจไม่ใช่วิธีแก้ปัญหาที่ได้รับการยอมรับ แต่ก็ใช้ได้ผลสำหรับฉัน โรเบิร์ตสำหรับกรณีเหล่านั้นคุณไม่สามารถดึงคุณสมบัติ css overflow เพื่อทดสอบกรณีเหล่านั้นได้div.scrollHeight>div.clientHeight && !(div.style.overflow && div.style.overflow == 'hidden')หรือไม่(เช่น)
vol7ron

7
สิ่งนี้ล้มเหลวในหลาย ๆ กรณี หากองค์ประกอบของคุณล้น: มองเห็นได้; ความกว้าง: 200px; และมีลูกที่มีความกว้าง 500px องค์ประกอบของคุณไม่มีแถบเลื่อน แต่มี scrollWidth เป็น 500px และ clientWidth 200px
Joseph Lennox

1
หากมองเห็นหรือซ่อนส่วนเกินมักจะไม่มีแถบเลื่อน
Hubert Grzeskowiak

16

ลอง:

สำหรับแถบเลื่อนแนวตั้ง

el.scrollHeight> el.clientHeight

สำหรับแถบเลื่อนแนวนอน

el.scrollWidth> el.clientWidth

ฉันรู้ว่าสิ่งนี้ใช้ได้กับ IE8 และ Firefox 3.6+ เป็นอย่างน้อย


2
ฉันชี้ให้เห็นว่าใช่สิ่งนี้บอกฉันว่าองค์ประกอบบางอย่างมีขนาดใหญ่กว่าที่คิด แต่ไม่ได้หมายความว่ามันแสดงแถบเลื่อน มันสามารถมีได้เช่นกันoverflow:hiddenและจะไม่สามารถเลื่อนได้อีกต่อไป
Robert Koritnik

1
และการตรวจสอบด้วยค่า clientHeight / clientWidth ไม่ได้ให้ผลลัพธ์ที่ดีเนื่องจากองค์ประกอบต่างๆสามารถมีเส้นขอบได้เช่นกันซึ่งไม่รวมอยู่ในการวัดนี้ ตรวจสอบสูตรของฉัน ทำงานได้ดีกว่าของคุณ
Robert Koritnik

นั่นเป็นเรื่องจริงเกี่ยวกับการใช้ offsetHeight / offsetWidth เพื่อตรวจสอบแถบเลื่อนแทน clientHeight / clientWidth ขอบคุณที่ชี้ให้เห็น
Gary

@RobertKoritnik - ดังนั้นเพียงตรวจสอบว่าองค์ประกอบนั้นมีoverflow:hiddenอยู่หรือไม่ ... นี่ยังเป็นคำตอบที่ถูกต้องในความคิดของฉันเนื่องจากเป็นวิธีที่ง่ายที่สุด
vsync

14

สิ่งนี้อาจดูเหมือน(หรือเป็น)แฮ็กเล็กน้อย แต่คุณสามารถทดสอบคุณสมบัติscrollTopและscrollLeft

หากมีค่ามากกว่า 0 แสดงว่ามีแถบเลื่อน หากเป็น 0 ให้ตั้งค่าเป็น 1 และทดสอบอีกครั้งเพื่อดูว่าคุณได้ผลลัพธ์เป็น 1 หรือไม่จากนั้นตั้งค่ากลับเป็น 0

ตัวอย่าง: http://jsfiddle.net/MxpR6/1/

function hasScroll(el, direction) {
    direction = (direction === 'vertical') ? 'scrollTop' : 'scrollLeft';
    var result = !! el[direction];

    if (!result) {
        el[direction] = 1;
        result = !!el[direction];
        el[direction] = 0;
    }
    return result;
}

alert('vertical? ' + hasScroll(document.body, 'vertical'));
alert('horizontal? ' + hasScroll(document.body, 'horizontal'));

ฉันเชื่อว่ามีคุณสมบัติที่แตกต่างออกไปสำหรับ IE ดังนั้นฉันจะอัปเดตในอีกสักครู่

แก้ไข:ดูเหมือนว่า IE อาจรองรับคุณสมบัตินี้ (ฉันไม่สามารถทดสอบ IE ได้ในขณะนี้)

http://msdn.microsoft.com/en-us/library/ms534618(VS.85).aspx


มันง่ายมากที่จะตรวจสอบการเลื่อนถ้าคุณเปรียบเทียบและoffsetHeight clientHeightส่วนหลังจะเล็กกว่าตามขนาดของแถบเลื่อนเสมอเมื่อมีแถบเลื่อน
Robert Koritnik

@ โรเบิร์ต: ไม่แน่ใจว่าง่ายกว่า แต่ฉันเห็นว่ามันทำงานอย่างไร จากนั้นฉันคิดว่าถ้าองค์ประกอบมีoverflow:scrollคุณต้องการให้รายงานว่าเลื่อนได้ไม่ว่าจะเปิดใช้งานแถบเลื่อนหรือไม่ แน่นอนวิธีแก้ปัญหาของฉันอาจมีปัญหาหากมีการแนบเหตุการณ์ onscroll
user113716

ไม่จริง หากคุณตรวจสอบปลั๊กอิน jQueryของฉันฉันต้องหาบรรพบุรุษที่เลื่อนได้จริงมิฉะนั้นฉันจะไม่สามารถเลื่อนองค์ประกอบเพื่อดูได้
Robert Koritnik

8
@RobertKoritnik ไม่จริง; เบราว์เซอร์บางตัวอาจมีแถบเลื่อนที่ไม่ลดความกว้าง บน OS X เช่น หรือสัมผัสอุปกรณ์
daniel.gindi

1
คืนค่าเท็จเสมอ
Fatih Erol

14

นี่เป็นวิธีแก้ปัญหาอื่น:

ดังที่มีคนไม่กี่คนชี้ให้เห็นเพียงแค่การเปรียบเทียบ offsetHeight และ scrollHeight นั้นไม่เพียงพอเนื่องจากมีความแตกต่างกันในองค์ประกอบที่มี overflow ที่ซ่อนอยู่ ฯลฯ ซึ่งยังไม่มีแถบเลื่อน ที่นี่ฉันกำลังตรวจสอบด้วยว่ามีการเลื่อนล้นหรืออัตโนมัติในรูปแบบที่คำนวณสำหรับองค์ประกอบ:

var isScrollable = function(node) {
  var overflowY = window.getComputedStyle(node)['overflow-y'];
  var overflowX = window.getComputedStyle(node)['overflow-x'];
  return {
    vertical: (overflowY === 'scroll' || overflowY === 'auto') && node.scrollHeight > node.clientHeight,
    horizontal: (overflowX === 'scroll' || overflowX === 'auto') && node.scrollWidth > node.clientWidth,
  };
}

ถ้าoverflow*เป็นscrollมีจะเป็นแถบเลื่อนดังนั้นฉันคิดว่าคุณต้องการvertical: overflowY === 'scroll' || overflowY === 'auto' && node.scrollHeight > node.clientHeightฯลฯ (เช่นลบวงเล็บเพื่อscroll*VS client*มีการทดสอบเฉพาะเมื่อoverflow*เป็นauto) มิฉะนั้นจะเป็นวิธีแก้ปัญหาที่ถูกต้องที่สุด
Jake

@Jake ถ้า scrollHeight <clientHeight เมื่อเลื่อนล้นแถบเลื่อนจะอยู่ที่นั่น แต่จะถูกปิดใช้งาน (กล่าวคือองค์ประกอบไม่สามารถเลื่อนได้) ดังนั้นฉันคิดว่ามันขึ้นอยู่กับการใช้งาน การแก้ไขของคุณถูกต้องสำหรับคุณเพียงต้องการตรวจสอบแถบเลื่อนไม่สำคัญว่าสถานะ สำหรับฉันเมื่อฉันคิดสิ่งนี้ขึ้นมาฉันต้องการใช้การปรับอัตโนมัติสำหรับส่วนประกอบดังนั้นการปิดใช้งานแถบเลื่อนจึงไม่มีประโยชน์ในกรณีนั้น ที่ดูเหมือนจะเป็นเช่นนั้นสำหรับคำถามนี้ (ต้อง "เลื่อนโดยมนุษย์")
lotif

6

ฉันอาจจะไปงานปาร์ตี้ช้าหน่อย แต่ ...

ฉันเชื่อว่าคุณสามารถตรวจจับแถบเลื่อนด้วย e.offsetWidth กับ e.clientWidth ความกว้างออฟเซ็ตประกอบด้วยเส้นขอบและแถบเลื่อนช่องว่างภายในและความกว้าง ความกว้างของไคลเอ็นต์รวมถึงช่องว่างภายในและความกว้าง โปรดมอง:

https://developer.mozilla.org/en/DOM/element.offsetWidth (ภาพที่สอง) https://developer.mozilla.org/en/DOM/element.clientWidth (ภาพที่สอง)

คุณต้องตรวจสอบ:

  1. องค์ประกอบนั้นมีการตั้งค่า overflow เป็น auto / scroll (รวมถึง overflowX / Y) โดยใช้สไตล์ที่คำนวณ / cascaded / current หรือไม่
  2. หากองค์ประกอบมีโอเวอร์โฟลว์ตั้งค่าเป็นอัตโนมัติ / เลื่อน สร้าง offsetWidth และ clientWidth
  3. ถ้า clientWidth น้อยกว่า offsetWidth - เส้นขอบด้านขวา (พบอีกครั้งผ่านสไตล์ที่คำนวณ / cascaded / current) แสดงว่าคุณมีแถบเลื่อน

ทำเช่นเดียวกันสำหรับแนวตั้ง (offset / clientHeight)

IE7 รายงานไคลเอ็นต์ความสูง 0 สำหรับองค์ประกอบบางอย่าง (ฉันไม่ได้ตรวจสอบว่าทำไม) ดังนั้นคุณจึงต้องมีการตรวจสอบโอเวอร์โฟลว์ครั้งแรกเสมอ

หวังว่านี่จะช่วยได้!


3

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

ดังนั้นเนื่องจากการแสดงผลของเบราว์เซอร์ไม่บ่อยนักคุณสามารถตรวจสอบการมีการเลื่อนด้วยการเปลี่ยนการเลื่อนแล้วตั้งค่ากลับ:

const hasScrollBar = (element) => {
  const {scrollTop} = element;

  if(scrollTop > 0) {
    return true;
  }

  element.scrollTop += 10;

  if(scrollTop === element.scrollTop) {
    return false;
  }

  // undoing the change
  element.scrollTop = scrollTop;
  return true;
};


1

เพียงแค่วุ่นวายที่นี่เนื่องจากวิธีแก้ปัญหาข้างต้นไม่ได้ผลสำหรับฉัน (จนถึงตอนนี้) ฉันพบว่าประสบความสำเร็จในการเปรียบเทียบความสูงของแผ่นเลื่อน Div กับ offsetHeight

var oh = $('#wrapDiv').get(0).offsetHeight;
var sh = $('#wrapDiv').get(0).scrollHeight;

ดูเหมือนว่าจะให้ฉันเปรียบเทียบอย่างเฉียบแหลม ... จนถึงตอนนี้ มีใครรู้บ้างว่าถูกต้องตามกฎหมายหรือไม่?


2
ฉันคิดว่าคุณต้องการ scrollHeight และ clientHeight: stackoverflow.com/questions/4106538/…
rich remer

1

สำหรับIE11 (Internet Explorer 11) ฉันต้องเปลี่ยนตรรกะเป็น:

// Subtract 3 (a small arbitrary number) to allow for IE reporting a difference of 1 when no scrollbar is present
var hasVerticalScrollbar = div.scrollHeight - 3 > div.clientHeight;

เนื่องจาก IE รายงาน scrollHeight เท่ากับ 1 ที่ใหญ่กว่า clientHeight เมื่อไม่มีแถบเลื่อน แต่มีขนาดใหญ่กว่าประมาณ 9 เมื่อมีแถบเลื่อน


0

หากคุณต้องการทราบว่ามีแถบเลื่อนสำหรับหน้าเว็บทั้งหมดหรือไม่และด้วยการสนับสนุนเบราว์เซอร์เต็มรูปแบบคุณสามารถใช้สิ่งนี้:

const hasScrollbar = document.body.scrollHeight > window.innerHeight

สิ่งสำคัญคือต้องใช้window.innerHeightแทนdocument.body.clientHeightเนื่องจากในเบราว์เซอร์บนมือถือบางตัวClientHeightจะไม่ได้รับขนาดของแถบที่อยู่ แต่จะscrollHeightดังนั้นคุณจึงคำนวณผิด


-5

คำตอบนี้ไม่ถูกต้อง คุณต้องใช้สิ่งนี้:

var div = document.getElementById('container_div_id');

var hasHorizontalScrollbar = (div.offsetWidth > div.clientWidth);
var hasVerticalScrollbar = (div.offsetHeight > div.clientHeight);

สิ่งนี้ถูกลดลงเนื่องจากได้รับการคัดลอก / วางจากคำตอบที่ยอมรับเมื่อ 6 ปีที่แล้วและคุณไม่จำเป็นต้องมีวงเล็บเพื่อเปลี่ยนบางสิ่งให้เป็นบูลีน
moto

-6

เพิ่มองค์ประกอบกว้าง 100% ภายใน จากนั้นตั้งค่าล้นเป็นซ่อน หากรูปแบบที่คำนวณขององค์ประกอบ (จาก jQ) เปลี่ยนไปพาเรนต์จะมีแถบเลื่อน

แก้ไข: ดูเหมือนว่าคุณต้องการวิธีการข้ามเบราเซอร์เช่นgetComputedStyle ลอง:

function getCSS(_elem, _style)
{
    var computedStyle;
    if (typeof _elem.currentStyle != 'undefined')
        computedStyle = _elem.currentStyle;
    else
        computedStyle = document.defaultView.getComputedStyle(_elem, null);
    return computedStyle[_style];
}

1
ถ้าผมอยู่แล้วต้องการใช้ jQuery สำหรับเรื่องนี้ฉันอยากจะทำ$(el).css("overflow/overflowX/overflowY")และดูไม่ว่าจะเป็นการตั้งค่าให้อัตโนมัติหรือเลื่อน แต่ฉันต้องการหลีกเลี่ยงการใช้ jQuery
Robert Koritnik

16
สไตล์ CSS จะไม่บอกคุณว่าองค์ประกอบมีแถบเลื่อนหรือไม่ เท่านั้นหรือไม่ก็สามารถมีแถบเลื่อน อาจพบวิธีการข้ามเบราว์เซอร์ในการกำหนดความกว้างขององค์ประกอบด้านใน?
Soumya

@ Soumya92: การเปรียบเทียบขนาดระหว่างขนาดที่เลื่อนได้และขนาดจริงเป็นเรื่องเล็กน้อยและฉันได้เขียนไว้ข้างต้นแล้ว ... สิ่งที่ฉันต้องตรวจสอบตอนนี้คือการตั้งค่าการล้นปัจจุบันในองค์ประกอบเฉพาะ
Robert Koritnik

@ Soumya92: นั่นคือสิ่งที่ฉันต้องการ สามารถทำให้ง่ายขึ้นมากเช่นกันโดยใช้การรวมตัวกันcomputedStyle = el.currentStyle || document.defaultView.getComputedStyle(el, null);
Robert Koritnik

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