当flex子元素溢出父元素时,如何隐藏它们?

37
假设我有一个弹性盒子容器,其中内容可能会溢出父容器。我希望的是,如果任何项的大小超过容器的任何量,它将被隐藏。如果我设置overflow: hidden,它只会隐藏该项的溢出部分,而不是整个项。
考虑以下内容:
<nav id="top-nav">
    <div id="main-nav-container">
        <div class="menu">
            <ul>
                <li><a href="/">Item 1</a></li>
                <li><a href="/">Item 2</a></li>
                <li><a href="/">Item 3</a></li>
                <li><a href="/">Item 4</a></li>
            </ul>
        </div>
        <div class="menu">
            <ul>
                <li><a href="/">Other 1</a></li>
                <li><a href="/">Other 2</a></li>
            </ul>
        </div>
    </div>
</nav>

CSS:

#top-nav, #top-nav div.menu ul li {
  background-color: #444;
}

#main-nav-container {
  margin: 0 auto;
  max-width: 1200px;
  padding: 0 40px;
  display: -webkit-inline-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-box-pack: justify;
  -moz-justify-content: -moz-space-between;
  -ms-justify-content: -ms-space-between;
  justify-content: space-between;
}

#top-nav div.menu {
  -webkit-flex: 1;
  display: -webkit-inline-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}

#top-nav div.menu:last-child {
  display: -webkit-inline-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-justify-content: flex-end;
  -webkit-flex-direction: row;
  flex-direction: row;
  justify-content: flex-end;
}

#top-nav div.menu,
#top-nav div.menu ul {
  text-align: left;
  alignment-baseline: baseline;
  margin: 0;
  padding: 0;
}
#top-nav div.menu ul {
  list-style: none;
}
#top-nav div.menu > ul {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  white-space: nowrap;
}
#top-nav div.menu li {
  -webkit-flex-shrink: 0;
  -moz-flex-shrink: 0;
  -ms-flex-shrink: 0;
  flex-shrink: 0;
  margin: 0
  position: relative;
  font-size: 1.1em;
  cursor: pointer;
}
#top-nav div.menu ul li a {
  color: #E6E6E6;
  text-decoration: none;
  display: block;
  padding: 7px;
}
如果窗口缩小,我希望在“Other 1”开始覆盖“Item 4”时立即隐藏它。
一旦实现了这一点,我还需要一个选择器来定位那些被隐藏的内容。
在此处设置jsfiddle

你很可能无法直接针对溢出的 flex 项目进行定位。目前还没有专门用于此目的的选择器。 - BoltClock
抱歉,我不应该直接使用 CSS 来定位它们,但我可以使用 jQuery 来定位它们,例如 $("div.menu ul li:hidden")。最重要的是,我想要一种方法来隐藏整个元素,而不仅仅是溢出的内容。 - Brett Ryan
啊,那确实有道理。 - BoltClock
5个回答

34

你的问题的一个解决方法是添加以下CSS代码:

#top-nav div.menu > ul {
  flex-wrap: wrap;
  height: 34px;
  overflow: hidden;
}

如果您想知道哪些元素被隐藏了,您应该使用Javascript/jQuery来解决问题,因为您无法使用CSS知道这一点。


2
我喜欢这里的思路,但我更愿意避免输入高度。我认为在注释中要求针对那些隐藏的元素可能会引起混淆,不过我已经添加了一条说明性评论。 - Brett Ryan
我认为你应该考虑不隐藏元素;而是只需使用 flex-wrap: wrap。这样你就可以避免输入高度。 - Barun
在网页浏览器中,您可以使用键盘上的 TAB 键来导航到这些项目并将它们暴露出来。 这个解决方案对我不起作用。 - xeiton
这是解决方案,适用于 flexbox 本身不确定高度的情况。如果它包含在一个父元素中,并且该父元素基于其高度(以百分比表示),则这非常有效。 - Lukáš Řádek

5
我制作了一个多部分的 CodePen,演示了上述答案(例如使用溢出隐藏和高度),还演示了如何展开/折叠溢出项。
示例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>


0
我本来希望有一个 CSS 的解决方案,但最终我还是用了 JavaScript 实现。这里我使用了 jQuery,但并不是必须的。
$(function() {
  $(window).resize(function() {
    var max = $("#top-nav div.menu:last-child>ul>li:first-child").position().left;
    $("#top-nav div.menu:first-child > ul").children("li").each(function() {
      // We have to show first so we can get position/size
      var $this = $(this).show();
      if ($this.position().left + $this.width() > max) {
        $this.nextAll().andSelf().hide();
        return false;
      }
    });
  });
  $(window).resize();
});

获取其他地方的隐藏节点可以通过 $("#top-nav div.menu:first-child>ul>li:hidden"); 实现。我还可以为此添加一个类,以便单独对其进行定位,例如通过提供一个按钮来显示隐藏项。

0

这不是解决确切问题的答案,但标题与我的(稍微)不同的问题匹配,并且我通过谷歌搜索该术语到达了这里。

如果您知道将包装哪个元素并且不需要显示它(在我的情况下是“聪明”的间隔符),则可以将其高度设置为0。它会被包装,但不会增加任何高度。


-1

这是一个使用flexbox实现的例子;

* {
  box-sizing: border-box;
}

ul {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 400px;
  width: 300px;
  overflow: hidden;
  border: solid 1px red;
  margin: 0;
  padding: 0;
  list-style: none;
}

ul li {
  height: auto;
  padding: 15px;
  width: 100%;
  border: solid 1px #000;
  flex: 0 0 auto;
}
<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
  <li>E</li>
  <li>F</li>
  <li>G<br />klajlka</li>
  <li>H</li>
</ul>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接