写 CSS 这么多年,很多人其实从来没认真想过一个问题:给页面加样式,明明有好几种办法,到底该用哪种?大部分人的答案是”随便,能跑就行”。但这几种方式背后的加载机制、性能表现、维护成本差别很大,选错了轻则拖慢页面,重则埋下维护的坑。这篇文章就把这几种方式掰开揉碎讲清楚。
先把四种方式过一遍
1. <link> 标签
<link rel="stylesheet" href="style.css">
写在 <head> 里,引入一个外部 CSS 文件。这是目前最主流、最推荐的方式。
2. <style> 标签
<style>
body { margin: 0; }
</style>
直接把 CSS 代码写在 HTML 文件里,不需要额外的文件。
3. @import
@import url("other.css");
这个东西比较特殊,它不是 HTML 标签,而是写在 CSS 内部的一条语句,用来在一个 CSS 文件里引入另一个 CSS 文件(也可以写在 <style> 标签里)。
4. 内联样式(inline style)
<div style="color: red;"></div>
直接写在标签的 style 属性里,作用范围只有这一个元素。
核心区别:加载机制不一样,性能差异就来了
这是最容易被忽略、但其实最关键的一点。
<link> 标签引入的 CSS 文件,浏览器会并行下载。 也就是说,如果你的页面同时有多个 <link> 引入不同的 CSS 文件,浏览器会同时发起请求,谁也不用等谁,效率比较高。
@import 则不一样,它是”串行”的,而且有阻塞问题。
举个例子:主 CSS 文件里写了一句 @import url("theme.css"),浏览器必须先把主文件下载解析完,发现里面有 @import,才会再去请求 theme.css,等于多了一次”发现-再请求”的往返延迟。
如果套娃嵌套几层 @import,这个延迟会一层层叠加,页面渲染就会明显变慢。这也是为什么业内基本共识是:能不用 @import 就不用,尤其是在生产环境的关键路径上。
<style> 标签因为代码直接内嵌在 HTML 里,不需要额外的网络请求,理论上”最快”,但代价是没法利用浏览器缓存——每次加载页面都要重新传一遍这段 CSS,页面一多,重复的代码也跟着一遍遍传输,对于内容量大的网站反而不划算。
内联样式的加载谈不上什么机制,它是跟着 DOM 元素一起解析的,谈不上额外开销,但它的问题不在加载性能上,而在别的地方,往下看。
优先级和层叠顺序:谁能覆盖谁
CSS 的全称是”层叠样式表”,层叠规则决定了当多条规则冲突时谁生效。这里核心记住一点:优先级和”你用哪种方式写”关系不大,主要看选择器的权重和书写顺序。
具体来说:
- 内联样式的优先级最高(等同于选择器权重的最顶层),几乎可以覆盖外部样式表里的任何选择器,除非对方用了
!important。正因为这个”霸道”的特性,内联样式常常成为调试时的临时手段,但如果大量用在正式代码里,后续想统一改样式会非常痛苦,因为你没法用外部样式表覆盖它。 <link>、<style>、@import引入的样式,它们之间的优先级取决于代码在页面中生效的顺序,也就是”后来者覆盖先来者”,而不是取决于你用的是哪种引入方式。如果一段@import的内容在文档流中排在后面,它同样可以覆盖前面<link>引入的同选择器规则。
所以别再纠结”是不是 <style> 天生比 <link> 优先级高”这种问题了,真正决定权重的是选择器本身和代码顺序。
到底该怎么选?给你一套实用判断标准
说了这么多机制,落地到写代码的时候,可以按下面的思路来选:
日常开发,样式量正常的项目,首选 <link>。
原因很简单:可以并行加载、可以被浏览器缓存(用户第二次访问同一个站点,直接读缓存,不用重新下载)、也方便多个页面共用同一份样式文件,维护起来最省心。
这也是绝大多数正式项目的默认选择。
<style> 标签适合”这段样式只在这一个页面用,而且量不大”的场景。 比如一个营销落地页、一次性的活动页面,样式高度定制、复用率低,写成内联的 <style> 反而省了一次网络请求。
另外一个常见用法是首屏关键 CSS(Critical CSS)内联:把首屏渲染必需的一小部分样式直接写进 <style> 标签,让浏览器不用等外部文件下载就能先渲染出首屏内容,这是性能优化里的一个经典技巧,大型网站基本都在用。
@import 现在基本没有非用不可的理由了。 早些年它的存在感来自于”可以在 CSS 文件内部组织样式模块”,但现在有了 Sass/Less 这类预处理器的 @import(编译时合并,跟这里说的运行时 @import完全是两回事,性能没有问题),以及现代前端工程里的模块打包工具,运行时的原生 CSS @import 已经没什么用武之地了,能避免就避免。
内联样式尽量只用在两种情况:一是纯调试、临时验证效果;二是通过 JavaScript 动态设置样式,比如根据用户交互实时改变某个元素的位置或颜色,这种场景天然就得写在元素上,没法预先写进外部样式表。
除此之外,正式代码里大量堆内联样式,基本可以判断这是需要重构的信号。
一个容易忽略的细节:CSS 加载和页面渲染的关系
不管用哪种方式引入外部 CSS,有一点是共通的:浏览器在下载和解析 CSS 的过程中,会阻塞页面渲染(专业说法是”渲染阻塞资源”)。
这是为了避免用户先看到一个没有样式的”丑页面”,然后样式加载完又”跳一下”的糟糕体验。
所以不管选哪种引入方式,一个通用的优化原则是:尽量减少关键渲染路径上的 CSS 体积,该拆分的拆分、该按需加载的按需加载,而不是无脑把所有样式都塞进一个几百 KB 的文件里让首屏等着。
总结一句话
- 常规场景:用
<link>,能缓存、能并行、维护方便。 - 页面级、一次性、或者做首屏关键样式优化:用
<style>。 @import:能不用就不用,性能上是实打实的减分项。- 内联样式:留给调试和 JS 动态赋值,别在正式代码里大规模使用。
技术选型很多时候没有”唯一正确答案”,但这几种 CSS 引入方式的差异是实打实写在浏览器加载机制里的,理解了原理,选择自然就清楚了。