CSS 样式引入
在 HTML 中引入 CSS 样式有三种主要方式:使用 <link> 标签引入外部 CSS 文件、使用 <style> 标签内联样式、以及使用 @import 指令导入。本节将对比这三种方式的优缺点,并给出最佳实践建议。
前置知识
阅读本节前,建议先了解:link 标签
基础概念
三种 CSS 引入方式
| 方式 | 语法 | 位置 |
|---|---|---|
| 外部 CSS | <link rel="stylesheet" href="style.css"> | <head> |
| 内联 CSS | <style>body { color: red; }</style> | <head> 或 <body> |
| @import | @import url('style.css'); | <style> 或 .css 文件内 |
引入方式的对比
| 特性 | link 外部 CSS | style 内联 | @import |
|---|---|---|---|
| 文件分离 | 是 | 否 | 是 |
| 浏览器兼容 | 全部 | 全部 | 全部 |
| 渲染阻塞 | 是(阻塞渲染,不阻塞解析) | 是 | 是(额外阻塞) |
| 可缓存 | 是(单独文件缓存) | 否(随 HTML 缓存) | 是 |
| 并行下载 | 是 | 不适用 | 否(串行加载) |
| 推荐程度 | 强烈推荐 | 适量使用 | 不推荐 |
语法
方式一:link 外部 CSS(推荐)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>外部 CSS</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>使用外部 CSS 文件</h1>
</body>
</html>方式二:style 内联 CSS
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>内联 CSS</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
}
h1 {
color: #0066cc;
}
</style>
</head>
<body>
<h1>使用内联 CSS</h1>
</body>
</html>方式三:@import 导入
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@import CSS</title>
<style>
/* 在 style 标签中使用 @import */
@import url('css/base.css');
@import url('css/components.css');
@import url('css/layout.css');
</style>
</head>
<body>
<h1>使用 @import 导入 CSS</h1>
</body>
</html>也可以在 CSS 文件中使用 @import:
css
/* 在 main.css 中导入其他 CSS 文件 */
@import url('reset.css');
@import url('variables.css');
@import url('base.css');
/* 主要样式 */
body {
font-family: system-ui, sans-serif;
}详细说明
link 外部 CSS 的优势
1. 浏览器缓存
外部 CSS 文件可以被浏览器单独缓存。当用户访问多个页面时,相同的 CSS 文件只需下载一次:
用户访问 page1.html → 下载 style.css → 缓存
用户访问 page2.html → 直接使用缓存的 style.css
用户访问 page3.html → 直接使用缓存的 style.css2. 并行下载
多个 <link> 标签引入的外部 CSS 可以被浏览器并行下载:
html
<link rel="stylesheet" href="css/reset.css"> <!-- 并行下载 -->
<link rel="stylesheet" href="css/layout.css"> <!-- 并行下载 -->
<link rel="stylesheet" href="css/components.css"> <!-- 并行下载 -->3. 关注点分离
HTML 负责结构,CSS 负责样式,各司其职:
index.html → 页面结构
style.css → 页面样式
app.js → 页面行为4. 减小 HTML 文件大小
CSS 代码放在外部文件中,HTML 文件更小,首次渲染速度更快。
@import 的性能问题
@import 是 CSS 规范中的导入机制,但在性能方面有明显缺点:
1. 串行加载
@import 引入的 CSS 文件是串行加载的,一个接一个:
加载 style.css → 解析发现 @import 'reset.css'
→ 加载 reset.css → 解析完成
→ 解析发现 @import 'layout.css'
→ 加载 layout.css → 解析完成
→ ...相比之下,<link> 标签可以并行加载:
并行加载 reset.css ─┐
并行加载 layout.css ─┤→ 同时完成
并行加载 theme.css ─┘2. @import 嵌套加剧问题
css
/* a.css */
@import url('b.css');
/* b.css */
@import url('c.css');
/* c.css */
body { color: red; }加载顺序:a.css → b.css → c.css,完全串行。
style 内联 CSS 的适用场景
虽然外部 CSS 是推荐方式,但 <style> 内联 CSS 在以下场景中很有价值:
1. 关键 CSS 内联(Critical CSS)
将首屏渲染所需的关键 CSS 内联到 HTML 中,避免额外的网络请求:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>关键 CSS 内联</title>
<!-- 关键 CSS:首屏渲染所需 -->
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
.hero { height: 100vh; display: flex; align-items: center; justify-content: center; background: #0066cc; color: white; }
.loading { display: flex; align-items: center; height: 100vh; }
</style>
<!-- 非关键 CSS:异步加载 -->
<link rel="stylesheet" href="css/main.css" media="print" onload="this.media='all'">
</head>
<body>
<div class="hero">
<h1>欢迎</h1>
</div>
<script src="js/app.js" defer></script>
</body>
</html>2. 页面特定的少量样式
html
<style>
/* 仅本页面使用的特殊样式 */
.gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
</style>3. 动态注入的样式
javascript
// 通过 JavaScript 动态添加样式
var style = document.createElement('style');
style.textContent = '.highlight { background: yellow; }';
document.head.appendChild(style);CSS 加载顺序与优先级
当多种方式同时使用时,CSS 的优先级规则如下:
html
<!-- 1. 外部 CSS(最先加载) -->
<link rel="stylesheet" href="base.css">
<!-- 2. 内联 CSS(后加载,优先级相同但后声明覆盖先声明) -->
<style>
body { color: blue; } /* 如果 base.css 也设置了 body color,这个会覆盖 */
</style>
<!-- 3. 外部 CSS(在 style 之后,会覆盖前面的) -->
<link rel="stylesheet" href="override.css">优先级规则:在相同特异性的情况下,后声明的覆盖先声明的,无论使用的是 <link> 还是 <style>。
media 属性控制加载时机
html
<!-- 所有设备都加载(默认) -->
<link rel="stylesheet" href="style.css">
<!-- 仅打印时加载 -->
<link rel="stylesheet" href="print.css" media="print">
<!-- 仅大屏幕加载 -->
<link rel="stylesheet" href="desktop.css" media="(min-width: 1024px)">
<!-- 非关键 CSS 延迟加载(性能优化技巧) -->
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">实战示例
推荐的 CSS 引入方式
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 引入最佳实践</title>
<!-- 预连接第三方域名 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- 预加载关键字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<!-- 关键 CSS 内联(首屏渲染所需) -->
<style>
/* 重置样式 */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, -apple-system, sans-serif; line-height: 1.6; color: #333; background: #fff; }
/* 骨架屏 / 加载状态 */
.loading-screen { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.spinner { width: 40px; height: 40px; border: 4px solid #e0e0e0; border-top-color: #0066cc; border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
</style>
<!-- 主要 CSS 文件(外部引入) -->
<link rel="stylesheet" href="/css/main.css">
<!-- 非关键 CSS 延迟加载 -->
<link rel="stylesheet" href="/css/non-critical.css" media="print" onload="this.media='all'">
<!-- 打印样式 -->
<link rel="stylesheet" href="/css/print.css" media="print">
<!-- Google Fonts(外部) -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;700&display=swap">
</head>
<body>
<div class="loading-screen" id="loading">
<div class="spinner"></div>
</div>
<main id="app" style="display:none;">
<h1>页面内容</h1>
<p>主要内容区域。</p>
</main>
<script>
// 主要 CSS 加载完成后显示内容
window.addEventListener('load', function() {
document.getElementById('loading').style.display = 'none';
document.getElementById('app').style.display = 'block';
});
</script>
</body>
</html>CSS 加载顺序演示
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 加载顺序</title>
<style>
/* 样式 1:通过内联 style 设置 */
.box { padding: 20px; margin: 10px 0; text-align: center; font-family: monospace; }
</style>
<link rel="stylesheet" href="data:text/css,.box{background:%23d4edda;color:%23000;border:2px solid %23000;border-radius:4px;}">
<style>
/* 样式 3:后声明的内联 style 覆盖 link */
.box { background: #cce5ff; color: #0066cc; border-color: #0066cc; }
</style>
</head>
<body>
<h1>CSS 优先级演示</h1>
<div class="box">
这个盒子的样式由第三个声明(后声明的 style)决定。
<br>背景: 浅蓝 | 文字: 蓝色 | 边框: 蓝色
</div>
<p style="font-size:14px;color:#666;">
规则:相同特异性下,后声明的覆盖先声明的,无论 link 还是 style。
</p>
</body>
</html>注意事项
1. 不要过度使用 @import
css
/* 不推荐:多层 @import 导致串行加载 */
/* a.css */
@import url('b.css');
/* b.css */
@import url('c.css');2. link 和 @import 混用时的问题
html
<!-- 不推荐:在 link 加载的 CSS 中使用 @import -->
<link rel="stylesheet" href="main.css">
<!-- main.css 内容 -->
<!-- @import url('theme.css'); 这会导致 theme.css 串行加载 -->3. 内联 style 不应过大
html
<!-- 不推荐:大量内联 CSS -->
<style>
/* 数百行 CSS 代码... */
/* 这会增大 HTML 文件,无法利用浏览器缓存 */
</style>最佳实践
1. 优先使用 link 引入外部 CSS
html
<link rel="stylesheet" href="css/style.css">2. 关键 CSS 内联,非关键 CSS 外部引入
html
<style>/* 关键 CSS */</style>
<link rel="stylesheet" href="css/non-critical.css" media="print" onload="this.media='all'">3. 避免 @import
使用构建工具(Webpack、Vite)将多个 CSS 文件合并为一个,而不是使用 @import。
4. 合理安排 link 的顺序
html
<!-- 重置/基础样式 -->
<link rel="stylesheet" href="css/reset.css">
<!-- 组件样式 -->
<link rel="stylesheet" href="css/components.css">
<!-- 页面特定样式 -->
<link rel="stylesheet" href="css/page.css">
<!-- 覆盖/主题样式 -->
<link rel="stylesheet" href="css/overrides.css">5. 利用 media 属性延迟非关键 CSS
html
<link rel="stylesheet" href="print.css" media="print">
<link rel="stylesheet" href="large-screen.css" media="(min-width: 1200px)">下一节
继续学习:favicon 图标