9.1 文字的美化与装饰

2023/9/1 CSS

# 9.1.1 文字阴影属性text-shadow

text-shadow是文字阴影,box-shadow是盒阴影,两者语法类似,但仍有两点区别。

  • text-shadow不支持inset关键字,也就是text-shadow只有外阴影,没有内阴影。
  • text-shadow不支持阴影扩展,也就是text-shadow最多支持3个数值,分别表示水平偏移垂直偏移模糊大小,例如:
/* 分别往右方、下方偏移1px,同时模糊2px */
text-shadow: 1px 1px 2px black;
1
2

box-shadow属性最多支持4个数值。

除了上面两点区别,text-shadow和box-shadow属性的其他语法特性都是一样的,包括支持任意数量的阴影叠加。我们可以利用这一特性实现文字3D立体投影效果,例如:

<span class="text-shadow-3d">立体投影</span>

.text-shadow-3d {
 font-size: 60px;
 color: deepskyblue;
 text-shadow: 1px 1px #005A79, 2px 2px #005A79, 3px 3px #005A79, 4px 4px #005A79, 
              5px 5px #005A79, 6px 6px #005A79, 7px 7px #005A79, 8px 8px #005A79;
}
1
2
3
4
5
6
7
8

实现的效果如图9-1所示。

图9-1 文字3D立体投影效果示意

图9-1 文字3D立体投影效果示意


利用这一特性也可以实现文字外描边效果,例如:

<p class="text-stroke-out">外描边</p>

.text-stroke-out {
 font-size: 60px;
 color: #fff;
/* 如果描边宽度只有1px,则只需要4个方向的偏移,
因为这里描边宽度为2px,所以使用了8个方向的偏移 */
 text-shadow: 0 2px deeppink, 2px 0 deeppink, 0 -2px deeppink, -2px 0 deeppink, 
 2px 2px deeppink, -2px -2px deeppink, -2px 2px deeppink, 2px -2px deeppink;
}
1
2
3
4
5
6
7
8
9
10

实现的效果如图9-2所示。

图9-2 文字外描边效果示意

图9-2 文字外描边效果示意


查看案例 (opens new window)

text-shadow属性可以在::first-line::first-letter这两个伪元素中生效。IE9浏览器并不支持text-shadow属性,从IE10浏览器才开始支持该属性。

# 9.1.2 文字描边属性text-stroke

接下来介绍两个非标准但比较实用的CSS属性:text-stroketext-fill-color。顾名思义,两者分别用来实现文字描边效果和文字颜色填充效果。

兼容性

-webkit-text-stroke-webkit-text-fill-color的兼容性如表9-1所示。

表9-1 -webkit-text-stroke和-webkit-text-fill-color的兼容性


目前没有任何浏览器支持不需要-webkit-私有前缀的语法。另外,text-stroketext-fill-color属性的兼容性在移动端非常好。

# 1.text-stroke属性的语法

text-stroke属性的语法并不复杂,它与borderbackground属性类似,是若干个CSS属性的缩写。

text-stroke属性是text-stroke-widthtext-stroke-color这两个CSS属性的缩写,分别表示文字描边的宽度和文字描边的颜色。有别于border属性,text-stroke属性无法指定文字描边的类型,只支持实线描边,不支持点线或者虚线描边,也无法指定描边是外描边还是内描边居中描边(SVG描边中的stroke属性支持虚线描边外描边)。该属性的语法简单示意如下:

.stroke {
 -webkit-text-stroke: 2px red;
}
1
2
3

等同于:

.stroke {
 -webkit-text-stroke-width: 2px;
 -webkit-text-stroke-color: red;
}
1
2
3
4

text-stroke属性的另外一个和border属性的不同之处是宽度的默认值。border-width属性的宽度默认值是medium,最终表现等同于设置值为3px,但是text-stroke-width属性的宽度 默认值却是0(虽然text-stroke-width属性也支持medium关键字),这就意味着,当我们使用text-stroke属性的时候,是一定要设置描边的宽度值的。

至于描边的颜色,理论上可以不设置。但是由于描边的颜色默认是color属性的计算值,和文字自身的颜色一致,因此,如果不设置描边的颜色,最终的样式表现并不是描边,而是文字加粗效果,例如:

.stroke {
 font-size: 40px;
 -webkit-text-stroke: 2px;
}
1
2
3
4

实现的效果如图9-3所示。

图9-3 文字描边产生的加粗效果示意

图9-3 文字描边产生的加粗效果示意


实际开发的时候,确实存在需要使用特别粗的文字来表示强调的场景,因此上面的案例还是有一定的使用价值的。

# 2.text-stroke是居中描边

在日常开发中,文字的笔画粗细都是1px~2px,如果此时再设置一个居中描边效果,文字原本的颜色几乎都会被描边颜色覆盖,效果会很糟糕。例如下面这个例子,设置了40px粗细的文字和2px粗细的描边效果:

.stroke {
 font-size: 40px;
 -webkit-text-stroke: 2px red;
}
1
2
3
4

结果如图9-4所示。可以看到,下方设置了描边的文字中原本的黑色只剩丝丝残余,因为描边的一半,也就是1px粗细的红色描边覆盖了原本的黑色文字轨迹,所以最终的效果就变得有些奇怪。

图9-4 文字描边是居中描边效果示意

图9-4 文字描边是居中描边效果示意


我们实际开发更需要的则是外描边效果。不过存在即合理,虽然text-stroke属性无法实现我们预想的描边效果,但是可以用来实现削弱文字字重的效果。

# 3.text-stroke实现低字重字体效果

现代开源字体,例如思源黑体思源宋体苹方等字体,都有丰富的字重,给字体设置font-weight:100和font-weight:400后可以明显看出文字的笔画粗细不一样;但是对于微软雅黑字体,由于其缺失字重,设置font-weight:100和font-weight:400渲染出来的文字效果都是一样的,笔画都是正常粗细。

设置字体笔画的粗细在macOS中很好实现,因为苹方等字体字重丰富;而在用户使用率最高的Windows操作系统中,内置的中文字体字重缺失,就无法渲染出极细的文字。有了text-stroke的居中描边特性,理论上,在Windows操作系统中就有了字重缺失的解决方案。方法就是将描边颜色设置成和文字所在的背景色一样的颜色。

图9-5就是在Chrome浏览器1倍屏中不同描边宽度的渲染效果图。

图9-5 Chrome浏览器1倍屏中文字描边后的粗细效果示意

图9-5 Chrome浏览器1倍屏中文字描边后的粗细效果示意


可以看到文字笔画确实变细了,但同时文字看起来变淡了,或者说文字变淡让文字看起来更细了。出现这种效果的原因很简单,即屏幕密度太低。屏幕最小的显示单位为1px,所以,要想使描边宽度小于1px的描边效果生效,就需要用特殊的文字边缘渲染算法进行视觉上的处理,这种算法处理就会导致文字颜色看起来比较淡。

text-stroke与文字font-weight字重变细实例页面 (opens new window)

如果屏幕密度较高,例如iMac的5K屏幕和手机屏幕,渲染出的效果就会很理想。 例如,在3倍屏的Android手机中,最终的渲染效果如图9-6所示(1/2缩放大小)。

图9-6 Android手机3倍屏中文字描边后的粗细效果示意

图9-6 Android手机3倍屏中文字描边后的粗细效果示意


因此,text-stroke属性在让文字笔画变细并降低文字字重的技术上是没有任何问题的,关键就看用户的显示器的屏幕密度是否足够。移动端项目使用此技术没有任何顾虑;如果是桌面端项目,用户的显示设备一般都是普通的1倍屏显示器,因此建议在文字字号较大的场景中使用该技术,效果会好很多。

如果想要实现文字的外描边效果,一种方法是使用text-shadow属性模拟,这一点在9.1.1节已经展示过了。不过text-shadow实现的并不是真正的外描边效果,因为一个矩形四面投影的时候,4个边角实际上会有空隙,如果再加上4个边角的投影以修复间隙的问题,又会有重复投影的问题。实际上,使用text-stroke属性是可以实现效果更好的外描边效果的,只是操作上要复杂一些,不适合大段文字的场景。实现该效果的原理很简单:设置两层文字,下层的文字有描边,上层的文字没有描边。例如:

<span class="text-stroke-out" data-content="外描边">外描边</span>

.text-stroke-out {
 font-size: 60px;
 -webkit-text-stroke: 4px deeppink;
 letter-spacing: 4px;
}
[data-content]::before {
 content: attr(data-content);
 position: absolute;
 -webkit-text-stroke: 0;
 color: deepskyblue;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

text-stroke与文字外描边效果实例页面 (opens new window)

# 9.1.3 文字颜色填充属性text-fill-color

使用text-fill-color属性可以对文字进行颜色填充,还可以覆盖color属性设置的颜色,注意,只是覆盖color的渲染表现,实际上元素的颜色计算值还是由color属性决定的。

text-fill-color属性的语法使用示意如下:

-webkit-text-fill-color: transparent;
-webkit-text-fill-color: deepskyblue;
-webkit-text-fill-color: #228bff;
-webkit-text-fill-color: rgba(100, 200, 0, .6);
1
2
3
4

text-fill-color与渐变图像、常规图像文字填充效果实例页面 (opens new window)

text-fill-color属性还有另外一个作用,那就是在改变文字颜色的同时保护color属性。为什么color属性需要被保护呢?主要有以下两个原因。

  • color属性具有继承性,可以通过改变祖先元素的color值改变子元素的样式,方便维护与管理。
  • CSS中很多事物的默认颜色都是由color属性决定的,例如输入框中光标颜色边框色盒阴影颜色文字阴影颜色等。此时,如果希望光标颜色和文字颜色不一样,或者希望在CSS文字阴影语法上省略色值的同时让阴影颜色和文字颜色不一样,则文字颜色就不能使用color属性实现,color属性需要被保护。

# 1.容器元素改变color值实现换肤

button {
 background-color: black;
 color: #fff;
}
1
2
3
4

black是此时的主题色,要想black继承祖先元素的color属性值,我们第一反应就是使用currentColor关键字,代码如下:

button {
 background-color: currentColor;
 color: #fff;
}
1
2
3
4

但是,上面的写法显然是无效的,因为button选择器自己设置了color:#fff,所以此时background-color的值也是#fff,而非祖先元素的color属性值。这就是一个典型的color属性需要被保护的场景,此时,按钮文字颜色设为白色,就不能使用color属性,但可以使用text-fill-color属性,代码如下:

button {
 color: inherit; /* 因为按钮元素默认自身也有色值,所以这里重置 */
 background-color: currentColor;
 -webkit-text-fill-color: #fff;
}
1
2
3
4
5

此时,按钮的background-color色值就是由祖先元素决定的。

模块各个主要颜色通过color属性控制实例页面 (opens new window)

# 2.简化text-shadow的代码

.text-shadow-3d {
 font-size: 60px;
 color: deepskyblue;
 text-shadow: 1px 1px #005A79, 2px 2px #005A79, 3px 3px #005A79, 4px 4px #005A79,
  5px 5px #005A79, 6px 6px #005A79, 7px 7px #005A79, 8px 8px #005A79;
}
1
2
3
4
5
6

其中,色值#005A79出现了8次,如果要更换阴影色值,就需要替换8处,因此代码维护就比较麻烦,但可以使用text-fill-color属性进行优化,CSS代码如下:

.text-shadow-3d {
 font-size: 60px;
 -webkit-text-fill-color: deepskyblue;
 color: #005A79;
 text-shadow: 1px 1px, 2px 2px, 3px 3px, 4px 4px, 5px 5px, 6px 6px, 7px 7px, 8px 8px;
}
1
2
3
4
5
6

text-fill-color优化text-shadow 3D投影效果实例页面 (opens new window)

# 9.1.4 学会使用text-emphasis属性进行强调装饰

过去要想对某部分文字进行强调,通常的做法是加粗文字,或者给文字使用一个高亮的颜色;现在有了新的选择,即使用text-emphasis属性对文字进行强调装饰。

text-emphasis家族总共有如下4个CSS属性:

  • text-emphasis-color
  • text-emphasis-style
  • text-emphasis-position
  • text-emphasis

其中,text-emphasis是text-emphasis-colortext-emphasis-style这两个CSS属性的缩写。注意,text-emphasis并不包含text-emphasis-position属性,text-emphasis-position属性是独立的

# 1.text-emphasis-color

text-emphasis-color属性没什么好说的,它用来设置强调的字符的颜色,初始值就是当前文字的颜色。

# 2.text-emphasis-style

text-emphasis-style语法主要有下面3类:

text-emphasis-style: none
text-emphasis-style: [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ]
text-emphasis-style: <string>
1
2
3

其中,text-emphasis-style:none是默认声明,表示没有任何强调装饰。text-emphasis-style:<string>表示使用任意单个字符作为强调装饰符。

text-emphasis-style任意字符强调效果实例页面 (opens new window)

  • 显示的强调装饰符的字号大小是主文字内容字号大小的一半,例如文字的大小是16px,则上方的强调字符的大小则是8px。因此,在文字字号不是很大的时候,尽量不要使用造型复杂且字符区域较小的字符,如星号(*)和井号(#)等符号会在普通的显示设备中缩成一团,用户完全看不出来是什么字符。
  • 如果行高不是很高,则强调装饰符会自动增加当前这一行所占据的高度。
  • 强调装饰符和正文之间的距离是无法通过设置行高等属性进行调节的,距离的大小主要由字体决定。
  • 如果指定的是多个字符,则只会使用第一个字符作为强调装饰符。例如:
text-emphasis-style: 'CSS新世界';
1

等同于:

text-emphasis-style: 'C';
1

text-emphasis-style内置的几个装饰符效果,它们分别是dot(点)、circle(圆)、double-circle(双层圆)、triangle(三角)和sesame(芝麻点)。每一种装饰符都有实心和空心两种类型,这两种类型是由filledopen这两个关键字决定的。例如:

/* 实心的圆点 */
text-emphasis: filled dot;
/* 空心的圆点 */
text-emphasis: open dot;
1
2
3
4

由于内置字符都默认使用实心字符,因此text-emphasis:filled dot的效果等同于text-emphasis:dot。如果text-emphasis-style的属性值只有filled或open,则会采用dot作为强调装饰符。例如:

/* 等同于text-emphasis: filled dot */
text-emphasis: filled;
/* 等同于text-emphasis: open dot */
text-emphasis: open;
1
2
3
4

表9-2 强调装饰符的效果示意

表9-2 强调装饰符的效果示意

各个强调装饰符的字形大小受字体影响较大,要根据实际场景选择合适的强调装饰符。

# 3.text-emphasis-position

text-emphasis-position属性用来指定强调装饰符的位置,默认位置是在文字的上方,我们可以指定强调装饰符在文字的下方,也可以指定在文字竖向排版的时候强调装饰符是位于文字左侧还是位于文字右侧。

text-emphasis-position属性的语法如下:

text-emphasis-position: [ over | under ] && [ right | left ]
1

使用示意如下:

text-emphasis-position: over left;
text-emphasis-position: under right;
text-emphasis-position: under left;
text-emphasis-position: left over;
text-emphasis-position: right under;
text-emphasis-position: left under;
1
2
3
4
5
6

text-emphasis-position的初始值是over right。right定位用在文字竖向排版的时候,例如在设置writing-mode: vertical-rl后就可以看到强调装饰符在文字右侧了,效果如图9-14所示。

图9-14 强调装饰符在文字右侧的效果示意

图9-14 强调装饰符在文字右侧的效果示意


在强调中文内容时,除了要设置强调装饰符,还要设置强调装饰符的位置在文字底部,例如:

.chinese-emphasis {
 -webkit-text-emphasis: dot;
 text-emphasis: dot;
 -webkit-text-emphasis-position: under right;
 text-emphasis-position: under right;
}
1
2
3
4
5
6

在Chrome浏览器中,text-emphasis-position属性可以只设置垂直方向的方位值,无须设置水平方向的方位值。例如,下面的语法在Chrome浏览器中也是可以识别的:

-webkit-text-emphasis-position: under;
1

Chrome浏览器的这个做法其实是不对的,与规范中的描述不相符。规范要求text-emphasis-position属性值同时包含水平方位和垂直方位,因此建议还是同时设置两个值。

-webkit-text-emphasis-position: under right;
1

# 4.text-emphasis

text-emphasis是text-emphasis-colortext-emphasis-style这两个CSS属性的缩写,使用示意:

text-emphasis: circle deepskyblue;
1

text-emphasis是一个继承属性。这一点就和text-decoration属性完全不同,text-decoration属性是没有继承性的。另外一点小区别是text-emphasis属性会影响文字占据空间的高度,而text-decoration属性不会。

表9-3 text-emphasis属性的兼容性


Last Updated: 2025/7/13 10:30:39