CSS 实现多行文本“展开收起”

4,263 阅读5分钟

看这篇博文总结,详细点这里 本文只作为阅读这篇博文的阅读笔记

方法一

多行文本截断,超出部分省略号

<div class="text">
浮动元素是如何定位的 正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。 
</div>

提到限制行数,超出部分省略号显示,我们常用的就是display: -webkit-box 这里就是

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

当我们添加按钮,并需要使按钮有环绕效果,这个时候需要有 浮动 float

<div class="text">
    <button class="btn">展开</button>
     浮动元素是如何定位的
    正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
</div>
.btn { 
    float: right;
      margin-top: 45px;
      /*其他装饰样式*/
     
    }

会发现上面有一段空白,显然margin 并不能解决问题,但是整个文本还是受到了浮动按钮的影响,如果有多个浮动,他们也会依次排列,这个时候我们只需要让两个浮动元素上下排列就可以了,这样就保持了文本环绕效果,也不会有空白

.text::before{ 
    content: ''; 
    float: right; 
    width: 10px; 
    height: 45px;/*先随便设置一个高度*/
    background: red 
}
// 同时btn清除浮动
.btn {
    float: right;
    /*其他装饰样式*/
    clear: both;  /* 清除浮动*/
}

image.png

这个时候我们只需要把伪元素的width 设为0就可以了,同时伪元素的高度需要设置动态高度 使用css的 calc函数即可,当用calc(100% - 24px)时,可能会发生高度100%失效问题,这个时候只需要在最外层包裹一层div,设置为display:flex

写到这里,看上去要结束了,但是发现这段代码只能在chrome浏览器使用,在火狐,safari浏览器中完全失效,display: -webkit-box在,火狐之类的浏览器中,与chrome不一样,想要多浏览器兼容,我们只能寻找其他的方法

方法二

提到 CSS 状态切换,大家都能想到 input type="checkbox"  吧。这里我们也需要用到这个特性,首先加一个 input,然后把之前的 button 换成 label ,并且通过 for 属性关联起来

<div class="wrap">
    <input type="checkbox" class="exp" id="exp"> 
    <div class="text"> 
        <label class="btn" for="exp"></label> 
        浮动元素是如何定位的 正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
    </div> 
</div>

接下来是两种状态的切换,显示3行和不做行数限制

.exp:checked+.text{   
    max-height: none; /*可以直接设置最大高度 max-height为一个较大的值,或者直接设置为 none*/
}

有一个技巧,凡是碰到需要动态修改内容的,都可以使用伪类 content 生成技术,具体做法就是去除或者隐藏按钮里面的文字,采用伪元素生成

<label class="btn" for="exp"></label><!--去除按钮文字-->
.btn::after{   
    content:'展开' /*采用content生成*/ 
}

.exp:checked+.text .btn::after{  
    content:'收起' 
}
.exp:checked+.text .btn::before {
    visibility: hidden; /*在展开状态下隐藏省略号*/
}
.btn::before{
    content: '...';
    position: absolute;
    left: -5px;
    color: #333;
    transform: translateX(-100%)
  }

到这里基本已经完成了,但是还有一个问题,当文本较少的时候,隐藏按钮

  • 这里我们可以给容器设置一个 after 伪元素,设置如下样式,这个after就会占据末尾文字所在行的剩余空白空间,
  • 当文本较少,展开按钮跟它在一行的时候,能把展开按钮盖住,达到了隐藏展开按钮的效果
  • 当文本较多,多出的文本被.text容器的overflow:hidden给藏起来,这个时候 after伪元素 跟展开按钮不在一行,展开按钮自然露了出来,达到了文本较多,显示省略号和展开按钮的效果
.text::after {
    content: '';
    width: 100%;
    height: 100%;
    position: absolute;
    background: #fff;
}
  • 当点击展开按钮的时候,需要显示收起按钮,此时收起按钮是被 after 伪元素盖住的,这个时候,就需要把这个伪元素隐藏起来,所以我们需要如下的样式
.exp:checked+.text::after{
  visibility: hidden;
}
// 当被选中的时候,after元素隐藏

到这里,整个实现基本已经完成了,记得给input添加hidden属性,藏起来

总结

关于文本截断,-webkit-box属性并不是所有浏览器都支持的那么完美,所以为了兼容多浏览器,纯css实现的多行文本展开收起,还是比较靠谱的

  • 文本环绕效果首先考虑浮动 float
  • flex布局 子元素可以通过百分比计算高度
  • 多行文本截断可以结合文本环绕效果使用 max-height模拟实现
  • 状态切换可以借助checkbox 使用label和input实现
  • css改变文本可以用伪元素生成
  • 可以多利用css遮挡障眼法