今天逛掘金,又被阅文大佬秀了,他们用都知道的技术,解决了一个前端历史难题:css实现多行折叠功能。为什么说是历史难题呢?抛开js不说,仅用单纯的css+html去实现确实难度不小,即便加上js也需要控制字符长度,或者其他操作才能完美的实现这个功能。

传统多行隐藏功能

关于css多行隐藏前端最常用的就是使用“webkit-box” + “line-clamp”实现,这样确实能实现现代浏览器的多行隐藏问题,真是效果及样式如下:

.qui-h3{display:-webkit-box;overflow:hidden;text-overflow:ellipsis;-webkit-line-clamp:3;-webkit-box-orient:vertical;}

效果:
CSS实现多行折叠(展开/收起)的历史难题,就这样被攻破了!原来我们差的不是技术,而是想法。-QUI-Notes

但是,我们要是想在里面加个 折叠按钮,发现传统的插入,直接排在文本后面,被隐藏了,所以这样的布局给前端开发者造成了困扰,想要显示折叠就必须取消溢出隐藏的问题,那样与多行隐藏的功能相悖!

解决方案

大佬布局:

<div class="wrapper">
<input id="exp1" class="exp"  type="checkbox">
<div class="text">
<label class="btn" for="exp1"></label> 浮动元素是如何定位的
正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
在下面的图片中,有三个红色的正方形。其中有两个向左浮动,一个向右浮动。要注意到第二个向左浮动的正方形被放在第一个向左浮动的正方形的右边。如果还有更多的正方形这样浮动,它们会继续向右堆放,直到填满容器一整行,之后换行至下一行。
</div>
</div>

大佬样式:

.wrapper{display:flex;margin:50px auto;width:800px;overflow:hidden;border-radius:8px;padding:15px;box-shadow:20px 20px 60px #bebebe,-20px -20px 60px #ffffff}
.text{font-size:20px;overflow:hidden;text-overflow:ellipsis;text-align:justify;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;position:relative}
.text::before{content:'';height:calc(100% - 24px);float:right}
.btn{float:right;clear:both;margin-left:10px;font-size:16px;padding:0 8px;background:#3F51B5;line-height:24px;border-radius:4px;color:#fff;cursor:pointer}
.btn::before{content:'展开'}
.exp{display:none}
.exp:checked+.text{-webkit-line-clamp:999}
.exp:checked+.text .btn::before{content:'收起'}

等于说,文本截断都实现,就是如何将按钮一直显示到右下角的问题,这就要说到今天的重点了,下面看看大佬是如何操作的:

  • 1.btn设置浮动,实现一直在右侧;
  • 2.text::before伪元素同样浮动,用动态高度calc(100% - 24px),将btn撑高,始终保持在右下角;
  • 3.如果2不生效就是父级盒子wrapper没有开启flex布局,动态高度不生效导致的;

按照上面的步骤,就可以实现btn一直处于右下角了,那么css如何注册绑定点击事件?checkbox,没毛病,还记得之前看到过大佬用checkbox实现2048小游戏,全是用checkbox实现的,真是亮瞎了,秀的一比!那么分析上面的代码,

  • 4.label实现btn,并绑定了一直隐藏的checkbox,这样就给css增加了可操作事件:checked,通过:checked事件实现显示隐藏状态切换。

到这,等于这个功能已经结束,效果如下:
CSS实现多行折叠(展开/收起)的历史难题,就这样被攻破了!原来我们差的不是技术,而是想法。-QUI-Notes

你以为这样就结束了?不还有个bug,那就是内容比较少的时候,不到溢出边界时,btn应该隐藏的,而不是一直显示,what?

  • 5.::after占位,在文本后面增加一个正行,内容少时,将btn按钮撑出。

完整css代码:

.wrapper{display:flex;margin:50px auto;width:500px;overflow:hidden;border-radius:8px;padding:15px;box-shadow:20px 20px 60px #bebebe,-20px -20px 60px #ffffff}
.text{font-size:20px;overflow:hidden;text-overflow:ellipsis;text-align:justify;position:relative;line-height:1.5;max-height:4.5em;transition:.3s max-height}
.text::before{content:'';height:calc(100% - 26px);float:right}
.text::after{content:'';width:100%;height:100%;position:absolute;background:#fff}
.btn{position:relative;float:right;clear:both;margin-left:20px;font-size:16px;padding:0 8px;background:#3F51B5;line-height:24px;border-radius:4px;color:#fff;cursor:pointer}
.btn::after{content:'展开'}
.exp{display:none}
.exp:checked+.text{max-height:200px}
.exp:checked+.text::after{visibility:hidden}
.exp:checked+.text .btn::before{visibility:hidden}
.exp:checked+.text .btn::after{content:'收起'}
.btn::before{content:'...';position:absolute;left:-5px;color:#333;transform:translateX(-100%)}

整体分析,用到的css技术都是常见的,关键是阅文大佬的思维很可怕啊,人家硬是将浮动和flex结合使用了,再配合伪元素,来了个偷梁换柱,不得不评论:秒哇!

技术原文:《CSS 实现多行文本“展开收起”》https://juejin.cn/post/6963904955262435336