- 作者:陈大鱼头
- github: KRISACHAN
前言
在日常的开发中,我们对
例如因为看不惯浏览器默认样式而用 JS 一顿猛如虎操作的 自定义滚动条 。
或者是嗖~一下就到顶的 回到顶部 。
又或者是想去哪点哪的 标题导航 。
但是在过去的开发中,要实现这些功能并不是那么轻松的一件事情。
例如我们要实现一个有滚动效果的 回到顶部 功能,我们可能需要写下这些代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let timer = null; let backTop = document.querySelector("#backTop"); backTop.addEventListener("click", () => { cancelAnimationFrame(timer); let startTime = +new Date(); let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; let totalTime = 300; timer = requestAnimationFrame(() => { let lastTime = totalTime - Math.max(0, startTime - +new Date() + totalTime); document.documentElement.scrollTop = document.body.scrollTop = (lastTime * -scrollTop) / totalTime + scrollTop; timer = requestAnimationFrame(func); if (lastTime === totalTime) { cancelAnimationFrame(timer); } }); }); |
(免责声明:伪代码未经测试,如有 BUG,跪求原谅。)
嘤,意思就是要写个动画,不断修改当前页面的垂直滚动距离,直到为 0。
(吃瓜群众:“很难嘛?是你太菜了吧,大叔!”)
但其实随着时间的推移, web api 以及 css 规范的不断改进,那些我们曾经认为实现起来很麻烦的功能也变得简单了起来。下面我们可以一起来探讨一下这些改进的内容。
Web API 中的 scroll 家族
我们来康康 scroll 家族 里有趣的 API。
scroll 与 scrollTo
语法如下:
- scroll/scrollTo(x, y)
x :元素要移动的位置横坐标。y :元素要移动的位置纵坐标。
- scroll/scrollTo(options)
top :元素要移动的位置横坐标。lef: :元素要移动的位置纵坐标。behavior :元素的运动模式,如果是auto ,则没有动画效果,如果是smooth ,则是平滑滚动。
我们来康康栗子:
上面例子来自 MDN 的 GitHub 仓库dom-examples
核心 JS 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let scrollOptions; const form = document.querySelector("form"); const leftInput = document.getElementById("left"); const topInput = document.getElementById("top"); const scrollInput = document.getElementById("scroll"); form.addEventListener("submit", e => { e.preventDefault(); scrollOptions = { left: leftInput.value, top: topInput.value, behavior: scrollInput.checked ? "smooth" : "auto" }; window.scrollTo(scrollOptions); }); |
scrollBy
语法如下:
- scrollBy(x, y)
x :元素要移动的位置横坐标。y :元素要移动的位置纵坐标。
- scrollBy(options)
top :元素要移动的位置横坐标。lef: :元素要移动的位置纵坐标。behavior :元素的运动模式,如果是auto ,则没有动画效果,如果是smooth ,则是平滑滚动。
再举个栗子:
核心代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let scrollOptions; const form = document.querySelector("form"); const leftInput = document.getElementById("left"); const topInput = document.getElementById("top"); const scrollInput = document.getElementById("scroll"); form.addEventListener("submit", e => { e.preventDefault(); scrollOptions = { left: leftInput.value, top: topInput.value, behavior: scrollInput.checked ? "smooth" : "auto" }; window.scrollBy(scrollOptions); }); |
Mmmmm,没错,就是只是把上面的 DEMO 中的
Element.scrollIntoView
**
语法如下:
- scrollIntoView(alignToTop)
如果值为
- scrollIntoView(scrollIntoViewOptions)
behavior :元素的运动模式,如果是auto ,则没有动画效果,如果是smooth ,则是平滑滚动。block :定义垂直方向的对齐方式,值可以是start ,center ,end 或nearest 之一。默认为nearest 。inline :定义水平方向的对齐方式,值可以是start ,center ,end 或nearest 之一。默认为nearest 。
来来来,我给大家解释一下
start :跟当前元素它爹的头发(顶部)对齐。center :跟当前元素它爹的肚子(中间)对齐。end :跟当前元素它爹的 jio(底部)对齐。nearest :就近原则,挨哪里近去哪,如果在中间就不动。
如果是
有点绕?快来康康栗子呀:https://codepen.io/krischan77/pen/mdJMQpz
好了,上述就是杀马特,哦不是,
CSS scroll
分享完 JS 中的
scroll-behavior
我们上面在讲这个 JS 中的
Mmmm,所以你们猜猜这个
嗯,没错,你们猜对啦,是有关系的。
(吃瓜群众:“都没人理你~”)
如果定义为
其效果可以参照本文第一小节的 DEMO。
Scroll Snap
CSS Scroll Snap 是 CSS 中一个比较新的独立模块,它的第一个正式版本CSS Scroll Snap 模块 Level 1也是在 2019 年 3 月 19 日才发布。
CSS Scroll Snap 模块 可以让页面容器停止滚动时,捕捉并让其自动滑动到指定元素的指定位置。
一给我哩 giaogiao!这可是非常了不起的特性啊~
它分了两部分,一部分作用于滚动容器上,一部分作用于相对的滚动子元素上,具体关系如下表:
| 作用于滚动容器 | 作用于滚动子元素 |
|---|---|
| scroll-snap-type | scroll-snap-align |
| scroll-padding | scroll-snap-stop |
| scroll-margin |
scroll-snap-type
它可选的方向值有:
- x :捕捉 X 轴上的位置
- y :捕捉 Y 轴上的位置
- block :捕捉块轴上的位置(逻辑意义上与 y 意义)
- inline :捕捉内联轴上的位置(逻辑意义上与 x 意义)
- both :捕捉两个方向上的位置
它可选的严格值有:
- none :默认值,Mmmm,啥也不干
- proximity :一个感性的值,如果元素进入到了容器的捕捉位置范围内,则进行捕捉并滚动,否则就不管,至于这个范围是多少,约莫着 45%的位置吧(手动测的,W3C 没给出具体算法,瞎猜吧,哈哈哈)。
- mandatory :一个靠谱点的值,只要有参数,停止滚动时就肯定能对齐。
我们来康康这玩意到底是啥效果:
以上 DEMO 来自于 MDN 的scroll-snap-type
####scroll-snap-align
- none :默认值,啥也不干 0.0。
- start :跟开始位置对齐。
- end :跟结束位置对齐。
- center :居中对齐。
效果如下:
以上 DEMO 来自于 Andy Adams 的scroll-snap-align
####scroll-snap-stop
因为 Scroll Snap 元素会有几个捕捉的位置,而
- normal :默认值,滚动的时候,可以忽略捕捉位置。
- always :滚动的时候,不能忽略捕捉位置,还必须定位到第一个捕捉元素的位置。
栗子如下:
以上 DEMO 来自于 MDN 的scroll-snap-stop
scroll-margin
当我们点击
普通操作:
1 2 | h3 { } |
添加了
1 2 3 | h3 { scroll-margin-top: 5rem; } |
上面 DEMO 来自于 Chris Coyier 的Fixed Headers and Jump Links? The Solution is scroll-margin-top
从上面的两个 DEMO,我们可以清晰地对比,假设
不仅如此,我们再看下面的 DEMO:
以上 DEMO 源自于 Andy Adams 的scroll-margin
当我们设置了
scroll-margin-top scroll-margin-right scroll-margin-bottom scroll-margin-left scroll-margin-block scroll-margin-inline scroll-margin-block-start scroll-margin-inline-start scroll-margin-block-end scroll-margin-inline-end
scroll-padding
来个 DEMO:
以上 DEMO 源自于 Andy Adams 的scroll-padding
scroll-padding-top scroll-padding-right scroll-padding-bottom scroll-padding-left scroll-padding-block scroll-padding-inline scroll-padding-block-start scroll-padding-inline-start scroll-padding-block-end scroll-padding-inline-end
CSS overscroll
overscroll-behavior
它也是个简写属性,具体的属性有:
- overscroll-behavior-x :正常情况下,处理横轴滚动条滚动到边界时的表现。
- overscroll-behavior-y :正常情况下,处理纵轴滚动条滚动到边界时的表现。
- overscroll-behavior-inline :跟
overscroll-behavior-x 一样。 - overscroll-behavior-block :跟
overscroll-behavior-y 一样
可选的值为:
- auto :默认值。
- contain :当一个元素滚动到边界时,不会再影响临近的滚动元素。
- none :当一个元素滚动到边界时,不仅不会不会再影响临近的滚动元素,连默认滚动到边界的表现都会被阻止。
栗子如下:
使用了
默认情况
课外姿势
新旧逻辑属性
不知道各位有没有注意上述各个属性的值,除了有常规的
所以这到底是什么呢?
其实是因为 W3C 为了照顾到非西文排序国家的书写习惯,特意修改了 CSS 的逻辑属性。
对于像我们国家或者是美国这样,文档排列是从上到下,从左到右的,
但是像日本或者阿拉伯等书写排列跟我们不一样的国家,在逻辑上就会有不合理的地方,例如:
- 在阿拉伯,他们的
padding-left 实际上方向是我们的padding-right - 在日本,他们的
padding-left 实际上方向是我们的padding-top
按照上面的情况,这就比较诡异。所以 W3C 出来新的逻辑属性,新旧的对比如下:
| 旧的逻辑属性 | 新的逻辑属性 |
|---|---|
| top | inset-block-start |
| bottom | inset-block-end |
| left | inset-inline-start |
| right | inset-inline-end |
| margin-top | margin-block-start |
| margin-right | margin-inline-end |
| margin-bottom | margin-block-end |
| margin-left | margin-inline-start |
| border-top | border-block-start |
| border-right | border-inline-end |
| border-bottom | border-block-end |
| border-left | border-inline-start |
| padding-top | padding-block-start |
| padding-right | padding-inline-end |
| padding-bottom | padding-block-end |
| padding-left | padding-inline-start |
| width | inline-size |
| height | block-size |
总结一下就是横坐标为
最后来个特效
这是一个利用
我们先来看看效果。
源码地址在这:
https://codepen.io/krischan77/pen/zYOjyry
由于代码太长,就不完全贴出来了,但是核心逻辑就是利用
1 2 3 4 5 6 7 8 9 10 11 12 13 | let pageIndex = 1; const urlChangeHandler = event => { const { newURL } = event; const current = newURL.replace(/.+\#page\-(\d)/, "$1"); pageIndex = +current; console.log(pageIndex); history.pushState( {}, window.location.href, window.location.origin + window.location.pathname ); }; window.onhashchange = urlChangeHandler; |
大家也不妨尝试下用所掌握的姿势增添点生活情趣呀~
后记
吃瓜群众:我看完了整篇,没看到哪里有跟忍术相关的内容啊?骗我流量,赔钱。
鱼头:没有又咋啦?说好的宠我,你现在凶我是什么意思?
参考资料
-
scrollIntoView block vs inline
-
CSSOM View Module
-
Element.scrollIntoView()
-
CSS Scroll Snap Module Level 1
-
CSS TRICK scroll-snap-type
-
MDN scroll-snap-type
-
CSS TRICK scroll-snap-align
-
scroll-snap-stop
-
scroll-margin
-
scroll-padding
-
Fixed Headers and Jump Links? The Solution is scroll-margin-top
如果你喜欢探讨技术,或者对本文有任何的意见或建议,非常欢迎加鱼头微信好友一起探讨,当然,鱼头也非常希望能跟你一起聊生活,聊爱好,谈天说地。
鱼头的微信号是:krisChans95
也可以扫码关注公众号,订阅更多精彩内容。