天天看點

細說alternate三兩事「精修版」

alternate?你沒搞錯吧?這不就是“交替、替換”嗎?這有什麼好說的?

但是如果我問出來:alternate在HTML中的用法,具體作用,可能你隻能說:“诶這不是那啥麼”。

說實話我一開始也壓根不知道有這個東西,但是就在前兩天這玩意解決了我的一大“難題”,頓時這興趣不就來了麼!

細說alternate三兩事「精修版」

alternate在網站換膚方面的應用

好吧想來你也遇到過這種情況:網頁換膚!

其實我們的選擇還是挺多的,比如:

  • 設定不同顔色,用JavaScript去一個一個的操控、替換(或者設定“全局的”class名)
  • 用JavaScript替換link标簽的href值

對啊,這兩個怎麼看都感覺非常好啊 —— 那是你不知道:

  • 全局class控制樣式提高了樣式優先級
  • 使用JS改變href屬性會帶來加載延遲
永遠不要在大場景中使用js直接操作css樣式或者足以引起重排 and 重繪的HTML屬性

但是link标簽的rel中支援值“alternate”值 ,事情瞬間就不一樣了。我們先來看下關于此屬性值相關的一些寫法:

原理介紹

<link href="index.css" rel="stylesheet" type="text/css">      

↑ 沒有title屬性,rel屬性值僅僅是stylesheet的​

​<link>​

​ —— 無論如何都會加載并渲染;

<link href="default.css" rel="stylesheet" type="text/css" title="預設">      

↑ 有title屬性,但rel屬性值仍僅僅是stylesheet的​

​<link>​

​ —— 作為預設樣式CSS檔案加載并渲染;

如果這時候有一個具有title的link和一個沒有title屬性的link标簽同時存在,那麼浏覽器依然會按照“就近原則”取離标簽近的那個css檔案執行裡面的代碼。
<link href="gray.css" rel="alternate stylesheet" type="text/css" title="灰色">      

↑ 有title屬性,rel屬性值同時包含alternate stylesheet的​

​<link>​

​ —— 作為備選樣式CSS檔案加載,預設不渲染;

這裡有個非常有趣的特性,那就是 rel=“stylesheet” 的 link标簽 如果有 title屬性 并有值,性質上就變成了一個可以控制其渲染或者不渲染的特殊元素了。—— 張鑫旭

渲染不渲染?這不就相當于display了?

如此,使用JavaScript代碼修改​​

​<link>​

​元素DOM對象的disabled值為false,可以讓預設不渲染(rel含有alternate)的外鍊CSS開始渲染。注意,必須是DOM元素對象的disabled屬性,而不是HTML元素的disabled屬性, link 元素是沒有disabled屬性的 。就像這樣:

document.querySelector('link[href="gray.css"]').disabled = false;      
“DOM的”和“HTML的”兩者有本質差別:HTML元素的屬性通常是指其CSS樣式,即​

​xxx.style.xxx​

​ ;而DOM對象的屬性通常是“挂載到對象原型上的屬性”(函數才有“原型鍊”)

我們可以看到:具有alternate的css檔案在下載下傳完成後并不會被建構到CSSOM中!可以很好地适配我們的需求。

代碼實作

我們可以用input的radio标簽來控制「切換」:

//head中部分内容:
<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="綠色">
//HTML代碼:
<p>
    選擇樣式:
    <input id="default" type="radio" name="skin" value="default.css" checked><label for="default">預設</label>
    <input id="red" type="radio" name="skin" value="red.css"><label for="red">紅色</label>
    <input id="green" type="radio" name="skin" value="green.css"><label for="green">綠色</label>
</p>
//JS代碼:
var eleLinks = document.querySelectorAll('link[title]');
var eleRadios = document.querySelectorAll('input[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) {
                link.disabled = false;
            }
        });
    });
});      

alternate的其他用途

你以為就這?

比如:如果網頁有對應的移動版變體,就要為其添加 rel=“alternate” ,并使其【指向】此網頁的移動版:

<link rel="alternate" media="only screen and (max-width: 640px)" href="xxx" >      

這對于網站的性能提升是巨大的!

alternate在SEO方面的應用

​link​

​​中​

​rel​

​​屬性還有一個值:​

​canoncial​

​ 。當站記憶體在多個内容相同或相似的頁面時,可以使用該标簽來指向其中一個作為規範頁面。要知道,不隻是主路由不同,即便是 http 協定不同(http / https)、查詢字元串的微小差異(有無參數 / 參數異同),搜尋引擎都會視為完全不同的頁面 / 連結。假如有很多這種雷同頁面,其權重便被無情稀釋了。

假如搜尋引擎遵守該标簽的約定,則會很大程度避免頁面權重的分散,不至影響搜尋引擎的收錄及排名情況。它的含義與 http-301 永久重定向相似(我們可以在“網站進行了改版,将舊的内容搬到了新的URL連結上,但是沒有做301重定向”的時候使用它)。不同之處在于,使用者通路标記了 ​

​canonical​

​ 标簽的頁面并不會真的重定向到其他頁面。

它通常和 ​

​alternate​

​​ 一起使用 —— 理論上說:假如你為移動端和 pc 端裝置分别提供了單獨的站點,這個标簽或許能派上用場。

我們可以用它們告訴搜尋引擎在哪種場景下應該選擇哪個資源!

但是這個用法目前筆者還沒有找到合适的實踐,也沒有查到相關探索。慎用!

使用alternate的優勢

  1. 相容性非常好
  2. 語義非常好。使用者,開發者,尤其搜尋引擎或者其他輔助閱讀裝置能夠準确識别網站還有其他替換CSS樣式。(alternate的語義就是“可替換的”)
  3. 互動體驗更好。​

    ​rel=alternate​

    ​方法實作的換膚功能在網站樣式變換的時候是瞬間切換,完全無感覺。因為浏覽器已經把換膚的CSS檔案預加載好了,比JS改變href位址的體驗要更好。

擴充:換膚還有什麼高效的方法

// 擷取任意 Dom 節點上的 CSS 變量
getComputedStyle(element).getPropertyValue("--my-var");

// 修改一個 Dom 節點上的 CSS 變量
element.style.setProperty("--my-var", jsVar + 4);      
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>* {
        margin: 0;
        padding: 0;
      }
      :root {
        --bg: #000;
        --fontSize: 25px;
      }
      .pink-theme {
        --bg: hotpink;
        --fontColor: red;
      }
      body {
        transition: background 1s;
        background: var(--bg);
      }
      button {
        position: fixed;
        top: 50%;
        left: 50%;
        transition: color 1s;
        transform: translate(-50%, -50%);
        padding: 20px;
        border: none;
        background: var(--bg);
        font-size: var(--fontSize);
        color: var(--fontColor);
      }</style>
  </head>
  <body>
    <button>點選切換</button>
    <script>.querySelector("button").addEventListener("click", () => {
        if (document.body.classList.contains("pink-theme")) {
          document.body.classList.remove("pink-theme");
        } else {
          document.body.classList.add("pink-theme");
        }
      });</script>
  </body>
</html>      

繼續閱讀