Skip to content

Instantly share code, notes, and snippets.

@josephbergdoll
Last active August 29, 2015 14:25
Show Gist options
  • Save josephbergdoll/bc31ca99ad63af5ac216 to your computer and use it in GitHub Desktop.
Save josephbergdoll/bc31ca99ad63af5ac216 to your computer and use it in GitHub Desktop.
course fixed
// Assumes all of your images are wrapped in a container with the class .js-image-container
// I use separate "js-" prepended classes so that way interactivity couplings are separate from
// visual style changes. => https://coderwall.com/p/qktuzw/decouple-javascript-classes-from-css-ones-by-using-prefix
//
// this is written with the notion that you are using markup as follows:
// <div class="img-container js-img-container">
// <img src="../path/to/image.jpeg" data-width="[width of jpeg without px]" data-height="[height of jpeg without px]">
// </div>
// somewhere in your CSS, you want the following:
// .img-container {
// height: 0;
// img {
// height: 0;
// max-width: 100%;
// display: block;
// margin: 0;
// opacity: 0;
// transition: opacity 400ms ease-out;
// }
// &.lazy-loaded {
// height: auto;
// img {
// opacity: 1;
// }
// }
// }
// Settings for fixed titles. desiredWidth should be the width you want fixedTitles to function at.
// scrollThreshold is how far from the top of the window should the title fix itself
// fixedContainerSelector should be added to the parent project for which the title is shown
// fixedTitleSelector should be added to the title element you wish to make fixed
var
desiredWidth = 768,
scrollThreshold = 40,
fixedContainerSelector = '.js-has-fixed-title',
fixedTitleSelector = '.js-fixed-title';
function setFixed() {
var
$fixedContainers = $('body').find(fixedContainerSelector),
fixedClass = 'fixed',
fixedSelector = '.'+fixedClass,
fixedStyles = {
'position': 'fixed',
'top': scrollThreshold
},
bottomStyles = {
position : 'absolute',
},
bottomClass = 'bottom',
bottomSelector = '.'+bottom;
$(window).scroll(function() {
var winWidth = $(window).width();
if (winWidth >= desiredWidth) {
var sT = $(window).scrollTop();
$fixedContainers.each(function() {
var
$this = $(this),
thisTop = $this.offset().top,
thisLeft = $this.offset().left,
thisHeight = $this.outerHeight(),
thisBottom = thisTop + thisHeight,
$fixedTitle = $this.find(fixedTitleSelector);
// if the scroll distance is within the project
if (sT > (thisTop - scrollThreshold) && sT < thisBottom && !$fixedTitle.hasClass(bottomClass)) {
if ($fixedTitle.hasClass(bottomClass)) {
$fixedTitle.removeClass(bottomClass).removeAttr('style');
}
$fixedTitle.addClass(fixedClass).css(fixedStyles).css('left', thisLeft);
}
// if the bottom of the project is in view
else if (sT > thisBottom) {
$fixedTitle.removeClass(fixedClass).removeAttr('style').css(bottomStyles).css('bottom', thisBottom).addClass(bottomClass);
}
// if you're above the project
else {
if ($fixedTitle.hasClass(bottomClass)) {
$fixedTitle.removeClass(bottomClass);
$fixedTitle.removeAttr('style');
}
if ($fixedTitle.hasClass(fixedClass)) {
$fixedTitle.removeClass(bottomClass);
$fixedTitle.removeAttr('style');
}
}
});
// closed fixedContainers.each
}
});
// closed window scroll
// Reset the "left" margin on window resize
$(window).resize(function() {
if (winWidth >= desiredWidth) {
var
$titlesFixed = $body.find(fixedSelector),
$titlesBottom = $body.find(bottomSelector);
if ($titlesFixed) {
var
$parent = $titlesFixed.parents(fixedContainerSelector),
parentLeft = $parent.offset().left;
$titlesFixed.css('left', parentLeft);
}
if ($titlesBottom) {
$titlesBottom.each(function() {
var
$parent = $(this).parents(fixedContainerSelector),
parentLeft = $parent.offset().left;
$(this).css('left', parentLeft);
});
}
}
});
};
// Tell the container to take a padding-bottom equivalent to the aspect ratio of the image within it, to act as a placeholder
var
$imageContainers = $('body').find('.js-image-container'),
containerLength = $imageContainers.length;
$imageContainers.each(function(index) {
var
$this = $(this),
$image = $this.find('img'),
imgWidth = $image.attr('data-width'),
imgHeight = $image.attr('data-height'),
imgAspectRatio = imgHeight / imgWidth,
pct = (imgAspectRatio*100).toFixed(1) + "%";
$this.css('padding-bottom', pct);
// if it's the last one, trigger the fixed calculations
if ((index -1) === containerLength) {
// run the set fixed script
setFixed();
}
});
// Set how far from the bottom of the page you want image to start loading
var heightThreshold = 500;
// Tell unveil to watch these, and load them lazily
$('.js-img-container > img').unveil(heightThreshold, function() {
// when it's loaded…
$(this).load(function() {
// get rid of the padding-bottom we had before as a placeholder
$(this).parent().removeAttr('style').addClass('lazy-loaded');
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment