CSS 揭秘笔记 - 文字效果

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

连字符断行

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

14970731555270.jpg

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

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

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

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

插入换行

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

<dl>
    <dt>Name:</dt>
    <dd>Lea Verou</dd>
    
    <dt>Email:</dt>
    <dd>lea@verou.me</dd>
    <dd>leaverou@mit.edu</dd>
    
    <dt>Location:</dt>
    <dd>Earth</dd>
</dl>

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

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

dd::after {
  content: "\A";
  white-space: pre;
}

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

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

dd + dt::before {
  content: '\A';
  white-space: pre;
}

dd + dd::before {
  content: ', ';
  font-weight: normal;
}

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

dd + dd::before {
  content: ', ';
  font-weight: normal;
  margin-left: -.25em;
}

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

文字行的斑马线

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

然而如果使用:

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

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

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

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

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

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

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

调整 Tab 宽度

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

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

pre {
  tab-size: 2;
}

连字

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

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

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

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

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

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

font-variant-ligatures: common-ligatures;

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

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

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

华丽的 &

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

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

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

&".charCodeAt(0).toString(16); // 返回26
如果你想指定一个字符区间,还是要加上 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 就能实现:

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

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

空心字效果

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

文字外发光效果的研究

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

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

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

文字凸起效果

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

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

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

环形文字

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

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

<div class="circular">
<svg viewBox="0 0 100 100">
<path d="M 0,50 a 50,50 0 1,1 0,1 z" id="circle" />
        <text><textPath xlink:href="#circle">
            circular reasoning works because
        </textPath></text>
    </svg>
</div>

于是他可能是长这样的。

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

.circular path { fill: none; }

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

.circular {
    width: 30em;
    height: 30em;
    margin: 4em auto 0;
}

.circular svg {
    display: block;
    overflow: visible;
}

大功告成。

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识, 代码段, 语法

已有 3 条评论

  1. Frank_Kang

    Great!

  2. 我的IP在路上

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

  3. mavis

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

添加新评论