复用单个元素+data-src切换+preload="metadata"是最优方案;多个标签会导致预加载浪费、iOS静音失效及播放异常;正确做法是JS动态更新src并调用load()和play(),且play()必须在用户手势中触发。

单个 <video></video> 元素 + data-src 切换 + preload="metadata" 是最轻量、兼容性最好、且不触发 Safari 静音拦截的方案。别用多个 <video></video> 标签轮流显示,内存和加载开销都高,iOS 上尤其容易卡住或静音失效。
为什么不能每个视频都写一个
常见错误是把每个视频都套一层 <video controls><source src="xxx.mp4"></source></video>,再用 CSS 控制显隐。这会导致:
- 所有视频资源在页面加载时就触发
preload="auto"(即使没设),流量和内存双浪费 - iOS Safari 对隐藏
<video></video>的play()调用更敏感,常抛NotAllowedError - 多个
<video></video>共存时,浏览器可能只允许一个有声音播放,其余自动静音 - 缩略图 poster 加载逻辑混乱,无法统一控制加载时机
如何正确绑定点击切换逻辑
核心是复用同一个 <video></video> 元素,通过 JS 更新 src 并重置状态:
- 给列表项加
data-src、data-title等属性,不要把视频地址硬编码进 HTML 结构 - 点击时先调
videoEl.load(),再调videoEl.play()—— 缺少load()会导致部分浏览器(如 Firefox)不重载元数据,时长/封面错乱 - 必须在用户手势回调中调
play():比如click、touchstart,不能在canplay或loadeddata里直接调 - 首次播放建议加
muted autoplay属性占位,等用户点击后再videoEl.muted = false
CSS Grid 布局卡片时容易忽略的坑
用 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) 是对的,但以下三点不处理,卡片就会错位或文字溢出:
立即学习“前端免费学习笔记(深入)”;
- 必须全局加
* { box-sizing: border-box; },否则padding和border会让gap失效 - 标题截断要用
display: -webkit-box+-webkit-line-clamp: 2,只靠max-height+overflow: hidden会切字而非切行 -
<video></video>在 iOS Safari 上点击全屏时可能闪动,加video { -webkit-transform: translateZ(0); }可缓解
真正难的不是“怎么让视频播起来”,而是“怎么让第一次点击就成功播放且不静音”。Safari 的限制是硬性的,绕不过去,只能靠 muted → 用户交互 → unmute 这个链路。很多项目卡在这里,不是代码写错了,是没把 play() 放进真正的用户手势上下文里。



















