关于 material-design-3-layout
material-design-3-layout 是面向界面开发者的技能,指导实现 Material Design 3 的布局与尺寸层级。它涵盖间距、响应式网格、层次、容器和交互状态等设计规则。
主要功能
- 014dp 间距刻度与语义令牌
- 02响应式断点和网格列数
- 03组件尺寸与视觉层级
- 04海拔、模糊和表面分层
- 05触控目标与焦点指示规范
适用场景
- 01规划适配不同屏幕的页面网格
- 02统一组件间距和尺寸层级
- 03为弹窗与浮层设置深度关系
- 04检查交互控件的触控和焦点状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ shelbeely/ shelbeely-agent-skills --skill material-design-3-layout安装后在 Claude Code 中输入/material-design-3-layout确认已加载。
详细介绍
Material Design 3 布局与尺寸层级
概述
本技能介绍如何运用 Material Design 3(M3)Expressive 的布局与间距原则,打造清晰、有序且响应迅速的界面。
关键词:Material Design 3、M3、布局、间距、网格、响应式设计、断点、尺寸层级、高程、内边距、外边距
核心原则
布局理念
从 Material You 基础到 M3 Expressive,M3 布局注重:
- 清晰的层级:通过尺寸和间距体现视觉重要性
- 响应式适配:布局适用于各种屏幕尺寸
- 策略性间距:一致的间距营造节奏感与流畅感
- 基于尺寸的强调:较大的元素自然会吸引注意力
- 高程深度:分层表面展现元素间的关系
- 显式与隐式包含:通过边框和相邻关系实现视觉分组
- 背景模糊与分层:引导视觉焦点的深度效果(M3 Expressive)
间距比例系统
M3 对所有布局间距使用一致的 4dp 间距比例:
基础比例(以 4dp 为增量)
:root {
/* Spacing scale */
--md-sys-spacing-0: 0px;
--md-sys-spacing-1: 4px;
--md-sys-spacing-2: 8px;
--md-sys-spacing-3: 12px;
--md-sys-spacing-4: 16px;
--md-sys-spacing-5: 20px;
--md-sys-spacing-6: 24px;
--md-sys-spacing-7: 28px;
--md-sys-spacing-8: 32px;
--md-sys-spacing-9: 36px;
--md-sys-spacing-10: 40px;
--md-sys-spacing-12: 48px;
--md-sys-spacing-14: 56px;
--md-sys-spacing-16: 64px;
--md-sys-spacing-20: 80px;
--md-sys-spacing-24: 96px;
}
语义化间距
为常见模式定义语义化间距:
:root {
/* Component spacing */
--md-sys-spacing-component-gap: var(--md-sys-spacing-2); /* 8px */
--md-sys-spacing-component-padding: var(--md-sys-spacing-4); /* 16px */
/* Layout spacing */
--md-sys-spacing-section-gap: var(--md-sys-spacing-6); /* 24px */
--md-sys-spacing-page-margin: var(--md-sys-spacing-4); /* 16px */
/* List spacing */
--md-sys-spacing-list-item-gap: var(--md-sys-spacing-2); /* 8px */
--md-sys-spacing-list-padding: var(--md-sys-spacing-4); /* 16px */
}
响应式网格系统
断点
M3 为响应式设计定义了标准断点:
:root {
/* Breakpoints */
--md-sys-breakpoint-xs: 0px; /* Extra small (phones) */
--md-sys-breakpoint-sm: 600px; /* Small (tablets portrait) */
--md-sys-breakpoint-md: 905px; /* Medium (tablets landscape) */
--md-sys-breakpoint-lg: 1240px; /* Large (laptops) */
--md-sys-breakpoint-xl: 1440px; /* Extra large (desktops) */
}
网格列
手机(0-599px):
- 列数:4
- 边距:16px
- 槽距:16px
平板(600-904px):
- 列数:8
- 边距:24px
- 槽距:24px
桌面(905px+):
- 列数:12
- 边距:24px
- 槽距:24px
CSS 网格实现
.layout-grid {
display: grid;
gap: var(--md-sys-spacing-4);
padding: var(--md-sys-spacing-4);
/* Mobile: 4 columns */
grid-template-columns: repeat(4, 1fr);
}
@media (min-width: 600px) {
.layout-grid {
gap: var(--md-sys-spacing-6);
padding: var(--md-sys-spacing-6);
/* Tablet: 8 columns */
grid-template-columns: repeat(8, 1fr);
}
}
@media (min-width: 905px) {
.layout-grid {
/* Desktop: 12 columns */
grid-template-columns: repeat(12, 1fr);
}
}
组件间距
按钮
内边距:
- 水平:24px
- 垂直:10px
- 最小高度:40px
- 图标与文本间距:8px
.button {
padding: var(--md-sys-spacing-2) var(--md-sys-spacing-6);
min-height: 40px;
gap: var(--md-sys-spacing-2);
}
卡片
内边距:
- 标准:四边均为 16px
- 大卡片:四边均为 24px
- 紧凑:四边均为 12px
元素间距:
- 标题到内容:8px
- 内容到操作项:16px
- 操作项之间:8px
.card {
padding: var(--md-sys-spacing-4);
display: flex;
flex-direction: column;
gap: var(--md-sys-spacing-2);
}
.card-actions {
margin-top: var(--md-sys-spacing-4);
display: flex;
gap: var(--md-sys-spacing-2);
}
对话框
内边距:
- 四边:24px
- 内容内边距:16px
- 标题到内容:16px
- 内容到操作项:24px
尺寸:
- 最小宽度:280px
- 最大宽度:560px
- 手机:全宽并保留边距
.dialog {
padding: var(--md-sys-spacing-6);
min-width: 280px;
max-width: 560px;
display: flex;
flex-direction: column;
gap: var(--md-sys-spacing-4);
}
@media (max-width: 599px) {
.dialog {
width: calc(100% - 32px);
margin: var(--md-sys-spacing-4);
}
}
列表
间距:
- 列表项之间:0px(各项相接)
- 列表项内边距:水平 16px,垂直 8px
- 图标到文本:16px
- 文本到次要操作项:16px
.list-item {
padding: var(--md-sys-spacing-2) var(--md-sys-spacing-4);
display: flex;
align-items: center;
gap: var(--md-sys-spacing-4);
min-height: 56px;
}
导航
应用栏:
- 高度:64px(桌面)、56px(手机)
- 内边距:水平 16px
- 项目间距:24px
导航栏:
- 宽度:80px
- 项目高度:56px
- 项目间距:4px
底部导航:
- 高度:80px
- 项目宽度:平均分配
- 图标到标签:4px
.app-bar {
height: 56px;
padding: 0 var(--md-sys-spacing-4);
display: flex;
align-items: center;
gap: var(--md-sys-spacing-6);
}
@media (min-width: 600px) {
.app-bar {
height: 64px;
}
}
尺寸层级
使用尺寸进行强调
M3 Expressive 会策略性地使用尺寸来建立视觉层级:
主视觉元素(最大):
- 比标准尺寸大 2-3 倍
- 用于主要行动号召或精选内容
- 每个视图限 1-2 个
主要元素(较大):
- 比标准尺寸大 1.5 倍
- 主要内容、精选项目
- 每个视图 3-5 个
标准元素(基础):
- 大多数内容的默认尺寸
- 保持可读性与易用性
次要元素(较小):
- 标准尺寸的 0.75 倍
- 辅助信息、元数据
- 数量可以较多
三级元素(最小):
- 标准尺寸的 0.5 倍
- 时间戳、说明文字、细则
- 谨慎使用
尺寸示例
/* Hero button */
.button-hero {
padding: var(--md-sys-spacing-4) var(--md-sys-spacing-10);
min-height: 56px;
font-size: 18px;
}
/* Standard button */
.button-standard {
padding: var(--md-sys-spacing-2) var(--md-sys-spacing-6);
min-height: 40px;
font-size: 14px;
}
/* Small button */
.button-small {
padding: var(--md-sys-spacing-1) var(--md-sys-spacing-4);
min-height: 32px;
font-size: 12px;
}
高程系统
M3 使用高程来体现深度和层级:
海拔层级
Level 0(位于表面):
- 无阴影
- 背景元素
Level 1(轻微抬升):
- 阴影:
0 1px 2px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.15) - 卡片、列表项
- 使用:1dp
Level 2(抬升):
- 阴影:
0 2px 4px rgba(0,0,0,0.3), 0 3px 4px rgba(0,0,0,0.15) - 突起按钮、静止状态的 FAB
- 使用:3dp
Level 3(悬浮):
- 阴影:
0 4px 8px rgba(0,0,0,0.3), 0 6px 8px rgba(0,0,0,0.15) - 悬停状态的 FAB、应用栏
- 使用:6dp
Level 4(模态):
- 阴影:
0 8px 12px rgba(0,0,0,0.3), 0 12px 16px rgba(0,0,0,0.15) - 对话框、导航抽屉
- 使用:8dp
Level 5(高模态):
- 阴影:
0 12px 16px rgba(0,0,0,0.3), 0 16px 24px rgba(0,0,0,0.15) - 模态底部表单
- 使用:12dp
海拔令牌
:root {
--md-sys-elevation-0: none;
--md-sys-elevation-1: 0 1px 2px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.15);
--md-sys-elevation-2: 0 2px 4px rgba(0,0,0,0.3), 0 3px 4px rgba(0,0,0,0.15);
--md-sys-elevation-3: 0 4px 8px rgba(0,0,0,0.3), 0 6px 8px rgba(0,0,0,0.15);
--md-sys-elevation-4: 0 8px 12px rgba(0,0,0,0.3), 0 12px 16px rgba(0,0,0,0.15);
--md-sys-elevation-5: 0 12px 16px rgba(0,0,0,0.3), 0 16px 24px rgba(0,0,0,0.15);
}
带色调的海拔效果
M3 会为抬升的表面添加细微的颜色色调:
.elevated-surface {
background-color: var(--md-sys-color-surface);
box-shadow: var(--md-sys-elevation-1);
/* Add subtle tint using primary color */
background-image: linear-gradient(
rgba(var(--md-sys-color-primary-rgb), 0.05),
rgba(var(--md-sys-color-primary-rgb), 0.05)
);
}
响应式布局模式
移动优先方法
从移动端布局开始,然后针对更大的屏幕进行增强:
/* Mobile: Stack vertically */
.content-layout {
display: flex;
flex-direction: column;
gap: var(--md-sys-spacing-4);
padding: var(--md-sys-spacing-4);
}
/* Tablet: Two columns */
@media (min-width: 600px) {
.content-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--md-sys-spacing-6);
padding: var(--md-sys-spacing-6);
}
}
/* Desktop: Three columns with sidebar */
@media (min-width: 905px) {
.content-layout {
grid-template-columns: 250px 1fr 1fr;
}
}
容器查询
用于组件级响应式设计:
.card-container {
container-type: inline-size;
}
.card {
display: flex;
flex-direction: column;
}
@container (min-width: 400px) {
.card {
flex-direction: row;
gap: var(--md-sys-spacing-4);
}
}
常见布局模式
内容居中:
.centered-layout {
max-width: 1200px;
margin: 0 auto;
padding: var(--md-sys-spacing-6);
}
侧边栏布局:
.sidebar-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: var(--md-sys-spacing-6);
}
@media (max-width: 904px) {
.sidebar-layout {
grid-template-columns: 1fr;
}
}
仪表盘网格:
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--md-sys-spacing-4);
}
包含原则
显式包含
使用可见边界将相关内容分组:
/* Card containment with outline */
.contained-group {
border: 1px solid var(--md-sys-color-outline-variant);
border-radius: var(--md-sys-shape-corner-medium);
padding: var(--md-sys-spacing-4);
background: var(--md-sys-color-surface-container);
}
/* Elevated containment */
.elevated-group {
box-shadow: var(--md-sys-elevation-1);
border-radius: var(--md-sys-shape-corner-medium);
padding: var(--md-sys-spacing-4);
background: var(--md-sys-color-surface-container-low);
}
隐式包含
使用邻近关系、留白和对齐来对项目分组,无需可见边框:
/* Implicit grouping through proximity */
.implicit-group {
display: flex;
flex-direction: column;
gap: var(--md-sys-spacing-1); /* Tight spacing implies grouping */
}
/* Separated groups use larger spacing */
.section-gap {
margin-bottom: var(--md-sys-spacing-8); /* Larger gap separates groups */
}
何时使用各类型
| 包含类型 | 使用场景 |
|---|---|
| 显式(边框/卡片) | 交互内容、不同的区块、可操作的分组 |
| 显式(海拔) | 需要呈现“抬升”或模态效果的内容 |
| 隐式(邻近关系) | 相关文本块、标签-值对、顺序内容 |
| 隐式(对齐) | 网格布局、导航项、一致的结构 |
背景模糊和深度效果
M3 Expressive 引入背景模糊和分层效果,以提升深度感和聚焦效果:
背景模糊
在覆盖层、模态窗口和导航元素后方策略性地使用模糊效果:
/* Blur behind modal dialogs */
.dialog-backdrop {
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
background-color: rgba(0, 0, 0, 0.32);
}
/* Blur behind floating toolbars */
.floating-toolbar {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
background-color: rgba(var(--md-sys-color-surface-rgb), 0.85);
}
/* Blur behind navigation drawers */
.nav-drawer-scrim {
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
background-color: var(--md-sys-color-scrim);
opacity: 0.32;
}
何时使用模糊效果
- 模态窗口和对话框后方:将注意力集中在前景内容上
- 悬浮工具栏后方:将工具栏与内容分隔开,而不使用强烈的海拔效果
- 导航抽屉后方:柔化抽屉与内容之间的过渡
- 底部表单后方:营造深度感,同时不完全遮挡内容
- 不要用于内容本身:模糊效果用于遮罩层和背景,而非可读内容
深度分层
结合海拔、模糊和表面色调,形成清晰的分层效果:
/* Layer 1: Base content */
.base-layer {
background: var(--md-sys-color-surface);
}
/* Layer 2: Elevated content */
.elevated-layer {
background: var(--md-sys-color-surface-container);
box-shadow: var(--md-sys-elevation-1);
}
/* Layer 3: Overlay with blur */
.overlay-layer {
backdrop-filter: blur(16px);
background: rgba(var(--md-sys-color-surface-container-high-rgb), 0.9);
box-shadow: var(--md-sys-elevation-3);
}
交互状态
M3 为所有交互元素定义了一致的交互状态:
状态层系统
状态层是使用特定不透明度的内容颜色创建的覆盖层:
| 状态 | 不透明度 | 描述 |
|---|---|---|
| 启用 | 0% | 默认状态,无覆盖层 |
| 悬停 | 8% | 指针设备悬停 |
| 聚焦 | 12% | 键盘/无障碍焦点 |
| 按下 | 12% | 触摸/点击按下 |
| 拖动 | 16% | 正在进行拖动操作 |
| 禁用 | 0% | 不可交互(内容不透明度为 38%,背景不透明度为 12%) |
/* State layer implementation */
.interactive-element {
position: relative;
}
.interactive-element::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: var(--md-sys-color-on-surface);
opacity: 0;
transition: opacity 200ms var(--md-sys-motion-easing-standard);
pointer-events: none;
}
.interactive-element:hover::before { opacity: 0.08; }
.interactive-element:focus-visible::before { opacity: 0.12; }
.interactive-element:active::before { opacity: 0.12; }
/* Disabled state */
.interactive-element:disabled {
opacity: 0.38;
pointer-events: none;
}
.interactive-element:disabled::before {
opacity: 0;
}
状态优先级
一次只应用一个可见状态层。优先级顺序:
- 拖动(最高)
- 按下
- 聚焦
- 悬停
- 启用(最低)
触控目标和无障碍
最小触控目标尺寸
所有交互元素的尺寸必须至少为 48×48dp:
.touch-target {
min-width: 48px;
min-height: 48px;
/* Visual size can be smaller with padding */
padding: var(--md-sys-spacing-3);
}
焦点指示器
确保焦点环周围有足够的间距:
.focusable {
position: relative;
}
.focusable:focus-visible {
outline: 2px solid var(--md-sys-color-primary);
outline-offset: 2px;
}
最佳实践
建议做法
- ✅ 始终使用 4dp 间距比例
- ✅ 为常见模式定义语义化间距令牌
- ✅ 从移动优先开始,然后针对更大的屏幕进行增强
- ✅ 使用尺寸层级营造视觉强调
- ✅ 保持触控目标至少为 48×48dp
- ✅ 使用海拔效果展示组件之间的关系
- ✅ 在所有断点下测试布局
- ✅ 使用 CSS Grid 和 Flexbox 构建现代布局
不要做
- ❌ 不要使用随意的间距值(请遵循比例)
- ❌ 不要设计仅适用于桌面端的布局
- ❌ 不要在移动设备上使用过小的触控目标
- ❌ 不要过度使用立体效果(会造成视觉干扰)
- ❌ 不要忽略组件的容器查询
- ❌ 不要创建没有最大宽度限制的固定宽度布局
- ❌ 不要忘记移动设备上的水平滚动
性能注意事项
- 使用 CSS Grid/Flexbox:避免基于 float 的布局
- 尽量减少布局偏移:定义尺寸以防止 CLS
- 优化图片:使用带有 srcset 的响应式图片
- 延迟加载:延后加载屏幕外的内容
- 容器查询:对组件而言比媒体查询更好
布局实现检查清单
实现 M3 布局时,请确保:
- 已定义间距比例(以 4dp 为增量)
- 已创建语义化间距令牌
- 已定义断点(600px、905px、1240px)
- 采用移动优先的响应式设计方法
- 网格系统支持 4/8/12 列
- 触控目标至少为 48×48dp
- 已定义立体效果系统(5 个级别)
- 使用尺寸层级突出重点
- 所有间距均使用令牌(不使用硬编码值)
- 布局适用于所有屏幕尺寸
- 焦点指示器周围留有足够间距
- 对组件使用容器查询
- 设置最大内容宽度以提高可读性
- 对凸起表面应用立体色调
- 应用内聚原则(显式和隐式分组)
- 对模态框、抽屉和浮动元素使用背景模糊
- 使用正确的不透明度值实现交互状态
- 禁用状态使用 38% 的内容不透明度和 12% 的背景不透明度
- 状态层以适当的不透明度使用表面上方颜色
- 优化性能(Grid/Flexbox、延迟加载)