by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8512
本文可全文轉載,個人網站無需授權,只要保留原作者、出處以及文中鏈接即可,任何網站均可摘要聚合,商用請聯繫授權。
一、大多數開發人員的實現
大多數前端開發人員實現網站皮膚更換功能大致下面兩種方法:
- 一個全局class控制樣式切換;
- 改變皮膚link元素的href地址。例如:
<link id="skinLink" href="skin-default.css" rel="stylesheet" type="text/css">
換皮膚的時候JS改變href屬性值:
skinLink.href = 'skin-red.css';
例如我10年前模擬騰訊網首頁的換膚功能做的demo頁面就是這麼實現的。
都不完美。全局class控制樣式提高了樣式優先級,如果換膚樣式很多,代碼會非常囉嗦,不利於維護;使用JS改變href屬性會帶來加載延遲,樣式切換不流暢,體驗不佳。
實際上,瀏覽器有原生特性,非常適合實現網站換膚功能。
二、原生HTML特性下的網站換膚
此方法藉助HTML rel
屬性的alternate
屬性值實現。示意HTML如下:
<link href="reset.css" rel="stylesheet" type="text/css"> <link href="default.css" rel="stylesheet" type="text/css" title="默認"> <link href="red.css" rel="alternate stylesheet" type="text/css" title="紅色"> <link href="green.css" rel="alternate stylesheet" type="text/css" title="綠色">
上面4個<link>
元素,共出現了3中不同性質的CSS樣式文件加載:
- 沒有title屬性,rel屬性值僅僅是stylesheet的
<link>
無論如何都會加載並渲染,如reset.css; - 有title屬性,rel屬性值僅僅是stylesheet的
<link>
作爲默認樣式CSS文件加載並渲染,如default.css; - 有title屬性,rel屬性值同時包含alternate stylesheet的
<link>
作爲備選樣式CSS文件加載,默認不渲染,如red.css和green.css;
這裏有個非常有趣的特性,那就是rel="stylesheet"
的<link>
如果有title屬性並有值,性質上就變成了一個可以控制其渲染或者不渲染的特殊元素了。
如何控制呢?
一種說是瀏覽器自己會有樣式切換菜單,查看→頁面,選擇title屬性值對應的樣式。我猜這是10年前的說法了吧,現在瀏覽器根本沒有這些菜單選項,至少我找了好久,各個瀏覽器都找了個遍沒找到。
另外一種就是使用JS進行控制了,使用JavaScript代碼修改<link>
元素DOM對象的disabled
值爲false
,可以讓默認不渲染的CSS開始渲染。注意,必須是DOM元素對象的disabled屬性,而不是HTML元素的disabled屬性,<link>
元素是沒有disabled屬性的。
例如:
// 渲染red.css這個皮膚 document.querySelector('link[href="red.css"]').disabled = false;
因此,要實現換膚功能,只要在頁面上方几個換膚按鈕,點擊的時候改變對應<link>
元素DOM對象的disabled
值就可以了。
眼見爲實,我專門做了demo頁面,您可以狠狠地點擊這裏:link rel alternate實現網站換膚功能demo
結果如下GIF截圖所示(截自IE瀏覽器):
demo頁面是使用單選框模擬實現的,HTML和JS代碼如下:
<input id="default" type="radio" name="skin" value="default.css" checked> <input id="red" type="radio" name="skin" value="red.css"> <input id="green" type="radio" name="skin" value="green.css">
var eleLinks = document.querySelectorAll('link[title]'); var eleRadios = document.querySelectorAll('[type="radio"]'); [].slice.call(eleRadios).forEach(function (radio) { radio.addEventListener('click', function () { var value = this.value; [].slice.call(eleLinks).forEach(function (link) { link.disabled = true; if (link.getAttribute('href') == value) { // 該樣式CSS文件生效 link.disabled = false; } }); }); });
三、link rel=alternate方法實現優點
3大優點:
- 兼容性非常好。IE9+(IE8我沒測,理論也支持),Chrome和Firefox均支持這種更原生的換膚效果實現。
- 語義非常好。用戶,開發者,尤其搜索引擎或者其他輔助閱讀設備能夠準確識別網站還有其他替換CSS樣式。(alternate的語義就是可替換的)
- 交互體驗更好。rel=alternate方法實現的換膚功能在網站樣式變換的時候是瞬間切換,完全無感知。因爲瀏覽器已經把換膚的CSS文件預加載好了,比JS改變href地址的體驗要更好。配合http2.0,幾乎可以說是完美無瑕的解決方案了。
爲什麼之前沒有人提過這個方法?
此方法我也是最近在學習rel屬性值的時候知道的,看到MDN上關於Alternative_style_sheets文檔學到的,之前並不知曉還有這麼給力的實現。
Firefox4就開始支持這一特性,說明此方法很久遠了,我搜索了下,還是有少數前輩知道並使用這種方法換膚的,但是,至少對於新人前端(如果按照我在例會上的統計)幾乎無人知曉。
什麼原因造成這種現象呢?
首先,換膚是小衆需求;
其次,有符合常規認知的替換方案,最終效果也能接受;
然後,都在學習高大上的東西,什麼HTML基礎知識根本無人問津;
最後,缺少有影響力的的入口進行科普。