细说alternate三两事「精修版」

Posted 恪愚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了细说alternate三两事「精修版」相关的知识,希望对你有一定的参考价值。

alternate?你没搞错吧?这不就是“交替、替换”吗?这有什么好说的?

但是如果我问出来:alternate在html中的用法,具体作用,可能你只能说:“诶这不是那啥么”。

说实话我一开始也压根不知道有这个东西,但是就在前两天这玩意解决了我的一大“难题”,顿时这兴趣不就来了么!
heihei

alternate在网站换肤方面的应用

好吧想来你也遇到过这种情况:网页换肤!
其实我们的选择还是挺多的,比如:

  • 设置不同颜色,用javascript去一个一个的操控、替换(或者设置“全局的”class名)
  • 用JavaScript替换link标签的href值

对啊,这两个怎么看都感觉非常好啊 —— 那是你不知道:

  • 全局class控制样式提高了样式优先级 ,如果换肤样式很多,代码将“冗余”,不利于维护(JS代码将阻塞页面渲染、造成页面回流/重绘)
  • 使用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方面的应用

linkrel属性还有一个值:canoncial 。当站内存在多个内容相同或相似的页面时,可以使用该标签来指向其中一个作为规范页面。要知道,不只是主路由不同,即便是 http 协议不同(http / https)、查询字符串的微小差异(有无参数 / 参数异同),搜索引擎都会视为完全不同的页面 / 链接。假如有很多这种雷同页面,其权重便被无情稀释了。

假如搜索引擎遵守该标签的约定,则会很大程度避免页面权重的分散,不至影响搜索引擎的收录及排名情况。它的含义与 http-301 永久重定向相似(我们可以在“网站进行了改版,将旧的内容搬到了新的URL链接上,但是没有做301重定向”的时候使用它)。不同之处在于,用户访问标记了 canonical 标签的页面并不会真的重定向到其他页面。

它通常和 alternate 一起使用 —— 理论上说:假如你为移动端和 pc 端设备分别提供了单独的站点,这个标签或许能派上用场。
我们可以用它们告诉搜索引擎在哪种场景下应该选择哪个资源!

但是这个用法目前笔者还没有找到合适的实践,也没有查到相关探索。慎用!

使用alternate的优势

  1. 兼容性非常好
  2. 语义非常好。用户,开发者,尤其搜索引擎或者其他辅助阅读设备能够准确识别网站还有其他替换CSS样式。(alternate的语义就是“可替换的”)
  3. 交互体验更好。rel=alternate方法实现的换肤功能在网站样式变换的时候是瞬间切换,完全无感知。因为浏览器已经把换肤的CSS文件预加载好了,比JS改变href地址的体验要更好。

扩展:换肤还有什么高效的方法

其实我们刚才说不让js直接操作大量的css属性值还有一方面的考虑:js线程是阻塞GUI渲染线程的。大量的js同步代码运行会引起页面无响应。
但是,css自定义变量一定程度上解决了这个问题:

// 获取任意 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>
      document.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>

以上是关于细说alternate三两事「精修版」的主要内容,如果未能解决你的问题,请参考以下文章

关于字体图标的三两事

nodejs之mock与跨域代理的三两事

C++:MEMSET的大坑三两事

Java测试三两事

Cetos7安装nginx三两事

浅谈Docker三两事