Last active
January 10, 2017 10:30
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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