Smooth background image scrolling

Add large and beautiful background image to you web page.
See all of it no matter how long your document is.
Enabled with parallax scrolling effect.

Problem

Suppose you have nice, large image, and you want to set it on your web page as a background.
That shouldn't be too hard, add following CSS to the page

body{
	background-position: center 0;
	background-repeat: no-repeat;
	background-size: auto auto;
	background-image: url("pics/prettyimage.jpg");
}	
and there it is, page looks pretty. But here's the problem. Most large, or even very large, images have height less than 1500px. And if your document is longer than it (as most documents are), when user scrolls down, after image he or she will see blank white space in background. Which might be OK for some pages, but for most it isn't very pretty anymore.

This problem have two solutions with CSS.
One is to repeat image again. Change line of CSS above to background-repeat: repeat; Now there's no blank space, but composition is broken. There is a line where bottom of upper image meets the top of the one below which creates not very nice effect.

Another solution would be to change the height of image to some upper height limit of our document.
Change the line of CSS to let's say background-size: auto 2000px;. Now everything looks good for all documents that are shorter than 2000px. But this approach has its faults too. What if in some cases document is longer than 2000px (on narrow screens for example)? We can to be sure put background-size: auto 3000px;, but now image will become very stretched and we will never see the bottom of it.

Again, this might work well for some web sites, but the both aren't the real solutions.


Solution

One solution might be like this. When page is open we have situation depicted in picture. Top of document, background image, and browser window are all aligned.

Positions when document is scrolled to top
Positions when document is scrolled to top

And when scrolled to bottom, we want again all three to be aligned. This time at its bottoms. In all other scrolling positions, background image should be proportionally scrolled between the two end cases.
This means that image will scroll slower than document, which will give it nice parallax effect too.

Positions when document is scrolled to bottom
Positions when document is scrolled to bottom

Implementation

With first CSS block in place, the rest is implemented in Javascript. Document scroll event is caught and then depending on current scroll position and heights of document, image and browser window, proportion is made and image is scrolled for appropriate amount.
Here's the code for it:

$(window).on('scroll', function() {
	smoothBackgroundScroll("relative/image/url");
});

function smoothBackgroundScroll(imgsrc) {
	function loadImageHeight(url, width) {
		var img = new Image();
		img.src = url;
		if (width) {
			img.width = width;
		}
		return img.height;
	}

	var dh, wh, ih, st, posy, backh, backw;
	if (!this._smoothBackgroundScroll) {
		var bcksize = $(document.body).css('background-size');
		var bmatch = /(\w+)\s*(\w+)/.exec(bcksize);
		if (!bmatch || bmatch.length < 3) {
			backh = loadImageHeight(imgsrc)
		} else {
			backh = parseInt(bmatch[2]);
			if (isNaN(backh)) {
				backw = parseInt(bmatch[1]);
				backh = loadImageHeight(imgsrc, parseInt(backw));
			}
		}
		this._smoothBackgroundScroll = {
			dh: $(document).height()
			, wh: $(window).height()
			, ih: backh
		}
	}
	dh = this._smoothBackgroundScroll.dh;
	wh = this._smoothBackgroundScroll.wh
	ih = this._smoothBackgroundScroll.ih;
	st = $(document).scrollTop();
	posy = (dh - ih) * st / (dh - wh);
	document.body.style.backgroundPosition = 'center ' + posy + 'px';
}
						
Function smoothBackgroundScroll(imgsrc) will work for both cases when background-size CSS property is set or not. And it is also used on this page as an example, so you can see its effect and take working code from source.

Enjoy!

Comments