乐趣区

关于css:深入理解CSS字符转义行为

深刻了解 CSS 字符本义行为

  • 深刻了解 CSS 字符本义行为

    • 前言
    • 为什么要本义?
    • CSS 本义
    • 什么是非法 css 的表达式

      • 左半局部
      • 右半局部
    • 练习
    • 参考链接

前言

在日常的开发中,咱们常常写 css。比方常见的按钮:

<button class="btn"></button>,咱们往往写出这样的款式

.btn {
    display: inline-flex;
    cursor: pointer;
    user-select: none;
    /* ..more decl.. */
}

然而咱们有时候也会见到这样的元素:

<div class="2xl:text-base">Hello world</div>

与之对应失效的 CSS 款式为:

@media (min-width: 1536px) {
  .\32xl\:text-base {
      font-size: 1rem;
      line-height: 1.5rem;
  }
}

这时候就纳闷了,我明明写的是 2xl:text-base 啊?\:这个本义还好说,\3 这个又是哪来的呢?本篇文章就来从 W3C 的角度,对 css本义行为进行揭秘。

为什么要本义?

咱们先把眼光晋升一些,其实 本义 (Escaping) 这个行为,在各个语言零碎中都存在,小到正则表达式,htmlcss,大到 javascript 或者其余成熟的编程语言,都多少存在着这种行为。

那些须要本义的字符,往往是和语言中的特定关键字 (keywords/meta) 产生了抵触,所以被迫让位。

比方,正则表达式中的 . 就是一个元字符,代表的是匹配任意单个除了换行符的字符。要想匹配 . 就须要本义一下写成 \.

html 中的 <,> 须要写成 &lt;&gt;,不然就会和 html 中的标签匹配形式 (<div></div>) 产生抵触。

javascript 中咱们也常常写出这样的单 / 双引号字符串 'i\'m a "happy" fool' or "i'm a \"happy\"fool"

同样 css 也是如此。

CSS 本义

首先让咱们来看看 w3c css 本义的阐明:

https://www.w3.org/TR/css-syntax-3/#escaping

Any Unicode code point can be included in an ident sequence or quoted string by escaping it. CSS escape sequences start with a backslash (\), and continue with:

  • Any Unicode code point that is not a hex digits or a newline. The escape sequence is replaced by that code point.
  • Or one to six hex digits, followed by an optional whitespace. The escape sequence is replaced by the Unicode code point whose value is given by the hexadecimal digits. This optional whitespace allow hexadecimal escape sequences to be followed by “real” hex digits.

从这段阐明中,咱们了解了本义行为具体的逻辑。大抵如下图所示:

\0 是一个十分非凡的字符,本篇文章不对它进行探讨,有趣味能够自行搜寻相应文档。

能够看到本义逻辑是很简略的,无非就是加 \ 判断是否是 16 进制数字,而后进行判断走不同的分支罢了。比方:

<div class="a:">a:</div>

咱们既能够这么写,

.a\: {color: red;}

也能够这么写

.a\3a {color: blue;}

2 个选择器,成果上是等价的,然而它们各自走了不同的本义分支。

什么是非法 css 的表达式

这里咱们以最常应用的 <ident-token> 为例,咱们写的那些具体的选择器的值就须要合乎这样的标准,即:

这类流程图片,置信对正则相熟的同学,一眼就看懂了。

左半局部

咱们先重点看左半局部,能够看到表达式结尾必须以 ---,或者 _, a-z,A-Z,non-ASCII 结尾。

这里解释一下什么是 non-ASCII,实质上就是非 ASCII 字符,也就是 code point > 127 的字符。

接着让咱们来看看相熟可恶的 ASCII 表吧。

通过对照之后,能够筛选出表达式第一个字母的 code point 须要满足的要求是:

code === 45 || // -
code === 95 || // _
(code >= 97 && code <= 122) ||  // a-z
(code >=65 && code<=90) || // A-Z
code > 127 || // non-ASCII
(escape chars) // 或者转义字符

所以依据这个规定,所有不在上述范畴内的 ASCII 字符都须要本义,能力正确表白。留神下面的表达式是不包含数字的哟,所以数字结尾的类名,在写 css 选择器的时候都要进行本义,不管正负值。比方

<div class="2">2</div>

要想写选择器作用在这些元素上,就须要这样写:

.\32 {color: red;}

所以你就理解为什么抉择 class="2" 的这个 css 选择器是 .\32 了,因为这实质上是一个 十六进制(hex) 的字符。\32 换算一下就是 3 * 16 + 2 = 50,而 50 这个 code pointASCII 表里对应的字符就是 2 !

让咱们再来点进阶的例子:

<div class="2b">2b</div>
<div class="2g">2g</div>
<div class="-2g">-2g</div>

对应匹配的 css 选择器为(留神正文):

/* 补全 6 位,不须要跟空格 */
.\000032b {color: blue;}
/* 没有补全 6 位,须要跟空格 */
.\32 b {color: red;}
/* 没有补全 6 位,然而 16 进制示意的字符范畴是 0-f,而字符 g 曾经超出这个范畴,所以空格 可加可不加,而下面的 .\32 b 必须加空格,不然会认为 \32b 是一个 hex 数字整体 */
.\32g {color: red;}
/* 正数结尾,即第一位是 '-',第二位是数字的也须要本义 */
.-\32 g {color: red;}

右半局部

接下来咱们来察看表达式的右半局部。

再定义实现前置局部之后,右侧不止能够承受 _,a-z,A-Z,non-ASCII,也能够承受 0-9,- 这些字符了。用代码来表白则为:

code === 45 || // -
code === 95 || // _
(code >= 48 && code <= 57) || // 0-9
(code >= 97 && code <= 122) ||  // a-z
(code >=65 && code<=90) || // A-Z
code > 127 || // non-ASCII
(escape chars) // 或者转义字符

相比左半局部要宽泛一些。这里我给出一些示例:

<div class="a:b">a:b</div>
<div class="lg:[&:nth-child(3)]:hover:underline"></div>
<div class="bg-[url('/img/hero-pattern.svg')]">
  <!-- ... -->
</div>
<div class="text-[color:var(--my-var)]">...</div>
<div class="before:content-[' 我爱中国 \_icebreaker']">
  <!-- ... -->
</div>

与之对应的那些款式:

/*  
 语法错误
 : 字符是 ASCII 且不在非法范畴内
 须要本义为 \:
*/
.a:b{color: red;}

/* 非法表达式 */
@media (min-width: 1024px) {.lg\:\[\&\:nth-child\(3\)\]\:hover\:underline:hover:nth-child(3) {text-decoration-line: underline;}
}

.bg-\[url\(\'\/img\/hero-pattern\.svg\'\)\] {background-image: url(/img/hero-pattern.svg);
}

.text-\[color\:var\(--my-var\)\] {color: var(--my-var);
}

.before\:content-\[\'\6211\7231\4F60_\4E2D\56FD\\_icebreaker\'\]::before {content: '我爱你 中国_icebreaker';}

练习

如果你曾经了解了上述内容,能够试试为下方的元素增加对应的失效的款式:

<div class="-"> 单个 - 是非凡状况哟 </div>
<div class="我❤️中国, 你好, 世界。"> 我❤️中国, 你好, 世界。</div>
<div class="émotion">émotion</div>
<div class="-3:2yo:ur[x'\ds]">-3:2yo:ur[x'\ds]</div>

参考链接

https://www.w3.org/TR/css-syntax-3/#escaping

https://www.w3.org/TR/css-syntax-3/#ident-sequence

退出移动版