Skip to content

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 外部 CSSstyle 内联@import
文件分离
浏览器兼容全部全部全部
渲染阻塞是(阻塞渲染,不阻塞解析)是(额外阻塞)
可缓存是(单独文件缓存)否(随 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>
  <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;
}

详细说明

1. 浏览器缓存

外部 CSS 文件可以被浏览器单独缓存。当用户访问多个页面时,相同的 CSS 文件只需下载一次:

用户访问 page1.html → 下载 style.css → 缓存
用户访问 page2.html → 直接使用缓存的 style.css
用户访问 page3.html → 直接使用缓存的 style.css

2. 并行下载

多个 <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');
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>

最佳实践

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

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 图标

参考链接