I wrote a code snippet that allows you to use the bricks custom attributes in the editor to set background images. It works on the principles of the previous solution by @UbuntuProductions but aims to be more dynamic in how it treats the breakpoints.
All you need to do is add the dynamic video breakpoint as an attribute using the data-video-src-{breakpoint} on the section containing a background video:

If all goes well the video should update based on the screen resize.
Here is the code snippet:
const VERBOSE = false; // Debugging
const videoWrappers = document.getElementsByClassName('has-bg-video');
const activeVideos = new Map();
function setBreakpoints() {
Array.from(videoWrappers).forEach((wrapper, index) => {
const attributes = wrapper.dataset;
const videoSources = Object.keys(attributes).filter(key => key.includes("videoSrc-"));
const breakpoints = new Map();
videoSources.forEach(key => {
const breakpoint = parseInt(key.slice(key.lastIndexOf('-') + 1));
const src = attributes[key];
breakpoints.set(breakpoint, src);
const video = wrapper.querySelector('video');
if (!video) return;
video.setAttribute('data-video-id', index);
});
activeVideos.set(index, breakpoints);
});
}
function switchVideoSource() {
const screenWidth = window.innerWidth;
const videos = document.querySelectorAll('[data-video-id]');
videos.forEach((video) => {
try {
const videoId = parseInt(video.getAttribute('data-video-id'));
const breakpoints = activeVideos.get(videoId);
if (!breakpoints) return;
let activeBreakpoint;
let activeSource;
let smallestDifference;
for (const [breakpoint, source] of breakpoints) {
let difference = breakpoint - screenWidth;
if (VERBOSE){
console.log('bp:', breakpoint, 'sw:', screenWidth, 'diff:', difference, 'sd:', smallestDifference)
}
// Set smallest if not exist
if ( difference >= 0 && (!smallestDifference || difference < smallestDifference)) smallestDifference = difference;
if (screenWidth < breakpoint && difference === smallestDifference) {
activeBreakpoint = breakpoint;
activeSource = source;
} else if (screenWidth > breakpoint && !smallestDifference){
activeBreakpoint = breakpoint;
activeSource = source;
}
}
// Update video source if it's different
if (video.src !== activeSource && activeSource !== '') {
// const wasPlaying = !video.paused;
video.src = activeSource;
video.load();
video.setAttribute('data-active-breakpoint', activeBreakpoint.toString());
// if (wasPlaying) {
// video.play().catch(e => console.error('Error playing video:', e));
// }
if (VERBOSE) {
console.log(`Updated video ${videoId} to breakpoint ${activeBreakpoint} with source ${activeSource}`);
}
}
} catch (error) {
console.error('Error switching video source:', error);
}
});
}
// Cleanup function
function cleanup() {
activeVideos.clear();
// Remove event listeners
window.removeEventListener('resize', handleResize);
window.removeEventListener('unload', cleanup);
}
// Use requestAnimationFrame for smoother resize handling
let resizeTimer;
function handleResize() {
cancelAnimationFrame(resizeTimer);
resizeTimer = requestAnimationFrame(() => {
switchVideoSource();
});
}
// Initial call
window.addEventListener('load', function() {
setBreakpoints();
switchVideoSource();
window.addEventListener('resize', handleResize);
window.addEventListener('unload', cleanup);
});
PS: This was a proof of concept and I am sure it could be optimized
I would love to see this kind of implementation to the native breakpoints in bricks as the functionality is not too difficult really.