Verificar se o conteúdo de um elemento está transbordando?

153

Qual é a maneira mais fácil de detectar se um elemento foi excedido?

Meu caso de uso é: eu quero limitar uma determinada caixa de conteúdo para ter uma altura de 300px. Se o conteúdo interno for mais alto que isso, corte-o com um excesso. Mas se estiver cheio, quero mostrar um botão 'mais', mas se não estiver, não quero mostrar esse botão.

Existe uma maneira fácil de detectar estouro ou existe um método melhor?

atormentar
fonte

Respostas:

86

Se você deseja mostrar apenas um identificador para mais conteúdo, pode fazer isso com CSS puro. Eu uso sombras de rolagem puras para isso. O truque é o uso de background-attachment: local;. Seu CSS fica assim:

.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>

O código e o exemplo que você pode encontrar em http://dabblet.com/gist/2462915

E uma explicação que você pode encontrar aqui: http://lea.verou.me/2012/04/background-attachment-local/ .

RWAM
fonte
1
Boa ideia, mas no seu exemplo, o plano de fundo (sombra) estaria por trás do texto!
DreamTeK
Grande truque, no entanto no Chrome ele mostra apenas sombra estática no fundo, nunca desaparece eo superior sombra nunca mostra
Jared
214

O elemento pode ser estourado verticalmente, horizontalmente ou ambos. Esta função retornará um valor booleano se o elemento DOM estiver excedido:

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

Exemplo ES6:

const isOverflown = ({ clientWidth, clientHeight, scrollWidth, scrollHeight }) => {
    return scrollHeight > clientHeight || scrollWidth > clientWidth;
}
micnic
fonte
41
Ótima solução! Aqui está uma variante do jQuery (para ser usada com $("#element").overflown()):$.fn.overflown=function(){var e=this[0];return e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;}
Sygmoral
@micnic oi, eu estou usando ionic2 e tentando fazer a mesma coisa ... mas a função retornará verdadeiro sempre ... há uma maneira diferente de fazer as coisas angular 2
Yasir
@DavidBracoly, esta função é para puro API DOM, eu não tenho experiência com Ionic / Angular, eu acho que você deve obter o elemento DOM original e utilizar esta função
micnic
3
Only for Firefox: element.addEventListener ("overflow", () => log( "overflow" ), false);Referência: evento overflow
Reza
18

Comparando element.scrollHeightcom element.clientHeightdeve fazer a tarefa.

Abaixo estão as imagens do MDN explicando Element.scrollHeight e Element.clientHeight.

Altura de rolagem

Altura do cliente

Bergi
fonte
2
Sim, mas de acordo com o quirksmode, ele funciona mais - e é muito mais simples do que as outras soluções postadas.
Bergi 17/02/12
@ Harry: Ele é suportado em todos os navegadores atuais (pelo menos os de desktop), por isso não importa que seja formalmente fora do padrão.
Marat Tanalin
1
Aqui, essas propriedades sempre têm os mesmos valores.
precisa saber é
7

Fiz um codepen de várias partes demonstrando as respostas acima (por exemplo, usando overflow hidden e height), mas também como você expandiria / reduziria itens excedidos

Exemplo 1: https://codepen.io/Kagerjay/pen/rraKLB (Exemplo simples e real, sem javascript, apenas para cortar itens excedidos)

Exemplo 2: https://codepen.io/Kagerjay/pen/LBErJL (o manipulador de eventos único mostra mais / não mostra em itens excedidos)

Exemplo 3: https://codepen.io/Kagerjay/pen/MBYBoJ (Manipulador de eventos múltiplo em muitos mostra mais / mostra menos em itens excedidos)

Eu ligado exemplo 3 abaixo, assim , uso Jade / Pug por isso pode ser um pouco detalhado. Sugiro verificar os códigos que tornei mais fácil de entender.

// 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>

Vincent Tang
fonte
4

Algo assim: http://jsfiddle.net/Skooljester/jWRRA/1/ funcionaria? Apenas verifica a altura do conteúdo e a compara com a altura do contêiner. Se for maior do que você pode inserir no código para adicionar um botão "Mostrar mais".

Atualização: foi adicionado o código para criar um botão "Mostrar mais" na parte superior do contêiner.

ayyp
fonte
3

Se você estiver usando jQuery, tente um truque: faça div externa com overflow: hiddene div interna com conteúdo. Em seguida, use a .height()função para verificar se a altura da div interna é maior que a altura da div externa. Não sei se funcionará, mas tente.

TMS
fonte
1

use js para verificar se a criança offsetHeighté mais do que os pais. se for, faça com que os pais transbordem scroll/hidden/autoo que quiser e também display:blocknas div.

Vivek Chandra
fonte
1

Você pode verificar os limites em relação ao pai de deslocamento.

// 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;
}

Se você passar esse elemento, ele informará se seus limites estão inteiramente dentro de um contêiner e assumirá o padrão do deslocamento pai do elemento se nenhum contêiner explícito for fornecido. Usa

Mike Samuel
fonte
1

Outra questão que você deve considerar é a indisponibilidade de JS. Pense em encantamento progressivo ou degradação graciosa. Eu sugeriria:

  • adicionando "botão mais" por padrão
  • adicionando regras de estouro por padrão
  • botão oculto e, se necessário, modificações de CSS em JS após comparar element.scrollHeight com element.clientHeight
MFix
fonte
1

A seguir, um tutorial para determinar se um elemento foi estourado usando uma div de wrapper com overflow: hidden e JQuery height () para medir a diferença entre o wrapper e uma div de conteúdo interno.

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

Fonte: Estruturas e extensões em jsfiddle.net

user1295799
fonte
1

Esta é a solução jQuery que funcionou para mim. clientWidthetc não funcionou.

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

Se isso não funcionar, verifique se o pai dos elementos tem a largura desejada (pessoalmente, eu tive que usar parent().parent()). positionÉ relativo ao pai. Também incluí extra_widthporque meus elementos ("tags") contêm imagens que levam pouco tempo para serem usadas . load, mas durante a chamada de função eles têm largura zero, estragando o cálculo.Para contornar isso, eu uso o seguinte código de chamada:

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

Espero que isto ajude.

Dennis Golomazov
fonte
0
setTimeout(function(){
    isOverflowed(element)           
},500)

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

Isso foi trabalhado para mim. Obrigado.

Krunal
fonte
3
Como isso é diferente da resposta do micnic?
precisa
0

A alternativa jquery para a resposta é usar a tecla [0] para acessar o elemento bruto como este:

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

Estendi o Element por motivos de encapsulamento. Da resposta do micnic.

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

Use-o assim

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

    if(elementInQuestion.isOverflowing()){
        // do something
    }
David Clews
fonte