modernizr脚本必须同步加载且早于其他js执行,否则modernizr.canvas等属性未定义会报错;它同步探测并挂载结果到全局modernizr对象和类名,不响应运行时变化。

Modernizr 脚本必须同步加载且早于其他 JS 执行
Modernizr 不是 Promise,也不等回调;它靠同步执行探测逻辑,把结果挂到全局 Modernizr 对象上。如果放在 jQuery 或业务脚本后面,Modernizr.canvas 可能还没定义就报 ReferenceError。
正确做法:
- 把 <script></script> 放在 底部,紧挨着
- 或者放在 开头,紧贴 标签
- 禁用 defer 和 async 属性——它们会破坏执行顺序
- CDN 推荐用 https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js(v3+ 版本类名有变化,如 cssgrid 不再叫 cssgrids)
检测结果只能靠 html 类名或 Modernizr 对象属性读取,不能动态响应
Modernizr 在页面初始化时一次性写入 ,之后不再更新。它不监听 Cookie 禁用、触摸模式切换等运行时变化。
常见误用:
- 写 if (Modernizr.cookies) { initStorage() } —— 用户禁用 Cookie 后仍为 true,但实际调用会抛 SecurityError
- 用 Modernizr.serviceworker === true 就直接调用 navigator.serviceWorker.register() —— 构造函数存在 ≠ ready,仍需处理 .catch()
- 依赖 Modernizr.geolocation 判断权限状态 —— 它只表示 API 存在,getCurrentPosition() 仍可能进 error 回调
CSS 降级必须同时覆盖 .feature 和 .no-feature 两种情况
Modernizr 往 上加的类就是 flexbox 或 no-flexbox,不带前缀、不套壳。很多人只写 .flexbox .card,漏掉兜底规则,导致旧浏览器样式崩坏。
正确写法示例:
- .border-radius .card { border-radius: 8px; }
- .no-border-radius .card { border: 1px solid #ccc; }
- 别写 .modernizr-flexbox 或 .has-flexbox
- .no-js 是 JS 未加载时的临时类,可用于纯 CSS fallback,比如 .no-js .hero { opacity: 1; }
JS 中直接读布尔值没问题,但关键 API 必须二次验证
Modernizr.webp、Modernizr.video 这些属性加载完立即可用,但它们只是静态快照,不代表运行时一定能用。
安全做法:
- localStorage:包在 try/catch 里,捕获 SecurityError(隐私模式下 Safari/Chrome 常见)
- webp:用 new Image() + onload/onerror 动态验证,因为某些老安卓 WebView 会误报 true
- video:Modernizr.video 为 true 后,还得调 video.canPlayType('video/mp4'),返回值是 'probably'、'maybe' 或空字符串,不是布尔值
- canIUse 查兼容性细节比布尔值更可靠,比如 csscalc 在旧版 Safari 里部分支持,但 Modernizr.csscalc 会返回 true
真正麻烦的不是检测本身,而是那些“检测通过却用不了”的边界情况——比如用户刚点了拒绝定位,或者开了飞行模式,又或者在微信内置浏览器里触发了奇怪的缓存策略。这些地方 Modernizr 无能为力,得靠你手动补验证逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











