CodeSky 代码之空

随手记录自己的学习过程

CSS 揭秘笔记 - 文字效果

2017-06-10 15:35分类: CSS评论: 3

CSS 其实还是有很多学问的,上次正好说到了文字的一些效果,干脆就把 CSS Secret 中的文字效果都做一下笔记,还是有很多自己原来不知道的黑科技的。

连字符断行

在 Word 中我们经常会用两端对齐的效果,但是在浏览器渲染时会形成文字孤岛的效果,而在打印媒介中,两端对齐往往会伴随连字符的使用,所以在处理对齐时需要调整的间距就少很多,下图展示了 CSS 默认效果:

要想实现连字符,常见的方法有:

  1. 服务端预处理
  2. JavaScript 后期生成
  3. 在线生成器处理
  4. 手工插入软连字符­

怎么想想都觉得不如不用……

于是 CSS3 中引入了一个新的属性 hyphens,只要使用 hyphens: auto 即可实现我们想要的效果,为了确保奏效,你需要在 HTML 标签内插入 lang,当然,实际上这个特性还在草案中,兼容性并不是很好,你可以通过 MDN 看到它的兼容性表:https://developer.mozilla.org/en-US/docs/Web/CSS/hyphens

插入换行

如果我们要定义列表,在考虑语义的情况下,应该使用 <dt><dd>。我们最终所期待的效果如下:

1<dl>
2	<dt>Name:</dt>
3	<dd>Lea Verou</dd>
4	
5	<dt>Email:</dt>
6	<dd>[email protected]</dd>
7	<dd>[email protected]</dd>
8	
9	<dt>Location:</dt>
10	<dd>Earth</dd>
11</dl>
12

当然实际上并不会如我们所想的这么顺利<dt><dd> 都是块级元素,因此如果要实现以下效果,我们可能会开始修改 display 之旅。

加了 display: inline 之后我们的 Name 和 Email 都变成了同行的,看着不太靠谱,尝试打了个换行的补丁(<br>),破坏了原本的语义,所以我们考虑用 CSS 换行,Unicode 中有一个字符专门代表换行符:0x000A,在 CSS 中,这个字符可以写作 \A,我们把它插入到伪元素中,并且加入 white-space: pre 避免空白符和换行符合并:

1dd::after {
2  content: "\A";
3  white-space: pre;
4}
5

看上去我们即将达成效果:

接下来我们只要排除前面的 dd 的影响,只选择最后一个就可以了,可行的方法有许多种,这里我们换个思路,再通过相似的方法给与 dd 相邻的 dd 添加逗号:

1dd + dt::before {
2  content: '\A';
3  white-space: pre;
4}
5
6dd + dd::before {
7  content: ', ';
8  font-weight: normal;
9}
10

如果你的 dd 之间有未加注释的空白符,那么逗号前面会有一个空格,我们这里使用负外边距解决这个问题:

1dd + dd::before {
2  content: ', ';
3  font-weight: normal;
4  margin-left: -.25em;
5}
6

这种方法也有一种 hack 的味道,实际上也不是那么刚好,不过对于大多数字体,这个空隙宽度的不同导致的误差可以忽略,就达成了最终的效果:

文字行的斑马线

在平时我们可能最常用的地方就是代码高亮的渲染上,虽然我博客的代码高亮并没有用

然而如果使用:

1tr:nth-child(even) { background: rgba(0,0,0,.2); }
2

虽然确实能起到隔行换行的左右我们却不得不为每行都添加标签,破坏了语义化。不够理想。

之后我们考虑,可以通过创造条纹背景,调整间距的方法来实现:

1pre {
2  padding: .5em;
3  line-height: 1.5;
4  background: beige;
5  background-image: linear-gradient(rgba(0,0,0,.2) 50%, transparent 0);
6  background-size: auto 3em;
7}
8

加入条纹背景后大致的效果是这样的:

这和我们预期的效果有一定差距,不过距离成功只差一步,background-origin 可以修复这个问题,他告诉浏览器在解析 background-position 时以 content-box 的外沿做基准,而不是 padding-box。

最终我们做到了,如果需要改变 line-height 时,需要同时改变 background-size

调整 Tab 宽度

Tab 宽度默认是 8 字符,非常尴尬,即使是在 GitHub 我们也经常会看到八空白符的 Tab 带来的尴尬。

不过由于有 CSS3,一切都变得美好起来,CSS3 有一个 tab-size 属性可以设置为一个数字(表示字符数)或者长度值,以便我们添加 Tab 空白符,看上去太棒了:

1pre {
2  tab-size: 2;
3}
4

连字

由于字体设计时不同字形不一定会和谐共处,有时候会发生冲突。

所以有就有了连字的存在,有时设计师会设计一些额外的字体,但是浏览器默认并不会使用连字,如果需要使用连字,过去往往使用 Unicode 强制,这样会造成很大的问题:

  1. 结构不可辨识
  2. 当前字体可能不包含连字
  3. 并不是所有连字效果都有对应的 Unicode
  4. 破坏了文本的可访问性,包括复制粘贴和语言处理等等

在 CSS3 中引入了 font-variant-ligatures 属性,它可以帮助你启用连字效果,默认为 normal 而不是 none,需要启动所有可能的连字需要开启:

1font-variant-ligatures: common-ligatures discretionary-ligatures historical-ligatures;
2

如果只需要通用连字,那么只要设置为

1font-variant-ligatures: common-ligatures;
2

可以显式的把其他两种连字关闭:

1font-variant-ligatures: common-ligatures no-discretionary-ligatures no-historical-ligatures;
2

我们可以看下最终的效果:

华丽的 &

有时候我们要指定部分字用非常酷炫的效果,有一种方法是手动规定样式,但是这样需要把每一个字都插入标签,非常麻烦,我们期待在自然的情况下用 CSS 去解决这样的问题。

可以使用仅带这个字的字体,这样似乎就能搞定了,@font-face 会在解析不到其他字体时选择之后的字体方案,而我们需要的字体就用首选方案渲染好了。但是实际上我们还需要对字体本身进行处理,如果是自带的字体,看着就不太靠谱了。

实际上我们可以试用 unicode-range,我们可以通过 JavaScript 获得我们的 Unicode 码位。

1&".charCodeAt(0).toString(16); // 返回26
2

如果你想指定一个字符区间,还是要加上 U+ 前缀,比如 U+400-4FF。 实际上对于这个区间来说,你还可以使用通配符,以这样的方式来写: U+4??。同时指定多个字符或多个区间也是允许的,把它们用逗号隔开即可, 比如 U+26, U+4??, U+2665-2670

最终就可以实现了:

自定义下划线

text-decoration: underline; 默认的功能是在让人捉急,通常我们使用边框来模拟下划线,但是下划线的位置让人觉得尴尬,和文本的空隙很大,并且会受到文本正常换行的干扰,使用 box-shadow 也是一样。

于是我们又想到了 background 的神奇魔法,还可以调整线条,你只需要进行一些简单的设置:

值得庆幸的是,CSS 也在考虑加入 text-decoration-style 等新属性来改善这一情况,就不用再充满 hack 的味道去实现了,当然目前还得不到良好的浏览器支持。

现实中的文字效果

接下来轮到了 text-shadow 的现代魔法时间,这些字体都是可以比较常用于美化文字效果的方法,实现起来也不复杂。(下面的都比较短,就不贴 JSFiddler 了)

凸版印刷效果

我最初见到凸版印刷效果的时候还不会写代码,就觉得相当酷,简单的设置一下 text-shadow 就能实现:

1p {
2	padding: .8em 1em;
3	background: hsl(210, 13%, 60%);
4	color: hsl(210, 13%, 30%);
5	text-shadow: 0 1px 1px hsla(0,0%,100%,.8);
6}
7

预览:https://jsfiddle.net/csvwolf/qjxned96/

空心字效果

见:CSS 文字描边效果的研究

文字外发光效果的研究

外发光是我在 PS 时比较常用的效果(因为套个滤镜就可以了非常简单=_=),要实现这个效果,只需要多重叠几层 text-shadow 即可,颜色只要与文字保持一致,不需要考虑偏移,也非常容易:

1a {
2  text-shadow: 0 0 .1em, 0 0 .3em;
3}
4

预览:https://jsfiddle.net/csvwolf/doe77rrh/

文字凸起效果

文字凸起效果是使用一长串累加的投影,不设模糊并以 1px 的跨度逐渐错开,使颜色逐渐变暗,然后在底部加一层强烈模糊的暗投影,从而模拟完整的立体效果。

1body {
2	background: #58a;
3	color: white;
4	text-shadow: 0 1px hsl(0,0%,85%),
5	             0 2px hsl(0,0%,80%),
6	             0 3px hsl(0,0%,75%),
7	             0 4px hsl(0,0%,70%),
8	             0 5px hsl(0,0%,65%),
9	             0 5px 10px black;
10	font: bold 500%/1 Rockwell, serif;
11}
12

预览:https://jsfiddle.net/csvwolf/vsf3pur5/

环形文字

在 Word 中偶尔我们会使用环形文字,可是在 CSS 中并没有良好的解决方案,我们需要求助于 SVG。SVG 原生支持以任意路径排队文字。

我们需要做的就是用一个 <textPath> 包住这段文本,将他们装进<text>,在上方引入 <path> 规定路径。

1<div class="circular">
2<svg viewBox="0 0 100 100">
3<path d="M 0,50 a 50,50 0 1,1 0,1 z" id="circle" />
4        <text><textPath xlink:href="#circle">
5            circular reasoning works because
6        </textPath></text>
7    </svg>
8</div>
9

于是他可能是长这样的。

之后我们利用 CSS 设置 path 不可见来隐藏黑色的圆形:

1.circular path { fill: none; }
2

接下来最大的问题是,几乎所有的文本都跑到 SVG 元素的外面去了,而且遭到了裁切。为了修正这个问题,我们需要让这个容器元素变小,然后再给 SVG 元素应用 overflow: visible 样式,这样它就不会把内容的溢出部分裁切掉了,此外,我们设置了 margin 来处理溢出元素的占位:

1.circular {
2	width: 30em;
3	height: 30em;
4	margin: 4em auto 0;
5}
6
7.circular svg {
8	display: block;
9	overflow: visible;
10}
11

大功告成。

评论 (3)

mavis2018年3月29日 15:47

条纹背景的那个我试了一下,如果代码内容很多,会出现越来越往上偏移呢

我的IP在路上2017年6月17日 12:04

我也是用typecho,请问用的什么插件,代码高亮好看

Frank_Kang2017年6月16日 16:19

Great!