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>展开</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以下就不考虑了哈~




链接:https://juejin.cn/post/7007632958622269471

0 个评论

要回复文章请先登录注册