将视差滚动效果应用于多个背景,每个背景以不同的速度滚动

时间:2017-01-08 14:25:35

标签: javascript jquery css background-image parallax

我正在尝试制作一个仅涉及背景和页眉/页脚图像的视差效果,只留下主要内容标记(常规的wordpress循环)。

背景全部位于div #page中,它占据了整个文档,顶部横幅是img,位于顶部的单独div中.site-branding,填写body中的背景。

#page {
    background:url("http://i.imgur.com/jK3tbU8.png") no-repeat scroll bottom center, url("http://i.imgur.com/TSrLfq1.png") repeat-x scroll top center, url("http://i.imgur.com/Md0r0mw.png")repeat-x scroll bottom center;
    padding:0;
    margin:0;
    transition: 0s ease-in-out;
    transition-property: background-position;
}

body {
    background:url("http://i.imgur.com/910XVzz.jpg") repeat scroll top; 
    padding:0;
    margin:0;
    transition: 0s ease-in-out;
    transition-property: background-position;
}

.site-branding {
    margin-left:auto;
    margin-right:auto;
    min-width: 0;
    overflow: hidden;
    display: block;
}
.site-branding img {
    max-width:100%;
    margin-left:0;
}

顶部横幅以特定速度向上滚动,顶部背景以稍慢的速度向上滚动,填充正常在页面中间滚动...

到目前为止一切顺利(请参阅下面链接的JSFiddle以便更方便地了解所有这些内容。)

然后我想制作两个底部背景,jK3tbU8.pngMd0r0mw.png,以自己的速度向上滚动(例如,比滚动慢),最终停在底部页面jK3tbU8.png是一个"曼荼罗"页脚横幅,位于jK3tbU8.png之上,底部渐变背景。)

使用下面的脚本,我可以让它们以自己的速度出现:但是我不能让它们完全停在底部

我认为这可能主要是因为scrollTop()offset()都是基于顶部......?

你会认为这只是减去数值的问题,但我发现视口的高度当然会有所不同。如果视口发生变化,则图像会在较高或较低的位置结束,但差异非常小。

我想我需要在计算中考虑视口?但我不知道怎么做!

这是我的整个代码,我在其中添加了很多评论,希望它不会太难理解:

jQuery(function ($) {
    "use strict"; 

    $(document).ready(function(){
    var $win = $(window);

    $('div#page').each(function(){

        //set an arbitrary "speed"
        var scroll_speed1 = 8;

        var viewportHeight = $(window).height();

        //set heights of backgrounds (any easy way to get this dynamically?)
        var topFade = 600;
        var bottomFade = 870;
        var mandalaBottom = 457;

        var $this = $(this);

        //set background-attachment here, so that in style.css top-fade can be "scroll"
        //needed in case the script breaks
        $this.css("background-attachment", "scroll, fixed, scroll");

        //set all the initial positions
        //the idea is that if the images are down below (= higher number)
        //they will scroll up faster, at a matching speed (= number dimishing faster)
        var bgP1 = ( ($this.outerHeight()*2) + mandalaBottom ); //mandala-bottom
        var bgP2 = $this.offset().top; //top-fade
        var bgP3 = ($this.outerHeight()+(bottomFade)); //bottom-fade
        var initialValue = "center " + bgP1 + "px," + "center " + bgP2 + "px," + "center " + bgP3 + "px";

        //put the images in the css
        $this.css("background-position", initialValue);

        //bind to the scroll event  
        $(window).scroll(function() {

            //percent between viewport and height of page
            var viewportDiff = percentChange($this.outerHeight(), viewportHeight);
            console.log("the percent between viewport and height of page is: " + viewportDiff+ "%");

            //percent between position of pic and height of page
            var perDiff = percentChange(bgP1, $this.outerHeight());
            console.log("the percent between position of pic and height of page is: " + perDiff);

       /*   1) $win.scrollTop() = position of the scroll (increasing number) 
            2) perDiff = the proportion between the page and the position of the pic (%)
            3) viewportDiff= the proportion between the page and the viewport (%)
            4) $this.outerHeight() = height of the page
            => scroll + the x% of scroll (given by the difference with the position of the pic) - the x% of page (given by the difference between viewport and page) + the height of the image   */             
            var numberToSubstract = ( $win.scrollTop() + percentOf($win.scrollTop(), perDiff) - percentOf(viewportDiff, $this.outerHeight() ) + (mandalaBottom/2) );
            console.log("the initial position of the pic was: " + bgP1);
            console.log("we have substracted this much: " + numberToSubstract);
            var bgNP1 = bgP1 - numberToSubstract - (mandalaBottom);
            console.log("the pic now is here: " + bgNP1);
            console.log("the height of the page is: " + $this.outerHeight());            


            //this calculates where to put the top-fade as the page is scrolled
            var bgNP2 = -(($win.scrollTop() - $this.offset().top)/ scroll_speed1);

            //this calculates where to put the bottom-fade as the page is scrolled
            var perDiff3 = percentDiff(bgP3, $this.outerHeight());
            var numberToSubstract3 = ($win.scrollTop() + percentOf($win.scrollTop(), perDiff3)) / scroll_speed1;
            var bgNP3 = bgP3 - numberToSubstract3 - bottomFade;
            //put the new values in the css
            var newValue = "center " + bgNP1 + "px," + "center " + bgNP2 + "px," + "center " + bgNP3 + "px";
            $this.css("background-position", newValue);

            }); //scroll
        }); //page

            //this takes care of mandala-top
            $('div.site-branding').each(function(){

                //set an arbitrary speed
                var scroll_speed = 1.5;

                    //bind to the scroll event (again?)  
                    $(window).scroll(function() {            

                        //this calculates where to put the top-fade as the page is scrolled
                        var bgNP2 = -( ($win.scrollTop() /*- $this.offset().top --not needed since it is 0*/) / scroll_speed );

                        //put the new values in the css
                        var newValue2 = bgNP2 + "px";
                        $('#mandalaTop').css("position", "relative");
                        $('#mandalaTop').css("top",  newValue2);
                        $('#mandalaTop').height(448 /*height of top img*/);

                    }); //scroll

        }); //div.site-branding   

    });//document ready

    if(navigator.userAgent.match(/Trident\/7\./)) {
        $('body').on("mousewheel", function () {
            event.preventDefault();
            var wd = event.wheelDelta;
            var csp = window.pageYOffset;
            window.scrollTo(0, csp - wd);
        });
    }

    //following this calculation: 
    //http://www.calculatorsoup.com/calculators/algebra/percent-difference-calculator.php
    function percentDiff(val1, val2) {
        var difference = ( (val1 - val2) / ((val1+val2) / 2) ) * 100;
        return difference;
    }

    function percentOf(percent, value) {        
        var n = percent/100;
        return n * value;
    }

    function percentChange(bigVal, smallVal) {
       var change = ( (smallVal-bigVal) / bigVal ) * 100;
       return 100 + change;
    }

});

为了更好地理解上述内容,并查看包含所有内容的简单html标记,此处为JSFiddle

它应该工作,这意味着,顶部的一切都很好,但在底部搞砸了。

1 个答案:

答案 0 :(得分:0)

一个非常简单的解决方法是改变:

//put the new values in the css
var newValue = "center " + bgNP1 + "px," + "center " + bgNP2 + "px," + "center " + bgNP3 + "px";

要:

//put the new values in the css
var newValue = "center bottom," + "center " + bgNP2 + "px," + "center " + bgNP3 + "px";

基本上,不要将动态滚动偏移分配给底部装饰元素,因为您希望它粘在底部。

如果你仍然希望动画但底部元素但是将其粘贴到底部,则可以使用简单的条件。在这种情况下,457是图像高度。因此,如果偏移量小于页面高度 - 图像高度,请将图像粘贴到底部以避免间隙:

if(bgNP1 < $this.outerHeight() - 457)
{
    bgNP1 = $this.outerHeight() - 457;
}

//put the new values in the css
var newValue = "center " + bgNP1 + "px," + "center " + bgNP2 + "px," + "center " + bgNP3 + "px";