使用jQuery和CSS创建一个粘性标题栏

如今,网页设计的一个热门趋势是使用粘性标题,其中包含基本元素的页面的顶部(例如菜单栏一旦滚动过去)在页面上固定,继续保持可见。 以下是粘性标题的示例。就像效果看起来一样简单,实现一个优化良好,可靠的粘性标题比参与眼睛更复杂。在本教程中,我们将解决陷阱,并了解如何使用jQuery和CSS 创建理想的粘性标头:


 准备 - 样本布局

首先,让我们建立一个我们将用来最终使标题粘在一起的基本布局。这是一个带有顶部徽标部分,标题部分的简单页面,最后是一个主要内容部分:

CSS:

1

2

3

4

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

<font style="vertical-align: inherit;"><font style="vertical-align: inherit;">身体{</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    保证金:0;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    填充:0;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

}</font></font><font></font>

<font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

身体 *{</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    -webkit-box-sizing:border-box;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    -moz-box-sizing:border-box;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    box-sizing:border-box;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

}</font></font><font></font>

<font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

DIV#头{</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    宽度:100%;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    身高:100px;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    背景:浅蓝色;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    保证金:0;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    填充:5px;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

}</font></font><font></font>

<font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

DIV#{含量 - </font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

    填充:10px;</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

}</font></font>

HTML:

1

2

3

4

6

7

8

9

10

11

12

13

<font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><div id =“logo”></font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

<a href="http://www.javascriptkit.com"> <img src =“jksitelogo.gif”/> </a></font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

</ DIV></font></font><font></font>

<font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

<div id =“header”></font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

<p>一些标题内容</ p></font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

</ DIV></font></font><font></font>

<font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

<div id =“contentarea”></font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

<b>主要内容从这里开始</ b></font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

这里有更多文字</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

这里有更多文字</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">

</ DIV> </font></font>


如您所见,所有部分都是静态和顺序定位的。我们接下来会看到的是如何定位其中一个部分 - 在我们的例子中是标题 - 并且每当用户开始滚动到该部分的顶部时将其固定到位。

 使标题粘滞,或有条件地固定到位

通过使用CSS的 "fixed"属性,修复元素的关键很好。然而,我们想要的粘性元素只是有条件地修复的,通过在满足这些条件时有选择地将CSS属性添加到我们的元素,并在没有时删除它。在粘性标题的情况下,要检查的特定条件是用户是否滚动超过标题的顶部(因此其中一部分被遮挡)。为此,我们需要确定两件事:

  1. 标题的顶部偏移量,或标题顶部和文档顶部之间的距离

  2. 用户当前相对于文档顶部垂直滚动的程度

可以使用offset()元素上的方法在jQuery中获取头的顶部偏移值:

1

targetoffsetTop = $('#header').offset().top // get distance between top of header element and top of document

为了确定用户相对于文档顶部滚动页面的程度,我们scrollTop() 在document自身上调用jQuery的方法:

1

var scrollTop = $(document).scrollTop()

只要2)的值超过1)的值,那就是我们想要在页面上修复标题的时候; 在其他时候,标题应保持未固定状态。

有了我们背后的基本逻辑,让我们现在介绍使标题部分变粘的代码,然后将其分解以解释它是如何工作的以及这种方法的好处:

附加CSS:

1

2

3

4

6

7

8

9

10

body.sticky div#header{<font></font>

    position: fixed;<font></font>

    top: 0;<font></font>

    left: 0;<font></font>

    box-shadow: 0 5px 10px rgba(0,0,0,0.3);<font></font>

}<font></font>

<font></font>

body.sticky div#contentarea{<font></font>

    margin-top: 100px; /* shift contentarea downwards by height of the header so it's fully in view when the header is fixed */<font></font>

}

粘性JavaScript:

1

2

3

4

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

三十

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

window.requestAnimationFrame = window.requestAnimationFrame<font></font>

    || window.mozRequestAnimationFrame<font></font>

    || window.webkitRequestAnimationFrame<font></font>

    || window.msRequestAnimationFrame<font></font>

    || function(f){return setTimeout(f, 1000/60)}<font></font>

<font></font>

<font></font>

;(function($){ // enclose everything in a immediately invoked function to make all variables and functions local<font></font>

<font></font>

    var $body,<font></font>

    $target,<font></font>

    targetoffsetTop,<font></font>

    resizetimer,<font></font>

    stickyclass= 'sticky' //class to add to BODY when header should be sticky<font></font>

    <font></font>

    function updateCoords(){<font></font>

        targetoffsetTop = $target.offset().top<font></font>

    }<font></font>

    <font></font>

    function makesticky(){<font></font>

        var scrollTop = $(document).scrollTop()<font></font>

        if (scrollTop >= targetoffsetTop){<font></font>

            if (!$body.hasClass(stickyclass)){<font></font>

                $body.addClass(stickyclass)<font></font>

            }<font></font>

        }<font></font>

        else{<font></font>

            if ($body.hasClass(stickyclass)){<font></font>

                $body.removeClass(stickyclass)<font></font>

            }<font></font>

        }<font></font>

    }<font></font>

    <font></font>

    $(window).on('load', function(){<font></font>

        $body = $(document.body)<font></font>

        $target = $('#header')<font></font>

        updateCoords()<font></font>

        $(window).on('scroll', function(){<font></font>

            requestAnimationFrame(makesticky)<font></font>

        })<font></font>

        $(window).on('resize', function(){<font></font>

            clearTimeout(resizetimer)<font></font>

            resizetimer = setTimeout(function(){<font></font>

                $body.removeClass(stickyclass)<font></font>

                updateCoords()<font></font>

                makesticky()<font></font>

            }, 50)<font></font>

        })<font></font>

    })<font></font>

<font></font>

})(jQuery)


上面的代码就是将蜘蛛人力量添加到标题中所需的全部内容。让我们先把注意力转向功能 makesticky(),这就是附加的CSS,实际上根据用户滚动条的位置粘贴和取消标题:

1

2

3

4

6

7

8

9

10

11

12

13

function makesticky(){<font></font>

    var scrollTop = $(document).scrollTop() // how much user has scrolled<font></font>

    if (scrollTop >= targetoffsetTop){<font></font>

        if (!$body.hasClass(stickyclass)){<font></font>

            $body.addClass(stickyclass)<font></font>

        }<font></font>

    }<font></font>

    else{<font></font>

        if ($body.hasClass(stickyclass)){<font></font>

            $body.removeClass(stickyclass)<font></font>

        }<font></font>

    }<font></font>

}

调用时函数获取文档“滚动顶部”的最新值,并将其与标题的偏移顶部值进行比较。如果前者较大,则会向BODY添加一个CSS类“sticky”,如果不是,则删除此类。然后为了实际使我们的标头变粘,它将该任务交给CSS来定位并fixed在存在“sticky”类时使用“ ”位置设置标题样式:

1

2

3

4

6

7

8

9

10

body.sticky div#header{<font></font>

    position: fixed;<font></font>

    top: 0;<font></font>

    left: 0;<font></font>

    box-shadow: 0 5px 10px rgba(0,0,0,0.3);<font></font>

}<font></font>

<font></font>

body.sticky div#contentarea{<font></font>

    margin-top: 100px; /* shift contentarea downwards by height of the header so it's fully visible once header is fixed */<font></font>

}

通过使用JavaScript仅添加/删除指示条件是否已满足的CSS类,并将两个不同状态的标头的实际样式委托给CSS,我们利用纯CSS的简单性来定义所需的样式为标题。请注意makesticky(),在分别添加或删除该类之前,每次调用时都会检查“sticky”类的存在与否。这样可以优化代码,因此它不会不断地将“粘性”类添加/移除到BODY元素,而是每次只满足条件更改的阈值时。

makesticky()无论何时滚动或调整窗口大小,都会调用该函数。我们稍后会详细讨论后者,但为了实现前者,我们scroll在jQuery中向窗口对象附加一个“ ”事件,并调用所需的代码在其中运行:

1

2

3

$(window).on('scroll', function(){<font></font>

    requestAnimationFrame(makesticky)<font></font>

})

在窗口scroll事件中运行代码可能非常昂贵,可能每秒触发多次,具体取决于用户滚动的速度。在这里我们应用另一种优化技术,使用window的 方法来调用函数而不是直接调用 函数。该方法基于屏幕何时准备好进行下一次重绘而智能地限制传递到其中的函数的执行,而不管连续调用多少次 (由用户滚动窗口的速度或速度确定)。对于在窗口事件中运行并且对用户屏幕进行更改的代码,通常最佳做法是将其汇总。 requestAnimationFrame()makesticky() requestAnimationFrame()scroll requestAnimationFrame() 我们的makesticky()功能也会在窗口调整大小时运行,因为在调整大小时页面上的内容可能已经转移,正如空乘人员所说的那样。我们特别感兴趣的是标题的原始偏移顶部值(标题和文档顶部之间的距离)的任何更改。在今天的响应式设计中,元素高度也可以是流动的,这很可能发生。这就是为什么当窗口调整大小时,我们有以下内容来获取标头的最新偏移顶部值,并重新评估标头是否应保持粘性:

1

2

3

4

6

7

8

$(window).on('resize', function(){<font></font>

    clearTimeout(resizetimer)<font></font>

    resizetimer = setTimeout(function(){<font></font>

        $body.removeClass(stickyclass)<font></font>

        updateCoords()<font></font>

        makesticky()<font></font>

    }, 50)<font></font>

})

在突出显示的代码中,第一行至关重要。它会暂时将标题恢复为原始的“未固定”状态,以便之后可以获得标题的正确新偏移顶部值。当标题固定在位置时尝试获取此值会返回标题从文档顶部移动以保持固定在页面上的距离,这不是我们想要的。由于标头暂时不固定,我们先调用updateCoords()首先获取标头的最新顶部偏移量,然后makesticky()根据新数据确定标头的定位方式(固定或不固定)。

注意我们希望在resize 事件中运行的代码是如何通过setTimeout()计时器调用的。这是另一种优化技术,它限制了用户调整窗口大小时发生的代码调用次数。resize大多数浏览器中窗口对象的事件在用户调整窗口大小时会多次触发,而不是在用户从一个屏幕大小转到另一个屏幕大小时触发一次。这意味着此事件中的任何代码每次都会被触发多次,通常是不必要的。通过使用 setTimeout()计时器在执行我们想要的代码之前添加延迟,结合使用clearTimeout()取消之前排队的操作,结果是在resize事件结束时只运行一次的所需代码。使用这种技术可以减少对窗口resize事件内部代码的潜在调用雪崩。

最后,我们的粘贴标题代码在文档完全加载时初始化。在这一点上,我们得到标题的偏移顶部值以确保它是准确的,在诸如可能影响该值的标题的图像之类的项目已经加载之后。如果您的页面上没有这样的项目,您可以通过在使标题粘滞之前等待DOM加载来加快初始化过程,或者将两个世界中的最佳组合结合如下:

1

2

3

4

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

jQuery(function(){ // on DOM load<font></font>

    $body = $(document.body)<font></font>

    $target = $('#header')<font></font>

    updateCoords()<font></font>

    $(window).on('scroll', function(){<font></font>

        requestAnimationFrame(makesticky)<font></font>

    })<font></font>

    $(window).on('resize', function(){<font></font>

        clearTimeout(resizetimer)<font></font>

        resizetimer = setTimeout(function(){<font></font>

            $body.removeClass(stickyclass) // unstick header so we can get accurate header offset top value<font></font>

            updateCoords()<font></font>

            makesticky()<font></font>

        }, 50)<font></font>

    })<font></font>

})<font></font>

$(window).on('load', function(){<font></font>

    $body.removeClass(stickyclass) // unstick header so we can get accurate header offset top value<font></font>

    updateCoords() // get sticky header's offset top value again to ensure it's accurate<font></font>

    makesticky()<font></font>

})

通过在DOM加载后运行脚本,但在窗口完全加载时刷新标题的顶部偏移值,我们可以吃蛋糕并吃掉它!注意窗口“ load”事件中的代码现在如何改变,以包括在调用之前首先从BODY中删除“sticky”类updateCoords()- 这与我们为什么在窗口“ resize”事件中执行此操作的原因相同,以及获得标题的正确顶部偏移量,而它不是 “ fixed”的位置。

 结论

在本教程中,我们学习了如何使页面上的元素有条件地固定在位以创建流行的粘性标题效果。通过正确的考虑,特别是考虑到代码优化,结果是对页面UI的无缝,积极的补充。


猜你喜欢

转载自blog.51cto.com/13959020/2285827