Skip to content

Instantly share code, notes, and snippets.

@ithinkandicode
Last active May 5, 2022 20:48
Show Gist options
  • Save ithinkandicode/1061ba9574c014a8ed4164eb7bbb3a90 to your computer and use it in GitHub Desktop.
Save ithinkandicode/1061ba9574c014a8ed4164eb7bbb3a90 to your computer and use it in GitHub Desktop.
Responsive BG
/**
* Responsive Background Image (ES5)
*
* Uses an invisible <picture> element with srcset to change the parent
* container's background image
*
* https://gist.github.com/ithinkandicode/1061ba9574c014a8ed4164eb7bbb3a90
*
* @version ES5-1.0.1
*/
/*
Example:
<div style="background-image: url('mobile-size.jpg')" data-responsive-bg>
<div class="visibility-hidden">
<picture>
<source media="(min-width: 1280px)" srcset="xl-size.jpg">
<source media="(min-width: 992px) and (max-width: 1199px)" srcset="lg-size.jpg">
<source media="(min-width: 768px) and (max-width: 991px)" srcset="md-size.jpg">
<source media="(min-width: 576px) and (max-width: 767px)" srcset="sm-size.jpg">
<img src="mobile-size.jpg" alt="">
</picture>
</div>
</div>
*/
// IIFE
(function()
{
// ES5 pesudo-class
var RSPBG = {
init: function()
{
var self = this;
var $rspBgs = $( '[data-responsive-bg]' );
$rspBgs.each( function( i, element )
{
var $el = $( element );
try
{
var img = $el.find( 'img' )[0];
// Store current src in element's data
// Updated in main()
$el.data( 'bgsrc', '' );
// Ensure all is valid
self.validateElements( img, $el );
// If validation passed, proceed
self.main( img, $el );
}
catch( err )
{
console.error( '[ResponsiveBG] ' + err.message, $el );
return;
}
});
},
main: function( img, $el )
{
// Triggered when the browser loads in a new source image
$( img ).on( 'load', () => this.updateBg( img, $el ) );
// If image was already loaded, update BG immediately
if( img.complete )
{
this.updateBg( img, $el );
}
},
updateBg: function( img, $el )
{
// Get current src
var currentSrc = ( typeof img.currentSrc !== 'undefined' ) ? img.currentSrc : img.src;
if ( $el.data( 'bgsrc' ) !== currentSrc )
{
// Image src has changed since we last checked, so update the BG img
$el.data( 'bgsrc', currentSrc );
$el.css( 'background-image', 'url("' + currentSrc + '")' );
}
},
/**
* Check container's elements to ensure they're valid
*
* Throws errors if validaiton fails. Errors must be caught in calling function
*/
validateElements: function( img, $el )
{
if ( !img )
{
throw new Error( 'Responsive BG container must contain an <img> element' );
}
if ( img.src === '' )
{
throw new Error( 'Responsive BG container contains an image with an empty src attribute' );
}
const isPicture = ( $el[0].tagName === 'PICTURE' );
const hasPicture = ( $el.find( 'picture' ).length );
const hasSource = ( $el.find( 'source' ).length );
if ( !(isPicture || hasPicture) )
{
throw new Error( 'Responsive BG container must contain a <picture> element' );
}
if ( !hasSource )
{
throw new Error( 'Responsive BG container must contain a <source> element' );
}
}
};
// Auto-init
$( document ).ready(function()
{
RSPBG.init();
});
})();
/**
* Responsive Background Image
*
* Uses an invisible <picture> element with srcset to change the parent
* container's background image
*
* https://gist.github.com/ithinkandicode/1061ba9574c014a8ed4164eb7bbb3a90
* @version ES6-1.0.0
*/
/*
Example:
<div style="background-image: url('mobile-size.jpg')" data-responsive-bg>
<div class="visibility-hidden">
<picture>
<source media="(min-width: 1280px)" srcset="xl-size.jpg">
<source media="(min-width: 992px) and (max-width: 1199px)" srcset="lg-size.jpg">
<source media="(min-width: 768px) and (max-width: 991px)" srcset="md-size.jpg">
<source media="(min-width: 576px) and (max-width: 767px)" srcset="sm-size.jpg">
<img src="mobile-size.jpg" alt="">
</picture>
</div>
</div>
*/
/**
* Component Init: Responsive Background Image
*
* @return {void}
*/
function init()
{
const $rspBgs = $( '[data-responsive-bg]' );
$rspBgs.each( ( i, element ) =>
{
const $el = $( element );
try
{
const img = $el.find( 'img' )[0];
// Store current src in element's data
// Updated in main()
$el.data( 'bgsrc', '' );
validateElements( img, $el );
// If validation passed, proceed
main( img, $el );
}
catch( err )
{
console.error( `[ResponsiveBG] ${err.message}`, $el );
return;
}
});
}
function main( img, $el )
{
// Triggered when the browser loads in a new source image
$( img ).on( 'load', () => updateBg( img, $el ) );
// If image was already loaded, update BG immediately
if( img.complete )
{
updateBg( img, $el );
}
}
function updateBg( img, $el )
{
// Get current src
let currentSrc = ( typeof img.currentSrc !== 'undefined' ) ? img.currentSrc : img.src;
if ( $el.data( 'bgsrc' ) !== currentSrc )
{
// Image src has changed since we last checked, so update the BG img
$el.data( 'bgsrc', currentSrc );
$el.css( 'background-image', `url("${currentSrc}")` );
}
}
/**
* Check container's elements to ensure they're valid
*
* Throws errors if validaiton fails. Errors must be caught in calling function
*/
function validateElements( img, $el )
{
if ( !img )
{
throw new Error( 'Responsive BG container must contain an <img> element' );
}
if ( img.src === '' )
{
throw new Error( 'Responsive BG container contains an image with an empty src attribute' );
}
const isPicture = ( $el[0].tagName === 'PICTURE' );
const hasPicture = ( $el.find( 'picture' ).length );
const hasSource = ( $el.find( 'source' ).length );
if ( !(isPicture || hasPicture) )
{
throw new Error( 'Responsive BG container must contain a <picture> element' );
}
if ( !hasSource )
{
throw new Error( 'Responsive BG container must contain a <source> element' );
}
}
export const ResponsiveBG = { init };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment