Appearance
响应式设计
响应式设计使网页能够适应不同设备和屏幕尺寸,提供良好的用户体验。
视口设置
在 HTML 中设置视口:
html
<meta name="viewport" content="width=device-width, initial-scale=1.0">视口属性
| 属性 | 说明 |
|---|---|
width | 视口宽度,通常设为 device-width |
initial-scale | 初始缩放比例 |
maximum-scale | 最大缩放比例 |
minimum-scale | 最小缩放比例 |
user-scalable | 是否允许用户缩放 |
媒体查询
媒体查询是响应式设计的核心,根据设备特性应用不同样式。
基本语法
css
@media media-type and (media-feature) {
/* CSS 样式 */
}媒体类型
css
@media all { } /* 所有设备 */
@media screen { } /* 屏幕 */
@media print { } /* 打印 */
@media speech { } /* 屏幕阅读器 */常用媒体特性
css
/* 宽度 */
@media (width: 600px) { }
@media (min-width: 768px) { }
@media (max-width: 576px) { }
/* 高度 */
@media (height: 800px) { }
@media (min-height: 600px) { }
@media (max-height: 400px) { }
/* 设备方向 */
@media (orientation: portrait) { } /* 竖屏 */
@media (orientation: landscape) { } /* 横屏 */
/* 分辨率 */
@media (min-resolution: 2dppx) { } /* 高清屏 */
@media (min-resolution: 300dpi) { }
/* 悬停能力 */
@media (hover: hover) { } /* 支持悬停 */
@media (hover: none) { } /* 不支持悬停 */
/* 指针类型 */
@media (pointer: fine) { } /* 鼠标 */
@media (pointer: coarse) { } /* 触摸屏 */逻辑操作符
css
/* and - 同时满足 */
@media screen and (min-width: 768px) and (max-width: 1024px) { }
/* or - 逗号分隔 */
@media screen, print { }
/* not - 排除 */
@media not screen { }
/* only - 仅限旧浏览器 */
@media only screen and (min-width: 768px) { }断点设置
常用断点:
css
/* 手机 */
@media (max-width: 575.98px) { }
/* 平板竖屏 */
@media (min-width: 576px) and (max-width: 767.98px) { }
/* 平板横屏 */
@media (min-width: 768px) and (max-width: 991.98px) { }
/* 小桌面 */
@media (min-width: 992px) and (max-width: 1199.98px) { }
/* 大桌面 */
@media (min-width: 1200px) { }移动优先 vs 桌面优先
css
/* 移动优先 - 从小到大 */
.element {
font-size: 14px;
}
@media (min-width: 768px) {
.element {
font-size: 16px;
}
}
@media (min-width: 1024px) {
.element {
font-size: 18px;
}
}
/* 桌面优先 - 从大到小 */
.element {
font-size: 18px;
}
@media (max-width: 1023px) {
.element {
font-size: 16px;
}
}
@media (max-width: 767px) {
.element {
font-size: 14px;
}
}响应式单位
相对单位
css
/* em - 相对父元素字体大小 */
.parent { font-size: 16px; }
.child { font-size: 1.5em; } /* 24px */
/* rem - 相对根元素字体大小 */
html { font-size: 16px; }
.element { font-size: 1.5rem; } /* 24px */
/* vw - 视口宽度的 1% */
.element { width: 50vw; }
/* vh - 视口高度的 1% */
.element { height: 100vh; }
/* vmin - vw 和 vh 中较小的值 */
.element { font-size: 5vmin; }
/* vmax - vw 和 vh 中较大的值 */
.element { font-size: 3vmax; }
/* % - 相对父元素 */
.element { width: 50%; }calc() 函数
css
.element {
width: calc(100% - 20px);
height: calc(100vh - 60px);
font-size: calc(16px + 0.5vw);
}clamp() 函数
css
.element {
/* 最小值 | 首选值 | 最大值 */
font-size: clamp(14px, 2vw, 24px);
width: clamp(300px, 50%, 800px);
}响应式图片
max-width
css
img {
max-width: 100%;
height: auto;
}srcset 属性
html
<img
src="small.jpg"
srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
sizes="(max-width: 600px) 480px, 800px"
alt="响应式图片">picture 元素
html
<picture>
<source media="(min-width: 800px)" srcset="large.jpg">
<source media="(min-width: 400px)" srcset="medium.jpg">
<img src="small.jpg" alt="响应式图片">
</picture>object-fit
css
img {
width: 100%;
height: 200px;
object-fit: cover; /* 裁剪填满 */
object-fit: contain; /* 完整显示 */
object-fit: fill; /* 拉伸填满 */
object-fit: none; /* 原始大小 */
object-position: center;
}响应式布局
Flexbox 响应式
css
.container {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 1 1 300px; /* 基础宽度300px,可伸缩 */
margin: 10px;
}Grid 响应式
css
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
}响应式网格系统
css
.row {
display: flex;
flex-wrap: wrap;
margin: -10px;
}
.col {
flex: 1;
padding: 10px;
}
/* 响应式列 */
@media (max-width: 767px) {
.col { flex: 0 0 100%; }
}
@media (min-width: 768px) and (max-width: 991px) {
.col-md-6 { flex: 0 0 50%; }
.col-md-4 { flex: 0 0 33.333%; }
}
@media (min-width: 992px) {
.col-lg-4 { flex: 0 0 33.333%; }
.col-lg-3 { flex: 0 0 25%; }
}响应式字体
css
html {
font-size: 16px;
}
@media (min-width: 768px) {
html {
font-size: 18px;
}
}
@media (min-width: 1200px) {
html {
font-size: 20px;
}
}
/* 流体字体 */
h1 {
font-size: clamp(1.5rem, 5vw, 3rem);
}响应式导航
css
.nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.nav-menu {
display: flex;
list-style: none;
}
/* 移动端隐藏菜单 */
@media (max-width: 767px) {
.nav-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
flex-direction: column;
padding: 20px;
}
.nav-menu.active {
display: flex;
}
.nav-toggle {
display: block;
}
}
@media (min-width: 768px) {
.nav-toggle {
display: none;
}
}隐藏元素
css
/* 仅屏幕显示 */
.screen-only {
display: block;
}
@media print {
.screen-only {
display: none;
}
}
/* 仅打印显示 */
.print-only {
display: none;
}
@media print {
.print-only {
display: block;
}
}
/* 仅移动端显示 */
.mobile-only {
display: block;
}
@media (min-width: 768px) {
.mobile-only {
display: none;
}
}
/* 仅桌面端显示 */
.desktop-only {
display: none;
}
@media (min-width: 768px) {
.desktop-only {
display: block;
}
}实践示例
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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
color: #333;
}
/* 响应式导航 */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background-color: #333;
color: white;
position: relative;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
}
.nav-menu {
display: flex;
list-style: none;
gap: 20px;
}
.nav-menu a {
color: white;
text-decoration: none;
transition: color 0.3s;
}
.nav-menu a:hover {
color: #007bff;
}
.nav-toggle {
display: none;
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
}
@media (max-width: 767px) {
.nav-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
background-color: #333;
flex-direction: column;
padding: 20px;
text-align: center;
}
.nav-menu.active {
display: flex;
}
.nav-toggle {
display: block;
}
}
/* 响应式网格 */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
margin-top: 20px;
}
.card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.card-img {
width: 100%;
height: 200px;
object-fit: cover;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.card-body {
padding: 20px;
}
.card-title {
font-size: clamp(1.1rem, 2vw, 1.25rem);
margin-bottom: 10px;
}
.card-text {
color: #666;
font-size: clamp(0.9rem, 1.5vw, 1rem);
}
/* 响应式字体 */
h1 {
font-size: clamp(1.5rem, 5vw, 2.5rem);
text-align: center;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #666;
font-size: clamp(0.9rem, 2vw, 1.1rem);
margin-bottom: 30px;
}
/* 响应式布局示例 */
.layout-demo {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 30px;
}
.main-content {
flex: 1 1 300px;
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
}
.sidebar {
flex: 0 0 250px;
background: #e9ecef;
padding: 20px;
border-radius: 8px;
}
@media (max-width: 767px) {
.sidebar {
flex: 1 1 100%;
}
}
/* 响应式图片 */
.responsive-img {
width: 100%;
height: auto;
max-width: 100%;
border-radius: 8px;
margin: 20px 0;
}
</style>
</head>
<body>
<nav class="navbar">
<div class="logo">Logo</div>
<button class="nav-toggle" onclick="toggleMenu()">☰</button>
<ul class="nav-menu" id="navMenu">
<li><a href="#">首页</a></li>
<li><a href="#">产品</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">关于</a></li>
<li><a href="#">联系</a></li>
</ul>
</nav>
<div class="container">
<h1>响应式设计示例</h1>
<p class="subtitle">调整浏览器窗口大小查看效果</p>
<div class="grid">
<div class="card">
<div class="card-img"></div>
<div class="card-body">
<h3 class="card-title">卡片标题 1</h3>
<p class="card-text">这是一段卡片描述内容,展示响应式卡片布局。</p>
</div>
</div>
<div class="card">
<div class="card-img"></div>
<div class="card-body">
<h3 class="card-title">卡片标题 2</h3>
<p class="card-text">这是一段卡片描述内容,展示响应式卡片布局。</p>
</div>
</div>
<div class="card">
<div class="card-img"></div>
<div class="card-body">
<h3 class="card-title">卡片标题 3</h3>
<p class="card-text">这是一段卡片描述内容,展示响应式卡片布局。</p>
</div>
</div>
<div class="card">
<div class="card-img"></div>
<div class="card-body">
<h3 class="card-title">卡片标题 4</h3>
<p class="card-text">这是一段卡片描述内容,展示响应式卡片布局。</p>
</div>
</div>
</div>
<div class="layout-demo">
<div class="main-content">
<h2>主内容区域</h2>
<p>这是页面的主要内容区域,在小屏幕上会占满宽度,在大屏幕上与侧边栏并排显示。</p>
</div>
<div class="sidebar">
<h3>侧边栏</h3>
<p>侧边栏内容,在小屏幕上会移到主内容下方。</p>
</div>
</div>
</div>
<script>
function toggleMenu() {
const menu = document.getElementById('navMenu');
menu.classList.toggle('active');
}
</script>
</body>
</html>