百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

七爪源码:纯 CSS 和 JS 的原生平滑滚动

zhezhongyun 2024-12-26 17:42 49 浏览

纯 CSS 和 JS 的原生平滑滚动

你想要一个平滑的滚动吗? 忘记 JQuery,我们已经过去了。 让我向您介绍我们的原生平滑滚动工具。


CSS 滚动行为

CSS scroll-behavior 属性接受三个值之一 - 实际上是两个值,因为其中一个已被弃用。

  1. scroll-behavior: auto 是我们已经习惯的默认即时滚动行为。
  2. scroll-behavior:instant 与 auto 相同,这就是它被弃用的原因。 如果你想要它,只需使用自动。
  3. scroll-behavior: smooth 在以编程方式触发滚动事件时应用平滑过渡。

我说“以编程方式触发”是因为它不会平滑滚动鼠标滚轮。

以编程方式触发滚动事件的一些方法是:

-    Window.scrollTo()
-    Window.scrollBy()
-    Element.scrollTo()
-    Element.scrollBy()
-    Element.scrollIntoView()
-    Element.scrollLeft = x
-    Element.scrollTop = y

我们将分别探索这些方法。


(注)Window.scroll() 和 Element.scroll()

也许你已经注意到我没有提到 scroll() 方法。

这是因为 Window.scroll() 和 Element.scroll() 实际上是与 Window.scrollTo() 和 Element.scrollTo() 相同的方法。为避免重复内容,我将仅参考 scrollTo()。在实践中,您可以使用任何一种,只需选择一个并保持一致。


Window.scrollTo() 和 Element.scrollTo()

此方法非常适合滚动到绝对坐标。如果您有要将用户滚动到的位置的 x 和 y 坐标,您可以简单地调用 window.scrollTo(x, y) ,它会尊重页面的 CSS 滚动行为。

这同样适用于可滚动元素。您只需调用 element.scrollTo(x, y) ,它就会尊重元素的 CSS 滚动行为。

这个方法还有一个新的签名,它使用一个对象而不是两个数字参数,通过这个新的签名,我们可以显式地设置我们的滚动行为。

// For window
window.scrollTo({
  left: x,
  top: y,
  behavior: 'smooth'
});
// For element
const el = document.querySelector(...);
el.scrollTo({
  left: x,
  top: y,
  behavior: 'smooth'
});


Element.scrollLeft 和 Element.scrollTop

设置元素 .scrollLeft 和 .scrollTop 属性与使用坐标调用 Element.scrollTo() 相同。 它将尊重元素的 CSS 滚动行为。

const el = document.querySelector(...);
const x = 100;
const y = 500;
// Setting .scrollLeft and .scrollTop with smooth scroll
el.style.scrollBehavior = 'smooth';
el.scrollLeft = x;
el.scrollTop = y;
// Is the same as calling Element.scrollTo()
el.scrollTo({ left: x, top: y, behavior: 'smooth' });


(注)负元素.scrollLeft

如果你的元素文本的方向是 rtl,scrollLeft = 0 表示水平滚动的最右边位置,并且随着你向左移动,值会减小。

对于宽度为 100px,可滚动宽度为 500px,方向为 rtl 的可滚动元素,最左边的位置是 scrollLeft = -400。

<div id="scrollable" style="width: 100px; overflow: auto" dir="rtl">
  <div style="width: 500px; height: 100px; background: green"></div>
</div>
<p id="output"></p>
const scrollable = document.querySelector('#scrollable');
const output = document.querySelector('#output');
const updateOutput = () => {
  output.textContent = `scrollLeft: ${scrollable.scrollLeft}`;
};
updateOutput();
scrollable.addEventListener('scroll', updateOutput);


Window.scrollBy() 和 Element.scrollBy()

此方法与 Window.scrollTo() 或 Element.scrollTo() 具有完全相同的签名。 它接受 x 和 y 作为两个数字参数或作为具有可选 left、top 和 behavior 属性的对象的单个参数。

这里的区别是我们不是传递绝对坐标,而是相对值。 如果我们 scrollBy({ top: 10 }),我们从当前位置向下滚动 10 个像素,而不是从页面开头向下滚动 10 个像素。

// For window
window.scrollBy({ top: 10 }); // Scroll 10px down
window.scrollBy({ left: 20 }); // Then 20px to the right
window.scrollBy({ top: 50 }); // And then 50px down
// For element
const el = document.querySelector(...);
el.scrollBy({ top: 10 }); // Scroll 10px down
el.scrollBy({ left: 20 }); // Then 20px to the right
el.scrollBy({ top: 50 }); // And then 50px down


(注) Window.scrollByLines() 和 Window.scrollByPages()

Firefox 更进一步,实现了滚动多行或多页的方法。 这是一个仅适用于 Firefox 的非标准功能,因此您可能不想在生产中使用它。

通过将 100vh(用于页面)和 1rem(用于行)转换为像素并将该值传递给 Window.scrollBy(),您可以在所有主要浏览器中实现类似的效果。

const toPixels = require('to-px'); // From NPM
const page = toPixels('100vh');
window.scrollBy(0, page); // window.scrolByPages(1)
const line = toPixels('1rem');
window.scrollBy(0, line); // window.scrolByLines(1)


Element.scrollIntoView()

但大多数时候,我们并不关心任何硬编码的坐标,我们只想将用户滚动到屏幕上的特定元素。 这可以通过 Element.scrollIntoView() 轻松(更明确地)完成。

可以不带参数调用此方法,它将滚动页面(尊重 CSS 滚动行为)直到元素在顶部对齐(除非元素在页面底部,在这种情况下,它会 尽可能滚动)。

<div style="height: 2000px">Some space</div>
<div id="target" style="background: green">Our element</div>
<div style="height: 500px">More space</div>
const target = document.querySelector('#target');
target.scrollIntoView();

您可以通过传递布尔值或对象来进一步自定义元素在视图中的位置。

const el = document.querySelector(...);
// Default, aligns at the top
el.scrollIntoView(true);
// Aligns at the bottom
el.scrollIntoView(false);
// Aligns vertically at the center
el.scrollIntoView({ block: 'center' });
// Vertical top and horizontal center
el.scrollIntoView({ block: 'start', inline: 'center' });
// Vertical bottom and horizontal right
el.scrollIntoView({ block: 'end', inline: 'end' });
// Vertical center and smooth
el.scrollIntoView({ block: 'center', behavior: 'smooth' });
// Vertical nearest
el.scrollIntoView({ block: 'nearest' });

当使用一个对象来定义元素的位置时,注意 block 是指垂直放置,而 inline 是指水平放置。此外,“最近”的位置可以是顶部/左侧或底部/右侧,以最近的为准,如果元素已经在视图中,它也可以是空的。


浏览器支持

{关于浏览器支持} 在撰写本文时,所有主流浏览器(Safari 除外)都支持平滑滚动和本文中描述的滚动方法。

如果你需要更多的保证,我在我的项目中使用了一个非常好的平滑滚动 polyfill。它填充了 scroll()、scrollTo()、scrollBy()、scrollIntoView() 和 CSS 滚动行为。它不支持通过设置 scrollLeft/scrollTop 来平滑滚动,也不支持 scrollIntoView() 选项(它总是在顶部对齐元素)。

如果你有更多的好奇心,我强烈建议你研究一下 polyfill 的源代码,总共不到 500 行。我做了一个 PR 来稍微改进文档,你可能会发现代码更容易理解。


祝你有美好的一天,很快见到你。

相关推荐

3 分钟!AI 从零开发五子棋全过程曝光,网友:这效率我服了

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8...

一行代码实现display&quot;过渡动画&quot;原理

作者:Peter谭老师转发链接:https://mp.weixin.qq.com/s/XhwPOv62gypzq5MhhP-5vg写本文的起因上篇文章,提到如何让display出现过渡动画,却没有仔...

脑洞:琼恩·雪诺、蝙蝠侠和魔形女的灵魂宠物了解一下

AlekseiVinogradovisaRussianfreelancedigitalartistwhoshareshisskillsandtalentwith120k...

浏览器的渲染机制、重绘、重排

1、什么是重排和重绘网页生成过程:HTML被HTML解析器解析成DOM树css则被css解析器解析成CSSOM树结合DOM树和CSSOM树,生成一棵渲染树(RenderTree)生成布局(flo...

托福写作高频考题写作思路&amp;词汇丨考虫独家

科技话题与媒体话题是托福写作的常考话题很多考生对这两类话题里的专有词汇表达也许很不了解所以今天就跟随考虫托福写作老师刘云龙老师一起来学习在这些话题的写作里你可以使用哪些有用的表达。希望大家有收获!记得...

在优麒麟上使用 Electron 开发桌面应用

使用Web标准来创建桌面GUI,上手快、成本低、跨平台、自适应分辨率,这些都是Electron的优势。作者/来源:优麒麟Electron是由Github开发,用HTML、CSS和...

php手把手教你做网站(三十八)jquery 转轮盘抽奖,开盲盒

抽奖和开盲盒性质一样的都是通过ajax读取后台的随机数据。1、转轮盘本来是想直接绘图实现轮盘,但是没有找到怎么填充文字,只好把轮盘弄成了背景图,通常用于游戏抽道具,商城积分抽奖,公司年末员工抽奖点击抽...

用 CSS 整活!3D 轮播图手把手教学,快乐代码敲出来

兄弟们,今天咱来搞点好玩的——用CSS整一个3D轮播图!咱野生程序员就是要在代码里找乐子,技术和快乐咱都得要!代码是写不完的,但咱能自己敲出快乐来,走起!一、先整个容器,搭个舞台咋先写一个...

实现一个超酷的 3D 立体卡片效 #前端开发

今天我们来实现一个超酷的3D立体卡片效果。正常情况下就是一个普通的图片展示卡片,鼠标悬停的时候图片会跳出卡片,并将影子投射到背景卡片上,在视觉上有一个3D立体感。html主要分成3个部分:容器→背景层...

Vue 3 Teleport与Suspense:解决UI难题的两个&quot;隐藏大招&quot;

模态框的"层级噩梦"与Teleport的救赎"这个模态框怎么又被父容器截断了?"团队协作开发后台系统时,小张第N次遇到这个问题。多层嵌套的组件结构里,弹窗被overfl...

让交互更加生动!有意思的鼠标跟随 3D 旋转动效

今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现:简单分析一下,这个交互效果主要有两个核心:借助了CSS3D的能力元素的旋转需要和鼠标的移动相结合本文,就将讲述如何使用纯CSS...

填坑:transform元素导致zindex失效终极方法

今天遇到了使用css3动画的元素层级被放大置顶的问题,ios浏览器上没问题,安卓原生浏览器和安卓微信上有问题。使用了css3动画的元素z-index失效,兄弟元素设置多高的z-index都盖不住解决办...

诡异的层级错乱:一个被transform隐藏的CSS陷阱

周五下午三点十七分,设计部突然发来紧急截图——原本应该悬浮在顶部的导航菜单,此刻正诡异地被下方的轮播图遮挡。我盯着屏幕上错乱的层级关系,手指下意识地敲下z-index:9999,心里清楚这不过是程序...

动画篇--碎片动画

本文授权转载,作者:Sindri的小巢(简书)前言从最开始动笔动画篇的博客,至今已经过去了四个多月。这段时间回头看了看自己之前的动画文章,发现用来讲解动画的例子确实不那么的赏心悦目。于是这段时间总是想...

Nature:大洋转换断层处的拉张构造与两阶段地壳增生

Nature:大洋转换断层处的拉张构造与两阶段地壳增生转换断层是三种基本的板块边界之一,全球总长度超过48000km(Bird,2003),它们的发现为板块构造理论的建立奠定了重要的基础(Wil...