旧系统升级后可访问性变差,根本原因在于语义结构被“表面升级”破坏:仅替换为却未清理嵌套、未补alt、未校验空,导致屏幕阅读器读取乱码;lighthouse报“document does not have a main landmark”常因被嵌套在/中、存在多个、为空或服务端条件渲染未输出;表单页问题源于仅换标签未重构label-input关系,如for/id缺失、label内混入、错误提示未用aria-describedby;php模板动态html需防退化,须校验空值、强制alt fallback、htmlspecialchars转义、非空判断标题等,修复必须始于dom结构可信度而非aria堆砌。

旧系统升级后可访问性反而变差,不是因为没加 aria-label,而是语义结构被“表面升级”破坏了——比如把 <div class="main"> 换成 <code><main></main>,但没清理嵌套在里面的 <table> 布局、没补 <code>alt、没校验空 <label></label>,结果屏幕阅读器读出来是一串无序 div+table+span 的乱码。
为什么加了,Lighthouse 还报“Document does not have a main landmark”
常见错误现象:DOM 里确实有 <main></main> 标签,但 Lighthouse 或 Chrome DevTools 的 Accessibility 面板仍提示缺失主地标。
-
<main></main>被包在<header></header>或<footer></footer>里(HTML5 规范禁止嵌套) - 页面存在多个
<main></main>(每个 HTML 文档只允许一个) -
<main></main>是空的,或仅含不可访问内容(如未设alt的图片、无文本的<div>) <li>服务端模板里用了条件渲染(如 PHP <code>if),导致某些路径下<main></main>根本没输出 - label 包裹 input,但内部混入
<span></span>或<br>,破坏可访问性树结构 - 错误提示用
<div class="error"> 浮在 input 下方,但没加 <code>aria-describedby - 禁用状态的 input 缺少
aria-disabled="true"(原生disabled属性会被读作“不可用”,但部分旧屏幕阅读器需显式声明) -
echo '<img src="'.%24row['avatar'].'">'——$row['avatar']为空时生成<img src="">,alt 缺失且触发无障碍警告 -
echo '<h2>'.$title.'</h2>'——$title为空时变成空<h2></h2>,破坏 heading outline - 未对用户输入做
htmlspecialchars(),导致引号、尖括号注入破坏标签结构(如title = 'User's "profile"'→<h2>User's "profile"</h2>)
实操建议:用浏览器开发者工具的 Elements 面板过滤 main,确认它是否直接子元素于 ;再用 document.querySelector('main') 在 Console 执行,看返回是否为 null 或 undefined;最后检查服务器端模板逻辑,确保所有分支都输出非空 <main></main>。
表单页升级后,屏幕阅读器跳过 input 或读错顺序
老 PHP/JSP 表单常靠 <table> 对齐、<code><font></font> 提示、<div> 包裹 label,升级时若只换标签不重构关系,ARIA 无法建立正确关联。
<ul>
<li>label 用 <code>for 属性但对应 input 的 id 缺失或重复
实操建议:优先采用 label 包裹 input 的写法(<label><input type="text">用户名</label>),避免 for/id 绑定出错;错误信息容器加上 id,并在 input 上设置 aria-describedby="error-id";禁用态统一用原生 disabled,不用仅靠 CSS class 模拟。
PHP 模板里动态生成的 HTML,怎么防可访问性退化
旧系统 PHP 模板常拼接字符串输出 HTML,升级时若只替换静态标签,却忽略变量插值处的空值、XSS 转义、缺失属性,可访问性会在运行时崩塌。
实操建议:所有动态插入点强制校验并 fallback,例如:<img src="<?=%20htmlspecialchars(%24row['avatar']%20?:%20'/placeholder.svg')%20?>" alt="<?= htmlspecialchars($row['name'] ?: '默认头像') ?>">;标题类输出加非空判断:<?php if (!empty($title)): ?><h2>= htmlspecialchars($title) ?></h2>
<?php endif; ?>;全局启用 ini_set('default_charset', 'UTF-8') 并统一用 htmlspecialchars($str, ENT_QUOTES, 'UTF-8')。
真正卡住可访问性升级的,从来不是“要不要加 aria”,而是老模板里那些没被显式声明、却实际承担语义角色的 <div> 和 <code><table> —— 它们一旦被机械替换,又没同步清理嵌套、补全属性、校验空值,就会在新环境中暴露为语义真空。修复必须从 DOM 结构可信度开始,而不是从 ARIA 属性堆砌开始。</table>











