CSS 带有截断的多行文本的过渡

CSS Transition with truncated multiline text

我有以下代码snippet:

如您所见,有一个截断的多行文本,如果单击它会展开。我还为 max-height 添加了一个过渡以实现平滑移动。

input[type='checkbox'] {
  display: none;
}

.flexbox {
  display: flex;
  flex-flow: row wrap;
  background-color: green;
}

.lbl-toggle {
  max-height: 30px;
  transition: max-height 1s ease-in-out;
}

.truncate {
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}

.toggle:checked+.lbl-toggle {
  max-height: 350px;
}

.toggle:checked+.lbl-toggle>span {
  text-overflow: initial;
  overflow: initial;
  white-space: initial;
}
<div>
  <input id="collapsible" class="toggle" type="checkbox">
  <label for="collapsible" class="flexbox lbl-toggle">
    <span class="truncate">Text here is very very long that it might get truncate if this box get resized too small. Text here is very very long that it might get truncate if this box get resized too small</span>
  </label>
</div>

然而,whitespace-属性 在与 max-height 和过渡的交互中出现问题。只有初始过渡有效,之后就不再有效了。我想如果我正在申请然后截断并设置 white-space: nowrap 我的最大高度不再应用并且过渡中断。

我唯一的想法是white-space属性用JS的时候需要延迟一下。但是,我不想使用 JS。还有其他解决方案吗?

遗憾的是,max-height in/out 转换的不一致是 CSS 中的一个众所周知的问题 - this article 很好地解释了这个问题,并提供了几个替代方案可能有用。

一个解决方案是摆脱省略号并将折叠的最大高度设置为行高,省略号和行高迫使您使用 white-space: nowrap;,这是有罪的过渡不能正常工作。 注意 max-height 属性 也应该应用于跨度 (.truncate) 如果你真的想控制这个 属性这个class(在我的代码中我应用到所有内部元素)

正如您猜对的那样,另一种解决方案是使用 JS,我不太明白您为什么要避免使用 JS。该脚本并不复杂,您不需要假复选框。

input[type='checkbox'] {
  display: none;
}

.flexbox {
  display: flex;
  flex-flow: row wrap;
  background-color: green;
}

.lbl-toggle/*, .lbl-toggle > **/ {
  max-height: 18px;
  transition: max-height 1s ease-in-out;
}

.truncate {
  overflow: hidden;
}

.toggle:checked+.lbl-toggle/*, .toggle:checked+.lbl-toggle > **/ {
  max-height: 350px;
}

.toggle:checked+.lbl-toggle > .truncate {
  overflow: initial;
}
<div>
  <input id="collapsible" class="toggle" type="checkbox">
  <label for="collapsible" class="flexbox lbl-toggle">
    <span class="truncate">Text here is very very long that it might get truncate if this box get resized too small. Text here is very very long that it might get truncate if this box get resized too small</span>
  </label>
</div>

JS解决方案:

var collapsibles = document.getElementsByClassName('lbl-toggle'),
    i, l = collapsibles.length;

for(i = 0; i < l; i++){
  collapsibles[i].onclick = function(){
    var self = this;
    if(self.classList.contains('expanded')){
      self.classList.remove('expanded');
      setTimeout(function(){
        //the if is a safety in case of many rapid clicks
        if(!self.classList.contains('expanded')){
          self.classList.add('nowrap');
        }
      }, 1000);
    }else{
      self.classList.add('expanded');
      self.classList.remove('nowrap');
    }
  };
}
.flexbox {
  display: flex;
  flex-flow: row wrap;
  background-color: green;
}

.lbl-toggle {
  max-height: 30px;
  transition: max-height 1s ease-in-out;
}

.nowrap .truncate{
  white-space: nowrap;
}

.truncate {
  text-overflow: ellipsis;
  overflow: hidden;
}

.expanded {
  max-height: 350px;
}

.expanded > .truncate {
  text-overflow: initial;
  overflow: initial;
}
<div>
  <label class="flexbox lbl-toggle nowrap">
    <span class="truncate">Text here is very very long that it might get truncate if this box get resized too small. Text here is very very long that it might get truncate if this box get resized too small</span>
  </label>
</div>