如何用css实现多行文本加载更多

1,252 阅读4分钟

如何用css实现多行文本加载更多

前言

之前我在实现该功能的时候专门封装了一个组件用js的状态来控制显示内容,而且由于切换按钮一直存在导致体验也不好,虽然可以用js判断是否超出来控制切换按钮的显隐,但总归是麻烦的。

我们要实现的大概效果如下图所示:

当超过设定行数时:

3.gif 当未超过行数时:

image-20240131172241716.png

思路

问题的关键点其实在于判断是否超过行数,未超过行数时需要隐藏切换按钮。

至于点击切换按钮显示全部行内容,这个通过input的切换状态就可以完成。

还有一个要求就是尽量保持HTML的语意化,因为使用input来切换通常会造成结构有点难以理解。

我们先确定大概的文档结构:

<article class="ac-article">
  <h2>标题</h2>
  <section>
    这里有很多内容………………
  </section>
  <div class="switch">
      <label>
          <span>^</span>
          <input type="checkbox" name="switch" />
      </label>
  </div>
</article>

这个结构是很清晰的,符合从上到下的内容设置。那么对应的css我们设置如下:

  /* 设置一个基本的背景颜色,方便阅读 */
  :root {
      --section-color: #ECEEF0; 
  }
  .ac-article {
      background-color: var(--section-color);
      border-radius: 6px;
      padding: 10px;
  }
  .ac-article h2 {
      text-align: center;
  }
   /* 设置多行省略,在这里可以设置一些属性选择器来设置line-clamp */
  .ac-article section {
      display: -webkit-box;
      -webkit-line-clamp: 3;
      -webkit-box-orient: vertical;
      overflow: hidden;
  }
  
  .ac-article .switch {
      display: flex;
      justify-content: center;
      align-items: center;
  }
   
  .ac-article .switch label{
      transform: translateY(30%);
      font-size: 24px;
      cursor: pointer;
      font-family: monospace;
  }
   /* input默认隐藏,通过label触发 */
  .ac-article .switch label input[name="switch"] {
      display: none;
  }
  /* 这里因为用了^来表示按钮,所以在切换时通过rotate来变化状态 */
  .ac-article .switch label:has(input[name="switch"]:checked) {
      transform: rotate(180deg) translateY(0%);
  }
  /* 在切换按钮时设置行数为一个较大的值,这样自然就可以展开内容了 */
  .ac-article:has(input[name="switch"]:checked) section {
      -webkit-line-clamp: 9999;
  }

到这里,其实我们已经完成了切换显示全部内容的功能。

实际效果如下:

剩下就是考虑怎么在行数较少的情况下,将切换按钮隐藏。

第一点,css中没有判断行数的伪类,我们想要隐藏是不太可能了,只可能盖住切换按钮,让它看起来“隐藏”了。

所以我们大概的思路就是在section元素里面加一个::after伪类,设置为block,这样它可以一直在section的尾行,当行数较多时,它会在底部,当行数较少时,它就直接覆盖切换按钮。

看起来是这样(橙色的是伪类):

image-20240131181812761.png

image-20240131180724842.png

在行数较少时,可以看到达到了我们的目标,盖住了切换按钮。

但也可以看到after伪类会超出显示,因为我们还没有设置section的position为relative。然后我们设置section的position为relative,使伪类只能在section中显示。

但是这样的话::after会因为overflow:hidden被隐藏,反而起不到效果。

image-20240131181055224.png

而我们通过overflow:hidden的定义得知:

如果需要,内容将被裁减以适应边距(padding)盒。不提供滚动条,也不支持允许用户滚动(例如通过拖拽或者使用滚轮)。内容可以以编程的方式滚动(例如,通过设置 scrollLeft 等属性的值或 scrollTo() 方法), 因此该元素仍然是一个滚动的容器。

判断的边界是padding,所以我们将section的底部padding设置为切换按钮的高度,然后将切换按钮设置margin为负高度值。

/* section设置底部padding */
.ac-article section {
    position: relative;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /*+++++*/
    padding-bottom: 28px;
}
/* section伪类,为了凸显设置为橙色背景 */
.ac-article section::after {
    position: absolute;
    display: block;
    content: '';
    width: 100%;
    height: 28px;
    /* background-color: var(--section-color); */
    background-color: #ee8262;
    z-index: 3;
}
/* 设置切换按钮负margin,并设置zIndex小于after伪类,这样才能盖住 */
.ac-article .switch {
    display: flex;
    justify-content: center;
    align-items: center;
    /*++++*/
    margin-top: -28px;
    position: relative;
    z-index: 2;
    background-color: var(--section-color);
}

设置完如下:

image-20240131180639210.png

image-20240131181848335.png

可以看到已经实现了效果,接下来我们只要替换掉颜色,并且保证在切换按钮点击状态下不被::after覆盖即可

.ac-article section::after {
    position: absolute;
    display: block;
    content: '';
    width: 100%;
    height: 28px;
    /*++*/
    background-color: var(--section-color);
    /*++*/
    z-index: 3;
}
.ac-article:has(input[name="switch"]:checked) section::after {
    visibility: hidden;
}

完整代码效果演示如下:

参考链接: developer.mozilla.org/zh-CN/docs/…

--分割线--2024/02/19
在移动端上特殊场景会有一些问题,建议在pc上使用。