阅读 2742

css做‘展开收起’功能,借鉴大佬思路

开局一张图

more.gif

上图所示,多行文本的展开收起是一个很常见的交互效果。

实现这一类布局和交互难点主要一下几点:

  • 位于多行文本右下角的“展开收起”按钮
  • “展开”和“收起”两种状态的切换
  • 当文本不超过指定行数时,不显示“展开收起”按钮

在此之前,单独看这个布局,即便是配合JavaScript也不那么容易做出好看的交互效果。经过各方学习,发现纯CSS也能完美实现。

第一步,"展开收起"按钮

多行文本截断

假设有如下的一段html结构

<div class='more-text'>
     如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。
</div>
复制代码

多行文本超出展示省略号的方式,大家平常也用得蛮多吧,关键代码如下

.more-text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
 }
复制代码

image.png

按钮右下角环绕效果
<div class='more-text'>
    <div class='more-btn'>展开</div>
     如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。
</div>
复制代码
.more-btn{
    float: left;
    /*其他装饰样式*/
}
复制代码

image.png

换为右浮动

.more-btn{
    float: right;
     /*其他装饰样式*/
}
复制代码

image.png

再移到右下角

.more-btn{
    float: right;
    margin-top: 50px;
     /*其他装饰样式*/
}
复制代码

image.png

不难看出,按钮确实到了右下角,但按钮上方空白空间太大了。并不是我们希望的效果。

此时,借鉴伪元素配合多个浮动元素来完成。

.more-text::before {
    content: '';
    float: right;
    width: 10px;
    height: 50px;
    background: red;
}
.more-btn{
    float: right;
    clear: both;
     /*其他装饰样式*/
}
复制代码

image.png

如上图,当按钮和伪元素before都浮动,并且按钮clear: both,此时,伪元素before成功将按钮顶到了右下角。让伪元素before的宽度去掉便出现如下效果。

.more-text::before {
    content: '';
    float: right;
    width: 0;
    height: 50px;
    background: red;
}
复制代码

image.png

如你所见,按钮环绕效果非~常完美符合预期。

但是before高度是固定的50px,不一定会满足场景所需。还需修改为calc动态计算。

.more-text::before {
    content: '';
    float: right;
    width: 0;
    height: calc(100% - 20px); 
    /*100%减去一个按钮的高度即可*/
    background: red;
}
复制代码

image.png

很可惜,calc并没有达到理想的效果。

为什么呢?打开控制台可以发现,calc计算所得高度为0。怎么会这样呢?原因其实是因为父级元素没有设置高度,calc里面的 100% 便失效了。但问题在于,这里所需要的高度是动态变化的,不可能给父级定下一个固定高度。

至此,我们需要对布局进行修改。利用flex布局。大概的方法就是在 flex 布局 的子项中,可以通过百分比来计算变化高度。

修改如下,给.more-text再包裹一层,再设置 display: flex

<div class='more-wrapper'>
    <div class='more-text'>
        <div class='more-btn'>展开</div>
        如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。
    </div>
</div>
复制代码
.more-wrapper{
    display: flex;
}
复制代码

这样修改之后,calc的计算高度便能够生效。如下图所示。

image.png

至此,按钮右下角环绕效果就基本完成了。配上一个按钮点击事件就大功告成了。

浏览器兼容性处理

上面的实现是最完美的处理方式。但是,在Firefox浏览器却出现了兼容性问题。

image.png

哦豁。如此就非常尴尬。祸不单行,Safari浏览器也出现了兼容问题。

经过多番查证,发现是display: -webkit-box;属性存在兼容问题。

问题就在于,如果没有display: -webkit-box;怎么实现多行截断呢?如果在知道行数的情况下设置一个最大高度,理论上也能实现多行截断。由此我们通过行高属性line-height去入手。如果需要设置成 3 行,那就将高度设置成为 line-height * 3。

.more-text {
    /*
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    */
    overflow: hidden;
    line-height: 1.5;
    max-height: 4.5em;
 }
复制代码

image.png

此时呢还缺少省略号...。可以利用伪元素实现。

.more-btn::before{
    content: '…';
    color: #333;
    font-size: 14px;
    position: absolute;
    left: -10px;
    transform: translateX(-100%);
}
复制代码

image.png

大功告成,接下来加上点击切换即可。

点击切换“展开“ 与 ”收起“。

咱们目标是纯CSS完成。那么CSS状态切换就必不可少了,完全可以用input type = "checkbox"这个特性来完成。

要用到input特性就得对html代码进行一些修改。

<div class="more-wrapper">
    <input type="checkbox" id="exp" />
    <div class="more-text">
      <!-- <div class="more-btn">展开</div> -->
      <label class="more-btn" for="exp">展开</label>
      如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。
    </div>
</div>
复制代码
#exp:checked + .more-text {
    -webkit-line-clamp: 999;
    max-height: none;
}
复制代码

more.gif

接下来,就是变换按钮文字,以及展开之后省略号隐藏。此时都可以利用伪元素处理。

<label class="more-btn" for="exp"></label>
 <!-- 去掉按钮文字 -->
复制代码
.more-btn::after {
    content: '更多';
}
复制代码

在:checked状态中

#exp:checked + .more-text .more-btn::after {
    content: '收起';
}
复制代码

省略号隐藏处理。

#exp:checked + .more-text .more-btn::before {
    visibility: hidden;
}
复制代码

more.gif

至此,我们需要的效果便成了。

当然咱们还可以添加一些过渡动画让展开收起效果更加美观。在此就不演示了。

最后,文本行数判断

此前的步骤已经能够满足使用需求。但是还是存在问题。比如当文本内容较少时,此时不会发生截断,便不需要省略号...以及展开收起按钮。

image.png

此时当然可以选择js方式去做判断。但我们的目标是纯CSS。

那CSS没有逻辑判断,咱们只能另辟蹊径,视觉欺骗。或者叫做障眼法

比如在上图中的场景,没有发生截断,那就不需要省略号...展开按钮。这时,如果在文本的最后加上一个元素。并且为了不影响布局,给此元素设置绝对定位。

.more-text::after {
    content: '';
    width: 100%;
    height: 100%;
    position: absolute;
    background: red;
}
复制代码

同时,我们把父级的overflow: hidden;先去掉。得到效果如下

image.png

如图可见,红色部分的元素非常完美的挡住了按钮部分。

那我们把红色改成父级一样的背景色,并且恢复父级的overflow: hidden;

more.gif

上图可见,发现展开之后呢,伪元素盖住了收起按钮。所以必须再做一些修改。

#exp:checked + .more-text::after {
    visibility: hidden;
}
复制代码

more.gif

如你所见,非~常的好用。

注:IE10以下就不考虑了哈~

实现思路借鉴于阅文前端团队 ,作者严文彬

文章分类
前端
文章标签