使用JavaScript和CSS实现异步移动侧边栏

最近帮同学(Simollus)搭建了WordPress博客。

尽管有过建Malash.me的基础,对WordPress轻车熟路,但仅限于插件之类表面的东西,在代码层面研究的并不多。这次建站一来想美化一下主题、优化一下功能,二来想拓宽一下自己的知识面,于是深入研究了一下JavaScript和CSS。

研究过程中发现ipc.me上有这样一篇文章(20个将JavaScript推到极致的网站)很有意思,其中Nike Better World的网站非常吸引我。当用户滚动页面时,会营造出一种有趣的视觉差。

受此启发,我写了一段JavaScript脚本在Simollus上实现了异步移动效果的侧边栏。

Simollus上的异步移动侧边栏

Simollus上的异步移动侧边栏预览(点击图片可看原图,未遮盖部分为浏览器可视区域)

可以看到,当可视区域下移(即滚动条下移)时,左侧的侧边栏会同时向下移动,这样无论什么时候都不会出现侧边栏留白的现象(加上Simollus使用的WPBus D2主题可以实现分辨率自适应,显示效果非常棒)。同时还可以发现,当可是区域在页面最上方时,侧边栏的顶部靠近浏览器顶部;但当显示区域在页面底部时,侧边栏的底部正好完全显示出来。这一点也在代码中有所体现。

首先要获得浏览器相关参数


function  getPagePos() {
    var st, sl, sw, sh, cw, ch;
    if (document.documentElement && document.documentElement.scrollTop) {
        st = document.documentElement.scrollTop;
        sl = document.documentElement.scrollLeft;
        sw = document.documentElement.scrollWidth;
        sh = document.documentElement.scrollHeight;
    } else if (document.body) {
        st = document.body.scrollTop;
        sl = document.body.scrollLeft;
        sw = document.body.scrollWidth;
        sh = document.body.scrollHeight;
    }
    cw = document.documentElement.clientWidth;
    ch = document.documentElement.clientHeight;
    return { scrollTop : st, scrollLeft: sl, scrollWidth: sw, scrollHeight: sh, clientWidth : cw, clientHeight : ch };
}

返回值分别为:

scrollTop:垂直滚动条位置

scrollLeft:水平滚动条位置

scrollHeight:页面总高度

scrollWidth:页面总宽度

scrollWidth:可见区域高度

clientWidth:可见区域宽度

这些参数对侧边栏位置的计算起到重要的作用。Simollus页面布局(div的id)如下:

Simollus页面布局

为了实现侧边栏的位移,我们可以用JavaScript改变CSS中的padding-top值(使用jQuery库),代码如下:


var nowPt = 0;
var aimPt = 0;
var asSteps = 12;
var pagePos;
var minDeltaPt = 3;
function asyncSidebar() {
    if (Math.abs(aimPt - nowPt) < 1)
    {
        setTimeout(function(){asyncSidebar();}, 500);
    } else {
        var deltaPt = (aimPt - nowPt) / asSteps;
        if (Math.abs(deltaPt) < minDeltaPt) {
            if (deltaPt > 0)
            {
                deltaPt = minDeltaPt;
            } else {
                deltaPt = -minDeltaPt;
            }
        }
        var gotoPt = nowPt + deltaPt;
        $("#sidebar").animate({paddingTop:gotoPt + "px"}, 1000 / asSteps * 0.95);
        nowPt = gotoPt;
        setTimeout(function(){asyncSidebar();}, 1000 / asSteps);
    }
}

function asyncSidebarUpdate() {
    var pagePos = getPagePos();
    aimPt = ($("#content").height() - $("#sidebar").height()) * pagePos.scrollTop / (pagePos.scrollHeight - pagePos.clientHeight);
}

$(function() {
    window.onscroll = asyncSidebarUpdate;
    asyncSidebar();
});

在这段代码中,我们设置window.onscroll监听器来更新滚动条位置,用asyncSidebar函数更新侧边栏CSS。这样的好处是便于控制侧边栏的重绘,不因onscroll监听器的调用导致卡顿。

在重绘CSS的代码中,将单帧时间乘以常数0.95,避免由于CPU计算能力导致jQuery队列过长(但改方法并未完全解决此问题,希望能找到更好的解决办法)

如果要移植这段代码非常简单,只需要根据主题修改各div的id即可。

一条评论

回复 Coolicer 取消回复