Autoplay videos on mobile (always)

Hello Community,

I have a few setions in my website that use videos in the background, usually the videos autoplay and they work correctly, altough sometimes the videos dont play and you need to manually click them to play them, is there a code for the base.css that ensures that the videos always autoplay?? in general for all the sections with videos to autoplay correctly.

thank you in advance! My store url is: sclpted.com

1 Like

Hi @sclpted!

I can see you’re having intermittent autoplay issues with background videos on your site. There are a few CSS and JavaScript solutions that can help ensure more reliable autoplay.

The Root Cause

Video autoplay failures usually happen due to:

  • Browser autoplay policies (especially on mobile)

  • Loading timing issues

  • User interaction requirements

  • Mobile data saving settings

CSS Solutions for base.css

Add this code to your base.css file to improve video autoplay reliability:

/* Enhanced video autoplay styles */
video[autoplay] {
  -webkit-playsinline: true;
  playsinline: true;
  muted: true;
  loop: true;
  preload: metadata;
}

/* Ensure videos start playing when visible */
.hero__video,
.background-video,
video[data-autoplay] {
  -webkit-playsinline: true;
  playsinline: true;
  muted: true;
  loop: true;
  autoplay: true;
  preload: metadata;
  pointer-events: none;
}

/* Fix for iOS Safari */
@supports (-webkit-appearance: none) {
  video[autoplay] {
    -webkit-playsinline: true;
    playsinline: true;
  }
}

/* Fallback for when autoplay fails */
video:not([autoplay]):hover {
  cursor: pointer;
}

JavaScript Enhancement (Optional)

If you want even more reliability, you can also add this JavaScript to your theme files:

// Force video autoplay when DOM loads
document.addEventListener('DOMContentLoaded', function() {
  const videos = document.querySelectorAll('video[autoplay]');
  
  videos.forEach(video => {
    // Ensure video properties are set
    video.muted = true;
    video.playsInline = true;
    video.loop = true;
    
    // Try to play the video
    const playPromise = video.play();
    
    if (playPromise !== undefined) {
      playPromise.catch(error => {
        console.log('Autoplay prevented:', error);
        // Fallback: play on user interaction
        document.addEventListener('click', function() {
          video.play();
        }, { once: true });
      });
    }
  });
});

// Intersection Observer for lazy-loaded videos
const videoObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const video = entry.target;
      video.play().catch(e => console.log('Video play failed:', e));
    }
  });
});

document.querySelectorAll('video[autoplay]').forEach(video => {
  videoObserver.observe(video);
});

just keep in mind:

  1. Mobile Limitations: Some mobile browsers will never autoplay videos until user interaction occurs - this is by design for data saving

  2. Muted Requirement: Videos must be muted to autoplay in most browsers

  3. Performance: Consider video file sizes and compression for better loading

The CSS solution should handle most cases, but the JavaScript provides additional fallbacks for edge cases.

Hope this helps! Let me know if you’re still seeing issues after implementing these changes.

Best regards,
Shubham | Untechnickle


P.S. - Your site looks great! The SCLPTED LIGHT product presentation is really well done.

Hi,

Hope this will help

  • CSS alone can’t autoplay a video. Use autoplay muted playsinline on tag + a small JavaScript fallback that ensures muted and calls .play() and retries on user interaction.
  • Host MP4s and use where possible — if you rely on YouTube/Vimeo embeds, autoplay is much less reliable.

Liquid / HTML (section file or snippet) Example

<div class="video-container">
  <video
    class="bg-video autoplay"
    autoplay
    muted
    loop
    playsinline
    webkit-playsinline
    preload="auto"
    poster="{{ section.settings.video_poster | img_url: '2048x' }}"
    aria-hidden="true"
    muted="muted"
  >
    <source src="{{ section.settings.video | file_url }}" type="video/mp4">
    <!-- optionally provide webm / ogg sources -->
  </video>
</div>

JavaScript (assets/theme.js or assets/global.js — include before ) Example

document.addEventListener('DOMContentLoaded', function () {
  var videos = document.querySelectorAll('video.autoplay, video.bg-video');

  videos.forEach(function (video) {
    // Make absolutely sure the element is muted & inline
    try {
      video.muted = true;
      video.playsInline = true;
      video.setAttribute('playsinline', '');
      video.setAttribute('webkit-playsinline', '');
      video.setAttribute('muted', '');
    } catch (e) {}

    // Try to play and handle promise rejection
    var playPromise = video.play();
    if (playPromise !== undefined) {
      playPromise.catch(function (err) {
        // If autoplay blocked, try again on next user gesture
        function resume() {
          video.play().catch(function(){});
          window.removeEventListener('click', resume);
          window.removeEventListener('touchstart', resume);
        }
        window.addEventListener('click', resume, { passive: true });
        window.addEventListener('touchstart', resume, { passive: true });
      });
    }

    // Optional: only play when visible (saves battery/data)
    var io = new IntersectionObserver(function(entries) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.play().catch(function(){});
        } else {
          entry.target.pause();
        }
      });
    }, { threshold: 0.1 });
    io.observe(video);
  });
});

CSS (assets/base.css or assets/theme.css) Example

.video-container {
  position: relative;
  overflow: hidden;
}

.bg-video {
  position: absolute;
  inset: 0;            /* top:0; right:0; bottom:0; left:0; */
  width: 100%;
  height: 100%;
  object-fit: cover;   /* crop to fill */
  object-position: center;
  pointer-events: none; /* so it doesn't block clicks */
  z-index: -1;         /* behind content; adjust as needed */
  display: block;
}