CSS @property,讓不可能變可能
根據(jù) MDN -- CSS Property[1],@property CSS at-rule 是 CSS Houdini API 的一部分, 它允許開發(fā)者顯式地定義他們的 CSS 自定義屬性,允許進(jìn)行屬性類型檢查、設(shè)定默認(rèn)值以及定義該自定義屬性是否可以被繼承。
CSS Houdini 又是什么呢,CSS Houdini 開放 CSS 的底層 API 給開發(fā)者,使得開發(fā)者可以通過這套接口自行擴(kuò)展 CSS,并提供相應(yīng)的工具允許開發(fā)者介入瀏覽器渲染引擎的樣式和布局流程中,使開發(fā)人員可以編寫瀏覽器可以解析的 CSS 代碼,從而創(chuàng)建新的 CSS 功能。當(dāng)然,它不是本文的重點(diǎn),不過多描述。
CSS Property 如何使用呢?我們將通過一些簡單的例子快速上手,并且著重介紹它在 CSS 動(dòng)畫中起到的關(guān)鍵性的作用,對(duì) CSS 動(dòng)畫帶來的巨大提升。
示例
正常而言,我們定義和使用一個(gè) CSS 自定義屬性的方法是這樣的:
- :root {
- --whiteColor: #fff;
- }
- p {
- color: (--whiteColor);
- }
而有了 @property 規(guī)則之后,我們還可以像下述代碼這樣去定義個(gè) CSS 自定義屬性:
- <style>
- @property --property-name {
- syntax: '<color>';
- inherits: false;
- initial-value: #fff;
- }
- p {
- color: var(--property-name);
- }
- </style>
簡單解讀下:
- @property --property-name 中的 --property-name 就是自定義屬性的名稱,定義后可在 CSS 中通過 var(--property-name) 進(jìn)行引用
- syntax:該自定義屬性的語法規(guī)則,也可以理解為表示定義的自定義屬性的類型
- inherits:是否允許繼承
- initial-value:初始值
其中,@property 規(guī)則中的 syntax 和 inherits 描述符是必需的。
當(dāng)然,在 JavaScript 內(nèi)定義的寫法也很簡單,順便一提:
- <script>
- CSS.registerProperty({
- name: "--property-name",
- syntax: "<color>",
- inherits: false,
- initialValue: "#c0ffee"
- });
- </script>
支持的 syntax 語法類型
syntax 支持的語法類型非常豐富,基本涵蓋了所有你能想到的類型。
- length
- number
- percentage
- length-percentage
- color
- image
- url
- integer
- angle
- time
- resolution
- transform-list
- transform-function
- custom-ident (a custom identifier string)
syntax 中的 +、#、| 符號(hào)
定義的 CSS @property 變量的 syntax 語法接受一些特殊的類型定義。
- syntax: '
- syntax: '
- syntax: '
':接受單個(gè)長度或者以空格分隔的長度值列表
OK,鋪墊了這么多,那么為什么要使用這么麻煩的語法定義 CSS 自定義屬性呢?CSS Houdini 定義的自定義變量的優(yōu)勢在哪里?下面我們一一娓娓道來。
使用 color syntax 語法類型作用于漸變
我們來看這樣一個(gè)例子,我們有這樣一個(gè)漸變的圖案:
- <div></div>
- div {
- background: linear-gradient(45deg, #fff, #000);
- }
我們改造下上述代碼,改為使用 CSS 自定義屬性:
- :root {
- --colorA: #fff;
- --colorB: #000;
- }
- div {
- background: linear-gradient(45deg, var(--colorA), var(--colorB));
- }
得到的還是同樣的一個(gè)漸變圖:
我們?cè)偌由弦粋€(gè)過渡效果:
- :root {
- --colorA: #fff;
- --colorB: #000;
- }
- div {
- background: linear-gradient(45deg, var(--colorA), var(--colorB));
- transition: 1s background;
- &:hover {
- --colorA: yellowgreen;
- --colorB: deeppink;
- }
- }
看看鼠標(biāo) Hover 的時(shí)候,會(huì)發(fā)生什么:
雖然我們?cè)O(shè)定了 1s 的過渡動(dòng)畫 transition: 1s background,但是很可惜,CSS 是不支持背景漸變色的直接過渡變化的,我們得到的只是兩幀之間的之間變化。
使用 CSS @property 進(jìn)行改造
OK,接下來我們就是有本文的主角,使用 Houdini API 中的 CSS 自定義屬性替換原本的 CSS 自定義屬性。
簡單進(jìn)行改造一下,使用 color syntax 語法類型:
- @property --houdini-colorA {
- syntax: '<color>';
- inherits: false;
- initial-value: #fff;
- }
- @property --houdini-colorB {
- syntax: '<color>';
- inherits: false;
- initial-value: #000;
- }
- .property {
- background: linear-gradient(45deg, var(--houdini-colorA), var(--houdini-colorB));
- transition: 1s --houdini-colorA, 1s --houdini-colorB;
- &:hover {
- --houdini-colorA: yellowgreen;
- --houdini-colorB: deeppink;
- }
- }
我們使用了 @property 語法,定義了兩個(gè) CSS Houdini 自定義變量 --houdini-colorA 和 --houdini-colorB,在 hover 變化的時(shí)候,改變這兩個(gè)顏色。
需要關(guān)注的是,我們?cè)O(shè)定的過渡語句 transition: 1s --houdini-colorA, 1s --houdini-colorB,在這里,我們是針對(duì) CSS Houdini 自定義變量設(shè)定過渡,而不是針對(duì) background 設(shè)定過渡動(dòng)畫,再看看這次的效果:
Wow,成功了,漸變色的變化從兩幀的逐幀動(dòng)畫變成了補(bǔ)間動(dòng)畫,實(shí)現(xiàn)了從一個(gè)漸變色過渡到另外一個(gè)漸變色的效果!而這,都得益于 CSS Houdini 自定義變量的強(qiáng)大能力!
CodePen Demo -- CSS Houdini 自定義變量實(shí)現(xiàn)漸變色過渡動(dòng)畫[2]
使用 CSS @property 實(shí)現(xiàn)漸變背景色過渡動(dòng)畫
在上述的 DEMO 中,我們利用了 CSS Houdini 自定義變量,將原本定義在 background 的過渡效果嫁接到了 color 之上,而 CSS 是支持一個(gè)顏色變換到另外一個(gè)顏色的,這樣,我們巧妙的實(shí)現(xiàn)了漸變背景色的過渡動(dòng)畫。
在之前我們有討論過在 CSS 中有多少種方式可以實(shí)現(xiàn)漸變背景色過渡動(dòng)畫 -- 巧妙地制作背景色漸變動(dòng)畫![3],到今天,我們又多了一種實(shí)現(xiàn)的方式!
- @property --colorA {
- syntax: '<color>';
- inherits: false;
- initial-value: fuchsia;
- }
- @property --colorC {
- syntax: '<color>';
- inherits: false;
- initial-value: #f79188;
- }
- @property --colorF {
- syntax: '<color>';
- inherits: false;
- initial-value: red;
- }
- div {
- background: linear-gradient(45deg,
- var(--colorA),
- var(--colorC),
- var(--colorF));
- animation: change 10s infinite linear;
- }
- @keyframes change {
- 20% {
- --colorA: red;
- --colorC: #a93ee0;
- --colorF: fuchsia;
- }
- 40% {
- --colorA: #ff3c41;
- --colorC: #e228a0;
- --colorF: #2e4c96;
- }
- 60% {
- --colorA: orange;
- --colorC: green;
- --colorF: teal;
- }
- 80% {
- --colorA: #ae63e4;
- --colorC: #0ebeff;
- --colorF: #efc371;
- }
- }
完整的代碼可以戳這里:
CodePen Demo -- CSS Houdini 自定義變量實(shí)現(xiàn)漸變色過渡動(dòng)畫2[4]
conic-gradient 配合 CSS @property 實(shí)現(xiàn)餅圖動(dòng)畫
OK,上面我們演示了 syntax 為 color 語法類型的情況。在文章一開頭,我們還列舉了非常多的 syntax 類型。
下面我們嘗試下其他的類型,使用 percentage 百分比類型或者 angle 角度類型,實(shí)現(xiàn)一個(gè)餅圖的 hover 動(dòng)畫。
如果我們還是使用傳統(tǒng)的寫法,利用角向漸變實(shí)現(xiàn)不同角度的餅圖:
- <div></div>
- .normal {
- width: 200px;
- height: 200px;
- border-radius: 50%;
- background: conic-gradient(yellowgreen, yellowgreen 25%, transparent 25%, transparent 100%);
- transition: background 300ms;
- &:hover {
- background: conic-gradient(yellowgreen, yellowgreen 60%, transparent 60.1%, transparent 100%);
- }
- }
將會(huì)得到這樣一種效果,由于 conic-gradient 也是不支持過渡動(dòng)畫的,得到的是一幀向另外一幀的直接變化:
好,使用 CSS Houdini 自定義變量改造一下:
- @property --per {
- syntax: '<percentage>';
- inherits: false;
- initial-value: 25%;
- }
- div {
- background: conic-gradient(yellowgreen, yellowgreen var(--per), transparent var(--per), transparent 100%);
- transition: --per 300ms linear;
- &:hover {
- --per: 60%;
- }
- }
看看改造后的效果:
CodePode Demo -- conic-gradient 配合 CSS @property 實(shí)現(xiàn)餅圖動(dòng)畫[5]
以往使用純 CSS 非常復(fù)雜才能實(shí)現(xiàn)的效果,如果可以輕松的達(dá)成,不得不感慨 CSS @property 強(qiáng)大的能力!
syntax 的 | 符號(hào)
順便演示一下定義 Houdini 自定義變量時(shí) syntax 的一些稍微復(fù)雜點(diǎn)的用法。
在 conic-gradient 中,我們可以使用百分比也可以使用角度作為關(guān)鍵字,上述的 DEMO 也可以改造成這樣:
- @property --per {
- syntax: '<percentage> | <angle>';
- inherits: false;
- initial-value: 25%;
- }
- ...
表示,我們的自定義屬性即可以是一個(gè)百分比值,也可以是一個(gè)角度值。
除了 | 符號(hào)外,還有 + 和 # 號(hào)分別表示接受以空格分隔、和以逗號(hào)分隔的屬性,感興趣的可以自行嘗試。
使用 length 類型作用于一些長度變化
掌握了上述的技巧,我們就可以利用 Houdini 自定義變量的這個(gè)能力,去填補(bǔ)修復(fù)以前無法直接過渡動(dòng)畫的一些效果了。
過去,我們想實(shí)現(xiàn)這樣一個(gè)文字下劃線的 Hover 效果:
- p {
- text-underline-offset: 1px;
- text-decoration-line: underline;
- text-decoration-color: #000;
- transition: all .3s;
- &:hover {
- text-decoration-color: orange;
- text-underline-offset: 10px;
- color: orange;
- }
- }
因?yàn)?text-underline-offset 不支持過渡動(dòng)畫,得到的結(jié)果如下:
使用 Houdini 自定義變量改造,化腐朽為神奇:
- @property --offset {
- syntax: '<length>';
- inherits: false;
- initial-value: 0;
- }
- div {
- text-underline-offset: var(--offset, 1px);
- text-decoration: underline;
- transition: --offset 400ms, text-decoration-color 400ms;
- &:hover {
- --offset: 10px;
- color: orange;
- text-decoration-color: orange;
- }
- }
可以得到絲滑的過渡效果:
CodePen Demo - Underlines hover transition(Chrome solution with Houdini)[6]
實(shí)戰(zhàn)一下,使用 CSS @property 配合 background 實(shí)現(xiàn)屏保動(dòng)畫
嗯,因?yàn)?CSS @property 的存在,讓以前需要非常多 CSS 代碼的工作,一下子變得簡單了起來。
我們嘗試?yán)?CSS @property 配合 background,簡單的實(shí)現(xiàn)一個(gè)屏保動(dòng)畫。
我們利用 background 可以簡單的得到這樣一個(gè)圖形,代碼如下:
- html, body {
- width: 100%;
- height: 100%;
- }
- body {
- background-image:
- radial-gradient(
- circle at 86% 7%,
- rgba(40, 40, 40, 0.04) 0%,
- rgba(40, 40, 40, 0.04) 50%,
- rgba(200, 200, 200, 0.04) 50%,
- rgba(200, 200, 200, 0.04) 100%
- ),
- radial-gradient(
- circle at 15% 16%,
- rgba(99, 99, 99, 0.04) 0%,
- rgba(99, 99, 99, 0.04) 50%,
- rgba(45, 45, 45, 0.04) 50%,
- rgba(45, 45, 45, 0.04) 100%
- ),
- radial-gradient(
- circle at 75% 99%,
- rgba(243, 243, 243, 0.04) 0%,
- rgba(243, 243, 243, 0.04) 50%,
- rgba(37, 37, 37, 0.04) 50%,
- rgba(37, 37, 37, 0.04) 100%
- ),
- linear-gradient(rgb(34, 222, 237), rgb(135, 89, 215));
- }
效果如下,還算可以的靜態(tài)背景圖:
在往常,我們想讓它動(dòng)起來,其實(shí)是需要費(fèi)一定的功夫的,而現(xiàn)在,通過 CSS @property,對(duì)我們希望進(jìn)行動(dòng)畫的一些元素細(xì)節(jié)進(jìn)行改造,可以得到非常不錯(cuò)的動(dòng)畫效果:
- body,
- html {
- width: 100%;
- height: 100%;
- }
- @property --perA {
- syntax: '<percentage>';
- inherits: false;
- initial-value: 75%;
- }
- @property --perB {
- syntax: '<percentage>';
- inherits: false;
- initial-value: 99%;
- }
- @property --perC {
- syntax: '<percentage>';
- inherits: false;
- initial-value: 15%;
- }
- @property --perD {
- syntax: '<percentage>';
- inherits: false;
- initial-value: 16%;
- }
- @property --perE {
- syntax: '<percentage>';
- inherits: false;
- initial-value: 86%;
- }
- @property --angle {
- syntax: '<angle>';
- inherits: false;
- initial-value: 0deg;
- }
- body {
- background-image:
- radial-gradient(
- circle at var(--perE) 7%,
- rgba(40, 40, 40, 0.04) 0%,
- rgba(40, 40, 40, 0.04) 50%,
- rgba(200, 200, 200, 0.04) 50%,
- rgba(200, 200, 200, 0.04) 100%
- ),
- radial-gradient(
- circle at var(--perC) var(--perD),
- rgba(99, 99, 99, 0.04) 0%,
- rgba(99, 99, 99, 0.04) 50%,
- rgba(45, 45, 45, 0.04) 50%,
- rgba(45, 45, 45, 0.04) 100%
- ),
- radial-gradient(
- circle at var(--perA) var(--perB),
- rgba(243, 243, 243, 0.04) 0%,
- rgba(243, 243, 243, 0.04) 50%,
- rgba(37, 37, 37, 0.04) 50%,
- rgba(37, 37, 37, 0.04) 100%
- ),
- linear-gradient(var(--angle), rgb(34, 222, 237), rgb(135, 89, 215));
- animation: move 30s infinite alternate linear;
- }
- @keyframes move {
- 100% {
- --perA: 85%;
- --perB: 49%;
- --perC: 45%;
- --perD: 39%;
- --perE: 70%;
- --angle: 360deg;
- }
- }
效果如下(因?yàn)?Gif 上傳大小限制,加快了速率,截取了其中一部分,簡單做個(gè)示意):
整體的效果還是挺不錯(cuò)的,完整的 Demo 你可以戳這里:
CodePen Demo -- CSS @property PureCSS Wrapper[7]
參考文獻(xiàn):
CSS Properties and Values API Level 1[8]
最后
好了,本文到此結(jié)束,介紹了 CSS Houdini API 中的 CSS @property 部分,并且利用它實(shí)現(xiàn)了一些以往無法簡單實(shí)現(xiàn)的動(dòng)畫效果,希望對(duì)你有幫助 :)
更多精彩 CSS 技術(shù)文章匯總在我的 Github -- iCSS[9] ,持續(xù)更新,歡迎點(diǎn)個(gè) star 訂閱收藏。
如果還有什么疑問或者建議,可以多多交流,原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,萬望告知。
參考資料
[1]MDN -- CSS Property:
https://developer.mozilla.org/zh-CN/docs/Web/CSS/@property
[2]CodePen Demo -- CSS Houdini 自定義變量實(shí)現(xiàn)漸變色過渡動(dòng)畫:
https://codepen.io/Chokcoco/pen/eYgyWLB?editors=1100
[3]巧妙地制作背景色漸變動(dòng)畫!:
https://github.com/chokcoco/iCSS/issues/10
[4]CodePen Demo -- CSS Houdini 自定義變量實(shí)現(xiàn)漸變色過渡動(dòng)畫2:
https://codepen.io/Chokcoco/pen/Bapmzbd
[5]CodePode Demo -- conic-gradient 配合 CSS @property 實(shí)現(xiàn)餅圖動(dòng)畫:
https://codepen.io/Chokcoco/pen/QWdqMvo
[6]CodePen Demo - Underlines hover transition(Chrome solution with Houdini):
https://codepen.io/Chokcoco/pen/jOymJZR
[7]CodePen Demo -- CSS @property PureCSS Wrapper:
https://codepen.io/Chokcoco/pen/VwPxMBP
[8]CSS Properties and Values API Level 1:
https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule
[9]Github -- iCSS:
https://github.com/chokcoco/iCSS