Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
者近期在將前端架構 webpack 升級到 5 時,一些配套模塊也需要進行升級,其中包括了 css 處理模塊 PostCSS。舊版本使用的是 PostCSS 7,在升級至 PostCSS 8 的過程中,筆者發現部分插件前置依賴還是停留在 7 版本,且年久失修,在 PostCSS 8 中出現各種各樣的問題,無奈只能研究源碼,將目前部分舊版本插件升級至新版本。這里,筆者將升級插件的過程進行簡化和提煉,讓讀者自己也可以編寫一個 PostCSS 8 插件。
PostCSS 是一個允許使用 JS 插件轉換樣式的工具。開發者可以根據自己的實際需求,在編譯過程將指定 css 樣式進行轉換和處理。目前 PostCSS 官方收錄插件有 200 多款,其中包括使用最廣泛的Autoprefixer自動補全 css 前綴插件。
PostCSS 和插件的工作原理其實很簡單,就是先將 css 源碼轉換為 AST,插件基于轉換后 AST 的信息進行個性化處理,最后 PostCSS 再將處理后的 AST 信息轉換為 css 源碼,完成 css 樣式轉換,其流程可以歸結為下圖:
下面我們通過實際例子看看 PostCSS 會將 css 源碼轉換成的 AST 格式:
const postcss=require('postcss')
postcss().process(`
.demo {
font-size: 14px; /*this is a comment*/
}
`).then(result=> {
console.log(result)
})
復制代碼
代碼中直接引用 PostCSS,在不經過任何插件的情況下將 css 源碼進行轉換,AST 轉換結果如下:
{
"processor": {
"version": "8.3.6",
"plugins": []
},
"messages": [],
"root": {
"raws": {
"semicolon": false,
"after": "\n"
},
"type": "root",
// ↓ nodes字段內容重點關注
"nodes": [
{
"raws": {
"before": "\n",
"between": " ",
"semicolon": true,
"after": "\n"
},
"type": "rule",
"nodes": [
{
"raws": {
"before": "\n ",
"between": ": "
},
"type": "decl",
"source": {
"inputId": 0,
"start": {
"offset": 11,
"line": 3,
"column": 3
},
"end": {
"offset": 26,
"line": 3,
"column": 18
}
},
"prop": "font-size", // css屬性和值
"value": "14px"
},
{
"raws": {
"before": " ",
"left": "",
"right": ""
},
"type": "comment", // 注釋類
"source": {
"inputId": 0,
"start": {
"offset": 28,
"line": 3,
"column": 20
},
"end": {
"offset": 48,
"line": 3,
"column": 40
}
},
"text": "this is a comment"
}
],
"source": {
"inputId": 0,
"start": {
"offset": 1,
"line": 2,
"column": 1
},
"end": {
"offset": 28,
"line": 4,
"column": 1
}
},
"selector": ".demo", // 類名
"lastEach": 1,
"indexes": {}
}
],
"source": {
"inputId": 0,
"start": {
"offset": 0,
"line": 1,
"column": 1
}
},
"lastEach": 1,
"indexes": {},
"inputs": [
{
"hasBOM": false,
"css": "\n.demo {\n font-size: 14px;\n}\n",
"id": "<input css vi1Oew>"
}
]
},
"opts": {},
"css": "\n.demo {\n font-size: 14px;\n}\n"
}
復制代碼
AST 對象中 nodes 字段里的內容尤為重要,其中存儲了 css 源碼的關鍵字、注釋、源碼的起始、結束位置以及 css 的屬性和屬性值,類名使用selector存儲,每個類下又存儲一個 nodes 數組,該數組下存放的就是該類的屬性(prop)和屬性值(value)。那么插件就可以基于 AST 字段對 css 屬性進行修改,從而實現 css 的轉換。
PostCSS 插件其實就是一個 JS 對象,其基本形式和解析如下:
module.exports=(opts={ })=> {
// 此處可對插件配置opts進行處理
return {
postcssPlugin: 'postcss-test', // 插件名字,以postcss-開頭
Once (root, postcss) {
// 此處root即為轉換后的AST,此方法轉換一次css將調用一次
},
Declaration (decl, postcss) {
// postcss遍歷css樣式時調用,在這里可以快速獲得type為decl的節點(請參考第二節的AST對象)
},
Declaration: {
color(decl, postcss) {
// 可以進一步獲得decl節點指定的屬性值,這里是獲得屬性為color的值
}
},
Comment (comment, postcss) {
// 可以快速訪問AST注釋節點(type為comment)
},
AtRule(atRule, postcss) {
// 可以快速訪問css如@media,@import等@定義的節點(type為atRule)
}
}
}
module.exports.postcss=true
復制代碼
更多的 PostCSS 插件 API 可以詳細參考官方postcss8文檔,基本原理就是 PostCSS 會遍歷每一個 css 樣式屬性值、注釋等節點,之后開發者就可以針對個性需求對節點進行處理即可。
了解了 PostCSS 插件的格式和 API,我們將根據實際需求來開發一個簡易的插件,有如下 css:
.demo {
font-size: 14px; /*this is a comment*/
color: #ffffff;
}
復制代碼
需求如下:
根據第三節的插件格式,本次開發只需使用Comment和Declaration接口即可:
// plugin.js
module.exports=(opts={ })=> {
return {
postcssPlugin: 'postcss-test',
Declaration (decl, postcss) {
if (decl.value==='#ffffff') {
decl.value='white'
}
},
Comment(comment) {
comment.text=''
}
}
}
module.exports.postcss=true
復制代碼
在 PostCSS 中使用該插件:
// index.js
const plugin=require('./plugin.js')
postcss([plugin]).process(`
.demo {
font-size: 14px; /*this is a comment*/
color: #ffffff;
}
`).then(result=> {
console.log(result.css)
})
復制代碼
運行結果如下:
.demo {
font-size: 14px; /**/
color: white;
}
復制代碼
可以看到,字體顏色值已經成功做了轉換,注釋內容已經刪掉,但注釋標識符還依舊存在,這是因為注釋節點是包含/**/內容存在的,只要 AST 里注釋節點還存在,最后 PostCSS 還原 AST 時還是會把這段內容還原,要做到徹底刪掉注釋,需要對 AST 的 nodes 字段進行遍歷,將 type 為 comment 的節點進行刪除,插件源碼修改如下:
// plugin.js
module.exports=(opts={ })=> {
// Work with options here
// https://postcss.org/api/#plugin
return {
postcssPlugin: 'postcss-test',
Once (root, postcss) {
// Transform CSS AST here
root.nodes.forEach(node=> {
if (node.type==='rule') {
node.nodes.forEach((n, i)=> {
if (n.type==='comment') {
node.nodes.splice(i, 1)
}
})
}
})
},
Declaration (decl, postcss) {
// The faster way to find Declaration node
if (decl.value==='#ffffff') {
decl.value='white'
}
}
}
}
module.exports.postcss=true
復制代碼
重新執行 PostCSS,結果如下,符合預期。
.demo {
font-size: 14px;
color: white;
}
復制代碼
通過實操開發可以看到,開發一個 PostCSS 插件其實很簡單,但在實際的插件開發中,開發者需要注意以下事項:
Build code that is short, simple, clear, and modular.
盡量使你的插件和使用者代碼解耦,開放有限的 API,同時開發者在使用你的插件時從名字就可以知道插件的功能。這里推薦一個簡單而優雅的 PostCSS 插件postcss-focus,讀者可以從這個插件的源碼中體會這個設計理念。
如果你對自己的項目有個新點子,想自己開發一個插件去實現,在開始寫代碼前,可以先到 PostCSS 官方注冊的插件列表中查看是否有符合自己需求的插件,避免重復造輪子。不過截止目前(2021.8),大部分插件依舊停留在 PostCSS 8 以下,雖然 PostCSS 8 已經對舊版本插件做了處理,但在 AST 的解析處理上還是有差異,從實際使用過程中我就發現 PostCss8 使用低版本插件會導致 AST 內的source map丟失,因此目前而言完全兼容 PostCSS 8 的插件還需各位開發者去升級。
升級你的 PostCSS 插件具體可以參考官方給出的升級指引。這里只對部分關鍵部分做下解釋:
具體示例如下。
舊版插件:
- module.exports=postcss.plugin('postcss-dark-theme-class', (opts={})=> {
- checkOpts(opts)
- return (root, result)=> {
root.walkAtRules(atrule=> { … })
- }
- })
復制代碼
升級后插件:
+ module.exports=(opts={})=> {
+ checkOpts(opts)
+ return {
+ postcssPlugin: 'postcss-dark-theme-class',
+ Once (root, { result }) {
root.walkAtRules(atrule=> { … })
+ }
+ }
+ }
+ module.exports.postcss=true
復制代碼
把邏輯代碼都放在Once回調內還不夠優雅,PostCSS 8 已經實現了單個 css 的代碼掃描,提供了Declaration(), Rule(), AtRule(), Comment() 等方法,舊版插件類似root.walkAtRules的方法就可以分別進行重構,插件效率也會得到提升:
module.exports={
postcssPlugin: 'postcss-dark-theme-class',
- Once (root) {
- root.walkAtRules(atRule=> {
- // Slow
- })
- }
+ AtRule (atRule) {
+ // Faster
+ }
}
module.exports.postcss=true
復制代碼
通過本文的介紹,讀者可以了解 PostCSS 8 工作的基本原理,根據具體需求快速開發一個 PostCSS 8 插件,并在最后引用官方示例中介紹了如何快速升級舊版 PostCSS 插件。目前 PostCSS 8 還有大量還沒進行升級兼容的 PostCSS 插件,希望讀者可以在閱讀本文后可以獲得啟發,對 PostCSS 8 的插件生態做出貢獻。
nicode 聯盟(Unicode Consortium)
Unicode 聯盟(Unicode Consortium)開發了 Unicode 標準(Unicode Standard)。他們的目標是使用標準的 Unicode 轉換格式(即 UTF,全稱 Unicode Transformation Format)取代現有的字符集。
Unicode 標準是一個成功的創舉,在 HTML、XML、Java、JavaScript、E-mail、ASP、PHP 中都得到實現。Unicode 標準也得到許多操作系統和所有現代瀏覽器的支持。
Unicode 聯盟與領先的標準開發組織合作,這些組織有 ISO、W3C 和 ECMA。
Unicode 字符集
Unicode 可以由不同的字符集實現。最常用的編碼是 UTF-8 和 UTF-16:
字符集 | 描述 |
---|---|
UTF-8 | UTF8 中的字符可以是 1 到 4 字節長。UTF-8 可以代表 Unicode 標準中的任何字符。UTF-8 向后兼容 ASCII。UTF-8 是電子郵件和網頁的首選編碼。 |
UTF-16 | 16 位 Unicode 轉換格式是一種可變長度的 Unicode 字符編碼,能夠編碼整個 Unicode 指令表。UTF-16 主要用于操作系統和環境,如 Microsoft Windows、Java 和 .NET。 |
提示:Unicode 的前 128 個字符(與 ASCII 一一對應)使用一個與 ASCII二進制值相同的八位組進行編碼,使有效的 ASCII 文本在進行 UTF-8 編碼時也是有效的。
提示:所有的 HTML 4 處理器支持 UTF-8,所有的 HTML 5 和 XML 處理器支持 UTF-8 和 UTF-16!
HTML5 標準:Unicode UTF-8
因為 ISO-8859 中字符集大小是有限的,且在多語言環境中不兼容,所以 Unicode 聯盟開發了 Unicode 標準。
Unicode 標準覆蓋了(幾乎)所有的字符、標點符號和符號。
Unicode 使文本的處理、存儲和運輸,獨立于平臺和語言。
HTML-5 中默認的字符編碼是 UTF-8。
下面列出了一些 HTML5 支持的 UTF-8 字符集:
字符集 | 十進制 | 十六進制 |
---|---|---|
C0 控制與基本的 Latin(C0 Controls and Basic Latin) | 0-127 | 0000-007F |
C1 控制與 Latin-1 的補充(C1 Controls and Latin-1 Supplement) | 128-255 | 0080-00FF |
Latin 擴展 A(Latin Extended-A) | 256-383 | 0100-017F |
Latin 擴展 B(Latin Extended-B) | 384-591 | 0180-024F |
如果 HTML5 網頁使用不同于 UTF-8 的字符,則需要在 <meta> 標簽中指定,如下:
實例
<meta charset="ISO-8859-1">
如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!
ello大家好,今天廣州藍景跟大家分享一些html的使用技巧。
1. 使用capture屬性打開設備攝像頭
正如input標簽具有email、text和password屬性一樣,我們也可以通過一些屬性打開移動設備的攝像頭以捕獲圖像。
那就是capture屬性,屬性值有兩個:
<input type="file" capture="user" accept="image/*">
2. 網站自動刷新
你可以在head標簽中將網站設置為定時刷新!
<head>
<meta http-equiv="refresh" content="10">
</head>
此代碼段可以實現每10秒刷新一次網站。
3. 激活拼寫檢查
你可以使用HTML的spellcheck屬性并將其設置為true以激活拼寫檢查。使用lang屬性指定待檢查的語言。
<input type="text" spellcheck="true" lang="en">
這是一個標準屬性,得到了大多數瀏覽器的支持。
4. 指定要上傳的文件類型
你可以使用accept屬性在input標簽中指定允許用戶上傳的文件類型。
<input type="file" accept=".jpeg,.png">
5. 阻止瀏覽器翻譯
將translate屬性設置為no會阻止瀏覽器翻譯該內容。如果你不想翻譯某個短語或單詞,例如logo、公司或品牌名稱,那就可以應用這個屬性。
<p translate="no">Brand name</p>
6. 在input標簽中輸入多個項目
這可以通過multiple屬性來完成。
<input type="file" multiple>
適用于文件和電子郵件。如果是電子郵件,則可以用逗號分隔。
7. 為視頻創建海報(縮略圖)
使用poster屬性,我們可以在視頻加載時,或者在用戶點擊播放按鈕之前,顯示指定的縮略圖。
如果不指定圖片,則默認使用視頻的第一幀作為縮略圖。
<video poster="picture.png"></video>
8. 點擊鏈接自動下載
如果你希望在單擊目標資源的鏈接時下載特定資源,那就添加download屬性。
<a href="image.png" download>
今天就分享到這里,想要了解更多前端技術知識,可以關注我們廣州藍景。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。