突发奇想!借助CSS自定义彩色字体来实现多行文本展开收起

2,183 阅读8分钟

欢迎关注我的公众号:前端侦探

之前写过这样一篇文章:CSS 实现多行文本“展开收起”,介绍了一些纯 CSS 实现多行文本展开收起的小技巧,特别是右下角的“展开收起”按钮,用到了浮动布局,非常巧妙,有兴趣的可以回顾一下。

Kapture 2023-03-25 at 13.56.18.gif

原本以为已经很完美了,或者说是 CSS 的极限了。但是最近突然冒出一个想法,借助自定义彩色字体也能完美实现这样的效果,而且实现起来更加简单,适用性和兼容性也更强,一起看看吧

一、彩色字体

说到字体图标,大家可能会想到一些平台,比如 iconfontfontawesome 等。没错,我们今天要用到的就是iconfont

在之前一段时期,iconfont 支持了全新的彩色字体图标,让我们可以更加方便的创建自己的彩色字体。

彩色字体(colors fontschromatic fonts)是一种字体技术,它允许在每个字形中使用多种颜色。它不仅可以用在图标和表情符号(emoji)的设计中,也可以用在普通的文本字体中

image.png

有兴趣的可以参考这篇文章:iconfont 支持全新的彩色字体图标 ,这里就不多重复了。简单来说,可以让指定字符渲染成自定义字符,包括彩色图案。

那么,这和本文多行文本展开收起有什么关系呢?

二、通过彩色字体自定义省略号

大家都知道多行文本,可以设置超出省略号

div{
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

效果如下

image.png

虽然这个省略号是自动生成的,但也是真真正正的省略号,只是页面上看不到而已

🤔

🤔

🤔

既然页面无法找到这个省略号,**那是不是可以通过字体改变他的外观?**比如做成展开按钮?

image.png

说干就干,首先在绘图工具上画一个带省略号的展开按钮,下面是figma

image.png

然后将这个 SVG 图标上传到自己的项目中

image.png

上传之后就是这样

image.png

接下来,编辑图标的字符或者Unicode,将这个图标和省略号一一对应,比如省略号就是(注意,中文省略号其实是两个英文省略号组成),或者直接写它的Unicode2026,如下

image.png

保存以后来到项目设置,把字体格式的“彩色”这一项给勾上,如果需要本地化可以勾上“Base64”

image.png

这样准备工作就算完成了,可以通过在线链接得到在线使用方式,如下

image.png

最后,我们将这个字体引入到 CSS 中

@font-face {
  font-family: 'iconfont';  /* Project id 2593077 */
  src: 
       url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAARQAAwAAAAAB0wAAAQCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIi4jGgZgAEQKh0yGHgE2AiQDFgsSAAQgBYF8ByAbtQXIHpIkUAoFJEQgAQAwBc/3+7Vz76qmTW9DUYm7mDXILNMtecQT3hgqZA/1J9RS+MO/p70snZKJVLdDcRD/VID/838u3iiApx9wIHsjm0jFZdo1RZXR8VEVVRkcMB7dsrrWEasO0IsHAAXCQApSS+cIZilOBBfgBi4yeDog4QdH7ZrGfy0f/p8EMP5CqM6udGoHSQiA4Wi8zKAoioAS1wACGI4ZGbUxBnvwpevhvP8AjjXA+e44ilrDhI19kNyei5Ix5AB4g28UMEaEv/7/JOP/86ePniQsIlOdl+qjiEqfYbfR6cTXyfUKBDdOJaEHhA5TqIPhJVfnUclMC65yhdaYm9FK1lYon6UFqWBqcoaOSlQ6j8skW7uNZm7dhcjz7yAZm7cyASou+HEA1OJevzLDOjeNMRFcEC6fVblxOCOe1lVRCIFQcgFYe8DptYywHBKJEEQN/ARI7EJ99Caw6wh/EEVgpA+Hs2qZYLkhEnnHeFrzoYkILShe9J/i5WeJrsgCnmm8+iaxDYIMzqlfEdF1hiDQNsWW7iRBoCWckkLrKCuMkoyuivLSQ6KrcdscGxp9ACvwa8fvo2hlay9v8zBzV98YglRsQJATw49opT/7FG1qY0IqCASZLhzbQesWia7KXVx47SsY0SOXEuD8Pq9XCIgHE5UAeGsDJgvLzoF9zMT85JqD/Rp7xAxgC8vBgRYmTAXnuN7ewNgfo0/YpwL1Mw4liU2JED8gydkEkmTg1wHvdJFRiVFxiHaJtlSKVbUVzdikcNZjF7pUFvVFKaNOh1wmE7TMaYiss6hlfw+eKHGSTDUKlAjUTudTQ8r4S5iDZwtgnmzy5fLBt4Eg7TiJOKNKyRemNDvBSY3rW+s5m3JNHAocm4Y8wYaex2HJxfG6ttyuWl1yPWQ05H0lsoKyeVsg8g8euxaN28NKxIXpi9HbKRU7f7DS+5XSZ05Q/s99Q5sQBTXOkHBZPdsusZD3Z5s/XKZLDOUWt5zY2UF9d8FZ1tz40jlTjm1Bu4nBgT2K4uS3wVTFodTPn3L0VdN0Z6zRNB+h5AsnAzp3XnInyVKJ36+fKb2wIM8gyqZmcVR9dxJ/TbsMJnJVLgxGH516EufpW4HbP60kk3H9n0qpXOcYyRgLWYtIyUjnbKnEgCipG8/jkvGy4Wtf2tZvCvgxhD5nORuj6ibw0ObHwnk/gjhBeLMTBY7BQ6782LcmvFc/Tjqtjg4MYOYxi0PiXvYg27ilv9zNCDDipARC9N9hM1XBEAXgoAIPcGJwAi5SJB1yY6ghnEBiiSGEn5eEA8GEkkwU/iQgjwxyQUwTG2xRNU5aDh8lrbXsIuPzuBDMfYmEwyDfBl0taoPx6exFFAEA') format('woff2'),
       url('//at.alicdn.com/t/font_2593077_78ql8ytgk.woff?t=1632398100463') format('woff'),
       url('//at.alicdn.com/t/font_2593077_78ql8ytgk.ttf?t=1632398100463') format('truetype');
}
.text{
  font-family: 'iconfont';
}

这样,刚才的省略号就变成了这个图标

image.png

由于省略号只是换了个字体,所以当默认省略号消失的时候,这个按钮跟着消失,比如下面是文本较少的时候

image.png

这样就无需借助浮动布局了,并且也能自动隐藏,是不是非常完美?

三、点击展开收起

虽然上面实现了展开按钮,但是是假的,还没有任何点击行为。接下来需要借助input checkbox来实现展开收起行为,原理和之前一样,下面是HTML

<div class="wrapper">
    <input id="exp" class="exp" type="checkbox" hidden>
    <div class="text">欢迎关注前端侦探,这里有一些有趣的、你可能不知道的HTML、CSS、JS小技巧技巧,比如这篇文章,通过iconfont自定义彩色字体来实现多行文本展开收起,一起看看吧</div>
    <label class="btn" for="exp"></label>
</div>

因为视觉上已经有展开按钮了,所以这里的label只需要定位在右下角就行了,并且设置透明度为0,目的是保留点击行为

.btn{
    position: absolute;
    right: 10px;
    bottom: 10px;
    opacity: 0; /*设置透明度为0*/
    cursor: pointer;
}

效果如下

image.png

然后通过:checked控制文本行数

:checked+.text{
    -webkit-line-clamp: 999;
}

这样就可以展开了

Kapture 2023-03-25 at 15.28.30.gif

由于label是隐藏的,所以在展开以后按钮也就不可见的,其实还是在右下角

image.png

因此,我们可以将这个label本身设置成收起的样式,在展开后显示就可以了,这里采用的也是彩色字体

:checked~.btn{
    opacity: 1;
}

这样就简单实现了展开收起

Kapture 2023-03-25 at 15.33.22.gif

四、文本较少时阻止点击

上面的实现在文本较多时很完美,在文本较少时会有点问题。

由于label按钮是定位在右下角的,所以无论文本多少,始终都是可以点击的,如下

image.png

虽然看不见,但可以点击,点击以后,收起按钮就出现了

Kapture 2023-03-25 at 15.43.00.gif

虽然不影响功能,但视觉上还是难以接受,有没有办法阻止这个按钮呢?

这下又需要用一些“障眼法”了,可以用一层足够大容器在文本较少时遮罩右下角的按钮,这里可以用伪元素生成

.text::after{
    content: '';
    position: absolute;
    width: 100vw;
    height: 100vw;
    z-index: 10;
}

注意,这里绝对定位不需要给定偏移量,这样伪元素会跟随文本,也就是当文本没有超过指定行数时,伪元素就会完全覆盖右下角,如下

关于这个绝对定位的小技巧可以参考之前这篇文章:你可能不知道的绝对定位

image.png

这样在文本较少时就可以覆盖右下角的label按钮,无法点击

Kapture 2023-03-25 at 16.00.21.gif

当然,这个背景是不需要的,完全透明的也行,目的只是阻止点击而已,下面是最终效果

Kapture 2023-03-25 at 16.02.08.gif

下面是完整代码,相比之前的实现要少不少

.text {
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: justify;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-height: 1.5;
    font-family: iconfont;
}
.text::after{
    content: '';
    position: absolute;
    width: 100vw;
    height: 100vw;
    z-index: 10;
}
.btn{
    position: absolute;
    right: 10px;
    bottom: 10px;
    opacity: 0;
    cursor: pointer;
    font-family: iconfont;
    line-height: 1.5;
}
.exp:checked+.text{
    -webkit-line-clamp: 999;
}
.exp:checked+.text::after{
    visibility: hidden;
}
.exp:checked~.btn{
    opacity: 1;
}

你也可以访问以下任意链接

五、总结和说明

以上就通过自定义彩色字体实现了多行文本展开收起的功能,相比之前的实现,除了实现上跟简洁之外,还有个比较大的优势在于对于背景没有要求,而不仅仅是纯色,如下

image.png

这种效果在之前的实现中是无法做到的,下面总结一下实现要点:

  1. 时代在变化,技术也在变化,思维也在变化,以前实现的功能可能会有更好的解决方案
  2. 整体思路其实是将默认的省略号自定义成了一个带展开按钮样式的彩色字体
  3. 这样的好处是无需借助布局,然后实现了右下角展开按钮和按钮的自动隐藏
  4. 用一层足够大容器设置绝对定位可以在文本较少时遮罩右下角的按钮
  5. 兼容性极佳,支持彩色字体即可,理论上兼容到 IE9+

整体实现还是非常简单的,只是一般情况下不容易想到,当初 iconfont 宣布支持彩色字体时也没有想到这种应用场景,所以需要一点点想象力。

对了,还有一些小细节,因为改变了省略号的字体,所以如果文本中本身包含有省略号就会变成这样

image.png

当然这个问题也比较好处理,因为文本中的内容是可控的,所以只需要提前用JS将文本内容处理一下,比如给省略号包裹一层标签

text.innerHTML = text.textContent.replace(/(…)/g, '<span>$1</span>')

然后给这个标签设置其他字体就行了

.text span{
  font-family: system-ui;
}

这样就正常了~

image.png

最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤

欢迎关注我的公众号:前端侦探

本文正在参加「金石计划」