viewport meta 标签必须置于 <head> 中且含 width=device-width, initial-scale=1,否则浏览器按 980px 渲染,@media 不触发;class 是最可靠的响应式状态载体;hidden 属性语义清晰但需兼容性 fallback;data-* 属性非响应式,不能直接驱动更新。

viewport meta 标签必须写对位置和参数
没加 <meta name="viewport" content="width=device-width, initial-scale=1">,其他所有响应式手段都白搭——浏览器默认按 980px 渲染,@media 规则根本不会触发。
它必须放在 <head> 里,不能塞进 <body> 或注释后;width=device-width 是硬性要求,写成 width=375 或漏掉都会失效。别加 user-scalable=no,这会锁死双击放大,iOS Safari 某些版本下还会让 maximum-scale 失效。
- 常见错误现象:页面在手机上显示极小、需手动缩放才能阅读
- 调试器里拖动宽度,样式完全不响应
- 桌面端正常,移动端所有
@media都没触发
class 属性是响应式状态切换最可靠的载体
用 element.classList.toggle('mobile-nav-open') 控制菜单显隐,比直接操作 className 或内联 style.display 更安全、可预测。框架(如 Alpine.js、htmx)也普遍监听 class 变更来驱动 UI 状态。
-
class变更会同步触发重绘和可访问性树更新,浏览器原生支持 - 避免用
data-*存布尔状态(如data-mobile-menu="open"),因为dataset.mobileMenu永远是字符串,且不响应后续变更 - 不要靠反复
display: none/block切换元素来“模拟换内容”,破坏语义与 SEO
hidden 属性适合轻量级条件渲染,但要注意兼容性
hidden 是布尔属性,存在即隐藏,删掉就显示,语义清晰、开销低。但它不是 CSS 的 display: none 替代品——它仍占用 DOM 流,只是不可见、不可聚焦、不被屏幕阅读器读出。
立即学习“前端免费学习笔记(深入)”;
- 旧版 Safari/IE 不完全支持,需 fallback:
el.hidden ? el.style.display = 'none' : el.style.display = '' - 别把它和
aria-hidden混用,二者语义不同:hidden是全局隐藏,aria-hidden="true"仅影响辅助技术 - 在 SSR 场景下,服务端渲染的
hidden属性会被客户端 JS 覆盖,但框架若未监听该属性变化,会导致首屏与 JS 状态不一致
data-* 属性不能直接当响应式状态源用
data-* 属性值全是字符串,且 dataset 只读取初始值。比如 data-breakpoint="sm" 在 JS 中始终是字符串 "sm",改了 el.setAttribute('data-breakpoint', 'lg'),组件也不会自动重渲染。
- 常见翻车点:把
data-config='{"theme":"dark"}'当 JSON 解析,没加try/catch,JSON.parse()报错中断初始化 - React/Vue 组件 mount 后改
el.setAttribute('data-id', '500'),但组件没重渲染 - 真正需要响应式数据桥接时,得配合
customElements+attributeChangedCallback,且必须在static get observedAttributes()显式声明(不含data-前缀)
复杂点在于:全局属性里能真正驱动 DOM 更新并被框架感知的其实很少——id、class、hidden、contenteditable、tabindex 才算“真响应”,其余多数只存信息、不触发行为。别高估 title 或 lang 的渲染影响力,它们只影响提示和辅助技术。



















