link和@import的区别浅析

2018-08-10 admin

我们都知道,外部引入 CSS 有2种方式,link标签和@import。 它们有何本质区别,有何使用建议,在考察外部引入 CSS 这部分内容时,经常被提起。

如今,很多学者本着知其然不欲知其所以然的学习态度,不求甚解,只求结论。 所以,本文遵循 css hack 的渐进识别原则, 结论 → 区别 → 争议 → 细节 → 祖坟 → 感想,逐渐加深理论层级, 力争每个 level 的读者,都能 get 到自己想要的内容,不必继续阅读下去。

结论 就结论而言,强烈建议使用link标签,慎用@import方式。 这样可以避免考虑@import的语法规则和注意事项,避免产生资源文件下载顺序混乱和http请求过多的烦恼。

区别 1.从属关系区别 @import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。

2.加载顺序区别 加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。

3.兼容性区别 @import是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link标签作为 HTML 元素,不存在兼容性问题。

4.DOM可控性区别 可以通过 JS 操作 DOM ,插入link标签来改变样式;由于 DOM 方法是基于文档的,无法使用@import的方式插入样式。

5.权重区别(该项有争议,下文将详解) link引入的样式权重大于@import引入的样式。

争议 不知从什么时候开始,当你在网上搜索link和@import的区别时,千篇一律的答案里就悄悄的多了一句“link引入的样式权重大于@import引入的样式”。 但是并没有一份答案,附带着对这句话的任何解释或实例。

这句话究竟是什么意思,该怎么理解呢?

发扬探索精神,我们不妨继续查阅资料。后来发现,还是有不少文章和帖子,对这句话表示质疑,进而自己写了 demo 去验证,验证的结果,确实无法与这句话相吻合。 而且,笔者也并未发现能清楚、正确、有理有据的解释这个结论到底对,还是不对的文章。

那么这个结论,最初是从哪里来的,可能已经无从考证了。

换个思维方式,不去争辩它的对错了,探索未果,我们就从这个结论的核心关键词“权重”出发,去研究它。

说到“权重”,有必要再解释一下:CSS 中的权重,指的是选择器的优先级。

CSS 选择器的权重高,即选择器的优先级高。 CSS 的优先级特性表现为,对同一 HTML 元素设置样式时,不同选择器的优先级不同,优先级低的样式将被高优先级的样式层叠掉。

CSS 权重优先级顺序简单表示为: !important > 行内样式 > ID > 类、伪类、属性 > 标签名 > 继承 > 通配符

为了便于理解权重的计算方式,我们按以下方式进行数值假设分析:

选择器 权重 通配符 0 标签 1 类/伪类/属性 10 ID 100 行内样式 1000 important 1/0(无穷大) 再举实例:

<!DOCTYPE html> <html lang=“en”> <head>

<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
    #myid { /* id选择器权重为100 */
        background-color: pink;
    }
    #divid .myspan input { /* 权重为 100 + 10 + 1 = 111 */
        background-color: yellow;
    }
    input[type="button"] { /* 权重为 10 */
        color: white !important; /* !important权重为无穷大 */
    }
    input.myclass { /* 此为标签指定式选择器,权重为 1 + 10 = 11 */
        color: black;
    }
</style>

</head> <body>

<div id="divid">
    <span class="myspan">
        <input type="button" id="myid" class="myclass" name="myname"
            value="点我" style=" color: green;">
            <!-- style样式的权重为1000 -->
    </span>
</div>

</body> </html> 每个样式的权重值,都在实例中,以注释的形式标明。 根据权重值可知,最终,这个按钮的样式一定是,蓝色背景,白色字,结果如下图:

存在!important时,不作他想,一定是权重最大的样式。

既然我们了解了,CSS 中的权重是怎么回事,那回到主题,“link引入的样式权重大于@import引入的样式”, 难道 CSS 的引入方式也有权重吗?其实我们不必纠结它是否有权重之说,我们只需理论结合实际的去分析,各种情况下,结果如何即可。 现有如下3个css文件:

/ green.css / div {

background-color: green;
border: 3px solid red;

}

/ yellow.css / div {

background-color: yellow;
border: 3px solid black;

}

/ blue.css / @import url(“green.css”); div{

background-color: blue;

} 实例1:

<!DOCTYPE html> <html lang=“en”> <head>

<meta charset="UTF-8">
<title>Document</title>
<!-- 实例1\. link标签引入yellow.css,内联样式引入green.css -->
<link rel="stylesheet" href="yellow.css">
<style type="text/css">
    @import url("green.css");
</style>

</head> <body>

<div style="width: 50px; height: 50px;"></div>
<!-- 盒子为,绿色背景,红色边框,即green.css生效 -->

</body> </html> 实例1结果如下图:

实例2:

<!DOCTYPE html> <html lang=“en”> <head>

<meta charset="UTF-8">
<title>Document</title>
<!-- 实例2\. 内联样式引入green.css,link标签引入yellow.css -->
<style type="text/css">
    @import url("green.css");
</style>
<link rel="stylesheet" href="yellow.css">

</head> <body>

<div style="width: 50px; height: 50px;"></div>
<!-- 盒子为黄色背景,黑色边框,即yellow.css生效 -->

</body> </html> 实例2结果如下图:

对比实例1和实例2这两个正好相反的结果可知,link和@import并没有产生类似权重的效果,只是单纯的体现了CSS的层叠性,写在后面的样式,覆盖前面的样式。

实例3:

<!DOCTYPE html> <html lang=“en”> <head>

<meta charset="UTF-8">
<title>Document</title>
<!-- 实例3\. 内联样式引入green.css,内联样式中设置粉色背景 -->
<style type="text/css">
    @import url("green.css");
    div {
        background-color: pink;
    }
</style>

</head> <body>

<div style="width: 50px; height: 50px;"></div>
<!-- 盒子为粉色背景,红色边框,即green.css已生效,但背景色被内联样式层叠为粉色 -->

</body> </html> 实例3结果如下图:

实例4:

<!DOCTYPE html> <html lang=“en”> <head>

<meta charset="UTF-8">
<title>Document</title>
<!-- 实例4\. link标签引入blue.css,blue.css中引入green.css -->
<link rel="stylesheet" href="blue.css">

</head> <body>

<div style="width: 50px; height: 50px;"></div>
<!-- 盒子为蓝色背景,红色边框,即green.css已生效,但背景色被blue.css层叠为蓝色 -->

</body> </html> 实例4结果如下图:

分析实例3和实例4的结果可知:

对于实例3,我们看到红色边框,证明内联样式中使用@import引入的green.css已经生效,但其背景样式被内联样式中的粉色背景层叠掉,这个现象表明,@import不只是如我们看到的那样,处于内联样式顶部,其被引入的样式,在结构上,也确实是被置于内联样式之前,所以内联样式才能够层叠掉它。

同理,实例4中,在link标签引入的blue.css文件内,顶部同样存在@import引入的green.css,红色边框依然可以证明,green.css已经生效,但其背景样式被blue.css本身的蓝色背景层叠掉,@import引入的样式在blue.css中也是被置于它本身样式之前的。

到此为止,我展开了大胆的猜想,“link引入的样式权重大于@import引入的样式”,这个结论的给出者,是想告诉大家:

在link标签引入的 CSS 文件中,使用@import时需注意,如果已经存在相同样式,@import引入的这个样式将被该 CSS 文件本身的样式层叠掉,表现出link标签引入的样式权重大于@import引入的样式这样的直观效果。

对于我设想的结论,似乎挺能说通的,毕竟这是实践出的结果。

那些验证过此结论的前人,他们都是在一个 HTML 页面中,一前一后分别使用link和内联样式的@import去比较的,我在实例1和实例2中也是如此做的,并不能反推出“link引入的样式权重大于@import引入的样式”这个结论,所以,我不自量力的认为,这个结论其实最初只是丢了个已知条件而已。

那么我们一起把这个结论重新梳理一下:在link标签引入的 CSS 文件中使用@import时,相同样式将被该 CSS 文件本身的样式层叠。

Ps.首先感谢各种看官的阅读。笔者属于学习阶段,学识尚浅,虽然本文结论已得到笔者编码验证,但不排除笔者大脑短路、措辞有误的可能,有缘阅读到此处的都是真爱,希望诸位大拿、大牛、大仙、大圣、大神们不吝赐教,及时指正,避免诱导萌新误入歧途,再次向你们表达笔者的谢意!

细节 既然已经说了这么多,就顺便提一下关于@import使用时的其它细节。

在《CSS权威指南》中写道:

@import一定要写在除@charset外的其他任何 CSS 规则之前,如果置于其它位置将会被浏览器忽略,而且,在@import之后如果存在其它样式,则@import之后的分号是必须书写,不可省略的。

到此为止,似乎事情都弄清楚了,但是突然又有个疑点浮现出来:

在讨论区别的时候,不是说加载页面时,link标签引入的 CSS 先于@import引入的 CSS 加载吗,那link标签引入的样式又怎会把@import引入的样式层叠掉呢?

要回答这个问题,首先我们要一起明确一些有关浏览器的概念:

浏览器执行过程可以简单分为加载、解析、渲染,这三个步骤。

加载:根据请求的URL进行域名解析,向服务器发送请求,接收响应文件(如 HTML、JS、CSS、图片等)。

解析:对加载到的资源(HTML、JS、CSS等)进行语法解析,构建相应的内部数据结构(比如HTML的DOM树,JS对象的属性表,CSS的样式规则等)。

渲染:构建渲染树,对各个元素进行位置计算、样式计算等,然后根据渲染树完成页面布局及绘制的过程(可以理解为“画”页面元素)。

这几个过程不是完全孤立的,会有交叉,比如HTML加载后就会进行解析,然后拉取HTML中指定的CSS、JS等。`

现在,我们应该已经了解了加载和渲染的概念,明白它们是两个不同的过程,那么对上文中抛出的疑问继续追问:

link先于@import加载,是不是也先于@import渲染呢?

实际上,渲染的动作一般都会执行多次,最后一次渲染,一定是依据之前加载过的所有样式整合后的渲染树进行绘制页面的,已经被渲染过的页面元素,也会被重新渲染。

那么我们就可以把@import这种导入 CSS 文件的方式理解成一种替换,CSS 解析引擎在对一个 CSS 文件进行解析时,如在文件顶部遇到@import,将被替换为该@import导入的 CSS 文件中的全部样式。

峰回路转,柳暗花明,终于弄明白为何@import引入的样式,会被层叠掉了。其虽然后被加载,却会在加载完毕后置于样式表顶部,最终渲染时自然会被下面的同名样式层叠。

至此为止,“link引入的样式权重大于@import引入的样式”这个结论,我终于为它圆了场。但愿此结论的作者,本意真如我的猜测,否则若是我多心而跑偏了的话,不敢想象这背后究竟隐藏着多大的秘密。

祖坟 有些细心而专业的读者可能已经发现了,我用自己的思路和措辞,粗略的解释了有关 CSS 加载和渲染的知识,有些涉世未深的前端爱好者可能会一头雾水,无法作为系统学习的依据。这不打紧,出来混,祖坟总是要刨的,想要透彻的学习相关内容,进一步了解底层原理的学者,我早已为你备下了丰厚的见面礼~

有关link和@import在性能分析方面的比较,国外的高手早在多年前就曾执过笔:

爱好母语的请戳我:https://www.stevesouders.com/… 阅读英语的请戳我:https://www.qianduan.net/high…

有关浏览器内部工作原理的神作,也是几年前出自歪果仁大牛:

1 为普通话:https://kb.cnblogs.com/page/1… 2 for English:http://taligarsiel.com/Projec…

对知识有所渴望的你,赶快点击上面的传送门,相信你一定会有丰富的收获。

感想 我喜欢读别人探究类的技术文章,不只是可以学习技术上的知识,更是可以学习别人探索的精神和思考问题的逻辑。或许已经有过不少前人如我一样,对本文的争议结论,有所质疑,前思后想过一番,得出了自己的见解,只是没有成文,或者没有发表而已。

那么其他人呢,就只是单纯的复制结论或记忆结论么。

其实我觉得,在咱们这个领域,不求甚解可以,人云亦云不行。一句含有信息量的句子,进入大脑时,总得自己考虑考虑吧,不要让我们的大脑充当转发器,最不济,也得是个解析器吧。

原文链接:https://segmentfault.com/a/1190000015950516

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-37655.html

文章标题:link和@import的区别浅析

相关文章
JavaScript实现PC手机端和嵌入式滑动拼图验证码三种效果
PC和手机端网站滑动拼图验证码效果源码,同时包涵了弹出式Demo,使用ajax形式提交二次验证码所需的验证结果值,嵌入式Demo,使用表单形式提交二次验证所需的验证结果值,移动端手动实现弹出式Demo三种效果 首先要确认前端使用页面,比如...
2017-03-17
Vue获取DOM元素样式和样式更改示例
在 vue 中用 document 获取 dom 节点进行节点样式更改的时候有可能会出现 ‘style’ is not definde的错误,这时候可以在 mounted 里用 $refs 来获取样式,并进行更改: &lt;template...
2017-03-13
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过。 1.CSS的color属性并非只能用于文本显示 对于CSS的color属性,相信所有Web开发人员...
2015-11-12
ajax为什么令人惊异?ajax的优缺点
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。 Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHT...
2015-11-12
HTML5的5个不错的开发工具推荐
HTML5规范终于在今年正式定稿,对于从事多年HTML5开发的人员来说绝对是一个重大新闻。数字天堂董事长,DCloud CEO王安也发表了文章,从开发者和用户两个角度分析了HTML对两个人群的优势。其实,关于HTML5的开发工具,我们以往的...
2015-11-12
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
AJAX的浏览器支持
AJAX 的要点是 XMLHttpRequest 对象。 不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的。 IE 浏览器使用 ActiveXObject,而其他的浏览器使用名为 XMLHttpRequest 的 Jav...
2015-11-12
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
JavaScript的组成
一个完整的JavaScript由3个部分组成:核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模型(BOM) ECMAScript 描述了该语言的语法和基本对象 ; DOM 描述了处理网页内容的方法和接口 ; BOM 描...
2015-11-12
回到顶部