Skip to main content

CSS Basic Notes

CSS Working Group

  • CSS working group: CSS WG.
  • W3C standard types:
    • ED: Editor's Draft.
    • FPWD: First Public Working Draft.
    • WD: Working Draft.
    • CR: Candidate Recommendation.
    • PR: Proposed Recommendation.
    • REC: a W3C Recommendation is a W3C Technical Report.

W3C Standard Process

CSS Cascading and Inheritance

Cascading Order

  1. Inherit styles.
  2. User agent normal styles.
  3. User normal styles.
  4. Author @layer normal styles.
  5. Author normal styles.
  6. Animation styles.
  7. Author !important styles.
  8. Author @layer !important styles.
  9. User !important styles.
  10. User agent !important styles.
  11. Transition styles.

Transition > Animation > Normal > @layer > User > User Agent > Inherit

Important Styles Reversion
  • 级联水平高的 styles 应用 !important 后, 其优先级变低.
  • 级联水平低的 styles 应用 !important 后, 其优先级变高.

CSS Cascading

Layer

Layer Formal Syntax

@layer formal syntax:

@layer [<layer-name># | <layer-name>?  {
<stylesheet>
}];
@layer base;
@layer theme, layout, components, utilities;

@layer base {
html {
font-size: 1rem;
}
}

@layer {
html {
font-size: 1rem;
}
}
@layer reset, externals, base, components, utilities;

@import url('reset.css') layer(reset);
@import url('carousel.css') layer(externals);
@import url('map.css') layer(externals);
<link rel="stylesheet" href="reset.css" layer="reset" media="supports(at-rule(@layer))" />

Layer Specificity

/* utilities > components > layout > theme */
@layer theme, layout, components, utilities;

/* c > c.d > a > a.b */
@layer a {
p {
color: red;
}

@layer b {
p {
color: green;
}
}
}

@layer c {
p {
color: orange;
}

@layer d {
p {
color: blue;
}
}
}

Layer Priority

Scope

@scope:

  • 局部上下文: 生效元素必须为 @scope 的子元素
  • 规则完整性: 规则中的每一行代码, 必须属于一个完整的规则, 不能是一条单独的 CSS 声明.
<section class="scope-root">
<h3>Scope Root</h3>
<p>Paragraph 1</p>
<!-- Selected -->
<img src="image.jpg" alt="Image" />
<p>Paragraph 2</p>
<figure class="scope-limit">
<!-- Not selected -->
<img src="image.jpg" alt="Image" />
<figcaption>Figure Caption</figcaption>
</figure>
</section>
@scope (.scope-root) to (.scope-limit) {
img {
background-color: red;
}

& img {
background-color: red;
}

:scope img {
background-color: red;
}
}

Nesting

& nesting:

ul {
& + & {
font-weight: bold;
color: red;
}
}

Specificity

Specificity (Selector Priority) has 4 bits, thousands, hundreds, tens, ones 0000:

  • Thousands: inline-style.
  • Hundreds: ID selector (实际开发中一般用 [id="Id"] 代替优先级过高的 ID selector).
  • Tens: class selector, attribute selector, pseudo class(:).
  • Ones: type selector, pseudo element(::).
Zero Specificity
  • Universal selector (*), combinators (+, >, ~, a b) and :where() have no effect on specificity.
  • :not()/:is()/:has() have no effect on specificity, but selectors in it have effect on specificity.
<!-- specificity: 1000 -->
<h1 style="color: black">Hello</h1>
/* specificity: 0001 */
h1 {
color: red;
}

/* specificity: 0100 */
#id {
color: green;
}

/* specificity: 0003 */
h1 + p::first-letter {
color: blue;
}

/* specificity: 0022 */
li > a[href*='link-url'] > .inline-warning {
color: yellow;
}

/* specificity: 0023 */
div li:nth-child(2) a:hover,
div li:nth-child(2) a:focus {
border: 10px dashed black;
}

/* specificity: 0024 */
div div li:nth-child(2) a:hover,
div div li:nth-child(2) a:focus {
border: 10px solid black;
}

/* specificity: 0033 */
div div .nav:nth-child(2) a:hover,
div div .nav:nth-child(2) a:focus {
border: 10px double black;
}

/* specificity: 0101 */
#outer a {
background-color: red;
}

/* specificity: 0104 */
#outer div ul li a {
color: yellow;
}

/* specificity: 0113 */
#outer div ul .nav a {
color: white;
}

/* specificity: 0201 */
#outer #inner a {
background-color: blue;
}

Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule:

#parent {
color: green;
}

/* <h1> element will be purple */
h1 {
color: purple;
}

Increasing specificity by duplicating selector:

.my-class.my-class.my-class span {
/* 0-3-1 */
color: white;
}

:is(.my-class.my-class.my-class, span) {
/* 0-3-0 */
color: white;
}

Inheritance

  • Most CSS properties that affect the text node are inherited properties: color, font-size, font-family, etc.
  • Most CSS properties that affect the element node are non-inherited properties.
  • When the unset value is set on an inherited property, it resets the property value to its inherited value.
  • unset value resets a non-inherited property to its initial value.
  • revert reverses the CSS default values to the browser user-agent styles.

Inheritable CSS Property

CSS Selectors

CSS Selectors

Universal Selector

*:

  • 不影响选择器优先级.
  • 匹配自定义元素, <script>, <style>, <title>.
  • 不匹配伪元素.

Type Selector

p {
margin-bottom: 1em;
line-height: 1.5em;
}

Attribute Selector

E[attr]:

/* 定位页面里所有具有必填属性 "required" 的 input */
input[required] {
border: 1px solid #f00;
}

E[attr=value] match value:

/* 定位页面里的密码输入框 */
input[type='password'] {
border: 1px solid #aaa;
}

E[attr|=value] match value/value-:

/**
* 定位页面里所有的 pre 里具有 class 属性且属性值为 language 或是 language- 开头的
* 比如 class="language", class="language-tsx"
*/
pre[class|='language'] {
color: #333;
}

E[attr~=value] match value/* value *:

/**
* 定位页面里所有具有属性 title 且属性值里拥有完整单词 english 的 div 容器
* 比如 title="english", title="a english"
*/
div[title~='english'] {
color: #f88;
}

E[attr^=value] match ^value:

/**
* 定位页面里具有属性 class 且属性值以 a 开头的 div 容器
* 比如 class="a", class="ab"
*/
div[class^='a'] {
color: #666;
}

E[attr$=value] match value$:

/**
* 定位页面里具有属性 class 且属性值以 a 结尾的 div 容器
* 比如 class="nba", class="cba"
*/
div[class$='a'] {
color: #f00;
}

E[attr*=value] match *value*:

/* 定位所有 title 里具有 link 字符串的 a 链接 */
a[title*='link'] {
text-decoration: underline;
}

Descendant Combinator

E F 后代选择器:

ul li {
margin-bottom: 0.5em;
}

Using the descendant selector without more specificity can be really expensive. The browser is going to check every descendant element for a match because the relationship isn't restricted to parent and child.

For .container ul li a selector:

  • match every <a> on the page
  • find every <a> contained in a <li>
  • use the previous matches and narrow down to the ones contained in a <ul>
  • finally, filter down the above selection to the ones contained in an element with the class .container

Child Combinator

E > F 子代选择器:

ul > li {
list-style: none;
} /* 仅限ul的直接子元素li, 忽略嵌套子元素 */

General Sibling Combinator

E ~ F 一般兄弟选择器:

/* p before h1 */
p {
color: #fff;
}

/* 定位具有相同父元素的, h1标签之后的所有p标签 */
h1 ~ p {
color: #f00;
}

Checkbox input as hidden click event listener:

input.checkbox {
visibility: hidden;
opacity: 0;
}

nav {
transform: scale(0);
}

input.checkbox:checked ~ nav {
transform: scale(1);
}

Adjacent Sibling Combinator

E + F 相邻兄弟选择器:

* + * {
margin-top: 1.5em;
}
li + li {
border-top: 1px solid #ddd;
}

Location Pseudo Class

:link:

  • 只匹配未访问的 <a href>.
  • 可用 a/[href] 选择器代替.

Visited Pseudo Class

:visited:

  • 只匹配访问过的 <a href>.
  • 只支持设置颜色: color/background-color/outline-color/border-color/column-rule-color/text-decoration-color.
  • 不支持颜色透明度 (alpha).
  • 只支持重置已有颜色, 不能新增设置样式.
  • window.getComputedStyle 无法获取到 :visited 设置颜色.

:any-link:

  • 同时匹配 :link:visited 元素.
  • 匹配所有设置了 [href] 的链接元素: <a href>/<link href>/<area href>.

Target Pseudo Class

:target:

  • 该选择器定位当前活动页面内定位点的目标元素 (#anchor-name) #info:target {font-size:24px;}.
  • 可用于实现 tab/modal/carousel/gallery/slide:
    • 利用 display:none 隐藏 #id 元素, 不会触发页面滚动 (防止页面抖动), 可以触发 :target 伪类匹配.
    • :target ~ .content 控制实际内容切换.
<a href="#p1">p1</a>
<div id="p1">p1</div>

<style>
div:target {
background-color: purple;
}
</style>
.anchor {
display: none;
}

.content {
max-height: 0;
}

.anchor:target ~ .content {
max-height: 100%;
}

:target-within:

  • Selected when any children targeted.

User Action Pseudo Class

Hover Pseudo Class

:hover:

  • 鼠标移动到容器时的状态.
  • 不仅限于链接, 可用于页面中的任何元素.

Active Pseudo Class

:active:

  • 点击 (mouse click/screen touch) 时的状态.
  • 键盘访问无法激活 :active.
  • 不仅限于链接, 可用于任何具有 tabindex 属性的元素.

:link —> :visited —> :hover —> :active links:

/* Unvisited links */
a:link {
color: blue;
}

/* Visited links */
a:visited {
color: purple;
}

/* Hovered links */
a:hover {
background: yellow;
}

/* Active links */
a:active {
color: red;
}
[href]:active,
button:active,
[type='button']:active,
[type='reset']:active,
[type='submit']:active {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
background: linear-gradient(rgb(0 0 0 / 5%), rgb(0 0 0 / 5%));
outline: 999px solid rgb(0 0 0 / 5%);
outline-offset: -999px;
box-shadow: inset 0 0 0 999px rgb(0 0 0 / 5%);
}

Focus Pseudo Class

:focus:

  • 获得焦点时的状态 (包括键盘访问).
  • 不仅限于 <a href>/<button>/<input>/<select>/<area>/<summary>, 可用于任何具有 tabindex/contenteditable 属性的元素.

:focus-visible:

  • Selected when Tab (keyboard) focused.
  • 可用于区分鼠标与键盘激活样式.

Separate focus styles:

/* Tab Focus Style */
.button:focus-visible {
outline: 2px solid #416dea;
outline-offset: 2px;
box-shadow: 0 1px 1px #416dea;
}

/* Mouse Focus Style */
.button:focus:not(:focus-visible) {
outline: none;
}

:focus-within:

  • Selected when any children focused.
  • 可用于实现 dropdown.
.dropdown-list {
display: none;
}

.dropdown:focus-within .dropdown-list {
display: block;
}

Input Pseudo Class

  • :autofill.
  • :enabled: 匹配启用的界面元素, e.g input.
  • :disabled: 匹配禁用的界面元素 ([disabled]), e.g input.
  • :read-only: 匹配其内容无法供用户修改的元素 (<div>/[readonly]).
  • :read-write: 匹配其内容可供用户修改的元素 (<div contenteditable>/<input>).
  • :default: 匹配处于默认状态的表单元素, 可用于默认选项/推荐选项样式.
  • :checked: 匹配处于选中状态的表单元素, 可用于开关选框/多选框样式, e.g tab, dropdown, modal, carousel, tree, checkbox grid.
  • :indeterminate:
    • 匹配处于未选状态的单选框元素 <input type="radio">.
    • 匹配处于半选状态的复选框元素 <input type="checkbox">.
    • 匹配处于未设置 value 的进度条元素 <progress>.
  • :valid: 匹配输入验证有效的表单元素 (<input type>/<input pattern>).
  • :invalid: 匹配输入验证无效的表单元素.
  • :user-invalid: 匹配用户交互后仍然验证无效的表单元素.
  • :in-range: 匹配具有范围限制的元素, 其中该值位于限制范围内, e.g 具有 minmax 属性的 numberrange 输入框.
  • :out-of-range: 与 :in-range 选择相反, 其中该值位于限制范围外.
  • :required: 匹配具有必填属性 [required] 的表单元素.
  • :optional: 匹配没有必填属性 [required] 的表单元素.
  • :placeholder-shown: select input with placeholder, 可用于控制输入样式.
@media only screen and (prefers-reduced-motion: reduce) {
.msg {
transition: none;
}
}

.msg {
opacity: 0;
transition: opacity 0.2s ease-in-out;
}

.input:not(:placeholder-shown) ~ .label,
.input:focus ~ .label {
opacity: 1;
}

Structural Pseudo Class

  • :root:
    • 根元素, 始终指 html 元素.
    • :root 选择器优先级高于 html 选择器.
    • 为了代码可读性, :root 用于设置全局变量, html 用于设置全局样式.
  • :empty: 没有任何子元素的元素, 不能有注释节点与文本节点.
  • E F:nth-child(n):该选择器定位元素 E 的第 n 个子元素的元素 F,可省略 E.
  • E F:nth-last-child(n): 该选择器定位元素 E 的倒数第 n 个子元素的元素 F,可省略 E.
  • E F:first-child: 第一个孩子.
  • E F:last-child: 最后一个孩子.
  • E F:only-child: 单一后代.
  • E F:nth-of-type(n): 该选择器定位元素 E 的第 n 个 相同类型 子元素,可省略 E.
  • E F:nth-lash-of-type(n): 该选择器定位元素 E 的导数第 n 个 相同类型 子元素,可省略 E.
  • E F:first-of-type: 相同类型 的第一个元素.
  • E F:last-of-type: 相同类型 的最后一个元素.
  • E F:only-of-type: 孩子中只有一种该元素.
N Calculation

n start from 0, calculation result limit to > 0:

  • :nth-child(5n): 0, 5, 10, 15, ... -> 5, 10, 15, ....
  • :nth-child(3n + 4): 4, 7, 10, 13, ... -> 4, 7, 10, 13, ....
  • :nth-child(-n + 3): 3, 2, 1, 0, -1, ... -> 3, 2, 1.
  • :nth-child(n + 4):nth-child(-n + 10): 两个 n 分开计算, 4, 5, 6, ... + 10, 9, 8, ... -> 4, 5, 6, 7, 8, 9, 10.
li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4) ~ li {
/* 当列表正好包含 4 项时, 命中所有列表项 */
color: darkblue;
}

/* stylelint-disable-next-line no-descending-specificity */
li:first-child:nth-last-child(n + 4),
li:first-child:nth-last-child(n + 4) ~ li {
/* 当列表至少包含 4 项时, 命中所有列表项 */
color: darkblue;
}

li:first-child:nth-last-child(n + 2):nth-last-child(-n + 6),
li:first-child:nth-last-child(n + 2):nth-last-child(-n + 6) ~ li {
/* 当列表包含 2 ~ 6 项时, 命中所有列表项 */
color: darkblue;
}

Logical Pseudo Class

  • :not(<selector>):
    • Selector priority.
    • 选择与括号内的选择器不匹配的元素.
  • :is(<selector>):
    • Selector priority.
    • Legacy name: :any()/:matches().
  • :where(<selector>):
    • 0 priority.
  • <target>:has(<selector>):
    • Selector priority.
    • A target element has child elements: :has(> selector).
    • A target element has sibling elements: :has(+ selector).
:is(ol, ul) :is(ol, ul) li {
margin-left: 2rem;
}

Use :has() selector for conditional styling:

:root {
&:has(.size-selector [value='xs']:checked) {
--font-size: 0.8em;
}

&:has(.size-selector [value='s']:checked) {
--font-size: 0.9em;
}

&:has(.size-selector [value='m']:checked) {
--font-size: 1em;
}

&:has(.size-selector [value='l']:checked) {
--font-size: 1.2em;
}

&:has(.size-selector [value='xl']:checked) {
--font-size: 1.5em;
}

&:has(.theme-selector [value='dark']:checked) {
--background: #000;
--color: #fff;
--line-color: hotpink;
}

&:has(.theme-selector [value='light']:checked) {
--background: #ddd;
--color: #000;
--line-color: darkgoldenrod;
--button-background: #0001;
}

&:has(.theme-selector [value='colorful']:checked) {
--background: linear-gradient(60deg, maroon, darkblue);
--color: #aff;
--line-color: #f55;
--content-background: #0004;
}
}

body {
display: grid;
place-items: center;
min-height: 100vh;
margin: 0;
font-size: var(--font-size, 1em);
color: var(--color);
background: var(--background);
}

h1 {
text-decoration: underline;
text-decoration-color: var(--line-color, currentcolor);
}

button {
padding: 1em 2em;
color: var(--color);
background-color: var(--button-background, #fff3);
border: 2px solid var(--line-color, currentcolor);
}

section {
width: 100%;
max-width: 50ch;
padding: 2em;
background-color: var(--content-background, none);
}

Linguistic Pseudo Class

  • :dir(ltr)/:dir(rtl).
  • :lang(en): 具有使用双字母缩写 (en) 表示的语言的元素.
:lang(en) > q {
quotes: '\201C' '\201D' '\2018' '\2019';
}

:lang(fr) > q {
quotes: '<< ' ' >>';
}

:lang(de) > q {
quotes: '>>' '<<' '\2039' '\203A';
}

Misc Pseudo Class

  • :fullscreen.

First Letter and Line Pseudo Element

::first-letter/::first-line:

  • ::first-letter: 匹配文本首字母.
  • ::first-line: 匹配文本首行.
  • IE9 及以上版本浏览器支持双冒号, IE8 浏览器只支持单冒号写法.
  • 只作用于块级元素: display block/inline-block/list-item/table-cell/table-caption.
  • 只支持部分 CSS 属性:
    • color.
    • font properties: font-size, font-weight.
    • text properties: text-decoration, word-spacing.
    • background properties: background-color, background-image.
    • border properties: border-color.
    • float.

Selection Pseudo Element

::selection 匹配突出显示的文本:

  • color.
  • background-color.
  • cursor.
  • caret-color.
  • outline.
  • text-decoration.
  • text-emphasis-color.
  • text-shadow.
  • stroke-color.
  • fill-color.
  • stroke-width.
/* 定义选中的文本颜色与背景色 */
::selection {
color: #fff;
background: #444;
}

Target Text Pseudo Element

::target-text:

::target-text {
color: white;
background-color: rebeccapurple;
}

Before and After Pseudo Element

使用 content 属性生成额外的内容并插入在标记中:

a::after {
content: '↗';
}

attr(), 调用当前元素的属性:

a::after {
content: '(' attr(href) ')';
}

b::after {
content: '(' attr(data-language) ')';
}

url()/uri(), 用于引用媒体文件:

h1::before {
content: url('logo.png');
}

counter(), 调用计数器, 可以不使用列表元素实现序号功能, 配合 CSS3 中counter-incrementcounter-reset属性:

<div>
<h2>HTML</h2>
<h2>CSS</h2>
<h2>JS</h2>
</div>

<style>
div {
counter-reset: tidbit-counter 58;
}

h2::before {
content: counter(tidbit-counter, list-style-type) ': ';
counter-increment: tidbit-counter 1;
}
</style>

<!-- output
59: HTML
60: CSS
61: JS
output -->

伪元素可用于扩大可点击区域:

.btn-text::before {
position: absolute;
inset: -6px -8px;
content: '';
}

Backdrop Pseudo Element

::backdrop:

/* Backdrop is only displayed when dialog is opened with dialog.showModal() */
dialog::backdrop {
background: rgb(255 0 0 / 25%);
}

video::backdrop {
background-color: #448;
}

Marker Pseudo Element

::marker:

  • animation-*.
  • transition-*.
  • color.
  • direction.
  • font-*.
  • content.
  • unicode-bidi.
  • white-space.
li::marker {
font-variant-numeric: tabular-nums;
text-align: start;
text-align-last: start;
text-indent: 0;
text-transform: none;
unicode-bidi: isolate;
}

Shadow DOM Pseudo Class and Element

  • :host: shadow DOM root element.
  • :host-context: shadow DOM root parent element.
  • ::part().
  • ::slotted().

Focusable Selector

const FOCUSABLE_SELECTOR = [
'[contenteditable]',
'[tabindex="0"]:not([disabled])',
'a[href]',
'audio[controls]',
'button:not([disabled])',
'iframe',
'input:not([disabled]):not([type="hidden"])',
'select:not([disabled])',
'summary',
'textarea:not([disabled])',
'video[controls]',
].join(',')

CSS Data Types

CSS data types define typical values (including keywords and units) accepted by CSS properties and functions:

CSS data types list:

CSS Property Values

Inherit Value

Inherit from parent.

Initial Value

The initial value of a CSS property is its default value, as listed in its standard definition table.

Revert Value

Revert to user agent built in styles.

@supports (-webkit-overflow-scrolling: touch) {
progress {
all: revert;
}
}

Unset Value

Reset to inherit or initial value.

dialog {
all: unset; /* Exclude `unicode-bidi`, `direction`, custom variables */
}

Specified Value

The specified value of a CSS property is the value it receives from the document's style sheet

Computed Value

The computed value of a CSS property is the value that is transferred from parent to child during inheritance. It is calculated from the specified value by:

  1. Handling the special values inherit, initial, unset, and revert
  2. Doing the computation needed to reach the value described in the "Computed value" line in the property's definition table
span {
/* display computed to `block` */
position: absolute;
}

Used Value

The used value of a CSS property is its value after all calculations have been performed on the computed value:

  • The used values of dimensions (e.g., width, line-height) are in pixels
  • The used values of shorthand properties (e.g., background) are consistent with those of their component properties (e.g., background-color or background-size) and with position and float

Actual Value

The actual value of a CSS property is the used value of that property after any necessary approximations have been applied

The user agent performs four steps to calculate a property's actual (final) value:

  1. the specified value is determined based on the result of cascading, inheritance, or using the initial value.
  2. the computed value is calculated according to the specification (for example, a span with position: absolute will have its computed display changed to block)
  3. layout is calculated, resulting in the used value
  4. the used value is transformed according to the limitations of the local environment, resulting in the actual value
CSS Value Transform
  1. initial.
  2. specified.
  3. computed.
  4. used.
  5. actual value.

CSS Logical Properties and Values

CSS Logical Basis

In position/size/margin/padding/border/text alignment:

  • block-start for top.
  • block-end for bottom.
  • block for vertical.
  • inline-start for left.
  • inline-end for right.
  • inline for horizontal.
.logical {
/* stylelint-disable shorthand-property-no-redundant-values */
inset-block: 0 0;
inset-inline: 0 0;
inline-size: fit-content;
min-inline-size: min-content;
max-inline-size: max-content;
block-size: fit-content;
min-block-size: min-content;
max-block-size: max-content;
padding-block: 1rem 1rem;
padding-inline: 1rem 1rem;
margin-block: 1rem 1rem;
margin-inline: 1rem 1rem;
border-block-start: 1px solid blue;
border-block-end: 1px solid blue;
border-inline-start: 1px solid blue;
border-inline-end: 1px solid blue;
/* stylelint-enable shorthand-property-no-redundant-values */
}

Logical Properties

CSS Logical Reference

  • W3C CSS logical draft.
  • CSS logical properties guide.

CSS Variables

Scope Variables

Inherited Variables

CSS Variables 本质上具有继承特性, HTML 文档树中, 后代元素可以继承祖先元素的 CSS Variables:

<div class="alert alert-info">
<div class="alert-content">
<h2 class="alert-title">Info</h2>
<div class="alert-body">
<p>Info Message.</p>
</div>
</div>
</div>

Contextual Styling Variables

Contextual styling themes:

[data-theme='dark'] {
--fg: hsl(0deg 10% 70%);
--border: hsl(0deg 10% 10%);
--bg: hsl(0deg 0% 20%);
--button-bg: hsl(0deg 0% 25%);
--input-bg: hsl(0deg 0% 15%);
}

[data-theme='hero'] {
--fg: hsl(240deg 50% 90%);
--border: hsl(240deg 50% 10%);
--bg: hsl(240deg 33% 30%);
--button-bg: hsl(240deg 33% 40%);
--input-bg: hsl(240deg 33% 20%);
}

Contextual styling buttons:

:root {
--primary: hsl(260deg 95% 70%);
--secondary: hsl(320deg 95% 60%);
}

.button {
background-color: var(--button-background, transparent);
}

.button-primary {
--button-background: var(--primary);
}

.button-secondary {
--button-background: var(--secondary);
}

Contextual styling alerts:

.alert {
--primary: #777;
--secondary: #ccc;

background-color: var(--secondary);
border: 1px solid var(--primary);
}

.alert::before {
background-color: var(--primary);
}

.alert-title {
color: var(--primary);
}

.alert-success {
--primary: #40c057;
--secondary: #d3f9d8;
}

.alert-info {
--primary: #228be6;
--secondary: #d0ebff;
}

.alert-warning {
--primary: #fab005;
--secondary: #fff3bf;
}

.alert-error {
--primary: #fa5252;
--secondary: #ffe3e3;
}

Invalid and Empty Variables

  • --invalid-value: initial; is invalid value leading to var(--invalid-value) called failed, var(--invalid-value, backup-value) get backup-value.
  • --empty-value: ; is valid empty value leading to var(--empty-value) called succeeded, var(--empty-value, backup-value) get unset value (inherit or initial value).
  • Use invalid and empty value to implement if (true) statement, you can see real world case on tailwind.css.
:root {
--on: initial;
--off: ;
}

button {
--is-raised: var(--off);

border: 1px solid var(--is-raised, rgb(0 0 0 / 10%));
}

button:hover,
button:focus {
--is-raised: var(--on);
}
/**
* css-media-vars
* BSD 2-Clause License
* Copyright (c) James0x57, PropJockey, 2020
*/

html {
--media-print: initial;
--media-screen: initial;
--media-speech: initial;
--media-xs: initial;
--media-sm: initial;
--media-md: initial;
--media-lg: initial;
--media-xl: initial;

/* ... */
--media-pointer-fine: initial;
--media-pointer-none: initial;
}

/* 把当前变量变为空值 */
@media print {
html {
--media-print: ;
}
}

@media screen {
html {
--media-screen: ;
}
}

@media speech {
html {
--media-speech: ;
}
}

/* 把当前变量变为空值 */
@media (width <= 37.499em) {
html {
--media-xs: ;
--media-lte-sm: ;
--media-lte-md: ;
--media-lte-lg: ;
}
}

/** 移动优先的样式规则 */
.breakpoints-demo > * {
/** 小于 37.5em, 宽度 100% */
--xs-width: var(--media-xs) 100%;

/** 小于 56.249em, 宽度 49% */
--sm-width: var(--media-sm) 49%;
--md-width: var(--media-md) 32%;
--lg-width: var(--media-gte-lg) 24%;

width: var(--xs-width, var(--sm-width, var(--md-width, var(--lg-width))));

--sm-and-down-bg: var(--media-lte-sm) red;
--md-and-up-bg: var(--media-gte-md) green;

background: var(--sm-and-down-bg, var(--md-and-up-bg));
}

Space toggle for progressive enhancement

:root {
--in-oklab: ;
}

@supports (background: linear-gradient(in oklab, red, tan)) {
:root {
--in-oklab: in oklab;
}
}

/* Usage: */
.card {
background: linear-gradient(var(--in-oklab) #f00, #0f0);
}

Limit Variables

For some CSS values and units have limits (e.g <color>), use variables to implement if else statement.

:root {
--red: 44;
--green: 135;
--blue: 255;

/**
* 亮度算法:
* lightness = (red * 0.2126 + green * 0.7152 + blue * 0.0722) / 255
*/
--lightness: calc((var(--red) * 0.2126 + var(--green) * 0.7152 + var(--blue) * 0.0722) / 255);
}

.button {
/* 文字颜色, 只可能是黑色或白色 */
color: hsl(0% 0% calc((var(--lightness) - 0.5) * -999999%));

/* 文字阴影, 黑色文字才会出现 */
text-shadow: 1px 1px
rgb(calc(var(--red) + 50) calc(var(--green) + 50) calc(var(--blue) + 50) / calc((var(--lightness) - 0.5) * 9999));

/* 背景颜色 */
background: rgb(var(--red) var(--green) var(--blue));

/* 固定样式 */
border: 0.2em solid;

/* 边框样式, 亮度大于 0.8 才出现 */
border-color: rgb(
calc(var(--red) - 50) calc(var(--green) - 50) calc(var(--blue) - 50) / calc((var(--lightness) - 0.8) * 100)
);
}

Dark Mode Variables

:root {
/* Themes */
--bg-light: #fff;
--text-light: #000;
--bg-dark: #000;
--text-dark: #fff;

/* Defaults */
--bg: var(--bg-light);
--text: var(--text-light);
}

@media (prefers-color-scheme: dark) {
:root {
--bg: var(--bg-dark);
--text: var(--text-dark);
}
}

Variables API

.element {
height: 100vh; /* Fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
}
window.addEventListener('resize', () => {
const vh = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vh}px`)
})
const root = document.documentElement
const bgColor = getComputedStyle(root).getPropertyValue('--body-bg')

Change --cursor-x and --cursor-y via JavaScript API:

:root::before {
position: fixed;
z-index: 1000;
display: block;
width: 100%;
height: 100%;
pointer-events: none;
content: '';
background: radial-gradient(
circle 16vmax at var(--cursor-x) var(--cursor-y),
rgb(0 0 0 / 0%) 0%,
rgb(0 0 0 / 50%) 80%,
rgb(0 0 0 / 80%) 100%
);
}

Change --percent via JavaScript API:

.bar {
display: flex;
height: 20px;
background-color: #f5f5f5;
}

.bar::before {
display: flex;
justify-content: end;
width: calc(var(--percent) * 1%);
font-size: 12px;
color: #fff;
white-space: nowrap;
content: counter(progress) '%\2002';
counter-reset: progress var(--percent);
background: #2486ff;
}

Properties and Values API

@property:

@property --property-name {
syntax: '<color>';
inherits: false;
initial-value: #c0ffee;
}

CSS.registerProperty():

window.CSS.registerProperty({
name: '--my-color',
syntax: '<color>',
inherits: false,
initialValue: '#c0ffee',
})

CSS 不支持背景渐变色的直接过渡动画, 需要使用两层背景渐变 (background + ::before/::after background) opacity 变化 实现渐变背景的过渡动画.

现在, 可以对 CSS Houdini 自定义变量 设置 transition/animation, 快速实现渐变背景的过渡动画:

@property --houdini-color-a {
syntax: '<color>';
inherits: false;
initial-value: #fff;
}

@property --houdini-color-b {
syntax: '<color>';
inherits: false;
initial-value: fuchsia;
}

.box {
background: linear-gradient(45deg, var(--houdini-color-a), var(--houdini-color-b));

/* stylelint-disable-next-line custom-property-no-missing-var-function */
transition: 1s --houdini-color-a;
animation: change 10s infinite linear;
}

.box:hover {
--houdini-color-a: yellowgreen;
}

@keyframes change {
20% {
--houdini-color-b: red;
}

40% {
--houdini-color-b: #ff3c41;
}

60% {
--houdini-color-b: orange;
}

80% {
--houdini-color-b: #ae63e4;
}
}

@property --per {
syntax: '<percentage>';
inherits: false;
initial-value: 25%;
}

.pie {
background: conic-gradient(yellowgreen, yellowgreen var(--per), transparent var(--per), transparent 100%);

/* stylelint-disable-next-line custom-property-no-missing-var-function */
transition: --per 300ms linear;
}

.pie:hover {
--per: 60%;
}

@property feature detection and fallback:

@property --parent-em {
syntax: '<length>';
initial-value: 0;
inherits: true;
}

@property --no-at-property-fallback {
syntax: '*';
inherits: false;
}

select {
--parent-em: 1em;
--no-at-property-fallback: 1em;
}

optgroup {
/* Will only inherit if `@property` not supported */
font-size: var(--no-at-property-fallback, 0);
}

optgroup > * {
font-size: var(--parent-em);
}

CSS Colors

Current Color

currentcolor:

  • currentcolor 变量使用当前 color 计算值.
  • border-color/outline-color/caret-color/text-shadow/box-shadow 默认表现为 currentcolor.

Accent Color

accent-color:

Change user-interface controls accent color.

HSL Color

hsl():

  • H: hue.
  • S: saturation (stay 50% etc.).
  • L: lightness (easy to theme colors).

Change hue to get color palette:

  • Complement hue: 180deg, brand and secondary color.
  • Mix hue to get natural color.

Change lightnessto get color palette:

  • Decease lightness to get :hover/:focus color.
  • Increase lightness to get secondary/ghost color.
/* Hover Button */
:root {
--primary-h: 221;
--primary-s: 72%;
--primary-l: 62%;
}

.button {
background-color: hsl(var(--primary-h) var(--primary-s) var(--primary-l));
}

.button:hover,
.button:focus {
--primary-l: 54%;
}

.button-secondary {
--primary-l: 90%;

color: #222;
}

.button-ghost {
--primary-l: 90%;

background-color: transparent;
border: 3px solid hsl(var(--primary-h) var(--primary-s) var(--primary-l));
}

Change lightness to get gradient color:

.section {
background: linear-gradient(
to left,
hsl(var(--primary-h) var(--primary-s) var(--primary-l)),
hsl(var(--primary-h) var(--primary-s) 95%)
);
}

.section-2 {
--primary-h: 167;
}

HWB Color

hwb(H W B [/ A]):

  • H: hue (<angle>).
  • W: whiteness (<percentage>).
  • B: blackness (<percentage>).
  • A: alpha (<percentage>).

Color Scheme

color-scheme:

:root {
color-scheme: normal;
color-scheme: light dark;
color-scheme: light;
color-scheme: dark;
}

CSS Color Mix

Creating color palettes with color-mix():

:root {
--yellow: rgb(221 215 141);
--peach: rgb(220 191 133);
--chocolate: rgb(139 99 92);
--khaki: rgb(96 89 77);
--grey: rgb(147 162 155);
--mix-warm: red;
--mix-cool: blue;
}

.palette > div {
--color: var(--yellow);

background: color-mix(in srgb, var(--color), var(--mix, var(--color)) var(--amount, 10%));

&:nth-child(2) {
--color: var(--peach);
}

&:nth-child(3) {
--color: var(--chocolate);
}

&:nth-child(4) {
--color: var(--khaki);
}

&:nth-child(5) {
--color: var(--grey);
}
}

.cool {
--mix: var(--mix-cool);
}

.cool-20 {
--amount: 20%;
}

.warm {
--mix: var(--mix-warm);
}

.warm-20 {
--amount: 20%;
}

CSS Color Reference

  • CSS color module level 5 guide:
    • hwb.
    • lab.
    • lch.
    • color-mix.
    • color-contrast.
    • color.
    • accent-color.
  • CSS color value.

CSS Math

Calculation Function

calc():

  • 支持多种数据类型: <length>/<frequency>/<angle>/<time>/<percentage>/<number>/<integer>.
  • 支持加减乘除 4 种运算.
  • 运算符前后带单位或者带百分号的值只能进行加减运算, 不能进行乘除运算.
  • 加号和减号两侧一定要有空格, 乘号和除号两侧无须空格.
  • 结合 CSS Variables, 拥有强大功能与可维护性.
html {
font-size: calc(16px + 2 * (100vw - 375px) / 39);
}

.button {
width: calc(100% - 20px);
}

.list {
--size: calc(100% - 2rem);

width: calc(var(--size) / 6);
}
Broken Calculation

If calc() result breaks, check cache plugin or build tool. Some tools like to remove whitespace always lead to broken calc() addition and subtraction operator.

Min and Max Function

Flexible size:

.box {
width: min(100vw - 3rem, 80ch);
width: max(10px * 10, 10em);
width: min(calc(10px * 10), 10em);
width: max(10px * 10, var(--width));
margin-block-start: min(4rem, 8vh);
}
.legacy-container {
width: 100%;
max-width: 1024px;
}

.modern-container {
width: min(100%, 1024px);
}
.legacy-container {
width: 100%;
min-width: 768px;
}

.modern-container {
width: max(100%, 768px);
}

Clamp Function

Fluid size:

.clamp {
width: max(75px, min(25vw, 125px));
width: clamp(30ch, 80%, 80ch);
padding: clamp(1rem, 3%, 1.5rem);
margin-bottom: clamp(4px, 6.5vh, 5.5rem);
font-size: clamp(2.25rem, 2vw + 1.5rem, 3.25rem);
text-indent: clamp(15px, 10%, 1.5rem);
letter-spacing: clamp(0.1rem, 1.5vw, 0.5rem);
}

Generate fluid size for Tailwind.css:

const settings = {
typography: {
fontSizeMin: 1.125,
fontSizeMax: 1.25,
msFactorMin: 1.125,
msFactorMax: 1.2,
lineHeight: 1.6,
},
screensRem: {
'min': 20,
'sm': 40,
'md': 48,
'lg': 64,
'xl': 80,
'2xl': 96,
},
grid: {
cols: 24,
},
}

const remToPx = rem => `${rem * 16}px`

const screens = {
'sm': remToPx(settings.screensRem.sm),
'md': remToPx(settings.screensRem.md),
'lg': remToPx(settings.screensRem.lg),
'xl': remToPx(settings.screensRem.xl),
'2xl': remToPx(settings.screensRem['2xl']),
}

const fsMin = settings.typography.fontSizeMin
const fsMax = settings.typography.fontSizeMax
const msFactorMin = settings.typography.msFactorMin
const msFactorMax = settings.typography.msFactorMax
const screenMin = settings.screensRem.min
const screenMax = settings.screensRem['2xl']

function calcMulti(multiMin = 0, multiMax = null) {
return {
fsMin: fsMin * msFactorMin ** multiMin,
fsMax: fsMax * msFactorMax ** (multiMax || multiMin),
}
}

function clamp(multiMin = 0, multiMax = null) {
const _calcMulti = calcMulti(multiMin, multiMax || multiMin)
const _fsMin = _calcMulti.fsMin
const _fsMax = _calcMulti.fsMax
return `clamp(${_fsMin}rem, calc(${_fsMin}rem + (${_fsMax} - ${_fsMin}) * ((100vw - ${screenMin}rem) / (${screenMax} - ${screenMin}))), ${_fsMax}rem)`
}

const fontSize = {
'xs': clamp(-2),
'sm': clamp(-1),
'base': clamp(0),
'lg': clamp(1),
'xl': clamp(2),
'2xl': clamp(3),
'3xl': clamp(4),
'4xl': clamp(5),
'5xl': clamp(6),
'6xl': clamp(7),
'7xl': clamp(8),
'8xl': clamp(9),
'9xl': clamp(10),
}

module.exports = {
theme: {
screens,
fontSize,
},
}
:root {
/* Fluid type scale */
--size-step-minus-2: clamp(0.6944rem, 0.6376rem + 0.284vi, 0.84rem);
--size-step-minus-1: clamp(0.8333rem, 0.7488rem + 0.4228vi, 1.05rem);
--size-step-0: clamp(1rem, 0.878rem + 0.6098vi, 1.3125rem);
--size-step-1: clamp(1.2rem, 1.028rem + 0.8598vi, 1.6406rem);
--size-step-2: clamp(1.44rem, 1.2016rem + 1.1918vi, 2.0508rem);
--size-step-3: clamp(1.728rem, 1.402rem + 1.6302vi, 2.5635rem);
--size-step-4: clamp(2.0736rem, 1.6323rem + 2.2063vi, 3.2043rem);
--size-step-5: clamp(2.4883rem, 1.8963rem + 2.9602vi, 4.0054rem);
--size-step-6: clamp(2.986rem, 2.1974rem + 3.943vi, 5.0068rem);
--size-step-7: clamp(3.5832rem, 2.5392rem + 5.2201vi, 6.2585rem);

/* Fluid space scale */
--space-3xs: clamp(0.25rem, 0.2256rem + 0.122vi, 0.3125rem);
--space-2xs: clamp(0.5rem, 0.4268rem + 0.3659vi, 0.6875rem);
--space-xs: clamp(0.75rem, 0.6524rem + 0.4878vi, 1rem);
--space-s: clamp(1rem, 0.878rem + 0.6098vi, 1.3125rem);
--space-m: clamp(1.5rem, 1.3049rem + 0.9756vi, 2rem);
--space-l: clamp(2rem, 1.7561rem + 1.2195vi, 2.625rem);
--space-xl: clamp(3rem, 2.6341rem + 1.8293vi, 3.9375rem);
--space-2xl: clamp(4rem, 3.5122rem + 2.439vi, 5.25rem);
--space-3xl: clamp(6rem, 5.2683rem + 3.6585vi, 7.875rem);
}

Create fluid typography with clamp():

  • Calculating factor: factor = (max-value - min-value ) / (max-viewport-width - min-viewport-width).
  • Calculating relative value: relative-value = min-value - min-viewport-width * factor.
  • Calculating preferred value: fluid-value (vw) = 100vw * factor.
.fluid-typography {
--fluid-value: clamp(min-value, relative-value + fluid-value, max-value);
}

CSS Text

Text Alignment

text-align:

  • 对 block level element 无效.
  • start/end/left/right/center/match-parent.
  • justify: 自适应, 左右都无空格.
.wrap {
text-align: justify;
text-align-last: justify; /* 一个块或行的最后一行对齐方式 */
text-justify: distribute-all-lines; /* ie6-8 */
}

text-align-last:

最后一行文字对齐方式.

text-justify:

  • type of justification for text-align: justify.
  • none: turn off text-align: justify.
  • auto.
  • inter-word.
  • inter-character.

Text Indent

text-indent:

  • 作用于 block container, 但实际作用于第一行内联盒子内容.
  • display: inline 替换元素无效.
  • display: inline-* 替换元素有效.
  • Percentage text-indent calculate by containing block width.
.hidden-text {
font: 0/0;
color: transparent;
text-indent: -9999px;
}

tab-size:

pre {
font-size: 100%;
tab-size: 2;
white-space: pre-wrap;
}

Text Spacing

在设计领域, 文本行之间的距离称为行距 (leading), 来源于印刷版每行文字之间添加的一条条的引导线 (lead). 字符之间的距离称之为字距 (tracking). tailwind.css 使用 leading-{size} 控制 line-height, 使用 tracking-{size} 控制 letter-spacing.

letter-spacing:

  • 继承性.
  • 默认值为 normal.
  • 支持负值, 小数值.

word-spacing:

  • 继承性.
  • 默认值为 normal.
  • 支持负值, 小数值, 百分比.
  • 最终间隔距离会受 text-align: justify 影响.
.paragraph {
line-height: 1.5em; /* 行间距 */
text-indent: 2em; /* 段落缩进 */
letter-spacing: 50px; /* 字间距 */
word-spacing: 50px; /* 词间距 */
}

Text Transform

p {
font-variant: small-caps; /* 小型的大写字母 */
text-transform: uppercase; /* 大写字母 */
text-transform: lowercase; /* 小写字母 */
text-transform: capitalize; /* 首字母大写 */
}

Text Decoration

.formal-syntax {
text-decoration: < 'text-decoration-line' > || < 'text-decoration-style' > || < 'text-decoration-color' > || <
'text-decoration-thickness' >;
}
.line {
text-decoration-line: overline; /* 上划线 */
text-decoration-line: line-through; /* 中划线 */
text-decoration-line: underline; /* 下划线 */
}

.text {
text-decoration: underline;
text-decoration: dotted underline;
text-decoration: red underline dashed;
text-decoration: wavy underline 3px red;
}

.wavy {
display: block;
height: 0.5rem;
padding-top: 0.5rem;
overflow: hidden;
letter-spacing: 100vw;
white-space: nowrap;
}

.wavy::before {
text-decoration: overline; /* IE */
text-decoration-style: wavy;
content: '\2000\2000';
}

下划线样式:

Text Emphasis

text-emphasis:

  • <'text-emphasis-style'> || <'text-emphasis-color'>.
  • text-emphasis-style:
    • none.
    • <character>.
    • [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ].
  • text-emphasis-color: currentcolor | <color>.
  • 重点符号字号默认为文字字号的一半.
.text {
/* Initial value */
text-emphasis: none;

/* <string> value */
text-emphasis: 'x';
text-emphasis: '点';
text-emphasis: '\25B2';
text-emphasis: '*' #555;

/* Keywords value */
text-emphasis: filled; /* filled dot */
text-emphasis: open; /* open dot */
text-emphasis: sesame; /* filled sesame */
text-emphasis: open sesame;

/* Keywords value combined with a color */
text-emphasis: filled sesame #555;
}

text-emphasis-position:

  • [ over | under ] && [ right | left ].
  • over: draws marks over text in horizontal writing mode.
  • under: draws marks under text in horizontal writing mode.
  • right: draws marks to right of text in vertical writing mode.
  • left: draws marks to left of text in vertical writing mode.
  • 默认在顶部或右侧画重点符号.
.text {
/* Initial value */
text-emphasis-position: over right;

/* Keywords value */
text-emphasis-position: over left;
text-emphasis-position: under right;
text-emphasis-position: left under;
text-emphasis-position: right over;
}

Text Size Adjust

禁止 iOS 横屏字号自动调整:

body {
/* stylelint-disable-next-line property-no-vendor-prefix */
-webkit-text-size-adjust: none;
}

Text Overflow

  • clip: 切除溢出部分.
  • ellipsis: 省略号标志 (要设置 width).
.truncation-article-container {
width: 500px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.article-container {
display: box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 4; /* 需要显示的行数 */
word-break: break-all;
-webkit-box-orient: vertical;
}

White Space

Web default:

  • 空格被解析为换行.
  • 换行被解析为空格.
  • 自动合并空格.

普通标签内自动忽略空格符, 并将其与空白符转换成一个空格进行输出, 可用 white-space 改变这一行为:

White Space换行符空格和制表符文字换行行尾空格
normal合并合并换行删除
nowrap合并合并不换行删除
pre保留保留不换行保留
pre-wrap保留保留换行挂起
pre-line保留合并换行删除
break-spaces保留保留换行换行
dd + dt::before {
white-space: pre;
content: '\A';
}

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

Text Wrap

Text wrapping and word breaking:

  • word-break:
    • normal: default line break rule.
    • keep-all: Word breaks should not be used for CJK text. Non-CJK text behavior is same as for normal.
    • break-all: word breaks should be inserted between any two characters (excluding CJK text).
  • overflow-wrap (word-wrap):
    • normal.
    • anywhere.
    • break-word.
  • line-break (break lines of CJK text when working with punctuation and symbols):
    • auto.
    • loose.
    • normal.
    • strict.
    • anywhere.
  • hyphens (how words should be hyphenated when text wraps across multiple lines):
    • manual: words are broken for line-wrapping only where - or &shy;.
    • auto: automatically break words at appropriate hyphenation points.
    • none: words are not broken at line breaks.
  • <wbr>: word break opportunity.
/* 不换行 */
.nowrap {
white-space: nowrap;
}

/* 自动换行 */
.auto-wrap {
hyphens: auto;
word-break: normal;
word-wrap: break-word;
line-break: anywhere;
}

/* 自动换行 */
pre {
hyphens: auto;
word-wrap: break-word; /* IE 5.5-7 */
white-space: pre-wrap; /* Modern Browsers */
line-break: anywhere;
}

/* 强制换行 */
.force-wrap {
word-break: break-all;
line-break: anywhere;
}

/* IE not support <wbr> */
wbr::after {
content: '\00200B';
}
Punctuation Types
  • 避头标点: 不在行首显示的标点, e.g 逗号, 顿号, 句号, 问号, 叹号.
  • 避尾标点: 不在行尾显示的标点, e.g 前引号, 前括号.
.text-truncate-box {
display: inline-block;
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: normal;
white-space: nowrap;
}

Text Horizontal Direction

Direction

Set direction of text, table columns, and horizontal overflow:

.ltr {
direction: ltr;
}

.rtl {
direction: rtl;
}

Unicode Bidi

unicode-bidi:

  • normal.
  • plaintext: 元素内文字 LTR.
  • embed: 中英文字符 LTR, 标点符号 RLT.
  • isolate: 中英文字符 LTR, 标点符号 RLT.
  • bidi-override: 所有字符 RTL.
  • isolate-override: 所有字符 RTL.
<p><button>button按钮?</button><span>span标签?</span>匿名内联元素?</p>

<style>
p {
direction: rtl;
}

span {
background-color: skyblue;
}
</style>

Unicode Bidi

Text Vertical Direction

Writing Mode

Set whether lines of text are laid out horizontally or vertically:

/* 单列展示 */
.wrap-single {
width: 25px;
height: auto;
padding: 8px 5px;
font-size: 12px;
hyphens: auto;
line-height: 18px;
word-wrap: break-word; /* 英文自动换行 */
}

/* 多列展示 */
.wrap-multiple {
height: 200px;
line-height: 30px;
text-align: justify;
writing-mode: horizontal-tb; /* 水平排列 */
writing-mode: vertical-lr; /* 竖直从左向右 */
writing-mode: vertical-rl; /* 竖直从右向左 */
writing-mode: lr-tb; /* IE: 水平排列 */
writing-mode: tb-lr; /* IE: 竖直从左向右 */
writing-mode: tb-rl; /* IE: 竖直从右向左 */
}

Text Orientation

text-orientation:

  • mixed: 中文字符正立, 英文字符旋转 90 度.
  • upright: 中文字符正立, 英文字符正立.
  • sideways/sideways-right: 中文字符旋转 90 度, 英文字符旋转 90 度.

Text Combine Upright

text-combine-upright:

  • none.
  • all: 横向合并所有类型字符.
  • digits <integer>?: 横向合并数字字符.

CSS Font

Font Family

Generic Font Family

  • serif: 衬线字体族.
  • sans-serif: 无衬线字体族.
  • monospace: 等宽字体族.
  • cursive: 手写字体族.
  • fantasy: 奇幻字体族.
  • emoji: 表情字体族.
  • math: 数学表达式字体族.
  • fangsong: 仿宋字体族.
  • system-ui: 系统 UI 字体族.
  • ui-serif: 系统衬线字体.
  • ui-sans-serif: 系统无衬线字体.
  • ui-monospace: 系统等宽字体.
  • ui-rounded: 系统圆形字体.

English Font Family

  • Segoe UI: Windows 从 Vista 版本开始默认的西文字体族.
  • Roboto: Android 中的一款无衬线字体.
  • Helvetica: macOS 和 iOS 中很常用的一款无衬线字体.
  • Arial: 全平台都支持的一款无衬线字体.
body {
font-family:
system-ui,
-apple-system,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif;
}

Emoji Font Family

  • Apple Color Emoji: macOS and iOS.
  • Segoe UI Emoji: Windows.
  • Segoe UI Symbol: Windows 7 新增字体, 是一种 Unicode 编码字体, 显示的是单色图案, 非彩色图形.
  • Noto Color Emoji: 谷歌出品的 emoji 字体, 用于 Android 和 Linux.
@font-face {
font-family: Emoji;
src: local('Apple Color Emoji'), local('Segoe UI Emoji'), local('Segoe UI Symbol'), local('Noto Color Emoji');
font-display: swap;
unicode-range: U+1F000-1F644, U+203C-3299;
}

body {
font-family:
system-ui,
-apple-system,
'Segoe UI',
Roboto,
Emoji,
Helvetica,
Arial,
sans-serif;
}

Icon Font Family

  • Complete guide on how to pair icons and typefaces to create consistent visual language (including awesome fonts list).

Math Font Family

  • Cambria Math: Windows 中的数学字体.
  • Latin Modern Math: macOS 中的数学字体.
math {
font-family: 'Cambria Math', 'Latin Modern Math', serif;
}

Chinese Font Family

宋体 SimSun
黑体 SimHei
微软雅黑 Microsoft YaHei
微软正黑体 Microsoft JhengHei
新宋体 NSimSun
新细明体 PMingLiU
细明体 MingLiU
标楷体 DFKai-SB
仿宋 FangSong
楷体 KaiTi
仿宋_GB2312 FangSong_GB2312
楷体_GB2312 KaiTi_GB2312

宋体: SimSun
华文细黑: STHeiti Light [STXihei]
华文黑体: STHeiti
华文楷体: STKaiti
华文宋体: STSong
华文仿宋: STFangsong
儷黑 Pro: LiHei Pro Medium
儷宋 Pro: LiSong Pro Light
標楷體: BiauKai
蘋果儷中黑: Apple LiGothic Medium
蘋果儷細宋: Apple LiSung Light

新細明體: PMingLiU
細明體: MingLiU
標楷體: DFKai-SB
黑体: SimHei
新宋体: NSimSun
仿宋: FangSong
楷体: KaiTi
仿宋_GB2312: FangSong_GB2312
楷体_GB2312: KaiTi_GB2312
微軟正黑體: Microsoft JhengHei
微软雅黑体: Microsoft YaHei

隶书: LiSu
幼圆: YouYuan
华文细黑: STXihei
华文楷体: STKaiti
华文宋体: STSong
华文中宋: STZhongsong
华文仿宋: STFangsong
方正舒体: FZShuTi
方正姚体: FZYaoti
华文彩云: STCaiyun
华文琥珀: STHupo
华文隶书: STLiti
华文行楷: STXingkai
华文新魏: STXinwei

Font Family Preset

Font stack:

.mi {
font-family: Arial, 'Microsoft YaHei', '黑体', '宋体', sans-serif;
}

.tao-ux {
font-family: Helvetica, 'Hiragino Sans GB', 'Microsoft Yahei', '微软雅黑', Arial, sans-serif;
}

.tao {
font:
12px/1.5 Tahoma,
Helvetica,
Arial,
'宋体',
sans-serif;
}

.tao-ued {
font:
12px/1 Tahoma,
Helvetica,
Arial,
'\5b8b\4f53',
sans-serif;
}

.one-plus {
font:
14px/1.5 'Microsoft YaHei',
Arial,
Tahoma,
'\5b8b\4f53',
sans-serif;
}

.github {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji',
'Segoe UI Emoji';
}

.font-sans-serif {
font-family:
-apple-system,
BlinkMacSystemFont,
'Avenir Next,' Avenir,
'Segoe UI',
'Helvetica Neue',
Helvetica,
Cantarell,
Ubuntu,
Roboto,
Noto,
Arial,
sans-serif;
}

.font-serif {
font-family: Georgia, Cambria, 'Iowan Old Style', 'Apple Garamond', Baskerville, 'Times New Roman', 'Droid Serif',
Times, 'Source Serif Pro', serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}

.font-mono {
font-family: Menlo, Consolas, Monaco, 'Liberation Mono', 'Lucida Console', 'Courier New', monospace;
}

Font Size

  • ch: calculate by 0 width.
  • ex: calculate by x width.
  • em:
    • Calculate by original font-size (inherit size or current size).
    • 当用 em 指定多重嵌套的元素的字号时, 会产生不断放大/缩小的结果, 故一般避免在 font-size 上使用 em.
    • margin/padding/border 上使用 em 时, 可使得布局随 font-size 大小改变而改变.
  • rem: calculate by root font-size.
  • <percentage>: calculate by parent font-size.
html {
/* 浏览器默认size为16px, 此时将html-size自动计算为10px */
font-size: 62.5%;
}

small {
/* 11px */
font-size: 1.1rem;
}

strong {
/* 18px */
font-size: 1.8rem;
}

Font Size Adjust

font-size-adjust:

  • 使字体保持大小, 不随字体类型改变而改变.
  • 不同字体有不同的值 (x-height/字体尺寸).

Font Stretch

font-stretch, selects a normal, condensed, or expanded face from a font:

  • normal.
  • ultra-condensed | extra-condensed | condensed | semi-condensed.
  • semi-expanded | expanded | extra-expanded | ultra-expanded.
  • <percentage>.
KeywordPercentage
ultra-condensed50%
extra-condensed62.5%
condensed75%
semi-condensed87.5%
normal100%
semi-expanded112.5%
expanded125%
extra-expanded150%
ultra-expanded200%

Font Kerning

font-kerning, 字距调整:

  • auto.
  • normal: enable kerning.
  • none: disable kerning.

Font Style

font-style:

  • normal.
  • italic.
  • oblique.
  • oblique <angle>.

Font Synthesis

font-synthesis:

  • Controls which missing typefaces, bold, italic, or small-caps may be synthesized by the browser.
  • Initial value: weight style.
  • Formal syntax: none | [ weight || style || small-caps ].
<em class="syn">Synthesize me! 站直。</em>
<br />
<em class="no-syn">Don't synthesize me! 站直。</em>

<style>
em {
font-weight: bold;
}

.syn {
font-synthesis: style weight small-caps;
}

.no-syn {
font-synthesis: none;
}
</style>

Font Synthesis

Font Variant

font-variant:

  • normal.
  • none.
  • font-variant-caps:
    • small-caps: 小体型大写字母.
    • all-small-caps.
    • petite-caps: 特小型大写字母.
    • all-petite-caps.
    • unicase: 混合模式, 可以有小体型大写字母, 大写字母, 大体型小写字母.
    • titling-caps: 标题大写字母.
  • font-variant-east-asian:
    • ruby: 日文上标假名.
    • jis78/jis83/jis90/jis04: 使用对应年份的日语字符集.
    • simplified: 简体字形.
    • traditional: 繁体字形.
    • proportional-width: 不等宽字形.
    • full-width: 等宽字形.
  • font-variant-ligatures:
    • common-ligatures: 使用连字效果.
    • discretionary-ligatures: 使用特殊连字效果, 设计师设计具体效果表现.
    • historical-ligatures: 使用古代连字效果.
    • contextual-ligatures: 使用上下文连字效果, 前后字母影响具体效果表现.
  • font-variant-numeric:
    • ordinal: 强制使用序数标记特殊的标志符号, e.g 1st, 2nd, 3rd, 4th.
    • slashed-zero: 强制使用带斜线的 0.
    • lining-nums: 沿基线对齐.
    • oldstyle-nums: 传统对齐方式.
    • proportional-nums: 不等宽数字.
    • tabular-nums: 等宽数字.
    • diagonal-fractions: 斜线分隔分子母
    • stacked-fractions: 水平线分隔分子母.

Font Display

The font display timeline:

  • block period: font face is not loaded, render an invisible fallback font face (use normally when loaded in this period)
  • swap period: font face is not loaded, render a fallback font face (use normally when loaded in this period)
  • failure period: the user agent treats it as a failed load causing normal font fallback

font-display decides how a font face is displayed based on whether and when it is downloaded and ready to use:

  • auto: font display strategy defined by the user agent.
  • block: a short block period and an infinite swap period.
  • swap: an extremely small block period and an infinite swap period.
  • fallback: an extremely small block period and a short swap period.
  • optional: an extremely small block period and no swap period.
@font-face {
font-family: ExampleFont;
font-style: normal;
font-weight: 400;
src:
url('/path/to/fonts/exampleFont.woff') format('woff'),
url('/path/to/fonts/exampleFont.eot') format('eot');
font-display: fallback;
}

Custom Font Face

@font-face 使用户使用自定义字体:

@font-face {
font-family: mySpecialFont;
font-style: inherit;
font-weight: inherit;
font-variant: inherit;
src: url('./Colleen.ttf');
font-display: swap;
}

.selector {
font-family: mySpecialFont, sans-serif;
}

Custom Font Format

@font-face {
font-family: 'Open Sans Regular';
font-style: normal;
font-weight: 400;
src:
local('Open Sans Regular'),
local('OpenSans-Regular'),
url('open-sans/OpenSans-Regular-Cyrillic.woff2') format('woff2'),
url('open-sans/OpenSans-Regular-Cyrillic.woff') format('woff'),
url('open-sans/OpenSans-Regular-Cyrillic.eot') format('embedded-opentype'),
url('open-sans/OpenSans-Regular-Cyrillic.ttf') format('truetype');
font-display: swap;
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1;
}

Custom Font Style and Weight

@font-face {
font-family: myFont;
font-weight: 400;
src: local('Font 40S');
}

@font-face {
font-family: myFont;
font-weight: 500;
src: local('Font 50S');
}

@font-face {
font-family: myFont;
font-weight: 600;
src: local('Font 60S');
}

@font-face {
font-family: myFont;
font-style: italic;
src: local('Font Italic');
}

.text-normal,
.text-medium,
.text-semibold,
.text-italic {
font-family: myFont, sans-serif;
}

.text-normal {
font-weight: 400;
}

.text-medium {
font-weight: 500;
}

.text-semibold {
font-weight: 600;
}

.text-italic {
font-style: italic;
}

Font Performance

Reduce web font size:

  • Compress fonts: better formats (e.g woff2/woff).
  • Subset fonts: unicode-range.
  • Local fonts: local().
@font-face {
/* Single value */
unicode-range: U+0026;
}

@font-face {
/* Range */
unicode-range: U+0000-007F;
}

@font-face {
/* Wildcard Range */
unicode-range: U+002?;
}

@font-face {
/* Multiple Values */
unicode-range: U+0000-007F, U+0100, U+02??;
}

CSS Content

content replaces an element with a generated value:

  • Objects inserted are Anonymous Replaced Elements.
  • CSS-generated content is not included in the DOM, will not be represented in accessibility tree.

CSS Counter

Adjust the appearance of content based on its location in a document.

/* Set a counter named 'section', and its initial value is 0. */
body {
counter-reset: section;
}

/* Increment the value of section counter by 1 */

/* Display the value of section counter */
h3::before {
content: counter(section);
counter-increment: section;
}

Nested counters counters(counterName, hyphenString):

ol {
list-style-type: none;
counter-reset: section; /* 为每个ol元素创建新的计数器实例 */
}

li::before {
content: counters(section, '.') ' '; /* 为所有计数器实例增加以`.`分隔的值 */
counter-increment: section; /* 只增加计数器的当前实例 */
}
<ol>
<li>item</li>
<!-- 1 -->
<li>
item
<!-- 2 -->
<ol>
<li>item</li>
<!-- 2.1 -->
<li>item</li>
<!-- 2.2 -->
<li>
item
<!-- 2.3 -->
<ol>
<li>item</li>
<!-- 2.3.1 -->
<li>item</li>
<!-- 2.3.2 -->
</ol>
<ol>
<li>item</li>
<!-- 2.3.1 -->
<li>item</li>
<!-- 2.3.2 -->
<li>item</li>
<!-- 2.3.3 -->
</ol>
</li>
<li>item</li>
<!-- 2.4 -->
</ol>
</li>
<li>item</li>
<!-- 3 -->
<li>item</li>
<!-- 4 -->
</ol>
<ol>
<li>item</li>
<!-- 1 -->
<li>item</li>
<!-- 2 -->
</ol>

CSS Reference