playsinline 和 webkit-playsinline 必须同时作为无值布尔属性并列书写,缺一则在 iOS 12–14 失效;autoplay、muted、playsinline 三者须初始声明于 HTML 标签中,且 muted 必须为 HTML 属性而非 JS 设置。

playsinline 和 webkit-playsinline 必须同时写
只写 playsinline 在 iOS 10–14 设备上大概率失效,尤其企业内网或旧版微信 WebView。Safari 的 WebKit 内核在不同版本中对属性的识别策略不一致:iOS 15+ 基本认 playsinline,但 iOS 12–14 仍强依赖 webkit-playsinline。两者是并行关系,不是替代关系。
错误写法:<video playsinline> 或 <video webkit-playsinline="true">(带值会失效)
正确写法:<video playsinline webkit-playsinline> —— 两个布尔属性并列,不赋值、不省略
autoplay + muted + playsinline 缺一不可
iOS Safari 对自动播放的拦截是原子级判断:只要三者不全在 HTML 标签上初始声明,play() 调用就会被静默拒绝,控制台可能无报错,但 video.paused 保持 true,readyState 卡在 0 或 1。
立即学习“前端免费学习笔记(深入)”;
-
muted必须是 HTML 属性,JS 后设(如video.muted = true)无效 -
autoplay单独存在 → 视频加载但不播;muted单独存在 → 不阻止全屏;playsinline单独存在 → Safari 直接忽略 - 微信 iOS 客户端额外要求
x5-video-player-type="h5-page",漏掉就 fallback 到 X5 全屏播放器
Vue/React 动态渲染时属性容易丢失
框架模板里写 :playsinline="true" 或 v-bind:playsinline,若没显式映射到原生 DOM 属性,最终生成的 <video> 可能不带该属性。React 中 playsInline(驼峰)是合法 prop,但必须透传给底层 <video> 元素。
实操建议:
- Vue:用
v-bind="{ playsinline: true, 'webkit-playsinline': true }"或直接写死在标签上 - React:确保 JSX 中是
playsInline(注意大小写),且组件未封装掉原生属性 - 避免用 JS 动态插入
<video>后再 setAttribute —— iOS 会认为上下文不可信
用户手势触发播放时,muted = false 必须紧挨 play()
想从静音切到有声,不能等 play() resolve 后再设 muted = false,更不能放在 setTimeout 或异步回调里。iOS 17+ 会中断播放流,导致黑屏或卡帧。
✅ 正确写法(在 click/touchstart 回调中):
button.addEventListener('click', () => {
video.play().then(() => {
video.muted = false;
}).catch(e => console.error(e));
});
❌ 错误写法:video.muted = false 放在 oncanplay、onloadeddata 或 Promise 外部;或用 video.play().then(() => setTimeout(() => video.muted = false, 0))
最易被忽略的一点:即使视频已静音播放数秒,Safari 仍要求你先调一次 play()(哪怕它立刻 resolve),再改 muted,否则无效。这不是“优化”,而是 WebKit 的强制执行链路。



















