link是html标签,@import是css规则;link并行加载,@import阻塞解析且串行请求;内联style权重最高但无作用域;无位置限制,作用域由选择器决定。

link 和 @import 语法层面就不是一回事
link 是 HTML 标签,写在 里;@import 是 CSS 规则,只能写在 CSS 文件顶部或
块内。浏览器解析时,link 加载的 CSS 会并行发起请求,而 @import 会阻塞后续样式的解析和渲染——哪怕它写在
里,也会让浏览器等它加载完才继续处理后面的规则。
常见错误现象:@import url("base.css"); 放在
中间,导致后面所有样式延迟生效,甚至触发 FOUC(Flash of Unstyled Content)。
-
@import在 CSS 文件中必须出现在所有非@charset规则之前,否则整个规则会被忽略 - IE6–8 不支持
@import的媒体查询语法(如@import url(x.css) screen and (min-width:768px)) - 用
@import加载多个文件时,实际是串行请求,性能明显差于多个link
内联 style 属性只作用于单个元素,且优先级最高
style 属性写在 HTML 标签上,比如
color、font-family)。它的层叠权重是 1000,高于任何选择器(包括 !important 的声明,除非后者也在内联中)。
使用场景有限:适合动态 js 注入的临时样式、服务端渲染时的首屏关键样式(如 SSR 中的 critical CSS),但绝不该用于维护长期样式逻辑。
立即学习“前端免费学习笔记(深入)”;
- 无法用伪类(
:hover)、伪元素(::before)或媒体查询 - 修改时必须操作 dom 属性,不能用 CSSOM 的
getComputedStyle()直接覆盖整块声明 - 服务端拼接时容易 xss,需严格转义
style值中的引号和分号
嵌入式
写在 中,样式作用于整个文档;但如果把它写在 某个元素内部(虽然合法但非常规),浏览器仍会将其提升到 后解析,**并不会**限制作用域到父容器。
真正影响作用范围的是 CSS 选择器本身,而不是
所在位置。不过现代开发中,可通过 scoped 属性(vue)或 :is() / :where() 配合属性选择器模拟局部作用:
/* Vue 单文件组件中 */ /* 编译后实际生成类似 */ .button[data-v-f3f3eg9] { color: blue; }
- 原生 HTML 中
没有作用域限制,即使放在
里,也能匹配中的元素 -
中的
@import行为与外部 CSS 文件一致,仍会阻塞解析 - 重复定义同名
块时,后出现的会覆盖前面的(按文档流顺序)
外部 CSS 文件的加载时机直接影响渲染流程
把 放在 末尾,和放在 开头,对页面渲染的影响天差地别。前者会触发「阻塞渲染」——浏览器会暂停构建 DOM 树,直到该 CSS 加载并解析完成;后者虽不阻塞 DOM 构建,但可能造成布局重排(layout shift)或样式闪烁。
更隐蔽的问题:如果在 中 late-load 一个 CSS 文件,其中包含 body { margin: 0; } 这类重置规则,用户可能先看到带默认 margin 的页面,再突然“跳动”一下。
- 关键 CSS 应内联在
中,非关键 CSS 用rel="preload"+onload注入 -
rel="stylesheet" media="print"的 CSS 默认不阻塞屏幕渲染,但一旦切到打印预览,就会立即加载 - http/2 下多个小 CSS 文件的合并收益变小,但过多
link仍会增加 TCP 队头阻塞风险(尤其在弱网下)
CSS 作用范围从来不由「写在哪」决定,而是由「选择器匹配逻辑」+「层叠顺序」+「加载时机」三者共同控制。最容易被忽略的是:即便你把
放在某个 div 里,它照样能干掉全局的 h1 样式——HTML 解析器根本不管这个。