Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[译] [506] [#25] 华丽的 & 符号 #13

Closed
cssmagic opened this issue Sep 30, 2015 · 1 comment
Closed

[译] [506] [#25] 华丽的 & 符号 #13

cssmagic opened this issue Sep 30, 2015 · 1 comment

Comments

@cssmagic
Copy link
Owner


本文是早期译版,未经校审。仅供参考。


Fancy ampersands

华丽的 & 符号

Prerequisites

  • Basic font embedding through @font-face rules

背景知识

  • 通过 @font-face 规则实现基本的字体嵌入

The problem

难题

You will find many hymns to the humble ampersand in typographic literature. No other character can instantly add the elegance a nicely designed ampersand has the power to add. Entire websites have been devoted to finding the font with the best looking ampersands. However, the font with the nicest ampersand is not necessarily the one you want for the rest of your text. After all, a really beautiful and elegant effect for headlines is the contrast between a nice sans serif font and beautiful, intricate serif ampersands.

在文学作品的字体排印中,你会发现简写的 & 符号倍受推崇。没有其他字符可以像精心设计过的 & 字符那样迅速传递出优雅的气质。所有网站都殚精竭虑,试图找出一种能够体现 & 字符之美的最佳字体。不过,可以显示出优美 & 字符的那些字体往往并不适用于页面中的其他文本。毕竟,对标题来说,真正美丽而优雅的效果正是来源于清爽的无衬线字体与华丽的衬线 & 符号之间的对比

图 5.18

FIGURE

A few nice ampersands in fonts that are readily available in most computers; from left to right: Baskerville, Goudy Old Style, Garamond, Palatino (all italic)

绝大多数电脑都包含了某种可以将 & 符号显示得很好看的字体;从左到右的字体分别为 Baskerville、Goudy Old Style、Garamond 和 Palatino(均以斜体风格显示)。

Web designers realized this a while ago, but the techniques employed to achieve it are rather crude and tedious. They usually involve wrapping every ampersand with a <span>, through a script or manually, like so:

网页设计师们在很早以前就意识到这一点了,但所能找到的实现方法却是十分的粗糙和繁琐。这些方法往往要求我们通过脚本或纯手工地把每个 & 符号用一个 <span> 标签包起来,就像这样:

HTML <span class="amp">&amp;</span> CSS

Then, we apply the font styling we want to just the .amp class:

然后,再给 .amp 这个类指定我们想要的字体样式:

.amp {
    font-family: Baskerville, "Goudy Old Style",
                 Garamond, Palatino, serif;
    font-style: italic;
}
图 5.19

FIGURE

Our “HTML & CSS” headline, before and after the ampersand treatment

这个 “HTML & CSS” 标题中的 & 符号在美化前后的效果对比。

This works fine and you can see the before and after in Figure XX.XX. However, the technique to achieve it is rather messy and sometimes even downright impossible, when we cannot easily modify the HTML markup (e.g., when using a CMS). Can’t we just tell CSS to style certain characters differently?

这种方法确实可以奏效,你可以在 图 5.19 中看到美化前后的对比图。但是,这个实现方法相当杂乱,而且有时还是完全不可行的——在某些情况下(比如在 CMS 环境下),我们根本无法轻易地修改 HTML 结构。难道我们就不能让 CSS 去单独美化某个特定字符吗?

The solution

解决方案

It turns out that we can, indeed, style certain characters (or even ranges of characters) with a different font, but the way to do it is not as straightforward as you might have hoped.

原来我们真的可以用另一种字体来单独美化某个特定字符(或是某个区间内的多个字符),但这个过程可能没有你想像的那么简单明了。

We usually specify multiple fonts (font stacks) in font-family declarations so that in case our top preference is not available, the browser can fall back to other fonts that would also fit our design. However, many authors forget that this works on a per-character basis as well. If a font is available, but only contains a few characters, it will be used for those characters and the browser will fall back to the other fonts for the rest. This applies to both local and embedded fonts included through @font-face rules.

我们通常会在 font-family 声明中同时指定多个字体(即 “字体队列”),这是为了万一当我们最优先指定的那款字体不可用时,浏览器还可以回退到其他符合整体设计风格的字体。但是,很多开发者都忽略了一点:这个机制对单个字符来说也是有效的。如果某款字体可用,但仅包括某几个字符时,那它就只会用来显示这几个字符;而在显示其他字符时,浏览器就会回退到其他字体。这个规则对本地字体和通过 @font-face 规则引入的嵌入字体都是有效的。

It follows that if we have a font with only one character (guess which one!), it will only be used for that one character, and all others will get the second, third, etc. font from our font stack. So, we have an easy way to only style ampersands: create a web font with just the ampersand we want, include it through @font-face, then use it first in your font stack:

在这个规则之下,如果我们有一款字体只包含一个字符(你肯定猜到是哪个了吧),那这款字体将只会用于显示这个字符,而其他字符将会由字体队列中排在第二、第三位或更后面的字体来显示。因此,我们只美化 & 符号的方法就浮出水面了:创建一种只包含我们想要的 & 字形的 Web 字体,通过 @font-face 将其引入到网页中,然后把它排在字体队列中的第一位:

@font-face {
    font-family: Ampersand;
    src: url("fonts/ampersand.woff");
}

h1 {
    font-family: Ampersand, Helvetica, sans-serif;
}

While this is very flexible, it’s suboptimal if all we wanted was to style ampersands with one of the built-in fonts. Not only is it a hassle to create a font file, it also adds an extra HTTP request, not to mention the potential legal issues, if the font you were going for forbids subsetting. Is there a way to use local fonts for this?

这个方法算是比较灵活的,但如果我们只想用系统内建字体中的某一款来美化 & 符号,那这个方法就不够理想了。不仅生成字体文件很麻烦,而且它还会增加一个额外的 HTTP 请求;如果你看中的这款字体并不允许拆解使用,那你可能还要面对版权上的问题。有没有一种办法可以用本地字体来实现这种效果呢?

You might know that the src descriptor in @font-face rules also accepts a local() function, for specifying local font names. Therefore, instead of a separate web font, you could instead specify a font stack of local fonts:

你可能已经了解到 @font-face 规则中的 src 描述符还可以接受 local() 函数,用于指定本地字体的名称。因此,不需要用到任何外部的 Web 字体,你可以直接在字体队列中指定一款本地字体:

@font-face {
    font-family: Ampersand;
    src: local('Baskerville'),
         local('Goudy Old Style'),
         local('Garamond'),
         local('Palatino');
}

However, if you try to apply the Ampersand font now, you will notice that our serif font was applied to the entire text (Figure XX.XX), as these fonts include all characters. This doesn’t mean we’re going the wrong way; it just means we are missing a descriptor to declare that we are only interested in the ampersand glyph from these local fonts. Such a descriptor exists, and its name is unicode-range.

但是,如果你马上就想试试 Ampersand 字体,你会发现整段文本都会被应用为我们指定的某款衬线字体(图 5.20),因为这些字体本身涵盖了这段文本的所有字符。不过这并不表示我们走错了路;这只表示我们还漏了一步没有走——我们还需要一个描述符来声明我们想用这几款本地字体来显示哪些字符。这个描述符确实是存在的,它叫作 unicode-range

图 5.20

FIGURE

Including local fonts through @font-face results in them being applied to the whole text by default

通过 @font-face 引入本地字体,导致这些字体会默认应用到整段文本上。

The unicode-range descriptor only works inside @font-face rules (hence the term descriptor; it is not a CSS property) and limits the characters used to a subset. It works with both local and remote fonts. Some browsers are even smart enough to not download remote fonts if those characters are not used in the page!

这个 unicode-range 描述符只在 @font-face 规则内部生效(因此这里用了 “描述符” 这个术语;它并不是一个 CSS 属性),它可以把字体作用的字符范围限制在一个子集内。它对本地字体和远程字体都是有效的。某些聪明的浏览器甚至可以做到当网页中的所有字符都用不到远程字体时就不去下载!

Unfortunately, unicode-range is as cryptic in its syntax as it is useful in its application. It works with Unicode codepoints, not literal characters. Therefore, before using it, you need to find the hexadecimal codepoint of the character(s) you want to specify. There are numerous online sources for that, or you can just use the following snippet of JS in the console:

这个 unicode-range 在实践中非常实用,但不幸的是它在语法上却非常晦涩。它的语法是基于 “Unicode 码位” 的,而不是基于字符的字面形态。因此,在使用之前,你需要查出你想指定的这些字符的十六进制码位。有不少网上工具可以做这件事情,或者你也可以在控制台试试下面这句 JS 代码:

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

{警告!!}

String#charCodeAt() returns incorrect results for Unicode characters beyond the BMP. However, 99.9% of the characters you will need to look up will be in it. If the result you get is in the D800-DFFF range, it means you have an “astral” character and you’re better off using a proper online tool to figure out what its Unicode codepoint is. The ES6 method String#codePointAt() will solve this issue.

对于 BMP(Basic Multilingual Plane,基本多文种平面)之外的 Unicode 字符来说,String#charCodeAt() 将会返回错误的结果。不过我们日常所需要查询的 99.9% 的字符应该都是在这个范围之内的。如果你得到的结果在 D800-DFFF 区间之内,则意味着这个字符太过 “超凡脱俗”,你最好换用一个靠谱的网上工具来查出它的真实码位。不过 ES6 的 String#codePointAt() 方法已经修复了这个问题。

Now that you have the hex codepoint(s), you can prepend them with U+ and you’ve already specified a single character! Here’s how the declaration would look for our ampersand use case:

这样你就得到了字符的十六进制码位,然后你需要在码位前面加上 U+ 作为前缀。这样一来,我们终于算是指定了一个字符!以 & 符号为例,我们需要这样来声明:

unicode-range: U+26;

If you wanted to specify a range of characters, you would still need one U+, like so: U+400-4FF. In fact, for that kind of range, you could have used wildcards and specified it as U+4?? instead. Multiple characters or ranges are also allowed, separated by commas, such as U+26, U+4??, U+2665-2670. In this case, however, a single character is all we need. Our code now looks like this:

如果你想指定一个字符区间,你还是要加上 U+ 前缀,比如这样:U+400-4FF。实际上对于这个区间来说,你还可以使用通配符,以这样的方式来写:U+4??同时指定多个字符或多个区间也是允许的,把它们用逗号隔开即可,比如这样:U+26, U+4??, U+2665-2670。不过在我们的例子中,只要能指定单个字符就足够了。我们的代码现在就变成这样了:

@font-face {
    font-family: Ampersand;
    src: local('Baskerville'),
         local('Goudy Old Style'),
         local('Palatino'),
         local('Book Antiqua');
    unicode-range: U+26;
}

h1 {
    font-family: Ampersand, Helvetica, sans-serif;
}
图 5.21

FIGURE

Applying a different font to our ampersands, with the help of font stacks and the unicode-range descriptor

借助字体队列和 unicode-range 描述符,我们给 & 符号应用了不同的字体。

If you try it out (Figure XX.XX), you will see that we did, in fact, apply a different font to our ampersands! However, the result is still not exactly what we want. The ampersand in Figure XX.XX was from the italic variant of the Baskerville font, as in general, italic serif fonts tend to have much nicer ampersands. We’re not styling the ampersands directly, so how can we italicize them?

如果你亲手试一试(结果参见 图 5.21),就会发现我们终于给 & 符号应用了不一样的字体!不过,这个结果还不完全是我们所期望的。图 5.19 中的 & 符号是用 Baskerville 字体的斜体风格来显示的,因为一般来说,斜体的衬线字体往往可以显示出更美观的 & 符号。但我们并不是在对 & 符号单独设置样式啊,我们该如何把它设为斜体呢?

Our first thought might be to use the font-style descriptor in the @font-face rule. However, this does not have the effect we want at all. It merely tells the browser to use these fonts in italic text. Therefore, it will make our Ampersand font be completely ignored, unless the whole headline is italic (in which case, we will indeed get the nice italic ampersand).

我们的第一个想法可能是在 @font-face 规则中使用 font-style 描述符。不过这并不会产生我们想要的效果。它只不过是告诉浏览器只在斜体文本中使用这些字体。因此,它会让我们的 Ampersand 字体被完全忽略掉,除非整个标题都是斜体的(确实在这种情况下,& 符号会显示为我们想要的样子)。

Unfortunately, the only solution here is a bit of a hacky one: instead of using the font family name, we need to use the PostScript Name of the individual font style/weight we want. So, to get the italic versions of the fonts we used, the final code would look like this:

很遗憾,我们在这里唯一的出路不得不用到一点儿奇技淫巧:我们在这里不去指定字体的家族名(family name),而是直接指定字体中我们想要的单个风格/字重所对应的 “PostScript 名称”。因此,为了指定这些字体的斜体版本,最终的代码会变成这样:

{原书注释!}

To find a font’s PostScript Name in Mac OS X, select it in the FontBook application and press ⌘I.

如果要在 Mac OS X 中查出某款字体的 “PostScript 名称”,则可以在字体簿程序中选中该字体,然后按 ⌘I

@font-face {
    font-family: Ampersand;
    src: local('Baskerville-Italic'),
         local('GoudyOldStyleT-Italic'),
         local('Palatino-Italic'),
         local('BookAntiqua-Italic');
    unicode-range: U+26;
}

h1 {
    font-family: Ampersand, Helvetica, sans-serif;
}

And this finally works great to give us the ampersands we wanted, just like in Figure XX.XX. Unfortunately, if we need to customize their styling even more (e.g., to increase their font size, reduce their opacity, or anything else), we would need to go the HTML element route. However, if we only want a different font and font style/weight, this trick works wonders. You can use the same general idea to also style numbers with a different font, symbols, punctuation--the possibilities are endless!

最终,这段代码可以完美地将 & 符号显示为我们想要的样式,跟 图 5.19 中的效果如出一辙。不过,如果我们还想进一步对它的样式进行自定义的话(比如增加大字号、改变透明度等等),就只能倒回到修改 HTML 的那条老路了。当然,如果我们只想把它设置为不同的字体或字体中特定的某个风格/字重,那这个技巧堪称完美。你还可以举一反三,用不同的字体来美化数字、符号、标点等等——各种创意完全停不下来!

{试一试} play.csssecrets.io/ampersands


{致敬}

Hat tip to Drew McLellan for coming up with the first version of this effect.

Drew McLellan 脱帽致敬,感谢他提出 这个效果的最初版本


Related specs

相关规范

@Kiris-tingna
Copy link

& 在css 预编译器里经常使用

@cssmagic cssmagic mentioned this issue Oct 20, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants