Parallax backgrounds with centered content

Responsive parallax background images with content centering and overflow

Updated
14/11/2015 - Fixed fullscreen on webkit, changed overflow class

The Solution

Demo
Demo
Demo and source code

Here's a simple and customizzable Css and jQuery solution to achieve parallax scrolling background animations like on spotify

It's based on the fullscreen backgrounds with centered content solution and they shares some of the code, and the same features like: vertical and orizzontal centering of content, content overflow (the background scale to fit content if it's higher than the window) and also do fullscreen backgrounds relative to the container (by using .not-fullscreen class instead of .fullscreen)

The parallax is disabled on touch devices, because it doesn't work with the touch scrolling, but it gracefully degrade to full-size images, like the fullscreen background solution.

If you don't need centered content you can remove the .content-a and .content-b tags and Css.

The Markup

To have fullscreen background images use the class .fullscreen to have fullscreen div, and .background to have the background size adjustments.

You have to apply the background-image style using the url of the image you want as background. The data-img-width and data-img-height attributes, with the pixel values of the background's width and height, are obligatory.

With the parallax version, you have to assign the .parallax class to the divs

to enable the parallax effect, and you have to assign the data-diff attribute to set the amout of parallax you want (preferably between 100 and 400, if less you have very little parallax, if more the image gets cropped too much).

<div class="fullscreen background parallax" style="background-image:url('http://www.minimit.com/images/picjumbo.com_IMG_6648.jpg');" data-img-width="1600" data-img-height="1064" data-diff="100">
    <div class="content-a">
        <div class="content-b">
            Centered content
        </div>
    </div>
</div>

The div and the background will have automatic overflow if the div content is higher than the window.

Tip: you can use the same code with only the .fullscreen class and .content-a .content-b divs to have fullscreen centered content.

<section class="fullscreen">
    <div class="content-a">
        <div class="content-b">
            Centered content
        </div>
    </div>
</section>

If you want to preserve the height of the div, instead of having it fullscreen, just use the .not-fullscreen class instead of .fullscreen

<div class="not-fullscreen background parallax" style="background-image:url('http://www.minimit.com/images/picjumbo.com_IMG_6643.jpg');" data-img-width="1600" data-img-height="1064" data-diff="100">
    <div class="content-a">
        <div class="content-b">
            Centered content
        </div>
    </div>
</div>

The Css

We set up the .background: you can set any background-position you want, the one with ie8- graceful degradation is needed to have proper centering on Internet Explorer 8-, since it will not scale the image.

/* background setup */
.background {
    background-repeat:no-repeat;
    /* custom background-position */
    background-position:50% 50%;
    /* ie8- graceful degradation */
    background-position:50% 50%9 !important;
}

Then just use the Css for fullscreen and content centering. Be sure to give height:100% to all tags from html to the divs with .fullscreen.

/* fullscreen setup */
html, body {
    /* give this to all tags from html to .fullscreen */
    height:100%;
}
.fullscreen,
.content-a {
    width:100%;
    height:100%;
    overflow:hidden;
}
.fullscreen.overflow,
.fullscreen.overflow .content-a {
    height:auto;
    min-height:100%;
}

/* content centering styles */
.content-a {
    display:table;
}
.content-b {
    display:table-cell;
    position:relative;
    vertical-align:middle;
    text-align:center;
}

The jQuery

Alert
Remember to include the jQuery library.

Just copy and paste all the jQuery after all the markup (just before the closing body tag), remember to use fullscreenFix() in case the .fullscreen content changes (it set overflow if needed).

/* detect touch */
if("ontouchstart" in window){
    document.documentElement.className = document.documentElement.className + " touch";
}
if(!$("html").hasClass("touch")){
    /* background fix */
    $(".parallax").css("background-attachment", "fixed");
}

/* fix vertical when not overflow
call fullscreenFix() if .fullscreen content changes */
function fullscreenFix(){
    var h = $('body').height();
    // set .fullscreen height
    $(".content-b").each(function(i){
        if($(this).innerHeight() > h){
            $(this).closest(".fullscreen").addClass("overflow");
        }
    });
}
$(window).resize(fullscreenFix);
fullscreenFix();

/* resize background images */
function backgroundResize(){
    var windowH = $(window).height();
    $(".background").each(function(i){
        var path = $(this);
        // variables
        var contW = path.width();
        var contH = path.height();
        var imgW = path.attr("data-img-width");
        var imgH = path.attr("data-img-height");
        var ratio = imgW / imgH;
        // overflowing difference
        var diff = parseFloat(path.attr("data-diff"));
        diff = diff ? diff : 0;
        // remaining height to have fullscreen image only on parallax
        var remainingH = 0;
        if(path.hasClass("parallax") && !$("html").hasClass("touch")){
            var maxH = contH > windowH ? contH : windowH;
            remainingH = windowH - contH;
        }
        // set img values depending on cont
        imgH = contH + remainingH + diff;
        imgW = imgH * ratio;
        // fix when too large
        if(contW > imgW){
            imgW = contW;
            imgH = imgW / ratio;
        }
        //
        path.data("resized-imgW", imgW);
        path.data("resized-imgH", imgH);
        path.css("background-size", imgW + "px " + imgH + "px");
    });
}
$(window).resize(backgroundResize);
$(window).focus(backgroundResize);
backgroundResize();

/* set parallax background-position */
function parallaxPosition(e){
    var heightWindow = $(window).height();
    var topWindow = $(window).scrollTop();
    var bottomWindow = topWindow + heightWindow;
    var currentWindow = (topWindow + bottomWindow) / 2;
    $(".parallax").each(function(i){
        var path = $(this);
        var height = path.height();
        var top = path.offset().top;
        var bottom = top + height;
        // only when in range
        if(bottomWindow > top && topWindow < bottom){
            var imgW = path.data("resized-imgW");
            var imgH = path.data("resized-imgH");
            // min when image touch top of window
            var min = 0;
            // max when image touch bottom of window
            var max = - imgH + heightWindow;
            // overflow changes parallax
            var overflowH = height < heightWindow ? imgH - height : imgH - heightWindow; // fix height on overflow
            top = top - overflowH;
            bottom = bottom + overflowH;
            // value with linear interpolation
            var value = min + (max - min) * (currentWindow - top) / (bottom - top);
            // set background-position
            var orizontalPosition = path.attr("data-oriz-pos");
            orizontalPosition = orizontalPosition ? orizontalPosition : "50%";
            $(this).css("background-position", orizontalPosition + " " + value + "px");
        }
    });
}
if(!$("html").hasClass("touch")){
    $(window).resize(parallaxPosition);
    //$(window).focus(parallaxPosition);
    $(window).scroll(parallaxPosition);
    parallaxPosition();
}