移动端垂直卡片轮播视频自动播放与内联播放问题排查及解决方案咨询
移动端垂直卡片轮播视频自动播放与内联播放问题排查及解决方案咨询
我正在开发一个带视频背景的垂直卡片轮播组件,桌面浏览器上一切正常——视频能自动内联播放,但到了移动浏览器上,视频自动播放的可靠性就很差,总是达不到预期效果。
我已经尝试了这些优化手段:
- HTML标签配置:给每个
<video>都加上了muted、playsinline以及preload="auto"属性 - JavaScript强制静音:通过代码主动设置
video.muted = true确保视频处于静音状态 - 主动触发播放:在页面加载完成后或者用户产生交互时调用
video.play()方法
但不管怎么调,手机上的视频还是得等用户手动交互才会显示出来。
我现在的核心需求有这几个:
- 自动播放:确保视频在小屏移动设备上也能无缝自动播放
- 内联播放:避免视频在移动端自动全屏打开
- 非活跃卡片处理:让非当前活跃的卡片在视频暂停时,显示视频的第一帧作为静态封面
我的实现代码
HTML 结构
<div class="carousel"> <div class="cards"> <a href="https://ozeta.loddo.no/om-oss/" class="card"> <div class="c-cards__media"> <video muted="true" loop playsinline preload="auto"> <source src="https://ozeta.loddo.no/wp-content/uploads/2024/12/about.mp4" type="video/mp4"> </video> <div class="c-cards__media-overlay"></div> </div> <div class="c-cards__content"> <h2>Om oss</h2> <h3>About Us</h3> <h4>Learn More</h4> </div> </a> <a href="https://ozeta.loddo.no/kultur/" class="card"> <div class="c-cards__media"> <video muted="true" loop playsinline preload="auto"> <source src="https://ozeta.loddo.no/wp-content/uploads/2024/12/culture.mp4" type="video/mp4"> </video> <div class="c-cards__media-overlay"></div> </div> <div class="c-cards__content"> <h2>Kultur</h2> <h3>Culture</h3> <h4>Explore More</h4> </div> </a> <a href="https://ozeta.loddo.no/prototype/" class="card"> <div class="c-cards__media"> <video muted="true" loop playsinline preload="auto"> <source src="https://ozeta.loddo.no/wp-content/uploads/2024/12/prototyping.mp4" type="video/mp4"> </video> <div class="c-cards__media-overlay"></div> </div> <div class="c-cards__content"> <h2>Prototyping</h2> <h3>Prototype</h3> <h4>Discover</h4> </div> </a> <a href="https://ozeta.loddo.no/produksjon/" class="card"> <div class="c-cards__media"> <video muted="true" loop playsinline preload="auto"> <source src="https://ozeta.loddo.no/wp-content/uploads/2024/12/production-1.mp4" type="video/mp4"> </video> <div class="c-cards__media-overlay"></div> </div> <div class="c-cards__content"> <h2>Produksjon</h2> <h3>Production</h3> <h4>Details</h4> </div> </a> <a href="https://ozeta.loddo.no/baerekraft/" class="card"> <div class="c-cards__media"> <video muted="true" loop playsinline preload="auto"> <source src="https://ozeta.loddo.no/wp-content/uploads/2024/12/production-1.mp4" type="video/mp4"> </video> <div class="c-cards__media-overlay"></div> </div> <div class="c-cards__content"> <h2>Bærekraft</h2> <h3>Bærekraft</h3> <h4>Details</h4> </div> </a> </div> </div>
CSS 样式
body { margin: 0; padding: 0; height: 100vh; overflow: hidden; font-family: "Neue Montreal", sans-serif; background: #f0f0f0; transition: background 0.5s ease; } .carousel { position: relative; perspective: 1000px; height: 100vh; display: flex; align-items: flex-end; justify-content: center; overflow: hidden; } .cards { position: relative; height: 70%; width: 70%; display: flex; flex-direction: column; align-items: center; justify-content: center; } .card { position: absolute; height: 100%; width: 100%; border-radius: 30px 30px 0 0; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); transform-origin: center; transition: transform 0.5s ease; display: flex; overflow: hidden; } .card .c-cards__media { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; overflow: hidden; background-size: cover; background-position: center; } .card .c-cards__media video { width: 100%; height: 100%; object-fit: cover; pointer-events: none; } .card .c-cards__media-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; } .card a { text-decoration: none; color: inherit; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; position: relative; z-index: 3; padding-bottom: 40px; } .card h2, .card h3, .card h4 { color: white; text-transform: uppercase; margin: 10px 0; text-align: center; } .card h2 { font-size: 18px; } .card h3 { font-size: 120px; } .card h4 { font-size: 18px; } .card { transform: translateY(50px) scale(0.8); } .card.active { transform: translateY(0) scale(1); z-index: 5; } .card.behind { transform: translateY(-80px) scale(0.9); z-index: 4; } .card.behind-2 { transform: translateY(-150px) scale(0.8); z-index: 3; } .card.behind-3 { transform: translateY(-215px) scale(0.7); z-index: 2; } .card.behind-4 { transform: translateY(-275px) scale(0.6); z-index: 1; } .card.ahead { transform: translateY(300px) scale(0.9); z-index: 0; }
JavaScript 逻辑
const cards = document.querySelectorAll('.card'); const body = document.body; const elementsToChange = document.querySelectorAll('.elementor-button, .elementor-widget-container a img'); let currentIndex = 0; let isScrolling = false; let touchStartY = 0; let touchEndY = 0; const bodyColors = ['#191d1c', '#534d3f', '#959185', '#bdb8b4', '#bec5bd']; // Funksjon for å oppdatere styling på spesifikke elementer function updateElementStyles() { const activeCard = cards[currentIndex]; const cardTitle = activeCard.querySelector('h2').textContent.trim(); const highlightCards = ['Om oss', 'Kultur']; // Kortene som skal trigge effekten if (highlightCards.includes(cardTitle)) { // Endre utseendet for de valgte elementene elementsToChange.forEach((el) => { if (el.tagName === 'IMG') { el.style.filter = 'invert(1)'; // Øk lysstyrken for bilder } else { el.style.color = '#ffffff'; // Sett tekstfarge til hvit el.style.transition = 'color 0.5s ease, filter 0.5s ease'; // Glatt overgang } }); } else { // Tilbakestill til standard utseende elementsToChange.forEach((el) => { if (el.tagName === 'IMG') { el.style.filter = 'invert(0)'; // Tilbakestill lysstyrken } else { el.style.color = ''; // Tilbakestill tekstfarge } }); } } function updateCards() { cards.forEach((card, index) => { const relativeIndex = (index - currentIndex + cards.length) % cards.length; const video = card.querySelector('video'); if (relativeIndex === 0) { card.className = 'card active'; video.play(); body.style.backgroundColor = bodyColors[index]; } else { card.className = relativeIndex === 1 ? 'card behind' : relativeIndex === 2 ? 'card behind-2' : relativeIndex === 3 ? 'card behind-3' : relativeIndex === 4 ? 'card behind-4' : 'card ahead'; video.pause(); } }); updateElementStyles(); // Oppdater styling på de valgte elementene } function handleScroll(direction) { if (isScrolling) return; isScrolling = true; if (direction === 'down') { currentIndex = (currentIndex + 1) % cards.length; } else if (direction === 'up') { currentIndex = (currentIndex - 1 + cards.length) % cards.length; } updateCards(); setTimeout(() => (isScrolling = false), 600); // Prevent rapid scroll/swipe } window.addEventListener('wheel', (e) => { handleScroll(e.deltaY > 0 ? 'down' : 'up'); }); // Touch events for mobile window.addEventListener('touchstart', (e) => { touchStartY = e.touches[0].clientY; }); window.addEventListener('touchend', (e) => { touchEndY = e.changedTouches[0].clientY; if (touchStartY > touchEndY + 50) { handleScroll('down'); // Swipe up } else if (touchStartY < touchEndY - 50) { handleScroll('up'); // Swipe down } }); updateCards();
备注:内容来源于stack exchange,提问作者Jurgen




