style 内联样式
<style> 元素用于在 HTML 文档中直接嵌入 CSS 样式规则。与 <link> 外部引入相比,<style> 的样式代码直接写在 HTML 文件中,适合页面特定的样式或性能优化中的关键 CSS 内联。
前置知识
阅读本节前,建议先了解:script 标签与 JavaScript
基础概念
style 的作用
<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>内联样式示例</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 20px;
line-height: 1.6;
color: #333;
}
h1 {
color: #0066cc;
border-bottom: 2px solid #0066cc;
padding-bottom: 10px;
}
</style>
</head>
<body>
<h1>页面标题</h1>
<p>页面内容使用内联 CSS 样式。</p>
</body>
</html>style 与 link 的区别
| 特性 | <style> 内联 | <link> 外部 |
|---|---|---|
| 样式位置 | HTML 文件内 | 独立的 CSS 文件 |
| 可缓存 | 否(随 HTML 缓存) | 是(单独缓存) |
| 文件大小 | 增大 HTML 文件 | 减小 HTML 文件 |
| 维护性 | 分散在多个 HTML 文件中 | 集中在 CSS 文件中 |
| 复用性 | 仅限当前页面 | 多个页面共享 |
| HTTP 请求 | 无额外请求 | 需要额外请求 |
| 适用场景 | 关键 CSS、页面特定样式 | 主要样式表 |
语法
基本语法
<style>
/* CSS 样式规则 */
选择器 {
属性: 值;
属性: 值;
}
</style>支持的属性
| 属性 | 说明 | 示例 |
|---|---|---|
media | 媒体查询条件 | media="(max-width: 768px)" |
type | 样式类型(默认 text/css) | type="text/css" |
title | 样式表标题(用于可选样式表) | title="蓝色主题" |
disabled | 禁用样式表 | disabled |
nonce | 内容安全策略 nonce 值 | nonce="abc123" |
scoped | 作用域样式(已废弃) | 不再使用 |
详细说明
media 属性
<style> 的 media 属性允许你为不同的设备或条件定义样式:
<!-- 所有设备 -->
<style>
body { font-family: system-ui, sans-serif; }
</style>
<!-- 仅打印时 -->
<style media="print">
body { font-family: serif; color: black; }
nav, footer, .no-print { display: none; }
</style>
<!-- 仅小屏幕 -->
<style media="(max-width: 768px)">
.sidebar { display: none; }
.main-content { width: 100%; }
</style>
<!-- 暗色模式 -->
<style media="(prefers-color-scheme: dark)">
body { background: #1a1a2e; color: #e0e0e0; }
</style>
<!-- 减少动画偏好 -->
<style media="(prefers-reduced-motion: reduce)">
* { animation: none !important; transition: none !important; }
</style>媒体查询不匹配时不加载
当 media 条件不匹配时,浏览器不会解析或应用该 <style> 中的 CSS 规则,也不会加载其内容。
type 属性
type 属性指定样式表的 MIME 类型,默认为 text/css:
<!-- 默认值,可以省略 -->
<style type="text/css">
body { color: #333; }
</style>
<!-- 不推荐:其他类型 -->
<!-- <style type="text/less"> -->
<!-- Less 样式,需要编译 -->title 属性与可选样式表
title 属性可以为样式表命名,配合 JavaScript 实现样式表切换:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>可选样式表</title>
<!-- 默认启用的样式表 -->
<style>
body { font-family: system-ui, sans-serif; margin: 0; padding: 20px; transition: all 0.3s; }
</style>
<!-- 可选样式表(默认不启用) -->
<style title="蓝色主题">
body { background: #e3f2fd; color: #0d47a1; }
h1 { color: #1565c0; }
</style>
<style title="绿色主题">
body { background: #e8f5e9; color: #1b5e20; }
h1 { color: #2e7d32; }
</style>
<style title="暗色主题">
body { background: #1a1a2e; color: #e0e0e0; }
h1 { color: #64b5f6; }
</style>
</head>
<body>
<h1>可选样式表演示</h1>
<p>点击下方按钮切换主题:</p>
<div>
<button onclick="switchTheme('默认')">默认</button>
<button onclick="switchTheme('蓝色主题')">蓝色</button>
<button onclick="switchTheme('绿色主题')">绿色</button>
<button onclick="switchTheme('暗色主题')">暗色</button>
</div>
<script>
function switchTheme(themeName) {
var sheets = document.querySelectorAll('style[title]');
sheets.forEach(function(sheet) {
sheet.disabled = (sheet.title !== themeName && themeName !== '默认');
});
}
</script>
</body>
</html>永久样式表 vs 可选样式表
没有 title 属性的 <style> 是"永久样式表",始终启用。有 title 属性的 <style> 是"可选样式表",默认也启用,但可以通过 JavaScript 切换。
disabled 属性
disabled 属性可以禁用样式表:
<style>
body { color: #333; }
</style>
<style disabled>
/* 这组样式被禁用,不会应用 */
body { color: red; background: yellow; }
</style>通过 JavaScript 动态切换:
var styleEl = document.querySelector('style#my-style');
styleEl.disabled = true; // 禁用
styleEl.disabled = false; // 启用nonce 属性(安全)
nonce(Number Used Once)属性配合内容安全策略(CSP)使用,允许只执行带有特定 nonce 值的内联样式:
<meta http-equiv="Content-Security-Policy" content="style-src 'self' 'nonce-abc123'">
<style nonce="abc123">
body { color: #333; }
</style>
<!-- 这个 style 没有 nonce,会被 CSP 阻止 -->
<!-- <style>body { color: red; }</style> -->scoped 属性(已废弃)
scoped 属性曾用于限制样式的作用域只影响父元素内部:
<!-- 已废弃!不再推荐使用 -->
<section>
<style scoped>
h1 { color: red; } /* 只影响当前 section 内的 h1 */
</style>
<h1>这个标题是红色的</h1>
</section>已废弃
scoped 属性从未被主流浏览器广泛支持,现已被 HTML 规范移除。替代方案:使用 CSS 的 :where() 选择器或 CSS Modules / CSS-in-JS 等方案。
style 标签的位置
在 <head> 中(推荐):
<head>
<style>
body { margin: 0; }
</style>
</head>
<body>
<h1>页面内容</h1>
</body>在 <body> 中(允许但不推荐作为主要样式):
<body>
<h1>页面内容</h1>
<style>
/* body 中的 style 也是合法的 */
.special { color: red; }
</style>
<p class="special">特殊样式</p>
</body>在 <body> 中使用 <style> 的合理场景:
- 组件化开发中,样式与组件放在一起
- 动态注入的样式
- 服务端渲染(SSR)中按需输出样式
实战示例
关键 CSS 内联(性能优化)
<!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>
*, *::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; }
.header { display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.logo { font-size: 20px; font-weight: bold; color: #0066cc; }
.nav { display: flex; gap: 20px; }
.nav a { text-decoration: none; color: #666; }
.hero { text-align: center; padding: 60px 24px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; min-height: 400px; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.hero h1 { font-size: 2.5em; margin-bottom: 16px; }
.hero p { font-size: 1.2em; opacity: 0.9; }
.skeleton { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; }
@keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
</style>
<!-- 非关键 CSS:延迟加载 -->
<link rel="stylesheet" href="/css/main.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>
</head>
<body>
<header class="header">
<div class="logo">MyApp</div>
<nav class="nav">
<a href="/">首页</a>
<a href="/about">关于</a>
</nav>
</header>
<main>
<section class="hero">
<h1>欢迎访问</h1>
<p>这是首屏内容,使用内联关键 CSS 确保快速渲染。</p>
</section>
<!-- 非关键内容区域 -->
<div class="content">
<div class="skeleton" style="height:200px;margin:20px;"></div>
<div class="skeleton" style="height:200px;margin:20px;"></div>
</div>
</main>
</body>
</html>使用 JavaScript 动态创建和操作 style
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态 style 操作</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
button { padding: 8px 16px; margin: 5px; cursor: pointer; background: #0066cc; color: white; border: none; border-radius: 4px; }
.demo { padding: 20px; margin: 15px 0; border: 1px solid #ddd; border-radius: 4px; }
</style>
</head>
<body>
<h1>动态 Style 操作</h1>
<div class="demo" id="demo-box">这是一个可样式化的盒子。</div>
<div>
<button id="btn-add">添加 style 标签</button>
<button id="btn-css-text">修改 CSS 文本</button>
<button id="btn-remove">移除 style 标签</button>
</div>
<script>
var dynamicStyle = null;
document.getElementById('btn-add').addEventListener('click', function() {
if (dynamicStyle) return;
dynamicStyle = document.createElement('style');
dynamicStyle.id = 'dynamic-style';
dynamicStyle.textContent =
'#demo-box { background: #e3f2fd; border-color: #0066cc; color: #0066cc; padding: 30px; font-size: 18px; }';
document.head.appendChild(dynamicStyle);
});
document.getElementById('btn-css-text').addEventListener('click', function() {
if (!dynamicStyle) return;
dynamicStyle.textContent =
'#demo-box { background: #fce4ec; border-color: #e91e63; color: #c2185b; padding: 40px; font-size: 20px; border-radius: 12px; }';
});
document.getElementById('btn-remove').addEventListener('click', function() {
if (dynamicStyle) {
dynamicStyle.remove();
dynamicStyle = null;
}
});
</script>
</body>
</html>注意事项
1. 多个 style 标签的优先级
<style>
h1 { color: red; }
</style>
<!-- 后面的覆盖前面的 -->
<style>
h1 { color: blue; } /* h1 最终是蓝色 */
</style>
<!-- 与 link 的顺序也遵循"后声明覆盖先声明" -->
<link rel="stylesheet" href="external.css"> <!-- 如果 external.css 设置了 h1 颜色 -->
<style>
h1 { color: green; } /* 这个会覆盖 external.css 中的 h1 颜色 */
</style>2. style 中的 @import 性能问题
<style>
/* 不推荐:@import 在 style 中也是串行加载 */
@import url('reset.css');
@import url('theme.css');
</style>3. 大量内联样式会影响 HTML 大小
<!-- 不推荐:几百行的内联 CSS -->
<style>
/* 大量样式代码... */
/* 这会显著增大 HTML 文件大小 */
/* 且无法利用浏览器缓存 */
</style>4. 内容安全策略(CSP)可能阻止内联样式
如果 CSP 设置了 style-src 'self'(不允许内联样式),<style> 标签会被阻止。需要添加 nonce 或 sha256- 哈希值。
最佳实践
1. 主要样式使用外部 CSS
<link rel="stylesheet" href="css/style.css">2. 仅将关键 CSS 内联
<style>/* 首屏关键样式 */</style>
<link rel="stylesheet" href="css/main.css">3. 为 style 标签添加 media 条件
<style media="(prefers-color-scheme: dark)">/* 暗色模式样式 */</style>4. 使用 nonce 提升 CSP 安全性
<style nonce="SERVER_GENERATED_NONCE">body { color: #333; }</style>5. 构建工具自动处理
现代构建工具(Vite、Webpack 等)会自动提取 <style> 中的 CSS 到外部文件中:
源码: HTML 中的 <style> → 构建后: 外部 .css 文件 + <link> 引入下一节
继续学习:noscript 标签