语义正确的卡片式导航菜单需用包裹并设aria-label,菜单项用或,触发按钮必须为且配aria-expanded和aria-controls,面板用配id,svg加aria-hidden="true"。

卡片式导航菜单的HTML结构怎么写才语义正确
直接用一堆 div 套 div 写“卡片菜单”,屏幕阅读器根本不知道这是导航,键盘用户按 Tab 会迷失在一堆无意义的容器里。必须从语义出发:
- 外层用
<nav></nav>,并加aria-label(如aria-label="主菜单"),让辅助技术识别这是导航区域 - 每个菜单项用
<section></section>或语义更明确的<article></article>(如果每张卡片代表独立内容单元) - 触发展开/收起的按钮必须是
<button></button>,不能用<div> + <code>onclick,否则无法键盘聚焦、空格/回车触发 - 折叠面板用
<div> 即可,但需配 <code>id,并让按钮通过aria-controls指向它 - 所有图标 SVG 需加
aria-hidden="true",避免被读屏重复播报 -
border-radius: 8px是安全起点;超过12px在小屏上易显突兀 - 阴影推荐组合:
box-shadow: 0 2px 8px rgba(0,0,0,0.08)(轻量)+0 4px 16px rgba(0,0,0,0.12)(中量),避免用inset或多层模糊导致渲染卡顿 - 卡片间间距统一用
gap(Flex/Grid 容器上),不用margin,防止外边距合并干扰布局 - 移动端卡片宽度建议设为
min-width: 280px,配合flex-wrap: wrap,比固定列数更可靠 - 图片占位慎用
object-fit: cover,若原始比例差异大,会导致关键内容被裁,优先用background-image+background-size: contain - 每次状态切换后,必须同步更新按钮的
aria-expanded值("true"/"false") - 收起时,焦点不应留在已隐藏的面板内;展开后,建议用
panel.focus()把焦点移到面板第一个可聚焦元素(如链接或表单控件) - 动画过渡必须用
transform+opacity,避免触发动画重排(height动画会强制浏览器反复计算布局) - 不要监听
click就完事——补上keydown监听,支持Enter和Space触发,且preventDefault()防止空格滚动页面 - 禁用
pointer-events: none隐藏面板,这会让键盘用户完全无法访问;应始终用hidden属性或visibility: hidden+aria-hidden="true" - 小屏(
max-width: 768px):默认全部收起,靠点击展开;避免自动展开导致首屏内容过长 - 中屏(
769px–1024px):可设为“前两项默认展开”,平衡信息密度与操作成本 - 大屏(
min-width: 1025px):考虑改用横向菜单 + 悬停展开(:hover),但必须保留点击 fallback,因为触摸设备不触发 hover - 横竖屏切换时,
resize事件监听开销大,优先用 CSS@media (orientation: landscape)控制布局,而非 JS 重绘 - 折叠状态不应存在“全局记忆”——用户旋转屏幕后,之前展开的项不必强制保持展开,反而可能造成误触
CSS实现卡片间距、圆角和阴影的关键参数
卡片看起来“浮起来”不是靠堆 box-shadow 数值,而是控制层次感和设备适配:
JavaScript控制展开/收起时容易忽略的可访问性细节
只调用 element.classList.toggle("open") 和 element.hidden = !isOpen 远不够:
响应式卡片菜单在不同设备上的行为差异
同一套代码,在手机、平板、桌面表现可能完全不同,别指望媒体查询一刀切:
最麻烦的从来不是写出来,而是让每张卡片在键盘、屏幕阅读器、触控、缩放 200% 的浏览器里都表现一致。一个没设 tabindex 的图标、一行漏掉 aria-hidden 的 SVG、一次没清理的 focus,都可能让整个菜单对某类用户彻底失效。











