1

So the actual problem I'm having is that I want a fixed background image effect while keeping the background image wide enough to fill a container. Unfortunately, the CSS way, using background-attachment:fixed; will only position the image relative to the viewport. This creates a problem on screen sizes that have drastically different aspect ratios than the background image where it causes unwanted clipping of the background image (which is a picture of a person).

The solution I've arrived at currently is using background-size: contain to prevent clipping of the image on all screen sizes while simulating the background-attachment: fixed with JavaScript by animating background-position-y on scroll. The problem is if I then click a button that causes a scrollTop animation down the page the background-position-y setting of the image is jerky.

Any idea how to prevent this jerkiness in the animation?

// Banner scroll function
    var scrollTop = $(window).scrollTop();
    var banner = $('.hero-banner').css('background-position-y',scrollTop+'px');
    var debounced_fixBG = function(){
        var newScrollTop = $(window).scrollTop();
        banner.css('background-position-y',newScrollTop+'px');
        scrollTop = newScrollTop;
    };
    $(window).scroll(debounced_fixBG);
    
     $('.scroll-down').on('click',function(){
        $('html,body').animate({
            easing: 'swing',
            scrollTop: $('#anchor').offset().top
        },2000);
    });
.hero-banner {
  background-image: url('http://londonprogressivejournal.com/site_images/741.jpg');
  height: 383px;
  background-repeat: no-repeat;
  background-attachment: contain;
  background-position-y: top;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<button class="scroll-down">
Scroll Down
</button>
<div class="hero-banner">
&nbsp;
</div>
<br>
<br>
<br>
<br>
<br>
<a id="anchor">Anchor</a>
Alex W
  • 37,233
  • 13
  • 109
  • 109
  • Why not `background-attachment:fixed` AND `background-size:contain`? – ezakto Oct 12 '16 at 02:18
  • It causes the image to get clipped when I do `background-attachment: fixed`. In the test image, you can see if you shrink the iframe his hair gets cut off. – Alex W Oct 12 '16 at 02:24
  • You mean his hair cutting off when scroll is 0? What about `background-attachment:fixed;background-position-y:[height of top element];background-size:contain`? I think I don't get the problem – ezakto Oct 12 '16 at 02:29
  • 1
    That [seems to work!](https://jsfiddle.net/s69yn27m/1/) Post as an answer and I'll accept. It was cutting off the bottom of the image but I can just add the top offset to the height of the image to fix it. – Alex W Oct 12 '16 at 02:41

4 Answers4

1

Posting answer from the comments:

You can use both background-attachment:fixed; and background-size:contain; and avoid the top cut by offsetting the image with background-position-y:[height of top element];.

ezakto
  • 3,174
  • 22
  • 27
0

You can set transition property to background-position-y .5s ease-in-out at .hero-banner element

// Banner scroll function
    var scrollTop = $(window).scrollTop();
    var banner = $('.hero-banner').css('background-position-y',scrollTop+'px');
    var debounced_fixBG = function(){
        var newScrollTop = $(window).scrollTop();
        banner.css('background-position-y',newScrollTop+'px');
        scrollTop = newScrollTop;
    };
    $(window).scroll(debounced_fixBG);
    
     $('.scroll-down').on('click',function(){
        $('html,body').animate({
            easing: 'swing',
            scrollTop: $('#anchor').offset().top
        },2000);
    });
.hero-banner {
  background-image: url('http://londonprogressivejournal.com/site_images/741.jpg');
  height: 383px;
  background-repeat: no-repeat;
  background-attachment: contain;
  background-position-y: top;
  transition: background-position-y .5s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<button class="scroll-down">
Scroll Down
</button>
<div class="hero-banner">
&nbsp;
</div>
<br>
<br>
<br>
<br>
<br>
<a id="anchor">Anchor</a>
guest271314
  • 1
  • 15
  • 104
  • 177
0

jQuery animation tends to be choppy because it is very high-level; there are a lot of things your computer needs to calculate to animate. If I were you, I would use a native CSS solution. Here are a few good tutorials.

theEpsilon
  • 1,800
  • 17
  • 30
0

In addition to the above answer try to use position fixed instead of moving the element on scroll. It will be much smoother .

Steve Tomlin
  • 3,391
  • 3
  • 31
  • 63