10月22, 2017

"粘粘"的侧边栏

说到zhan nian在页面某固定位置上的元素,大家都不陌生,但是其中一些细节可能一下子不容易想到。这里就之前项目遇到的情况一并总结了下。

常见的场景如,顶部的搜索框,信息流侧边的辅助信息(广告,工具栏,导航等),返回顶部的按钮。这些都是当页面在滚动时,它们只固定在自己的位置,不变。

实现起来也比较简单,只需要fixed定位 + scrollTop 的判断即可。只是在这其中会有一些不容易注意到的小细节。下面我们来看如下布局,类似于这样的效果,在实现时需要注意哪些地方:

主要难点

  1. 屏幕上一些高度之间的关系,随着页面的滚动,scrollTop是在不断变化的,元素的offset().top也是变化的。图片来源

  2. 问题:什么时候固定右侧 假设期望元素在距离视窗X时,固定位置。那么则有临界关系: X + sh = bh ,进而有:

     /*使右侧固定*/
     var _FIXED_SIDE_TOP = 10;
     if(scrollTop + _FIXED_SIDE_TOP > leftCardOffsetTop){
         if( !_this.rightEl.hasClass('fixed-it') ){
             _this.rightEl.addClass('fixed-it');
         }
     }else{
         if( _this.rightEl.hasClass('fixed-it') ){
             _this.rightEl.removeClass('fixed-it').css('left', 'auto');
         }
     }
    
  3. 问题:当底部有固定内容时,右侧定位容易超出覆盖底部的内容。

    期望:左右两部分底部对齐

    解决:临界值,屏幕高度 = 左侧元素距离屏幕底部距离 + 右侧元素高度,在到达页面底部之前,左侧元素距离屏幕底部距离是逐渐增大的。所以有:

     /*左侧元素的高度也可能也是在变的,异步取完数据后高度增加。取outerHeight计算padding*/
     var leftCardHeight = _this.leftEl.outerHeight();
     var card_to_btm = windowHeight + scrollTop - leftCardOffsetTop - leftCardHeight;
     // 这部分是始终固定的
     var bufferHeight = windowHeight - rightElHight;
    
     if(card_to_btm > bufferHeight){
         _this.rightEl.css({'top': 'auto', 'bottom': card_to_btm});
     }else{
         _this.rightEl.css({'top': '0', 'bottom': 'auto'});
     }
    

细节

  1. 滚动条,时有时无 以上都是如何计算右侧的高度,在确定右侧的左右位置时,最开始使用的是calc来确定的。但在chrome的某些版本中,滚动条会在不进行滚动操作时消失,而vw是等于window.innerWidth的,margin: 0 auto的是除去滚动条之后的宽度,所以在不确定浏览器的滚动条是否真的占位的情况下,视觉上看,页面在滚动时可能会产生抖动现象。

    /*这里计算left也是一样的*/
    right: calc((100vw - 1200px)/2);
    

    为了解决这个问题,改为在js中就先计算固定元素距离屏幕左侧的距离,此时无论有无滚动条都不会被影响到。

  1. 另外还需要响应屏幕大小变化时的情况,在resize是重新出发下scroll事件即可。

  2. 在小屏幕下如果不做处理,在横向滚动的时候,右侧显示的内容不完全,因为left是固定的。

    解决办法:

     * 在小屏幕下回到其自然位置,不做定位。(目前选择了这一种)
     * 实时计算右侧left的位置。但是第一视口中依然看不完全信息
    

优化

是否有必要使用函数节流来处理onscroll事件。

  • 如果不使用,到开始固定的位置,fixed事件共触发了108下。

  • 以差不多相同速度滚动,时间设定为100ms事,fixed事件触发了26下。

  • 对比起来,好像还挺明显的。不过大概由于PC端性能都比较好,看到的大部分网站都没有使用这个优化。

DEMO

最后附上本文中的小DEMO和源码

本文链接:https://imjiaolong.cn/post/Sticky-Sidebar .html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。