自定义标签在dom中被当作无语义的htmlelement处理,node.role为空字符串、display默认为inline,不触发sectioning root或heading层级重置,需显式添加aria属性才能保障语义和无障碍支持。

自定义标签在DOM中实际被当作什么处理
浏览器不会把 <my-header></my-header> 或 <custom-section></custom-section> 当作有语义的元素,而是统一降级为无角色、无结构意义的 HTMLElement。它既不是 <header></header>,也不等价于 <div> 的语义替代——虽然视觉渲染上可能一样,但 DOM 节点的 <code>node.role 为空字符串,getComputedStyle(node).display 默认是 inline,不是 block。
常见错误现象:写了 <app-card><h2>标题</h2></app-card>,结果屏幕阅读器跳过整个区块,或把 <h2></h2> 当作页面全局二级标题(而非卡片内标题);搜索引擎也不会给这个“卡片”额外结构权重。
- DOM 类型确实是
HTMLElement,但不触发任何 landmark、sectioning root 或 heading 级别重置逻辑 - 无法通过
document.querySelector('my-header')获取语义匹配结果(只靠标签名匹配,不走语义索引) - 无障碍树中该节点没有
role、没有name、没有properties,多数读屏软件直接读作 “group” 或完全忽略
为什么 <custom-section></custom-section> 不能替代 <section></section> 做语义划分
<section></section> 的 sectioning root 行为是浏览器硬编码实现的:它会重置 <h1></h1> 到 <h6></h6> 的隐式层级计数,并影响 :scope > h2 这类节内选择器的匹配范围。而 <custom-section></custom-section> 即使加了 role="region" 和 aria-labelledby,也做不到这点。
使用场景受限明显:比如你在组件里用 <custom-article><h1>子标题</h1></custom-article>,这个 <h1></h1> 依然会被解析为整页最高级标题,破坏 heading 流程——这是真正容易被忽略的细节。
-
<section></section>触发 sectioning root,<custom-section></custom-section>不触发,哪怕加了 ARIA 属性 -
<h1></h1>在自定义标签内仍沿用父级上下文,不会形成新节的标题起点 - 搜索引擎和爬虫只识别白名单标签(如
<article></article>、<section></section>),自定义标签内容会被提取,但无结构权重
想用自定义标签又保语义?必须手动补全 ARIA
坚持用 Web Components 或框架封装时,语义不能靠浏览器“猜”,必须显式声明。只加 role 是不够的,辅助技术需要 name、label、focusable 状态等完整上下文才能理解。
参数差异很关键:比如 role="main" 必须确保全页面唯一,否则违反 WCAG;role="article" 要求内容独立可分发,不是所有“卡片”都满足;role="navigation" 必须内部含至少一个可聚焦链接,否则会被读屏软件忽略。
- 基础语义:至少设
role+aria-label或aria-labelledby - 导航区域:用
role="navigation",且确保内部有<a href></a>或<button></button> - 主内容区:用
role="main",同一文档只能有一个 - 避免滥用
role="article":它不是“视觉卡片”的代名词,而是指可独立发布、订阅、归档的内容单元
display 默认值和布局陷阱
自定义标签默认 display: inline,这点和 <span></span> 一致,但开发者常误以为它像 <div> 那样是块级容器。没显式设 <code>display: block 或 display: flex,会导致子元素换行失效、margin 不生效等布局异常。
性能影响不大,但兼容性隐患真实存在:旧版 Safari 对未知标签的 display 推断更保守,某些 CSS 选择器(如 section > *)根本匹配不到 <custom-section></custom-section> 内部元素。
- 必须显式设置
display才能正常布局,推荐用display: block或display: flow-root - CSS 中用属性选择器(如
[is="my-header"])比标签选择器更可靠 - 不要依赖
element.tagName.toLowerCase() === 'my-header'做语义判断,应查element.getAttribute('role')
<h1></h1> 在 <custom-article></custom-article> 内仍被解析为页面最高级标题,而非该组件内的顶级标题。











