自定义滚动条

蚊子前端博客
发布于 2016-01-25 00:00
在PC端,无论哪款浏览器提供的默认滚动条,样式都是很丑,无法满足现在页面设计的要求,为此衍生出了无数的模拟滚动条的插件,这些插件可以使用CSS来美化滚动条

在 PC 端,无论哪款浏览器提供的默认滚动条,样式都是很丑,无法满足现在页面设计的要求,为此衍生出了无数的模拟滚动条的插件,这些插件可以使用 CSS 来美化滚动条。当然,在实际的项目中,还有其他常见的场景。

1. 无滚动条但依然可以滚动

实际内容超过了容器的高度,只能使用滚轮进行滚动。这种情形下,默认只能进行垂直滚动,不能进行上下滚动。当然,如果要实现滚轮进行横向滚动,这就需要借助 js 添加滚轮事件。这一小节里,我们只讨论垂直滚动的情况。

其实实现无滚动条但依然可以滚动,不用任何的 js 就能实现:比如.content是一个有滚动条的容器,他的高度和宽度分别是width:400px; height:300px;,我们可以在.content外面再添加一个 div(.wrap),让这个 div 的宽度正好遮住 .content 的滚动条:

COPYHTML

<style type="text/css"> .wrap { width: 400px; height: 300px; overflow: hidden; /* 遮住滚动条 */ border: 1px solid #aaa; } .content { width: 417px; /* 一般滚动条的宽度差不多是17px */ height: 300px; overflow: auto; } </style> <div class="wrap"> <div class="content"> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> <p> Curabitur rhoncus tortor eget orci fringilla non semper magna aliquet. Aliquam convallis elit sem. Proin fringilla fermentum pretium. Phasellus id nisl eu eros convallis eleifend. </p> <p> In hac habitasse platea dictumst. In at felis massa. Maecenas vitae quam non elit porta pellentesque ac in erat. Nullam a ante felis, ullamcorper suscipit felis. Maecenas sit amet nisl mattis ipsum ullamcorper aliquam vitae sed sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. </p> <p> Sed sed tellus dolor, non lobortis felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In eget nisl viverra risus feugiat vulputate tempus et leo. </p> <p> Nam metus nibh, tristique non sodales non, interdum et neque. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet aliquet vestibulum. Curabitur viverra tortor augue, a aliquet tellus. Vivamus eu felis vel lorem tincidunt imperdiet. Fusce iaculis luctus convallis. </p> <p> Proin adipiscing malesuada enim, et feugiat tortor sagittis eu. Cras convallis felis eu leo tempus et fermentum urna accumsan. In quis metus at metus ultricies fringilla. Maecenas sed lacus aliquam nibh semper dignissim et quis est. </p> </div> </div>

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Curabitur rhoncus tortor eget orci fringilla non semper magna aliquet. Aliquam convallis elit sem. Proin fringilla fermentum pretium. Phasellus id nisl eu eros convallis eleifend.

In hac habitasse platea dictumst. In at felis massa. Maecenas vitae quam non elit porta pellentesque ac in erat. Nullam a ante felis, ullamcorper suscipit felis. Maecenas sit amet nisl mattis ipsum ullamcorper aliquam vitae sed sapien. Class aptent taciti sociosquadlitora torquent per conubia nostra, per inceptos himenaeos.

Sed sed tellus dolor, non lobortis felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptoshimenaeos.In eget nisl viverra risus feugiat vulputate tempus et leo.

Nam metus nibh, tristique non sodales non, interdum et neque. Lorem ipsum dolor sit amet,consecteturadipiscingelit.Sedimperdietaliquet vestibulum. Curabitur viverra tortor augue, a aliquet tellus. Vivamus eu felis vel lorem tincidunt imperdiet. Fusce iaculisluctus convallis.

Proin adipiscing malesuada enim, et feugiat tortor sagittis eu. Cras convallis felis eu leo tempus et fermentum urna accumsan. Inquis metus at metus ultricies fringilla. Maecenas sed lacus aliquam nibh semper dignissim et quis est.

这种方式没有兼容性问题,在任何浏览器都可以,技术上实现起来也很简单;唯一的缺点就是用户对滚动不太敏感,可能不知道需要滚动才能查看下面的内容。

2. 美化后的滚动条

这种情形下,需要的是浏览器自带的滚动条,依然不需要借助 js,只不过需要对滚动条进行美化;但是滚动条的美化是有浏览器兼容性的,只有 webkit 内核的浏览器(chrome, opera, safari 等)才支持,firefox 到目前位置还不支持滚动条美化,IE 浏览器只支持修改滚动条的颜色,其他的则无法修改。

我们先来看看 webkit 下滚动条的美化,webkit 下是使用的伪元素

COPYCSS

/* 设置垂直滚动条的宽度和水平滚动条的高度 */ .demo::-webkit-scrollbar { width: 8px; height: 8px; } /* 设置滚动条的滑轨 */ .demo::-webkit-scrollbar-track { background-color: #ddd; } /* 滑块 */ .demo::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, 0.6); border-radius: 4px; } /* 滑轨两头的监听按钮 */ .demo::-webkit-scrollbar-button { background-color: #888; display: none; } /* 横向滚动条和纵向滚动条相交处尖角 */ .demo::-webkit-scrollbar-corner { /*background-color: black;*/ }

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Curabitur rhoncus tortor eget orci fringilla non semper magna aliquet. Aliquam convallis elit sem. Proin fringilla fermentum pretium. Phasellus id nisl eu eros convallis eleifend.

In hac habitasse platea dictumst. In at felis massa. Maecenas vitae quam non elit porta pellentesque ac in erat. Nullam a ante felis, ullamcorper suscipit felis. Maecenas sit amet nisl mattis ipsum ullamcorper aliquam vitae sed sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

Sed sed tellus dolor, non lobortis felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In eget nisl viverra risus feugiat vulputate tempus et leo.

Nam metus nibh, tristique non sodales non, interdum et neque. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet aliquet vestibulum. Curabitur viverra tortor augue, a aliquet tellus. Vivamus eu felis vel lorem tincidunt imperdiet. Fusce iaculis luctus convallis.

Proin adipiscing malesuada enim, et feugiat tortor sagittis eu. Cras convallis felis eu leo tempus et fermentum urna accumsan. In quis metus at metus ultricies fringilla. Maecenas sed lacus aliquam nibh semper dignissim et quis est.

看了上面美化滚动条的属性,如果不考虑兼容性的问题,我们还可以使用-webkit-scrollbar来隐藏滚动条,不用再在外面套一个 div 了,而且依然可以滚动。

IE 浏览器下滚动条下,使用样式进行美化,而且只能修改颜色:

  • scrollbar-arrow-color: color; /三角箭头的颜色/

  • scrollbar-face-color: color; /立体滚动条的颜色(包括箭头部分的背景色)/

  • scrollbar-3dlight-color: color; /立体滚动条亮边的颜色/

  • scrollbar-highlight-color: color; /滚动条的高亮颜色(左阴影?)/

  • scrollbar-shadow-color: color; /立体滚动条阴影的颜色/

  • scrollbar-darkshadow-color: color; /立体滚动条外阴影的颜色/

  • scrollbar-track-color: color; /立体滚动条背景颜色/

  • scrollbar-base-color:color; /滚动条的基色/

当前样式只在 IE 下有效果:

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Curabitur rhoncus tortor eget orci fringilla non semper magna aliquet. Aliquam convallis elit sem. Proin fringilla fermentum pretium. Phasellus id nisl eu eros convallis eleifend.

In hac habitasse platea dictumst. In at felis massa. Maecenas vitae quam non elit porta pellentesque ac in erat. Nullam a ante felis, ullamcorper suscipit felis. Maecenas sit amet nisl mattis ipsum ullamcorper aliquam vitae sed sapien. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

Sed sed tellus dolor, non lobortis felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In eget nisl viverra risus feugiat vulputate tempus et leo.

Nam metus nibh, tristique non sodales non, interdum et neque. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed imperdiet aliquet vestibulum. Curabitur viverra tortor augue, a aliquet tellus. Vivamus eu felis vel lorem tincidunt imperdiet. Fusce iaculis luctus convallis.

Proin adipiscing malesuada enim, et feugiat tortor sagittis eu. Cras convallis felis eu leo tempus et fermentum urna accumsan. In quis metus at metus ultricies fringilla. Maecenas sed lacus aliquam nibh semper dignissim et quis est.

3. 自定义滚动条

自定义滚动条借助 js 里的滚轮事件,mousemove 事件等,使用 div 来模拟一个滚动条,然后根据位移,滚动条和内容移动相应的距离。

这里需要先定义几个简单的变量:

  • wrap_height : 外层容器的高度

  • content_height : 内容的实际高度,通常大于外层容器的高度

  • content_dis : 内容当前的位置

  • bar_height : 滚动条的长度

  • bar_dis : 滚动条当前的位置

滚动条与其滚动区域的比例和外层容器与实际内容的比例是相等的,这样就能计算出滚动条的长度,即:

COPYJAVASCRIPT

bar_height / wrap_height = wrap_height / content_height; bar_height = (wrap_height * wrap_height) / content_height; // 滚动条的长度

同理,滚动条滚动的距离与内容滚动的距离也是成比例的,因为我们实际操作的是滚动条,通过这个我们能知道滚动条滚动的距离后,得出内容滚动的距离:

COPYJAVASCRIPT

bar_dis / (wrap_height - bar_height) = content_dis / (content_height - wrap_height); content_dis = ((content_height - wrap_height) * bar_dis) / (wrap_height - bar_height); // 内容当前的位置

滚动条和内容的滚动,实际上是修改这两者的top值。接下来就是为滚动条添加mousedown, mousemove, mouseup事件,通过这些事件修改滚动条的 top 值。在鼠标按下(mousedown)时,获取鼠标当前的 pageY1(IE 不支持 pageX、pageY 属性,但支持 offsetX、offsetY)和滚动条的 top 值,然后在鼠标移动(mousemove)时,再获取鼠标的 pageY2(offsetY),根据两个 pageY,计算出鼠标的偏移量(pageY2-pageY1),即滚动条的偏移量 bar_diff。bar_diff 加上滚动条初始时的 top 值,就是滚动条现在的 top 值。根据上面的公式也能计算出内容的偏移量。

这里简单的写下:

COPYJAVASCRIPT

$scroll_bar.css('height', scroll_bar_height).on('mousedown', function (event) { var $this = $(this), startX = event.pageY, top = $this.position().top; $(document) .on('mousemove', function (e) { var diff = e.pageY - startX; changePos(top + diff); }) .on('mouseup', function (event) { $(this).off('mousemove mouseup'); this.releaseCapture && this.releaseCapture(); }); this.setCapture && this.setCapture(); }); // 设置滚动条和内容的top值 // end表示滚动条当前滚动到的位置 function changePos(end) { if (end < 0) { end = 0; } else if (end > obj_height - scroll_bar_height) { end = obj_height - scroll_bar_height; } $scroll_bar.css('top', end); $scroll_con.css('top', (-(scroll_con_height - obj_height) * end) / (obj_height - scroll_bar_height)); }

如果容器的高度可能随着窗口变化,或者其他原因导致容器的高度发生变化,都需要重新计算滚动条的长度和能够滚动的区域。

张鑫旭大神在他自己的博客里曾经总结过关于滚轮的事件,这里拿来一下,相关链接请下拉到最后:

COPYJAVASCRIPT

var addEvent = (function (window, undefined) { var _eventCompat = function (event) { var type = event.type; if (type == 'DOMMouseScroll' || type == 'mousewheel') { event.delta = event.wheelDelta ? event.wheelDelta / 120 : -(event.detail || 0) / 3; } //alert(event.delta); if (event.srcElement && !event.target) { event.target = event.srcElement; } if (!event.preventDefault && event.returnValue !== undefined) { event.preventDefault = function () { event.returnValue = false; }; } /* ......其他一些兼容性处理 */ return event; }; if (window.addEventListener) { return function (el, type, fn, capture) { if (type === 'mousewheel' && document.mozHidden !== undefined) { type = 'DOMMouseScroll'; } el.addEventListener( type, function (event) { fn.call(this, _eventCompat(event)); }, capture || false, ); }; } else if (window.attachEvent) { return function (el, type, fn, capture) { el.attachEvent('on' + type, function (event) { event = event || window.event; fn.call(el, _eventCompat(event)); }); }; } return function () {}; })(window);

4. 使用 mCustomScrollbar

4.1 基本介绍

在第 3 小节只是简单的介绍了插件的编写,现在市面上已经有了很多成熟的插件,这里简单的介绍下 jQuery 插件mCustomScrollbar的使用方法。

mCustomScrollbar 提供了很多滚动条的样式(theme),同时还有不同的滚动方式,比如有:普通的垂直滚动,水平滚动,设置两端的箭头,进入区域显示滚动条离开区域隐藏,滚动固定距离(适用于表格,图片等场景),容器高度或宽度变化时滚动条自适应,js 追加内容时滚动条自适应等。

写几个推荐的理由吧:

  • 能使用class同时为多个容器添加滚动条,每个容器单独独立计算,互不影响

  • 兼容 IE6+

  • 26 个主题样式可供选择

  • 多种滚动方式:垂直滚动,水平滚动,固定距离滚动等

  • 对外提供了很多的参数和回调方法

使用的方法也很简单:

1.CSS: 如果要添加滚动条,容器需要是块状元素(display:block),且有高度或最大高度;如果是需要添加水平滚动条,则需要有宽度或最大宽度。当然,高度或宽度也可以在调用插件时设置(setWidth, setHeight)。

COPYHTML

<link rel="stylesheet" href="jquery.mCustomScrollbar.css" />

2.引入 js:

COPYHTML

// 因为插件是基于jQuery的,所以 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="jquery.mCustomScrollbar.concat.min.js"></script>

调用方法:

COPYHTML

<script> (function ($) { $(function () { $('.content').mCustomScrollbar(); }); })(jQuery); </script>

3.参数:

axis: 默认情况下,插件添加是垂直滚动条,不过我们可以通过参数来添加axis来设置我们想要的滚动条:y(垂直滚动条),x(水平滚动条),yx(同时添加垂直和水平滚动条)

COPYJAVASCRIPT

$('.content').mCustomScrollbar({ axis: 'x', });

theme: 设置滚动条的风格,该插件提供了 26 种风格的滚动条,【点此查看风格】。

COPYJAVASCRIPT

$('.content').mCustomScrollbar({ theme: 'dark', });

4.2 参数介绍

在 4.1 里介绍了两个参数,接下来再翻译一些参数,更详细的还请点这里查看官网【官网参数介绍】。

使用说明:

COPYJAVASCRIPT

$(selector).mCustomScrollbar({ option: value });

COPYJAVASCRIPT

$('#content').mCustomScrollbar({ theme : 'dark', scrollbarPosition : 'outside', // 滚动线的位置,在容器内部还是外部 inside(default)|outside (如果容器的position是static值,则添加position:relative) setTop : '-100px', // **内容**初始时距离顶部的距离 setLeft : '-100px', // **内容**初始时距离左端的距离 setWidth : '400px', // 设置容器的宽度,此设置将覆盖css属性,单位可以是px|% setHeight : '600px', // 设置容器的高度,同setWidth axis : 'yx' // 设置滚动的类型:y(垂直滚动条,默认), x(水平滚动条), yx(垂直和水平同时设置) scrollInertia : 1000, // 设置内容滚动时动画的缓冲时间(单位:ms),值为0则没有缓冲效果 autoDraggerLength : false, // 是否自动调整滚动条的长度 true(default)|false autoHideScrollbar : true, // 是否自动隐藏滚动条 autoExpandScrollbar : true, // 鼠标放在滚动区域时,是否自动放大滚动条 true|false(default) alwaysShowScrollbar : 1, // 当内容过短不至于产生滚动条时,是否依然显示滚动条: 0(不显示,default) | 1(只显示轨道但没有滚动条和两端的箭头) | 2(所有都显示) snapAmount : 60, // 滚动固定的长度,主要用于表格,幻灯片等(请注意,您的元素必须是相等的宽度或高度,以便使其正常工作);若y轴和x轴设定的长度不一样,可以用数组设置[y, x] mouseWheel :{ // 滚轮设置 enable : true, // 是否可以用滚轮进行滚动 scrollAmount : 30, // 内容滚动的距离, "auto"将根据情况自动调整滚动量 axis : 'y', // 同上 preventDefault : false, // 当 当前容器的滚动条在两端时,是否接着滚动父级容器的滚动条 true(default) | false invert : true, // 滚轮反向,设置为true后,当滚轮向上滚动时,滚动条会向下或向右滚动 disableOver : ["select"] }, scrollButtons :{ // 两端箭头的设置 enable : true, // 是否启用箭头 scrollAmount : 30, // 点击按钮时,内容滚动的距离, "auto"将根据情况自动调整滚动量 scrollType : "stepped", // 点击按钮不松开时滚动的类型: "stepless"(按钮一直按下时,内容持续滚动), "stepped"(每次按下时,内容只滚动一次,滚动的距离是**scrollAmount**设置的值) tabindex : 2 }, keyboard : { // 键盘设置 enable : true, // 是否启用键盘操作内容的滚动,支持四个方向键(上,下,左,右),Home键,End键,PageUp键,PageDown键 scrollAmount : 30, // 内容滚动的距离, "auto"将根据情况自动调整滚动量 scrollType : "stepped" // 按键不松开时滚动的类型: "stepless"(按键一直按下时,内容持续滚动), "stepped"(每次按下时,内容只滚动一次,滚动的距离是**scrollAmount**设置的值) }, contentTouchScroll : 50, // 触屏滑动内容时,内容滚动的距离,(默认是25);若要禁止触屏滑动,则设置为false advanced : { // 高级设置 updateOnContentResize : true, // 当内容,容器或窗口发生变化时,是否自动更新滚动条 updateOnImageLoad : true, // 容器内的图片完全加载完成时,是否自动更新滚动条 updateOnSelectorChange : 'ul li', // 当特定元素的个数发生变化时,是否自动更新滚动条 autoUpdateTimeout : 40 // 设置自动更新的时间(单位:ms),默认是60ms }, callbacks : { // 回调函数 // A function to call when plugin markup is created. (怎么翻译?) onCreate : function(){ console.log( 'create' ); }, // 当滚动条初始化完成时触发 onInit : function(){ console.log( 'init' ); }, // 滚动条开始滚动时触发 onScrollStart : function(){ console.log( 'scroll start...' ); }, // 滚动条在滚动过程中触发 whileScrolling : function(){ console.log( Date.now() ); }, // 滚动结束时触发 onScroll : function(){ console.log( 'scroll end...' ); }, // 当滚动结束且滚动条在最底部或最右端时触发 onTotalScroll : function(){ console.log( 'bottom or right' ); }, // 当滚动结束且滚动条在最顶部或最左端时触发 onTotalScrollBack : function(){ console.log( 'top or left' ); }, onTotalScrollOffset : 100, // 设置 onTotalScroll 触发的offset值,如设置为100,则当滚动条距离底部或右端 <=100时,触发 onTotalScroll onTotalScrollBackOffset : 100, // 设置 onTotalScrollBack 触发的offset值,触发同上 alwaysTriggerOffsets : true, // 当 onTotalScroll, onTotalScrollBack 在设置的offset内,是否一直触发;若设置为false,则每次滚动到范围内只触发一次(若离开offset范围后再次进入,还会触发,但只有一次) // 当垂直方向出现滚动条时 onOverflowY : function(){ console.log( '垂直方向出现了滚动条' ) }, // 当水平方向出现滚动条时 onOverflowX : function(){ console.log( '水平方向出现了滚动条' ); }, // 当垂直方向内容减少到滚动条消失时 onOverflowYNone : function(){ }, // 当水平方向内容减少到滚动条消失时 onOverflowXNone: function(){ }, // 滚动条发生变化之前 onBeforeUpdate : function(){ }, // 滚动变化之后 onUpate : function(){ } } });

5. 总结

其实现在出现这么多关于滚动条的情况,主要是前端发展太快,现在前端的页面很多,有各种酷炫的页面,各个页面需要不同样式的滚动条,而关于滚动条方面的标准却跟不上,目前只有 webkit 内核能对滚动条进行美化,其他内核的浏览器只能通过 js 事件进行模拟。

不过话说回来,即使所有浏览器都能进行滚动条的美化了,可能出现还有其他方面的要求,比如mCustomScrollbar中滚动时的缓冲效果。

参考链接:

标签:
阅读(1247)

公众号:

qrcode

微信公众号:前端小茶馆

公众号:

qrcode

微信公众号:前端小茶馆