网站如何无抖动地实现控件悬停效果

控件悬浮是网站的常见功能,指网页随滚动条滚动时,悬浮控件相对浏览器窗口保持不动的视觉效果。悬浮控件中通常用于放置一些小工具(比如“回顶部”按钮),或者显示一些希望访问者关注的内容(比如热门文章列表、广告等)。悬浮控件是一把双刃剑,如果被精心设计和实现,它控件可以大大提升网站用户体验和转换率;但当它以一种粗制滥造的面目呈现时,只能增加来访者的厌恶感,降低网站品质。比如,很多粗糙的企业网站都喜欢在右侧放置一个"联系我们"悬浮控件,当移动滚动条时,这个控件并不是老老实实地保持不动,而是一直上下抖动(你可以随便打开一个百度搜索结果中的减肥广告观察这个现象)。悬浮控件的色彩和布局,是设计师应该操心的问题;本文以实现一个悬浮广告为例,说明如何用js“无抖动”地实现一个“由滚动条调位置决定是否悬浮”的自定义悬浮控件。

粗制滥造的悬浮控件,只能增加来访者的厌恶感,降低网站品质(来自某减肥网站)

粗制滥造的悬浮控件,只能增加来访者的厌恶感,降低网站品质(来自某减肥网站)

问题缘起

许多广告联盟都会提供一种悬浮类型的广告:这种广告通常位于网站侧边栏最底部,开始时并不是悬浮的;只有当网页滚动到该广告所在位置时,它才会保持在左上角或右上角不动;当滚动条往上滚动时,该广告还会重新回到文档流中,随页面一起滚动。这种形式可以大大提高用户对广告的关注度,阿里妈妈和百度联盟都提供这种形式的广告。但美中不足的是,侧栏广告大小通常为300*250,其高度远远小于浏览器窗口宽度,导致当广告处于悬乎状态时,广告下部大概有400像素左右高度的空白区,既浪费浪费版面空间,又影响视觉效果。谷歌adsense提供300*600的巨幅广告,可以很好地弥补这个不足,但遗憾的是谷歌并不提供悬浮的广告形式。我实在无法割舍对google巨幅广告的喜爱,所以只能自己实现这个悬浮效果了。具体效果可以参照我网站左侧边栏的右下角。

原理

实现根据滚动条位置决定是否悬浮控件,需要监听html文档的滚动事件。每当滚动条发生移动时,计算其垂直移动的距离scrollTop,并与控件在自然状态下相对于文档左上角的高度offsetY进行比较,如果scrollTop>offsetY,则悬浮控件;如果scrollTop<=offsetY,则控件取消悬浮。

实现控件悬浮,最好最自然的方案是让控件采取固定定位方式,也就是将控件的position属性,设置为fixed,并根据实际情况为其top(或bottom)和left(或right)属性赋值。本例中,当控件处于悬浮状态时,其top值始终为0,其left值则等于控件在自然状态时相对于文档左上角的水平偏移量。

取消控件悬浮,只需让控件恢复默认的静态定位方式,回归文档流,也就是设置控件的position属性为static。

还有一个非常重要的问题,那就是当控件处于悬浮状态时,如果对浏览器窗口进行缩放,那么悬浮控件会发生定位错乱。解决这个问题,只需监听html的resize事件,当窗口大小发生变化时,重新计算控件的预期top(或bottom)和left(或right)并赋值。

最后,由于控件处于悬浮状态时脱离了文档刘,要注意调整z-index值,避免与网页的其他部分发生遮挡。

抖动问题

悬浮控件发生抖动,原因在于对控件采取了绝对定位方式(设置position属性为absolute),在滚动时不断地计算计算并为top(或bottom)和left(或right)赋值。固定定位和绝对定位的区别在于,前者是悬浮控件相对于浏览器窗口发生偏移,其top(或bottom)和left(或right)保持不变;而后者则是悬浮控件相对于整个文档发生偏移(比如文档左上角),当滚动发生时,文档顶部和浏览器顶部不再重叠,为了实现控件相对于浏览器窗口保持静止的效果,必须不断地根据滚动举例改变top(或bottom)和left(或right)的值。由于滚动事件发生的频率很高,采用绝对定位实现悬浮效果时,不仅会加大计算量,影响效率,还会导致偏移量的变化来不及"跟上滚动条",出现难看的抖动效果。下图是从前文中减肥广告网站中截取的代码,可以清楚地展示抖动发生的原因:

采用绝对定位(position:absolute)会导致悬浮控件抖动

采用绝对定位(position:absolute)会导致悬浮控件抖动

代码实现

上代码才是最实在的,呵呵。下面的js代码实现依赖于jquery库,代码被放在一个自执行的闭包中,其中top和left是该闭包中的全局变量,当resize事件发生时,重新计算并改变了这两个变量的值。你可以将代码中$('#main-aside-bottom')替换为你自己的悬浮控件。代码其实很简单,看不懂的童鞋可以留言。

(function(){
    var top = $('#main-aside-bottom').offset().top;
    var left = $('#main-aside-bottom').offset().left;
    $(window).bind({
        scroll:function(){
            if($(window).scrollTop() >= top){
               $('#main-aside-bottom').css({
                    position: 'fixed',
                    left: left,
                    top: 0
               });
            }else{
                $('#main-aside-bottom').css({
                    position: 'static',
                    left: 'auto',
                    top: 'auto'
               });
            }
        },
        resize:function(){
            $('#main-aside-bottom').css({
                position: 'static',
                left: 'auto',
                top: 'auto'
            });
            top = $('#main-aside-bottom').offset().top;
            left = $('#main-aside-bottom').offset().left;
            if($(window).scrollTop() >= top){
               $('#main-aside-bottom').css({
                    position: 'fixed',
                    left: left,
                    top: 0
               });
            }
        }
    });
})();
用支付宝钱包扫描此二维码,为本文付款
本文标签:
web前端悬浮广告

官方公众号:
查看更多有趣的信息,请扫码关注男儿邦官方微信公众号nanerbangblog。

公众号id:
男儿邦blog

版权声明:
本文为站长原创,如需转载,请联系作者,并以超链接形式注明出处

本文地址:
http://www.nanerbang.com/article/38/