三套转义:HTML / CSS / JS 怎么写出一个码位
字符的编码 那页讲清了「码位(code point)」是什么。那么知道了码位——比如 😀 是 U+1F600——怎么在源码里把它写出来?HTML、CSS、JS
各有一套转义语法:😀、\1F600、\u{1F600}。三套长得像、规则各不同,且各有一个易错点:CSS 的转义会贪心吞掉后面的 hex 字符,HTML 的数字引用不认代理对,JS 的 \uXXXX 工作在码元层、能造出「半个字符」。
1 · 同一个码位的各家写法
三条路各自走完,都该渲染出同一个字符。
2 · 易错点一:CSS 转义在哪结束
CSS 的转义是 \ 加 1~6 位 hex,没有花括号包边界——解析器会贪心吃 hex 字符,直到凑满 6 位或撞上非 hex 字符。想在转义后紧跟 A 或 0~9、a~f 这类字符,要么加一个终结空格(会被吞掉、不显示),要么把转义补零写满 6 位。
注 · 真想显示「转义 + 空格」时,因为终结空格会被吞,要写两个空格,或把空格也转义成 \20。另外 CSS 转义不只用在字符串里——标识符也靠它:id 以数字开头时选择器得写 #\31 st(1 是 U+0031),JS 里有现成的
CSS.escape('1st') 可以算。还有一处「直接写码位」的 CSS 语法是 unicode-range: U+4E00-9FFF,见 font-features 的 unicode-range 页。
3 · 易错点二:HTML 数字引用只认码位
HTML 的字符引用永远工作在码位层:十进制 😀、十六进制 😀,再大的码位直接写。反过来,把 UTF-16 代理对(字符的编码 里的 D83D + DE00)拆成两个引用拼不出 😀——代理区
U+D800~DFFF 不是合法字符,每个都被替换成 U+FFFD(�)。
4 · 易错点三:JS \uXXXX 在码元层
JS 字符串按 UTF-16 码元存,\uXXXX(恰 4 位)写的就是一个码元——所以单写一个高位代理 '\uD83D' 完全合法,得到一个 lone surrogate:长度 1、渲染成 �、传给只收合法 UTF-8 的 API(fetch body、TextEncoder)会被换成 U+FFFD。ES6 的
\u{…} 才工作在码位层。
isWellFormed() 读数。可点选写法逐个查看。
注 · 检测与修复:str.isWellFormed() 查字符串里有没有 lone surrogate,str.toWellFormed() 把它们替换成 U+FFFD(ES2024,现代浏览器均已支持,核对于 2026-08)。「为什么 astral 字符要拆成两个码元、怎么算」见
字符的编码。
5 · 速查:一个码位的全部写法
| 写法 | 用在哪 | 位数 | astral (>U+FFFF) |
|---|---|---|---|
😀 / 😀 |
HTML 文本、属性值 | hex / 十进制,任意位 | ✓ 直接写码位 |
— 等命名实体 |
HTML 文本(仅限有名字的字符) | — | 仅已命名字符 |
\1F600(+ 终结空格) |
CSS 字符串、标识符 | hex 1~6 位 | ✓ |
\u{1F600} |
JS 字符串 / 模板 / 正则(需 u/v) |
hex 1~6 位 | ✓ |
\uD83D\uDE00 |
JS、JSON(它只有这一种) | hex 恰 4 位 = 1 码元 | 要手拆代理对 |
\xE9 |
JS | hex 恰 2 位 | ✗ 仅 U+0000~00FF |
String.fromCodePoint(0x1F600) |
JS 运行时(读取端是 codePointAt / for...of) |
— | ✓ |
建议 · MDN 的 UTF-16 characters, Unicode code points, and grapheme clusters 把本页 JS 半边讲全:String 按码元工作、lone
surrogate 的来源(slice 切半也会造出它)、isWellFormed / toWellFormed、按码位遍历。「用户眼里的一个字符」还要再往上一层,见 字素簇。
6 · 参考文献
- WHATWG. HTML Standard §Named character references. 命名实体那一套的权威清单:逐条列出全部 2200 多个 named character reference 及其码位,并说明哪些可省略结尾分号。html.spec.whatwg.org
-
Chromium.
html_entity_names.csv. 浏览器引擎里这张表的样子:2231 行「实体名 → 码点」,构建期由make_html_entity_table.py生成html_entity_table.h,编译进 Blink 的 entity-matching 状态机。source.chromium.org