草庐IT

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

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

Kapture 2023-03-25 at 13.56.18

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

一、彩色字体

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

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

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

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

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

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

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

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

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

?

?

?

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

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

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

上传之后就是这样

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

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

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

最后,我们将这个字体引入到 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';
}
这样,刚才的省略号就变成了这个图标

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

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

三、点击展开收起

虽然上面实现了展开按钮,但是是假的,还没有任何点击行为。接下来需要借助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;
}
效果如下

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

:checked+.text{
-webkit-line-clamp: 999;
}
这样就可以展开了

Kapture 2023-03-25 at 15.28.30

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

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

:checked~.btn{
opacity: 1;
}
这样就简单实现了展开收起

Kapture 2023-03-25 at 15.33.22

四、文本较少时阻止点击

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

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

image-20230325154207642

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

Kapture 2023-03-25 at 15.43.00

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

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

.text::after{
content: '';
position: absolute;
width: 100vw;
height: 100vw;
z-index: 10;
}
注意,这里绝对定位不需要给定偏移量,这样伪元素会跟随文本,也就是当文本没有超过指定行数时,伪元素就会完全覆盖右下角,如下

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

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

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

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

.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;
}
你也可以访问以下任意链接

  • CSS color font expand (juejin.cn)[6]
  • CSS color font expand (runjs.work)[7]
  • CSS color font expand (codepen.io)[8]

五、总结和说明

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

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

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

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

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

text.innerHTML = text.textContent.replace(/()/g, '<span>$1</span>')
然后给这个标签设置其他字体就行了

.text span{
font-family: system-ui;
}
这样就正常了~

参考资料

[1]CSS 实现多行文本“展开收起”: https://juejin.cn/post/6963904955262435336

[2]iconfont: https://www.iconfont.cn/

[3]fontawesome: https://fontawesome.com/v6/search?o=r&m=free&s=regular%2Csolid

[4]iconfont 支持全新的彩色字体图标 : https://juejin.cn/post/6969503906112438303

[5]你可能不知道的绝对定位: https://juejin.cn/post/7204633786934607929

[6]CSS color font expand (juejin.cn): https://code.juejin.cn/pen/7214394078740840508

[7]CSS color font expand (runjs.work): https://runjs.work/projects/bda441664b394ec0

[8]CSS color font expand (codepen.io): https://codepen.io/xboxyan/pen/QWVzPvg

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

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby - capybara field.has_css?匹配器 - 2

    我在MiniTest::Spec和Capybara中使用以下规范:find_field('Email').must_have_css('[autofocus]')检查名为“电子邮件”的字段是否具有autofocus属性。doc说如下:has_css?(path,options={})ChecksifagivenCSSselectorisonthepageorcurrentnode.据我了解,字段“Email”是一个节点,因此调用must_have_css绝对有效!我做错了什么? 最佳答案 通过JonasNicklas得到了答案:No

  3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  6. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

    这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f

  7. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  8. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  9. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

  10. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

随机推荐