I realize that this is an old question, however, I recently stumbled upon this problem myself and spent a lot of time trying to find the best working code. Everything I found was either too complicated or didn't work without lagging a lot, especially in Chrome. As pointed out by others, the problem cannot be solved by pure CSS, but I made my own simple AngularJS directive to solve the problem:
app.directive("paraBack", ['$window', function ($window) {
return function(scope, element, attrs) {
element.css("background-image", "url("+attrs.paraBack+")"); // Apply the background image with CSS
element.css("background-attachment", "fixed"); // Disable background scrolling
var max = Infinity;
var image = new Image(); // Create a JavaScript image so that the code below can be run when the background is loaded
image.src = attrs.paraBack;
image.onload = function () {
max = image.height - window.innerHeight; // Stop scrolling after the bottom of the picture is reached
var xOffset = -(image.width/2-window.innerWidth/2);
element.css("background-position-x", xOffset+'px'); // Horizontally align the background
}
var scrollHandler = function () {
var offset = Math.floor(this.pageYOffset*0.1); // Set background to scroll at 10% of scrolling speed
if (offset<max) {
element.css('background-position-y', '-'+offset+'px'); // If not the bottom of the image is reached, move the background (scroll)
}
};
angular.element($window).on('scroll', scrollHandler); // Set the defined scrollHandler function to be ran when user scroll
scope.$on('$destroy', function () {
angular.element($window).off('scroll', scrollHandler); // Unbind the function when the scope is destroyed
});
};
}]);
It can be used in the html like this:
<body para-back="url/to/image">
If you want to see an example of what it looks like, you can visit this page.