요소의 내용이 넘치지 않는가?


153

요소가 오버플로되었는지 감지하는 가장 쉬운 방법은 무엇입니까?

사용 사례는 특정 콘텐츠 상자의 높이를 300px로 제한하고 싶습니다. 내부 내용이 그보다 크면 오버플로로 잘라냅니다. 그러나 오버플로가 발생하면 '더보기'버튼을 표시하고 싶지만 그렇지 않으면 해당 버튼을 표시하고 싶지 않습니다.

오버플로를 감지하는 쉬운 방법이 있습니까, 아니면 더 좋은 방법이 있습니까?

답변:


86

더 많은 콘텐츠에 대한 식별자 만 표시하려면 순수한 CSS를 사용하여이 작업을 수행 할 수 있습니다. 나는 이것을 위해 순수한 스크롤 그림자를 사용합니다. 트릭은의 사용입니다 background-attachment: local;. CSS는 다음과 같습니다.

.scrollbox {
  overflow: auto;
  width: 200px;
  max-height: 200px;
  margin: 50px auto;

  background:
    /* Shadow covers */
    linear-gradient(white 30%, rgba(255,255,255,0)),
    linear-gradient(rgba(255,255,255,0), white 70%) 0 100%,
    
    /* Shadows */
    radial-gradient(50% 0, farthest-side, rgba(0,0,0,.2), rgba(0,0,0,0)),
    radial-gradient(50% 100%,farthest-side, rgba(0,0,0,.2), rgba(0,0,0,0)) 0 100%;
  background:
    /* Shadow covers */
    linear-gradient(white 30%, rgba(255,255,255,0)),
    linear-gradient(rgba(255,255,255,0), white 70%) 0 100%,
    
    /* Shadows */
    radial-gradient(farthest-side at 50% 0, rgba(0,0,0,.2), rgba(0,0,0,0)),
    radial-gradient(farthest-side at 50% 100%, rgba(0,0,0,.2), rgba(0,0,0,0)) 0 100%;
  background-repeat: no-repeat;
  background-color: white;
  background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
  
  /* Opera doesn't support this in the shorthand */
  background-attachment: local, local, scroll, scroll;
}
<div class="scrollbox">
  <ul>
    <li>Not enough content to scroll</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
  </ul>
</div>


<div class="scrollbox">
  <ul>
    <li>Ah! Scroll below!</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>The end!</li>
    <li>No shadow there.</li>
  </ul>
</div>

찾을 수있는 코드와 예제 http://dabblet.com/gist/2462915에서

http://lea.verou.me/2012/04/background-attachment-local/ 에서 설명을 찾을 수 있습니다 .


1
좋은 생각이지만 예제에서 배경 (그림자)이 텍스트 뒤에있을 것입니다!
DreamTeK

훌륭한 트릭이지만 Chrome에서는 아래쪽에 정적 그림자 만 표시되고 사라지지 않으며 위쪽 그림자는 표시되지 않습니다.
Jared

214

요소는 수직, 수평 또는 둘 다 오버플로 될 수 있습니다. DOM 요소가 오버플로 된 경우이 함수는 부울 값을 반환합니다.

function isOverflown(element) {
  return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}

ES6 예 :

const isOverflown = ({ clientWidth, clientHeight, scrollWidth, scrollHeight }) => {
    return scrollHeight > clientHeight || scrollWidth > clientWidth;
}

41
훌륭한 솔루션! 다음과 함께 사용되는 jQuery 변형이 있습니다 $("#element").overflown().$.fn.overflown=function(){var e=this[0];return e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;}
Sygmoral

@micnic 안녕, 나는 ionic2를 사용하고 같은 일을하려고하지만 ... 함수는 항상 true를 반환 ... 각도 2에서 일을 수행하는 다른 방법이 있습니까
Yasir

@DavidBracoly,이 함수는 순수 DOM API를위한 것입니다. Ionic / Angular에 경험이 없습니다. 원래 DOM 요소를 가져
와서이

3
Firefox 만 해당 : element.addEventListener ("overflow", () => log( "overflow" ), false);참조 : overflow 이벤트
Reza

18

비교 element.scrollHeight를하는 element.clientHeight작업을해야한다.

아래는 Element.scrollHeight 및 Element.clientHeight를 설명하는 MDN의 이미지입니다.

스크롤 높이

클라이언트 높이


2
네, 그러나 quirksmode 에 따르면 가장 효과적이며 다른 게시 된 솔루션보다 훨씬 간단합니다.
Bergi

@Harry : 현재 모든 브라우저 (데스크톱 브라우저)에서 지원되므로 공식적으로 비표준적인 것은 중요하지 않습니다.
Marat Tanalin

1
여기서 이러한 속성은 항상 동일한 값을 갖습니다.
koppor

7

위의 답변 (예 : 오버플로 숨김 및 높이 사용)을 보여주는 멀티 파트 코드 펜을 만들었지 만 오버플로 된 항목을 확장 / 축소하는 방법

예 1 : https://codepen.io/Kagerjay/pen/rraKLB (실제 간단한 예, 자바 스크립트 없음, 오버플로 된 항목 잘라 내기)

예 2 : https://codepen.io/Kagerjay/pen/LBErJL (오버플로 된 항목에서 단일 이벤트 핸들러가 더 많이 표시 / 보이지 않음)

예 3 : https://codepen.io/Kagerjay/pen/MBYBoJ (많은 쇼에 멀티 이벤트 핸들러는 더 / 오버 플로우 항목에 덜 표시)

아래 예제 3첨부 했습니다. Jade / Pug를 사용하므로 다소 장황 할 수 있습니다. 이해하기 쉬운 코드 펜을 확인하는 것이 좋습니다.

// Overflow boolean checker
function isOverflown(element){
  return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}

// Jquery Toggle Text Plugin
$.fn.toggleText = function(t1, t2){
  if (this.text() == t1) this.text(t2);
  else                   this.text(t1);
  return this;
};

// Toggle Overflow
function toggleOverflow(e){
  e.target.parentElement.classList.toggle("grid-parent--showall");
  $(e.target).toggleText("Show More", "Show LESS");
}

// Where stuff happens
var parents = document.querySelectorAll(".grid-parent");

parents.forEach(parent => {
  if(isOverflown(parent)){
    parent.lastElementChild.classList.add("btn-show");
    parent.lastElementChild.addEventListener('click', toggleOverflow);
  }
})
body {
  background-color: #EEF0ED;
  margin-bottom: 300px;
}

.grid-parent {
  margin: 20px;
  width: 250px;
  background-color: lightgrey;
  display: flex;
  flex-wrap: wrap;
  overflow: hidden;
  max-height: 100px;
  position: relative;
}
.grid-parent--showall {
  max-height: none;
}

.grid-item {
  background-color: blue;
  width: 50px;
  height: 50px;
  box-sizing: border-box;
  border: 1px solid red;
}
.grid-item:nth-of-type(even) {
  background-color: lightblue;
}

.btn-expand {
  display: none;
  z-index: 3;
  position: absolute;
  right: 0px;
  bottom: 0px;
  padding: 3px;
  background-color: red;
  color: white;
}

.btn-show {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
  <p>Any grid-parent over 10 child items has a "SHOW MORE" button to expand</p>
  <p>Click "SHOW MORE" to see the results</p>
</section>
<radio></radio>
<div class="wrapper">
  <h3>5 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>8 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>10 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>13 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>16 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
  <h3>19 child elements</h3>
  <div class="grid-parent">
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="grid-item"></div>
    <div class="btn-expand">Show More</div>
  </div>
</div>


4

http://jsfiddle.net/Skooljester/jWRRA/1/ 과 같이 작동합니까? 내용의 높이를 확인하고 컨테이너의 높이와 비교합니다. 이 값보다 크면 "더보기"버튼을 추가하는 코드를 넣을 수 있습니다.

업데이트 : 컨테이너 상단에 "더보기"버튼을 만드는 코드가 추가되었습니다.


3

jQuery를 사용하는 경우 속임수를 사용하여 외부 div를 사용 overflow: hidden하고 내부 div를 내용으로 만듭니다. 그런 다음 .height()함수를 사용 하여 내부 div의 높이가 외부 div의 높이보다 큰지 확인하십시오. 나는 그것이 효과가 있을지 확신하지 못하지만 시도해보십시오.


1

js를 사용하여 자녀 offsetHeight가 부모보다 더 많은지 확인하십시오 . 그렇다면 부모가 scroll/hidden/auto원하는대로 오버플 display:block로하고 더 많은 구역에서 오버플 로하십시오.


1

오프셋 상위를 기준으로 경계를 확인할 수 있습니다.

// Position of left edge relative to frame left courtesy
// http://www.quirksmode.org/js/findpos.html
function absleft(el) {
  var x = 0;
  for (; el; el = el.offsetParent) {
    x += el.offsetLeft;
  }
  return x;
}

// Position of top edge relative to top of frame.
function abstop(el) {
  var y = 0;
  for (; el; el = el.offsetParent) {
    y += el.offsetTop;
  }
  return y;
}

// True iff el's bounding rectangle includes a non-zero area
// the container's bounding rectangle.
function overflows(el, opt_container) {
  var cont = opt_container || el.offsetParent;
  var left = absleft(el), right = left + el.offsetWidth,
      top = abstop(el), bottom = top + el.offsetHeight;
  var cleft = absleft(cont), cright = cleft + cont.offsetWidth,
      ctop = abstop(cont), cbottom = ctop + cont.offsetHeight;
  return left < cleft || top < ctop
      || right > cright || bottom > cbottom;
}

이 요소를 전달하면 해당 경계가 완전히 컨테이너 내부에 있는지 여부를 알려주고 명시 적 컨테이너가 제공되지 않으면 기본적으로 요소의 오프셋 부모로 설정됩니다. 사용합니다


1

고려해야 할 또 다른 문제는 JS를 사용할 수 없다는 것입니다. 점진적 인 마법 또는 우아한 저하에 대해 생각하십시오. 내가 제안 할게:

  • 기본적으로 "추가 버튼"추가
  • 기본적으로 오버플로 규칙 추가
  • element.scrollHeight와 element.clientHeight를 비교 한 후 버튼 숨기기 및 필요한 경우 JS의 CSS 수정

1

다음은 래퍼와 내부 내용 div의 차이를 측정하기 위해 overflow : hidden 및 JQuery height ()와 함께 래퍼 div를 사용하여 요소가 오버플로되었는지 여부를 확인하는 바이올린입니다.

outers.each(function () {
    var inner_h = $(this).find('.inner').height();
    console.log(inner_h);
    var outer_h = $(this).height();
    console.log(outer_h);
    var overflowed = (inner_h > outer_h) ? true : false;
    console.log("overflowed = ", overflowed);
});

출처 : jsfiddle.net의 프레임 워크 및 확장


1

이것이 나를 위해 일한 jQuery 솔루션입니다. clientWidth등이 작동하지 않았습니다.

function is_overflowing(element, extra_width) {
    return element.position().left + element.width() + extra_width > element.parent().width();
}

이없는 작업을 수행하는 경우, 내가 사용했다, 그 요소의 부모가 개인적으로 (원하는 폭 확인 parent().parent()). position부모에 상대적입니다. 나는 또한 포함했습니다 extra_width내 요소 ( "태그") 작은 시간이 걸릴 이미지를 포함하기 때문에 함수 호출 중에는 너비가 0이며 계산이 손상됩니다.

var extra_width = 0;
$(".tag:visible").each(function() {
    if (!$(this).find("img:visible").width()) {
        // tag image might not be visible at this point,
        // so we add its future width to the overflow calculation
        // the goal is to hide tags that do not fit one line
        extra_width += 28;
    }
    if (is_overflowing($(this), extra_width)) {
        $(this).hide();
    }
});

도움이 되었기를 바랍니다.


0
setTimeout(function(){
    isOverflowed(element)           
},500)

function isOverflowed(element){
    return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
}

이것은 나를 위해 일했습니다. 감사합니다.


3
이것이 마이크의 답변과 어떻게 다릅니 까?
carefulnow1

0

대답에 대한 jquery 대안은 [0] 키를 사용하여 다음과 같은 원시 요소에 액세스하는 것입니다.

if ($('#elem')[0].scrollHeight > $('#elem')[0].clientHeight){

0

캡슐화를 위해 요소를 확장했습니다. 마이크 답변에서.

/*
 * isOverflowing
 * 
 * Checks to see if the element has overflowing content
 * 
 * @returns {}
 */
Element.prototype.isOverflowing = function(){
    return this.scrollHeight > this.clientHeight || this.scrollWidth > this.clientWidth;
}

이렇게 사용하세요

let elementInQuestion = document.getElementById("id_selector");

    if(elementInQuestion.isOverflowing()){
        // do something
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.