收件箱页面必须采用语义化HTML结构,用<article>包裹每封邮件,<header><main><footer>分别承载元信息、摘要和操作;表格布局选<table>或Grid需依交互需求而定;状态变更须同步更新class、attribute及aria属性;分页优于虚拟滚动;键盘操作链路是基本准入门槛。

收件箱页面必须用语义化结构,别只靠堆
后台收件箱不是普通列表页,它需要被屏幕阅读器识别、被搜索爬虫理解、被未来维护者快速定位逻辑。用<article>包裹每封邮件,<header>放发件人和时间,<main>放正文摘要,<footer>放操作按钮——这些不是“多此一举”,而是让document.querySelector('article:nth-child(3) header time')能稳定取到第三封邮件的发送时间。常见错误是全用<div class="item">,结果后期加无障碍支持时要重写整个DOM树。
表格布局还是Flex/Grid?看筛选和排序需求
如果你的收件箱要支持列宽拖拽、表头冻结、横向滚动(比如显示12个自定义字段),<table>仍是唯一可靠选择:它的colgroup能精确控制列宽,sticky表头在Safari上比CSS Grid更稳。但若只需基础排序+响应式折叠(如手机端把“发件人/时间/主题”压成单行卡片),用display: grid配grid-template-areas更轻量。注意:别在<table>里塞<div>做复杂交互,会破坏aria-rowindex语义;也别用Grid模拟表格语义,屏幕阅读器不会把它当表格读。
未读标记和批量操作状态必须同步更新DOM,不能只改CSS
点击“全部标记为已读”后,如果只执行document.querySelectorAll('.unread').forEach(el => el.classList.remove('unread')),但没同步清除aria-label="未读邮件"或data-unread="true",键盘用户按Tab键时仍会听到“未读邮件”,自动化测试也会失败。实操建议:
• 所有状态变更必须同时更新class、attribute、aria属性
• 用dataset管理业务状态(如el.dataset.read = 'true')
• 批量操作后调用el.setAttribute('aria-checked', 'false')重置复选框可访问性状态
• 避免用visibility: hidden隐藏未读角标——它仍占空间且会被读屏软件朗读
分页加载和虚拟滚动别混用,选一个到底
10万封邮件不能一次性渲染,但简单分页(每页50条)会让用户反复点“下一页”。虚拟滚动看似先进,但在后台系统中容易踩坑:滚动时动态替换DOM节点,会导致焦点丢失、键盘导航中断、已展开的邮件详情突然收起。真实项目中更推荐“分页+缓存”组合:
• 首次加载只取第1页数据+总条数
• 点击页码时从内存缓存取数据(避免重复请求)
• 滚动到底部触发loadMore()时,追加渲染新DOM而非替换旧DOM
• 给每个<article>加唯一id="mail-12345",方便后续通过ID精准操作
立即学习“前端免费学习笔记(深入)”;
收件箱最易被忽略的是键盘操作链路:Enter键展开邮件、Space切换复选框、Ctrl+A全选、方向键移动焦点——这些不是锦上添花,而是后台系统的基本准入门槛。一旦DOM结构或事件绑定没对齐标准,整套交互就垮了。
后台收件箱不是普通列表页,它需要被屏幕阅读器识别、被搜索爬虫理解、被未来维护者快速定位逻辑。用<article>包裹每封邮件,<header>放发件人和时间,<main>放正文摘要,<footer>放操作按钮——这些不是“多此一举”,而是让document.querySelector('article:nth-child(3) header time')能稳定取到第三封邮件的发送时间。常见错误是全用<div class="item">,结果后期加无障碍支持时要重写整个DOM树。
表格布局还是Flex/Grid?看筛选和排序需求
如果你的收件箱要支持列宽拖拽、表头冻结、横向滚动(比如显示12个自定义字段),<table>仍是唯一可靠选择:它的colgroup能精确控制列宽,sticky表头在Safari上比CSS Grid更稳。但若只需基础排序+响应式折叠(如手机端把“发件人/时间/主题”压成单行卡片),用display: grid配grid-template-areas更轻量。注意:别在<table>里塞<div>做复杂交互,会破坏aria-rowindex语义;也别用Grid模拟表格语义,屏幕阅读器不会把它当表格读。
未读标记和批量操作状态必须同步更新DOM,不能只改CSS
点击“全部标记为已读”后,如果只执行document.querySelectorAll('.unread').forEach(el => el.classList.remove('unread')),但没同步清除aria-label="未读邮件"或data-unread="true",键盘用户按Tab键时仍会听到“未读邮件”,自动化测试也会失败。实操建议:
• 所有状态变更必须同时更新class、attribute、aria属性
• 用dataset管理业务状态(如el.dataset.read = 'true')
• 批量操作后调用el.setAttribute('aria-checked', 'false')重置复选框可访问性状态
• 避免用visibility: hidden隐藏未读角标——它仍占空间且会被读屏软件朗读
分页加载和虚拟滚动别混用,选一个到底
10万封邮件不能一次性渲染,但简单分页(每页50条)会让用户反复点“下一页”。虚拟滚动看似先进,但在后台系统中容易踩坑:滚动时动态替换DOM节点,会导致焦点丢失、键盘导航中断、已展开的邮件详情突然收起。真实项目中更推荐“分页+缓存”组合:
• 首次加载只取第1页数据+总条数
• 点击页码时从内存缓存取数据(避免重复请求)
• 滚动到底部触发loadMore()时,追加渲染新DOM而非替换旧DOM
• 给每个<article>加唯一id="mail-12345",方便后续通过ID精准操作
立即学习“前端免费学习笔记(深入)”;
收件箱最易被忽略的是键盘操作链路:Enter键展开邮件、Space切换复选框、Ctrl+A全选、方向键移动焦点——这些不是锦上添花,而是后台系统的基本准入门槛。一旦DOM结构或事件绑定没对齐标准,整套交互就垮了。



















