css做‘展开收起’功能,借鉴大佬思路
开局一张图
上图所示,多行文本的展开收起是一个很常见的交互效果。
实现这一类布局和交互难点主要一下几点:
- 位于多行文本右下角的“展开收起”按钮
- “展开”和“收起”两种状态的切换
- 当文本不超过指定行数时,不显示“展开收起”按钮
在此之前,单独看这个布局,即便是配合JavaScript也不那么容易做出好看的交互效果。经过各方学习,发现纯CSS也能完美实现。
第一步,"展开收起"按钮
多行文本截断
假设有如下的一段html结构
<div class='more-text'>
如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。
</div>
多行文本超出展示省略号的方式,大家平常也用得蛮多吧,关键代码如下
.more-text {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
按钮右下角环绕效果
<div class='more-text'>
<div class='more-btn'>展开</div>
如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。如何才能做好展开收起交互呢。
</div>
.more-btn{
float: left;
/*其他装饰样式*/
}
换为右浮动
.more-btn{
float: right;
/*其他装饰样式*/
}
再移到右下角
.more-btn{
float: right;
margin-top: 50px;
/*其他装饰样式*/
}
不难看出,按钮确实到了右下角,但按钮上方空白空间太大了。并不是我们希望的效果。
此时,借鉴伪元素配合多个浮动元素来完成。
.more-text::before {
content: '';
float: right;
width: 10px;
height: 50px;
background: red;
}
.more-btn{
float: right;
clear: both;
/*其他装饰样式*/
}
如上图,当按钮和伪元素before都浮动,并且按钮clear: both,此时,伪元素before成功将按钮顶到了右下角。让伪元素before的宽度去掉便出现如下效果。
.more-text::before {
content: '';
float: right;
width: 0;
height: 50px;
background: red;
}
如你所见,按钮环绕效果非~常完美符合预期。
但是before高度是固定的50px,不一定会满足场景所需。还需修改为calc动态计算。
.more-text::before {
content: '';
float: right;
width: 0;
height: calc(100% - 20px);
/*100%减去一个按钮的高度即可*/
background: red;
}
很可惜,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的计算高度便能够生效。如下图所示。
至此,按钮右下角环绕效果就基本完成了。配上一个按钮点击事件就大功告成了。
浏览器兼容性处理
上面的实现是最完美的处理方式。但是,在Firefox浏览器却出现了兼容性问题。
哦豁。如此就非常尴尬。祸不单行,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;
}
此时呢还缺少省略号...
。可以利用伪元素实现。
.more-btn::before{
content: '…';
color: #333;
font-size: 14px;
position: absolute;
left: -10px;
transform: translateX(-100%);
}
大功告成,接下来加上点击切换即可。
点击切换“展开“ 与 ”收起“。
咱们目标是纯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;
}
接下来,就是变换按钮文字,以及展开之后省略号隐藏。此时都可以利用伪元素处理。
<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;
}
至此,我们需要的效果便成了。
当然咱们还可以添加一些过渡动画
让展开收起效果更加美观。在此就不演示了。
最后,文本行数判断
此前的步骤已经能够满足使用需求。但是还是存在问题。比如当文本内容较少时
,此时不会发生截断,便不需要省略号...
以及展开收起
按钮。
此时当然可以选择js
方式去做判断。但我们的目标是纯CSS。
那CSS没有逻辑判断,咱们只能另辟蹊径,视觉欺骗
。或者叫做障眼法
。
比如在上图中的场景,没有发生截断,那就不需要省略号...
和展开
按钮。这时,如果在文本的最后加上一个元素。并且为了不影响布局,给此元素设置绝对定位。
.more-text::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
background: red;
}
同时,我们把父级的overflow: hidden;
先去掉。得到效果如下
如图可见,红色部分的元素非常完美的挡住了按钮
部分。
那我们把红色改成父级一样的背景色,并且恢复父级的overflow: hidden;
。
上图可见,发现展开之后呢,伪元素盖住了收起按钮。所以必须再做一些修改。
#exp:checked + .more-text::after {
visibility: hidden;
}
如你所见,非~常的好用。
注:IE10以下就不考虑了哈~
链接:https://juejin.cn/post/7007632958622269471