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.
- ED:
CSS Cascading and Inheritance
Cascading Order
- Inherit styles.
- User agent normal styles.
- User normal styles.
- Author
@layer
normal styles. - Author normal styles.
- Animation styles.
- Author
!important
styles. - Author
@layer
!important
styles. - User
!important
styles. - User agent
!important
styles. - Transition styles.
Transition > Animation > Normal >
@layer
> User > User Agent > Inherit
- 级联水平高的 styles 应用 !important 后, 其优先级变低.
- 级联水平低的 styles 应用 !important 后, 其优先级变高.
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;
}
}
}
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(
::
).
- 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 itsinitial
value.revert
reverses the CSS default values to the browser user-agent styles.
Inheritable CSS Property
- visibility
- cursor
- color
- direction
- font-family
- font-size
- font-style
- font-variant
- font-weight
- font
- line-height
- letter-spacing
- word-spacing
- white-space
- text-align
- text-indent
- text-transform
- border-collapse
- border-spacing
- caption-side
- empty-cells
- list-style-image
- list-style-position
- list-style-type
- list-style
- orphans
- quotes
- widows
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 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 Pseudo Class
: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
- 鼠标移动到容器时的状态.
- 不仅限于链接, 可用于页面中的任何元素.
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.ginput
.:disabled
: 匹配禁用的界面元素 ([disabled]
), e.ginput
.: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 具有min
和max
属性的number
和range
输入框.:out-of-range
: 与:in-range
选择相反, 其中该值位于限制范围外.:required
: 匹配具有必填属性[required]
的表单元素.:optional
: 匹配没有必填属性[required]
的表单元素.:placeholder-shown
: selectinput
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
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;
}
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 {
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-increment
和counter-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 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
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:
- Textual data types.
- Numeric data types.
- Quantities.
- Combinations of types.
- Color data types.
- Image data types.
- 2D
<position>
.
CSS data types list:
- CSS formal syntax.
- CSS values.
- CSS units.
- CSS functions.
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:
- Handling the special values
inherit
,initial
,unset
, andrevert
- 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:
- the specified value is determined based on the result of cascading, inheritance, or using the initial value.
- the computed value is calculated according to the specification (for example, a span with position: absolute will have its computed display changed to block)
- layout is calculated, resulting in the used value
- the used value is transformed according to the limitations of the local environment, resulting in the actual value
- initial.
- specified.
- computed.
- used.
- actual value.
CSS Logical Properties and Values
CSS Logical Basis
In position
/size
/margin
/padding
/border
/text alignment
:
block-start
fortop
.block-end
forbottom
.block
for vertical.inline-start
forleft
.inline-end
forright
.inline
for horizontal.
.logical {
inline-size: fit-content;
block-size: fit-content;
min-inline-size: min-content;
min-block-size: min-content;
max-inline-size: max-content;
max-block-size: max-content;
padding-block-start: 1rem;
padding-block-end: 1rem;
padding-inline-start: 1rem;
padding-inline-end: 1rem;
margin-block-start: 1rem;
margin-block-end: 1rem;
margin-inline-start: 1rem;
margin-inline-end: 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;
inset-block-start: 0;
inset-block-end: 0;
inset-inline-start: 0;
inset-inline-end: 0;
}
CSS Logical Reference
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
[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;
isinvalid
value leading tovar(--invalid-value)
called failed,var(--invalid-value, backup-value)
getbackup-value
.--empty-value: ;
is validempty
value leading tovar(--empty-value)
called succeeded,var(--empty-value, backup-value)
getunset
value (inherit
orinitial
value).- Use
invalid
andempty
value to implementif (true)
statement, you can see real world case ontailwind.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-name {
syntax: '<color>';
inherits: false;
initial-value: #c0ffee;
}
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
变量使用当前color
计算值.border-color
/outline-color
/caret-color
/text-shadow
/box-shadow
默认表现为currentcolor
.
Accent Color
Change user-interface controls accent color.