Skip to content

Instantly share code, notes, and snippets.

@willbroderick
Last active January 10, 2017 10:30
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save willbroderick/7691851 to your computer and use it in GitHub Desktop.
Save willbroderick/7691851 to your computer and use it in GitHub Desktop.
Set an image or iframe to fill its parent (like a desktop wallpaper)
/* Take an image, or any other element with height/width attrs (e.g. iframe) and stretch it to fill parent
* MIT license
*
* Dependencies:
* imagesLoaded: https://github.com/desandro/imagesloaded
*
* Usage examples:
* $('.fillcontainer img.main').willFillParent({ closest: '.fillcontainer', windowEvent: 'debouncedresize load' });
* $('.video-bg > .video').willFillParent({ windowEvent: 'resize' });
*
* $('#page-bg > img').willFillParent({
* changeURL: anotherImage,
* loadingHTML: '<i class="fa fa-cog fa-spin"></i>'
* });
*
* Add this to your CSS, if you're using it to fill the background on a phone
* - uses device height to avoid viewport-resize jump on scroll
*
* @media screen and (max-width: 767px) {
* #page-bg {
* min-height: 2px;
* }
*/
(function($){
$.fn.willFillParent = function(params){
var opts = $.extend({
closest: false, // provide a selector for $(this).closest() to find the parent to fill
windowEvent: false, // specify a window event to re-asses the fill on, e.g. 'resize', 'smartresize', 'debouncedresize'
loadingHTML: '', // what to show while loading images
changeURL: false // if provided, will replace the image
}, params);
$(this).each(function(){
var $img = $(this);
//Switching to a new image
if(opts.changeURL !== false && opts.changeURL != $img.attr('src')) {
var $fillcont = $img.data('fillcont');
//Show loading
var $loading = $('<span class="loading"/>').html(opts.loadingHTML).appendTo($fillcont);
//Fade out old
$img.fadeOut(500, function(){
//Remove old
$(this).remove();
});
//Create new image
$img = $('<img/>').attr('src', opts.changeURL).appendTo($fillcont).data('fillcont', $fillcont);
}
if($img.data('willloaded')) {
//Already loaded - do resize
var $fillcont = $img.data('fillcont');
$fillcont.css({
position: $fillcont.css('position') == 'static' ? 'relative' : null,
overflow: 'hidden'
});
var pw = $fillcont.outerWidth();
//A little optional hack for using device height - avoids jumping full screen backgrounds when mobile devices show/hide their chrome
var ph = $fillcont.css('min-height') == '2px' ? screen.height : $fillcont.outerHeight();
var pr = pw / ph;
if(pr > $img.data('nr')) {
var newHeight = pw / $img.data('nr');
$img.css({
width: pw,
height: newHeight,
left: 0,
top: (ph-newHeight)/2
});
} else {
var newWidth = ph * $img.data('nr');
$img.css({
width: newWidth,
height: ph,
left: (pw-newWidth)/2,
top: 0
});
}
} else {
//First-run. Get dimensions & other init
if(typeof $img.data('fillcont') === 'undefined') {
if(opts.closest) {
$img.data('fillcont', $img.closest(opts.closest));
} else {
$img.data('fillcont', $img.parent());
}
}
//Grab natural height/width ratio and init with that
if($img.is('img')) {
$img.imagesLoaded(function(){
//requires an image to be naturally shaped - i.e. min one dimension 'auto'
$img.css({
position: 'absolute',
maxWidth: 'none',
maxHeight: 'none',
minWidth: 0,
minHeight: 0,
height: 'auto'
});
$img.data('nw', $img.width()).data('nh', $img.height())
.data('nr', $img.data('nw') / $img.data('nh'))
.data('willloaded', true).addClass('loaded').willFillParent(); // no need for params after initial setup
//handle a src change nicely
$img.on('load', function(){
$img.css({height:'',width:''}).data('nw', $img.width()).data('nh', $img.height())
.data('nr', $img.data('nw') / $img.data('nh')).willFillParent();
});
$img.data('fillcont').find('.loading').stop().fadeOut(250, function(){ $(this).remove(); });
});
} else {
//REQUIRES width and height attrs
var nw = $img.attr('width');
var nh = $img.attr('height');
$img.data('nw', nw).data('nh', nh).data('nr', nw / nh).data('doFitRatherThanFill', opts.doFitRatherThanFill)
.data('willloaded', true).willFillParent(); // no need for params after initial setup
}
}
});
//Hook up resize event
if(opts.windowEvent && opts.windowEvent != null) {
var $this = $(this);
//TODO: Remove old event, scoped to element
var eventName = opts.windowEvent + '.willFillParent';
$(window).on(eventName, function(){
$this.willFillParent(); // no need for params after initial setup
});
}
return $(this);
}
})(jQuery);
/*
Some sample (S)CSS:
#page-bg {
position: fixed;
left: 0;
width: 100%;
top: 0;
height: 100%;
z-index: 0;
img {
opacity: 0;
transition: opacity 500ms;
z-index: 1;
&.loaded {
opacity: 1;
}
}
.loading {
position: absolute;
top: 50%;
left: 50%;
margin: -13px 0 0 -13px;
z-index: 2;
font-size: 25px;
line-height: 1em;
opacity: 0.8;
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment