问题
要建立一个阅读位置指示器,我们需要回答如下两个问题:
原则
这项技术的原则是基于用户不得不滚动滚到条到页面的底部的简单的一个事实。一旦用户滚动滚到条到了页面的底部,我们可以得到用户已经阅读完成了这篇文章。解决获取当前用户阅读位置这个问题的关键看起来就是解决滚动条滚动事件了。
标记
让我们从最基本的标记开始:
为指示器添加样式
我们想要让我们的指示器总是在页面的顶部显示,即使用户滚动窗口也是这样,我们将progress元素设置为fixed。另外,我们应该希望进度条的背景是transparent(透明)的,这样在页面滚动时就不会创建一个空的进度条阻碍用户视线。同时,这也会帮助我们处理好在javascript被禁用的时候浏览器的表现,后面我们会介绍这一点。
progress { /* Positioning */ position: fixed; left: 0; top: 0; /* Dimensions */ width: 100%; height: 5px; /* Reset the appearance */ -webkit-appearance: none; -moz-appearance: none; appearance: none; /* Get rid of the default border in Firefox/Opera. */ border: none; /* Progress bar container for Firefox/IE10+ */ background-color: transparent; /* Progress bar value for IE10+ */ color: red; }
progress::-webkit-progress-bar { background-color: transparent;}progress::-webkit-progress-value { background-color: red; } progress::-moz-progress-bar { background-color: red; }
交互
用javascript计算浏览器的width/height属性是非常麻烦的,同时,在不同内核的浏览器中的表现是非常可怕的。幸运的是,jquery抽象了这些复杂的操作,使得我们可以以清晰的方法去计算window和document的度量。因此,在接下来的内容中,我们将会通过jquery来处理与用户之间的交互。
var winHeight = $(window).height(), docHeight = $(document).height(); max = docHeight - winHeight; $(progress).attr('max', max);
var value = $(window).scrollTop(); $(progress).attr('value', value);
$(document).on('scroll', function() { value = $(window).scrollTop(); progressBar.attr('value', value); });
$(document).on('ready', function() { var winHeight = $(window).height(), docHeight = $(document).height(), progressBar = $('progress'), max, value; /* Set the max scrollable area */ max = docHeight - winHeight; progressBar.attr('max', max); $(document).on('scroll', function(){ value = $(window).scrollTop(); progressBar.attr('value', value); }); });
浏览器兼容性
这需要我们建立一个能够在不同浏览器中能够拥有相同表现的阅读位置指示器,我们建立的这个阅读位置指示器能够在所有良好支持html5进度条元素的浏览器中正常工作。但是,这种支持仅在firefox16+,opera 11+, chrome,safari 6+,ie 10+的浏览器上可用。opera 11和12不支持改变进度条的颜色。因此,我们的进度条将会是默认的绿色。
边界问题
在很多情况下,我们上述的代码可能会崩溃或者是不能够正确的指示出用户阅读的位置,让我们看看这些情况。
document高度<=window高度
我们的代码假设了document的高度总是大于window的高度,但是,实际情况并不总是这样的。幸运的是,浏览器会帮助我们处理这种情况,当document的高度比window的高度小的时候,浏览器会返回window的高度。因此,docHeight和winHeight是相同的。
max = docHeight - winHeight; // equal to zero.
用户改变window的尺寸
当用户改变window的尺寸的时候,window和document的高度将会发生改变。这意味着我们必须要重新计算max和value属性以反映出指示器当前正确的位置。我们将会通过resize事件处理器重新计算正确的位置。
$(window).on('resize', function() { winHeight = $(window).height(), docHeight = $(document).height(); max = docHeight - winHeight; progressBar.attr('max', max); value = $(window).scrollTop(); progressBar.attr('value', value); });
javascript被禁用
当javascript被禁用的时候,我们的进度条将会有一个最大值为1,当前默认值为0。
旧的浏览器兼容
旧的不支持html5的进度条元素的浏览器将会忽略掉progress标记。然而,对于一些站点来说,提供始终如一的体验是非常重要的(该方案略,详见原文)。
性能
通常,给滚动事件添加事件处理器被认为是非常不好的实践,因为每次滚动的时候,浏览器都会试图去重绘出现的内容。在我们的例子中,dom的结构和样式是比较简单的,在页面滚动的时候不会有任何明显会注意到的延迟或者是滞后。然而,当我们放大这里,在我们的拥有复杂的dom结构的站点中实现的时候,滚动的体验将会是产生很多性能的缺失。
造成的困惑
我不是一个UX专家,但是在一些情况下,我们的指示器的位置和外观可能会是模棱两可的并且会误导用户。ajax驱动的站点比如Medium,Youtube等,使用相似的进度条指示下一个页面载入的进度。Chrome移动浏览器本地使用蓝色的进度条作为页面加载进度。现在,如果你在框架上添加一个进度指示器,我保证肯定有很多人需要花费很长时间去理解这个顶部的指示器是有什么作用的。