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

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



















