semantic-html by schalkneethling/webdev-agent-skills
npx skills add https://github.com/schalkneethling/webdev-agent-skills --skill semantic-html编写能够传达含义、服务所有用户并尊重 Web 平台的 HTML。
在以下情况下使用此技能:
设计稿中的内容是理想化的。真实的内容是杂乱的。始终要考虑:
构建能够优雅处理真实世界内容的组件,而不仅仅是设计工具中看起来好看的组件。
在深入处理单个组件之前,先考虑完整的页面结构。这使您能够:
遵循 ARIA 的第一条规则:如果原生 HTML 元素提供了您需要的语义和行为,请使用它,而不是向通用元素添加 ARIA。
危险信号: 在非复杂组件中,高 div 数量与高 ARIA 数量结合,表明是在寻求补丁而非打好基础。
视觉样式和语义含义相关但并非耦合。CSS 类可以弥合这一差距:
.u-Heading-XXL 这样的实用类,以实现一致的视觉处理,无论语义级别如何广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
使用地标元素来传达页面结构:
| 元素 | 使用时机 | 备注 |
|---|---|---|
header | 页面或区域页眉 | 可以在不同上下文中多次出现 |
footer | 页面或区域页脚 | 联系信息、版权、相关链接 |
nav | 导航区域 | 必须带有标签;避免在标签中使用"navigation"(屏幕阅读器会读出这个) |
main | 主要内容 | 每页仅一个 |
aside | 间接相关内容 | 侧边栏、引用块、广告 |
search | 搜索功能 | 包含搜索表单,而非结果 |
form | 用户输入 | 仅当通过 aria-labelledby 或 aria-label 标记时才成为地标 |
article | 自包含的内容 | 适合联合发布或独立存在的内容 |
section | 主题分组 | 仅当被标记时才成为地标 |
没有可访问名称的 section 在语义上表现得像一个 div。使用 section 时:
aria-labelledby 将其与标题关联section 是否是正确选择超越博客文章来思考。对于任何自包含、独立存在有意义的内容,都可以使用 article:
测试: 如果将此内容提取出来,在没有周围上下文的情况下放在其他地方,它是否仍然有意义?
经常被误解。来自 HTML 规范:
address 元素表示其最近的 article 或 body 元素祖先的联系信息。
用于作者或所有者的联系信息——不用于通用邮政地址。对于邮政地址,请使用标准的 <p> 或适合上下文的标记结构。
保持逻辑性的标题结构:
h1(通常是主标题)对于包含标题的可复用组件:
示例模式:
Card (通用) → 标题级别可配置,默认 h3
└─ ProductCard (特定) → 继承配置,可根据已知上下文设置默认值
└─ 在包含 h2 的区域中使用 → 标题级别设置为 h3
有时文本看起来像标题,但在语义上不应该是标题。使用 CSS 类来应用类似标题的样式,而不影响文档大纲:
<p class="u-Heading-L">这看起来像一个标题</p>
当了解项目数量对用户有帮助时,列表最有用:
需要问的问题:
| 类型 | 使用时机 | 示例 |
|---|---|---|
ul | 无序集合,且数量重要时 | 导航项、搜索结果 |
ol | 顺序步骤或排名项目时 | 食谱、说明、前十名列表 |
dl | 术语-描述对时 | 词汇表、元数据、键值对 |
menu | 工具栏命令时 | 操作按钮,而非导航 |
有序列表属性: 使用 reversed 用于倒计时式列表(例如,从 10 到 1 列出的前十名)。使用 start 从特定值开始编号。两者都是原生 HTML——无需 JavaScript。
经常被忽视或与 details/summary 混淆。使用 dl 用于:
注意:一个 dt 可以有多个 dd 元素,用于多个相关描述。
传统规则: 按钮执行操作,链接跳转页面。
渐进增强视角: 如果当 JavaScript 失败时,URL 能提供有意义的回退方案,那么即使是类似操作的交互,使用链接也是有效的。
| 交互 | 默认选择 | 考虑使用链接的情况 |
|---|---|---|
| 显示更多内容 | button | URL 参数可以服务器端加载内容 |
| 切换视图(网格/列表) | button | URL 可以保存视图偏好 |
| 复制到剪贴板 | button | 复制的内容是一个可分享的 URL |
| 选项卡选择 | button | URL 可以加载特定选项卡内容 |
关键问题: 当 JavaScript 失败时会发生什么?如果 URL 能提供优雅降级,那么链接可能是更好的选择。
用于渐进式披露:
不能替代正确的标题结构或定义列表。
使用 fieldset 和 legend 进行主题分组,而非布局:
好处:
图例可以在视觉上隐藏,同时仍提供可访问的名称。
始终使用 label 元素。 没有例外。
label 元素时,切勿使用 aria-label为什么占位符会失败:
当前最佳实践(由于 aria-errormessage 的浏览器支持存在差距):
在无效输入上设置 aria-invalid="true"
通过 aria-describedby 关联错误消息
确保错误消息是可操作的(说明问题并指导修复)
对于动态错误(在失去焦点时显示),考虑在错误容器上使用 aria-live
<label for="email">邮箱</label> <input type="email" id="email" aria-invalid="true" aria-describedby="email-error" />
<p id="email-error" class="error"> 请输入有效的邮箱地址,例如 name@example.com </p>当数据在两个维度上都有有意义的关系时使用表格:
dl)始终包含:
caption —— 描述表格的用途thead、tbody、tfoot —— 结构分组scope 的 th —— 标识表头单元格及其方向按偏好顺序:
注意:现代浏览器(包括 Safari)在应用 display: grid 或 display: flex 时不再剥离表格语义,这为响应式设计开辟了新的可能性。
审查标记时,寻找:
div 数量过多请参阅 references/ 目录以获取特定主题的详细指导:
element-decision-trees.md —— 用于元素选择的快速决策框架heading-patterns.md —— 组件标题模式和配置策略每周安装次数
111
仓库
GitHub 星标数
3
首次出现
2026年1月24日
安全审计
安装于
opencode100
gemini-cli97
codex94
github-copilot91
amp83
kimi-cli82
Write HTML that conveys meaning, serves all users, and respects the web platform.
Use this skill when:
Design content is idealized. Real content is messy. Always account for:
Build components that handle real-world content gracefully, not just what looks good in design tools.
Before diving into individual components, consider the full page structure. This allows you to:
Follow the first rule of ARIA: if a native HTML element provides the semantics and behaviour you need, use it instead of adding ARIA to a generic element.
Red flag: High div count combined with high ARIA count on non-complex components signals reaching for patches rather than foundations.
Visual styling and semantic meaning are related but not coupled. CSS classes bridge the gap:
.u-Heading-XXL for consistent visual treatment regardless of semantic levelUse landmark elements to convey page structure:
| Element | Use When | Notes |
|---|---|---|
header | Page or section header | Can appear multiple times in different contexts |
footer | Page or section footer | Contact info, copyright, related links |
nav | Navigation sections | Must be labelled; avoid "navigation" in the label (screen readers announce this) |
main | Primary content | Only one per page |
aside | Tangentially related content |
A section without an accessible name behaves like a div semantically. When using section:
aria-labelledbysection is the right choiceThink beyond blog posts. Use article for any self-contained content that would make sense on its own:
Test: Would this content make sense if extracted and placed elsewhere with no surrounding context?
Often misunderstood. From the HTML specification:
The address element represents the contact information for its nearest article or body element ancestor.
Use for contact information about the author or owner—not for generic postal addresses. For postal addresses, use a standard <p> or structured markup appropriate to the context.
Maintain a logical heading structure:
h1 per page (typically the main title)For reusable components containing headings:
Example pattern:
Card (generic) → heading level configurable, default h3
└─ ProductCard (specific) → inherits config, may set default based on known context
└─ Used in section with h2 → heading level set to h3
Sometimes text looks like a heading but shouldn't be one semantically. Use CSS classes to apply heading-like styling without affecting document outline:
<p class="u-Heading-L">This looks like a heading</p>
Lists are most useful when knowing the number of items helps the user :
Questions to ask:
| Type | Use When | Example |
|---|---|---|
ul | Unordered collection where count matters | Nav items, search results |
ol | Sequential steps or ranked items | Recipes, instructions, top-10 lists |
dl | Term-description pairs | Glossaries, metadata, key-value pairs |
menu | Toolbar commands | Action buttons, not navigation |
Ordered list attributes: Use reversed for countdown-style lists (e.g., a top 10 listed from 10 to 1). Use start to begin numbering from a specific value. Both are native HTML—no JavaScript required.
Often overlooked or confused with details/summary. Use dl for:
Note: A single dt can have multiple dd elements for multiple related descriptions.
Traditional rule: Buttons do things, links go places.
Progressive enhancement lens: If a URL provides a meaningful fallback when JavaScript fails, a link is valid even for action-like interactions.
| Interaction | Default Choice | Consider Link When |
|---|---|---|
| Show more content | button | URL params could load the content server-side |
| Toggle view (grid/list) | button | URL could preserve view preference |
| Copy to clipboard | button | Copied content is a shareable URL |
| Tab selection | button | URL could load specific tab content |
Key question: What happens when JavaScript fails? If a URL provides graceful degradation, a link may be the better choice.
Use for progressive disclosure:
Not a replacement for proper heading structure or definition lists.
Use fieldset and legend for thematic grouping , not layout:
Benefits:
Legends can be visually hidden while still providing accessible names.
Always use alabel element. No exceptions.
aria-label when a proper label element worksWhy placeholders fail:
Current best practice (due to browser support gaps with aria-errormessage):
aria-invalid="true" on the invalid inputaria-describedbyaria-live on the error container<label for="email">Email</label>
<input
type="email"
id="email"
aria-invalid="true"
aria-describedby="email-error"
/>
<p id="email-error" class="error">
Enter a valid email address, like name@example.com
</p>
Use a table when data has meaningful relationships in both dimensions :
dl)Always include:
caption — Describes the table's purposethead, tbody, tfoot — Structural groupingth with scope — Identifies header cells and their directionIn order of preference:
Note: Modern browsers (including Safari) no longer strip table semantics when applying display: grid or display: flex, opening new responsive possibilities.
When reviewing markup, look for:
See the references/ directory for detailed guidance on specific topics:
element-decision-trees.md — Quick decision frameworks for element selectionheading-patterns.md — Component heading patterns and configuration strategiesWeekly Installs
111
Repository
GitHub Stars
3
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode100
gemini-cli97
codex94
github-copilot91
amp83
kimi-cli82
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
116,600 周安装
| Sidebars, pull quotes, advertising |
search | Search functionality | Contains the search form, not the results |
form | User input | Only becomes a landmark when labelled via aria-labelledby or aria-label |
article | Self-contained content | Would make sense syndicated or standalone |
section | Thematic grouping | Only becomes a landmark when labelled |