pin_drop当前位置:知识文库 ❯ 图文
布局结构:HTML媒体查询 - 完整教程与代码示例
一、教程简介
媒体查询(Media Queries)是CSS3中最重要的特性之一,它是实现响应式设计的核心技术。通过媒体查询,我们可以根据设备的各种特征(如屏幕宽度、高度、方向、分辨率等)来条件性地应用CSS样式。本教程将全面讲解@media语法、断点选择策略以及响应式布局的实践技巧。
二、核心概念
什么是媒体查询
媒体查询允许根据设备的特征来应用不同的CSS样式规则。它由一个媒体类型和零个或多个检查特定特征的条件表达式组成。
代码示例
@media screen and (min-width: 768px) {
/* 当屏幕宽度 >= 768px 时应用 */
.container {
max-width: 720px;
}
}媒体查询的组成
代码示例
@media [媒体类型] and [(媒体特性)] {
/* CSS样式 */
}
示例:
@media screen and (min-width: 768px) and (orientation: landscape) {
/* 样式 */
}
分解:
@media --> 媒体查询关键字
screen --> 媒体类型
and --> 逻辑操作符
(min-width: 768px) --> 媒体特性1
(orientation: landscape) --> 媒体特性2媒体类型
媒体特性
三、语法与用法
基本语法
代码示例
/* 1. 在样式表中使用 */
@media screen and (min-width: 768px) {
.sidebar { display: block; }
}
/* 2. 使用逻辑操作符 */
/* AND - 同时满足所有条件 */
@media screen and (min-width: 768px) and (max-width: 1023px) {
/* 平板设备样式 */
}
/* 逗号(,) - 满足任一条件(相当于OR) */
@media screen and (max-width: 480px), screen and (min-width: 1200px) {
/* 极小屏或极大屏样式 */
}
/* NOT - 取反 */
@media not screen and (max-width: 767px) {
/* 非小屏设备的样式 */
}
/* ONLY - 仅匹配指定媒体类型(防止旧浏览器误匹配) */
@media only screen and (min-width: 768px) {
/* 仅屏幕设备 */
}在HTML中引入
代码示例
<!-- 方式1:link标签的media属性 -->
<link rel="stylesheet" href="mobile.css" media="screen and (max-width: 767px)">
<link rel="stylesheet" href="desktop.css" media="screen and (min-width: 768px)">
<!-- 方式2:style标签的media属性 -->
<style media="screen and (min-width: 768px)">
.sidebar { display: block; }
</style>
<!-- 方式3:@import(不推荐,影响性能) -->
<style>
@import url("desktop.css") screen and (min-width: 768px);
</style>断点选择策略
常见断点参考:
移动优先断点(推荐)
代码示例
/* 默认样式:移动端 */
/* sm: 576px+ */
@media (min-width: 576px) { }
/* md: 768px+ */
@media (min-width: 768px) { }
/* lg: 992px+ */
@media (min-width: 992px) { }
/* xl: 1200px+ */
@media (min-width: 1200px) { }
/* xxl: 1400px+ */
@media (min-width: 1400px) { }桌面优先断点
代码示例
/* 默认样式:桌面端 */
/* lg以下 */
@media (max-width: 1199px) { }
/* md以下 */
@media (max-width: 991px) { }
/* sm以下 */
@media (max-width: 767px) { }
/* xs */
@media (max-width: 575px) { }用户偏好媒体查询
代码示例
/* 暗色模式 */
@media (prefers-color-scheme: dark) {
body {
background: #1a1a2e;
color: #eee;
}
}
/* 减少动画 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
/* 高对比度 */
@media (prefers-contrast: high) {
body {
background: black;
color: white;
}
}
/* 悬停能力 */
@media (hover: hover) {
.card:hover {
transform: translateY(-5px);
}
}
/* 精细指针(鼠标)vs 粗糙指针(触摸) */
@media (pointer: fine) {
.button { padding: 8px 16px; }
}
@media (pointer: coarse) {
.button { padding: 12px 24px; }
}四、代码示例
示例1:媒体查询断点演示
代码示例
<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Microsoft YaHei", sans-serif;
background: #f5f5f5;
color: #333;
}
/* 断点指示器 */
.breakpoint-indicator {
position: fixed;
bottom: 20px;
right: 20px;
padding: 10px 20px;
border-radius: 25px;
color: white;
font-weight: bold;
font-size: 14px;
z-index: 1000;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
transition: background 0.3s;
}
/* 默认 - xs */
.breakpoint-indicator { background: #e74c3c; }
@media (min-width: 576px) {
.breakpoint-indicator { background: #f39c12; }
}
@media (min-width: 768px) {
.breakpoint-indicator { background: #27ae60; }
}
@media (min-width: 992px) {
.breakpoint-indicator { background: #3498db; }
}
@media (min-width: 1200px) {
.breakpoint-indicator { background: #9b59b6; }
}
@media (min-width: 1400px) {
.breakpoint-indicator { background: #1abc9c; }
}
/* 页面布局 */
.page {
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* 头部 */
.header {
background: #2c3e50;
color: white;
padding: 15px 20px;
}
.header-inner {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
}
.nav {
display: none;
gap: 20px;
}
.nav a {
color: white;
text-decoration: none;
padding: 8px 12px;
border-radius: 4px;
transition: background 0.3s;
}
.nav a:hover {
background: rgba(255,255,255,0.1);
}
.menu-btn {
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
}
/* 主内容 */
.main {
flex: 1;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
width: 100%;
}
/* 卡片网格 */
.card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 20px;
}
.card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.card-img {
width: 100%;
height: 200px;
background: #3498db;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 2rem;
}
.card-body {
padding: 20px;
}
.card-body h3 {
color: #2c3e50;
margin-bottom: 10px;
}
.card-body p {
color: #666;
font-size: 14px;
line-height: 1.6;
}
/* 侧边栏 */
.sidebar {
display: none;
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.sidebar h3 {
color: #2c3e50;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #3498db;
}
.sidebar ul {
list-style: none;
}
.sidebar ul li {
padding: 8px 0;
border-bottom: 1px solid #eee;
}
.sidebar ul li a {
color: #555;
text-decoration: none;
}
/* 页脚 */
.footer {
background: #2c3e50;
color: #aaa;
text-align: center;
padding: 20px;
}
/* ===== 响应式断点 ===== */
/* sm: 576px+ */
@media (min-width: 576px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* md: 768px+ */
@media (min-width: 768px) {
.nav {
display: flex;
}
.menu-btn {
display: none;
}
.card-grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* lg: 992px+ */
@media (min-width: 992px) {
.main {
display: grid;
grid-template-columns: 1fr 300px;
gap: 20px;
}
.sidebar {
display: block;
}
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* xl: 1200px+ */
@media (min-width: 1200px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
}
}
</style>
</head>
<body>
<div class="page">
<header class="header">
<div class="header-inner">
<div class="logo">MediaQuery</div>
<nav class="nav">
<a href="#">首页</a>
<a href="#">产品</a>
<a href="#">关于</a>
<a href="#">联系</a>
</nav>
<button class="menu-btn">☰</button>
</div>
</header>
<div class="main">
<div>
<h2 style="margin-bottom: 20px; color: #2c3e50;">调整浏览器宽度查看响应式效果</h2>
<div class="card-grid">
<div class="card">
<div class="card-img" style="background: #e74c3c;">1</div>
<div class="card-body">
<h3>XS断点</h3>
<p>0-575px: 单列布局,导航隐藏,显示汉堡菜单</p>
</div>
</div>
<div class="card">
<div class="card-img" style="background: #f39c12;">2</div>
<div class="card-body">
<h3>SM断点</h3>
<p>576px+: 双列卡片布局</p>
</div>
</div>
<div class="card">
<div class="card-img" style="background: #27ae60;">3</div>
<div class="card-body">
<h3>MD断点</h3>
<p>768px+: 三列卡片,导航栏显示</p>
</div>
</div>
<div class="card">
<div class="card-img" style="background: #3498db;">4</div>
<div class="card-body">
<h3>LG断点</h3>
<p>992px+: 侧边栏出现,双列卡片</p>
</div>
</div>
<div class="card">
<div class="card-img" style="background: #9b59b6;">5</div>
<div class="card-body">
<h3>XL断点</h3>
<p>1200px+: 三列卡片+侧边栏</p>
</div>
</div>
<div class="card">
<div class="card-img" style="background: #1abc9c;">6</div>
<div class="card-body">
<h3>XXL断点</h3>
<p>1400px+: 更宽敞的布局</p>
</div>
</div>
</div>
</div>
<aside class="sidebar">
<h3>侧边栏</h3>
<ul>
<li><a href="#">HTML基础</a></li>
<li><a href="#">CSS布局</a></li>
<li><a href="#">JavaScript</a></li>
<li><a href="#">响应式设计</a></li>
<li><a href="#">媒体查询</a></li>
</ul>
</aside>
</div>
<footer class="footer">
<p>调整浏览器宽度,右下角指示器显示当前断点</p>
</footer>
</div>
<!-- 断点指示器 -->
<div class="breakpoint-indicator" id="bpIndicator">XS</div>
<script>
function updateBreakpoint() {
var w = window.innerWidth;
var indicator = document.getElementById('bpIndicator');
if (w >= 1400) indicator.textContent = 'XXL (1400px+)';
else if (w >= 1200) indicator.textContent = 'XL (1200px+)';
else if (w >= 992) indicator.textContent = 'LG (992px+)';
else if (w >= 768) indicator.textContent = 'MD (768px+)';
else if (w >= 576) indicator.textContent = 'SM (576px+)';
else indicator.textContent = 'XS (0-575px)';
}
updateBreakpoint();
window.addEventListener('resize', updateBreakpoint);
</script>
</body>
</html>示例2:用户偏好媒体查询
代码示例
<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 默认亮色主题 */
:root {
--bg: #ffffff;
--text: #333333;
--card-bg: #f8f9fa;
--border: #e0e0e0;
--primary: #3498db;
--shadow: rgba(0,0,0,0.1);
}
/* 暗色主题 */
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a2e;
--text: #e0e0e0;
--card-bg: #16213e;
--border: #2a2a4a;
--primary: #4fc3f7;
--shadow: rgba(0,0,0,0.3);
}
}
body {
font-family: "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--text);
padding: 20px;
transition: background 0.3s, color 0.3s;
}
.container {
max-width: 800px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: var(--primary);
}
.card {
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 8px var(--shadow);
transition: background 0.3s, border-color 0.3s;
}
.card h2 {
color: var(--primary);
margin-bottom: 10px;
font-size: 1.1rem;
}
.card p {
line-height: 1.8;
font-size: 14px;
}
/* 减少动画偏好 */
.animated-box {
width: 100px;
height: 100px;
background: var(--primary);
border-radius: 8px;
margin: 20px auto;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
.animated-box {
animation: none;
}
* {
transition-duration: 0.01ms !important;
}
}
/* 悬停能力检测 */
.hover-demo {
padding: 15px;
background: var(--primary);
color: white;
text-align: center;
border-radius: 8px;
cursor: pointer;
transition: transform 0.3s, box-shadow 0.3s;
}
@media (hover: hover) {
.hover-demo:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px var(--shadow);
}
}
/* 指针精度检测 */
.pointer-info {
padding: 15px;
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 8px;
text-align: center;
}
@media (pointer: fine) {
.pointer-info::after {
content: '精细指针(鼠标)';
color: #27ae60;
font-weight: bold;
}
}
@media (pointer: coarse) {
.pointer-info::after {
content: '粗糙指针(触摸)';
color: #e74c3c;
font-weight: bold;
}
}
@media (pointer: none) {
.pointer-info::after {
content: '无指针';
color: #f39c12;
font-weight: bold;
}
}
/* 方向检测 */
.orientation-info {
padding: 15px;
background: var(--card-bg);
border: 1px solid var(--border);
border-radius: 8px;
text-align: center;
}
@media (orientation: portrait) {
.orientation-info::after {
content: '竖屏模式';
color: #9b59b6;
font-weight: bold;
}
}
@media (orientation: landscape) {
.orientation-info::after {
content: '横屏模式';
color: #1abc9c;
font-weight: bold;
}
}
.tag {
display: inline-block;
padding: 3px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
margin: 3px;
}
.tag-css { background: #3498db; color: white; }
.tag-a11y { background: #27ae60; color: white; }
.tag-ux { background: #e74c3c; color: white; }
</style>
</head>
<body>
<div class="container">
<h1>用户偏好媒体查询</h1>
<div class="card">
<h2>暗色模式检测 <span class="tag tag-css">CSS</span></h2>
<p>使用 <code>prefers-color-scheme: dark</code> 检测用户系统是否启用了暗色模式。本页面会自动跟随系统主题切换,请在系统设置中切换深色/浅色模式查看效果。</p>
</div>
<div class="card">
<h2>减少动画偏好 <span class="tag tag-a11y">A11y</span></h2>
<p>使用 <code>prefers-reduced-motion: reduce</code> 检测用户是否偏好减少动画。下方方块默认有动画,开启减少动画后将停止。</p>
<div class="animated-box"></div>
</div>
<div class="card">
<h2>悬停能力检测 <span class="tag tag-ux">UX</span></h2>
<p>使用 <code>hover: hover</code> 检测设备是否支持悬停交互。鼠标设备支持悬停效果,触摸设备不支持。</p>
<div class="hover-demo">悬停试试</div>
</div>
<div class="card">
<h2>指针精度检测</h2>
<p>使用 <code>pointer: fine/coarse</code> 检测指针精度。当前设备:</p>
<div class="pointer-info">指针类型:</div>
</div>
<div class="card">
<h2>屏幕方向检测</h2>
<p>使用 <code>orientation: portrait/landscape</code> 检测屏幕方向。当前方向:</p>
<div class="orientation-info">屏幕方向:</div>
</div>
</div>
</body>
</html>五、浏览器兼容性
六、注意事项与最佳实践
1. 选择合适的断点
代码示例
/* 不推荐:基于特定设备宽度 */
@media (min-width: 375px) { } /* iPhone 6/7/8 */
@media (min-width: 414px) { } /* iPhone Plus */
/* 推荐:基于布局需求 */
@media (min-width: 576px) { } /* 内容需要更宽空间 */
@media (min-width: 768px) { } /* 可以并排显示 */
@media (min-width: 992px) { } /* 可以添加侧边栏 */2. 移动优先策略
代码示例
/* 推荐:min-width递增 */
.element {
/* 移动端默认样式 */
font-size: 14px;
}
@media (min-width: 768px) {
.element {
font-size: 16px;
}
}
@media (min-width: 1024px) {
.element {
font-size: 18px;
}
}3. 避免过多断点
代码示例
/* 不推荐:过多断点 */
@media (min-width: 320px) { }
@media (min-width: 375px) { }
@media (min-width: 414px) { }
@media (min-width: 480px) { }
@media (min-width: 576px) { }
@media (min-width: 640px) { }
@media (min-width: 768px) { }
/* 推荐:3-5个关键断点 */
@media (min-width: 576px) { }
@media (min-width: 768px) { }
@media (min-width: 992px) { }
@media (min-width: 1200px) { }4. 使用CSS自定义属性管理断点
代码示例
:root {
--bp-sm: 576px;
--bp-md: 768px;
--bp-lg: 992px;
--bp-xl: 1200px;
}
/* 注意:CSS变量不能直接用于媒体查询 */
/* 以下写法无效:*/
/* @media (min-width: var(--bp-md)) { } */
/* 替代方案:使用预处理器或直接写值 */
@media (min-width: 768px) { }5. 媒体查询的书写位置
代码示例
/* 推荐:媒体查询紧跟相关样式 */
.sidebar {
display: none;
background: white;
padding: 20px;
}
@media (min-width: 992px) {
.sidebar {
display: block;
width: 300px;
}
}
/* 不推荐:所有媒体查询集中在文件末尾 */
/* 这样会导致样式分散,难以维护 */七、代码规范示例
媒体查询项目规范
代码示例
/* ========================================
媒体查询规范
======================================== */
/* 1. 统一使用移动优先(min-width) */
/* 2. 断点值统一管理 */
/* 3. 媒体查询紧跟相关组件 */
/* ===== 断点定义 ===== */
/*
sm: 576px
md: 768px
lg: 992px
xl: 1200px
xxl: 1400px
*/
/* ===== 组件样式 + 响应式 ===== */
/* 导航组件 */
.nav {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
background: #2c3e50;
}
@media (min-width: 768px) {
.nav {
display: flex;
position: static;
width: auto;
gap: 20px;
}
}
/* 卡片网格组件 */
.card-grid {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
@media (min-width: 576px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 992px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
}
/* 页面布局组件 */
.page-layout {
display: flex;
flex-direction: column;
}
@media (min-width: 992px) {
.page-layout {
flex-direction: row;
}
.page-layout .sidebar {
width: 280px;
flex-shrink: 0;
}
.page-layout .content {
flex: 1;
}
}八、常见问题与解决方案
常见问题
问题1:媒体查询不生效
原因:viewport未设置或断点值错误。
解决方案:确保viewport设置正确,检查断点值是否正确,注意min-width和max-width不要混用导致冲突。
问题2:媒体查询被其他样式覆盖
原因:CSS选择器优先级问题。
解决方案:确保媒体查询在基础样式之后;提高选择器优先级;避免使用!important。
问题3:横竖屏切换时布局异常
原因:没有考虑orientation变化。
解决方案:使用orientation媒体查询或vmin单位确保元素在任何方向都合适。
问题4:暗色模式切换闪烁
原因:页面加载时先显示亮色再切换到暗色。
解决方案:在head中添加script,在渲染前设置主题class;同时保留媒体查询作为自动检测。
九、总结
媒体查询是响应式设计的核心技术,掌握其用法至关重要:
-
移动优先:使用
min-width从小屏向大屏递增,这是最佳实践 -
合理断点:基于布局需求而非特定设备选择断点,3-5个断点即可
-
用户偏好:利用
prefers-color-scheme、prefers-reduced-motion等提升用户体验 -
交互检测:使用
hover和pointer特性区分鼠标和触摸设备 -
就近原则:媒体查询紧跟相关组件样式,便于维护
-
避免冲突:注意min-width和max-width的边界值,避免同时匹配
-
渐进增强:先保证基础功能,再通过媒体查询增强体验
媒体查询与流式布局、弹性图片配合使用,才能构建出真正优秀的响应式网页。
本文涉及AI创作
内容由AI创作,请仔细甄别