分步指南:使用 JavaScript 将光标位置传递给 CSS 变量
设置 HTML 和 CSS
创建事件监听器并在 JavaScript 中传递变量
将带有 CSS 变量的转换添加到您的 CSS
为什么应该使用 CSS 变量来传递事件行为
一个新世界刚刚开启!
我的网站有一个小插图,可以追踪你的光标位置。这里唯一用到的 JavaScript 代码就是将光标位置传递给 CSS 变量。其他部分都用 CSS 的二维变换来实现。
在本教程中,您将学习如何使用 CSS 变量将事件行为传递给 CSS。
设置 HTML 和 CSS
我们将创建一个正方形,里面有一个小红点。稍后我们将通过变换来控制这个小红点。
HTML 代码非常简单:
<div class="container">
<div class="tracker"></div>
</div>
CSS 会将正方形置于窗口中央,并将红点置于容器左上角。我还喜欢在 CSS 中设置 CSS 变量的默认状态。CSS 变量通常默认为 0,但您可能并不总是希望如此。
这是 CSS:
:root {
--x: 0.5;
--y: 0.5;
}
.container, .tracker {
position: absolute;
}
.container {
width: 200px;
height: 200px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 3px solid #333;
}
.tracker {
width: 10px;
height: 10px;
left: 0;
top: 0;
background: red;
border-radius: 1000px;
}
最终效果如下:
创建事件监听器并在 JavaScript 中传递变量
接下来,我们创建事件监听器并将事件行为传递给 CSS 变量。
让我们首先声明位置 x 和 y,然后添加事件监听器本身:
const pos = { x : 0, y : 0 };
document.addEventListener('mousemove', e => { saveCursorPosition(e.clientX, e.clientY); })
如你所见,我们将创建一个函数saveCursorPosition
。我们将在这里传递 CSS 变量。两个参数分别是事件的clientX
和clientY
,也就是光标位置。
为了使光标位置具有响应性,我们将值除以innerWidth
和innerHeight
,如下所示:
pos.x = (x / window.innerWidth).toFixed(2);
pos.y = (y / window.innerHeight).toFixed(2);
我用来toFixed(2)
对值进行四舍五入。
之后,我们终于可以将位置传递给 CSS 变量了!要选择根元素,请使用document.documentElement
。您可能习惯使用 style 属性声明 CSS 值,例如。但这在 CSS 变量中无法实现,由于 CSS 变量的格式独特,style.transform = ''
您必须使用。最终您将得到以下结果:style.setProperty()
document.documentElement.style.setProperty('--x', pos.x);
document.documentElement.style.setProperty('--y', pos.y);
将这些放入你的函数中,你最终会得到这样的结果:
const pos = { x : 0, y : 0 };
const saveCursorPosition = function(x, y) {
pos.x = (x / window.innerWidth).toFixed(2);
pos.y = (y / window.innerHeight).toFixed(2);
document.documentElement.style.setProperty('--x', pos.x);
document.documentElement.style.setProperty('--y', pos.y);
}
document.addEventListener('mousemove', e => { saveCursorPosition(e.clientX, e.clientY); })
将带有 CSS 变量的转换添加到您的 CSS
现在一切准备就绪,我们将为红点添加 transform 属性。这需要一些数学知识,基本上就是将容器的宽度乘以 CSS 变量,然后加上使点居中的 -50%。
.tracker {
width: 10px;
height: 10px;
left: 0;
top: 0;
background: red;
border-radius: 1000px;
transform: translate(calc(-50% + 200px * var(--x)), calc(-50% + 200px * var(--y)));
}
或者,您也可以添加一个充当稳定器的过渡效果,只需添加一行代码即可transition: transform 0.1s
。最好将时间保持在 0.3 秒以下。我不建议在太多元素上使用它,但它确实能带来不错的效果。
就这样!transform 现在会根据 CSS 变量进行变化,从而跟随你的光标。最终结果可以在这个 JSFiddle 上看到(包括 transition 效果):
为什么应该使用 CSS 变量来传递事件行为
现在您知道如何使用 CSS 变量传递事件行为,但也许您仍然对 CSS 变量存在疑问。
可读性
可读性通常来说相当主观。但我认为这是使用 CSS 变量的主要原因。
我的一般经验法则始终是:所有与样式相关的功能都应留给 CSS,其他所有功能都留给 JavaScript。
JS 不是用来操作样式的。比如,看看这个:
const el = document.querySelector('.a-class');
const pos = { x : 1, y : 0.8 };
el.style.width = (250 * pos.x) + 'px';
el.style.height= (200 * pos.y) + 'px';
el.style.left= (100 * pos.x) + 'px';
el.style.top= (50 * pos.y) + 'px';
el.style.transform= `translate(${50 * pos.x}%, ${50 * pos.y}px)`;
就是不太优雅,明白吗?你可以用,cssText
这样至少不用多行代码。然而,如果这不是你唯一使用的内联 CSS,这仍然不方便。此外,即使使用了,可读性和可维护性也不会好多少cssText
。
出于同样的原因,我不喜欢使用 GSAP 和 anime.js 之类的库。除非动画非常复杂,以至于这些库的性能优于 CSS,否则我宁愿选择 CSS。
说到性能……
表现
事情从这里开始变得有点复杂,但简而言之:在脚本方面,它通常比 JS表现更好。
无论你使用 CSS 还是 JS 传递样式,在重新渲染方面都没有区别。这意味着你主要会发现 JS 本身的性能提升。
通常,每当您想要更改元素的位置时,您都会执行类似这样的操作el.style.transform= 'translateY(50%)';
。
假设你有 10000 个 div,你需要循环遍历每个元素来添加内联 CSS。使用 CSS 变量,你只需要在父元素或根元素上更改一次值。显然,后者的性能会更好。如果你对此有疑问,我使用Jsben.ch做了一些基准测试。以下是我所做的一些信息:
- 每次测试之前,我都创建了这 10000 个 div,设置了 CSS 变量,并使用 为所有 div 添加了内联 CSS
el.style.transform= 'translateY(var(--percent))';
。 - 第一个测试用例添加了带有常规变量的内联 CSS。
- 第二个测试用例改变了 CSS 变量。
差别真的很大啊。
为所有这些元素分别添加内联样式可能看起来很荒谬,但这正是我在很多网站上看到的。而使用 CSS 变量时,通常你已经在样式表中预先设置好了 CSS。你只需要修改 CSS 变量即可。
但是,如果两种情况都使用内联样式会怎么样呢?这时候使用常规变量的内联样式就更胜一筹了。
但我没看到有人这样做过……
当你在页面上使用 CSS 变量来实现大量的动画和过渡效果时,你可能会想改用 JS 来实现动画。这与其说是 CSS 变量的问题,不如说是 CSS 动画的整体性能问题。不过,你仍然可以使用 CSS 变量来传递 CSS,同时用 JS 来执行动画逻辑!这里有一篇关于如何在 GSAP 中使用 CSS 变量的简短文章。
浏览器支持情况如何?
CSS 变量如今应用非常广泛,而且有充分的理由!目前所有现代浏览器都支持此功能。如果您还需要支持旧版浏览器,则需要考虑以下几点:
- Internet Explorer 根本不支持 CSS 变量。如果您仍然需要支持 IE,您可以选择 polyfill,但在这种情况下,最好还是直接使用 JS。
- Edge 15(Chromium 之前的版本)存在一些 bug,可能会影响你的使用。但说实话,现在几乎不可能继续安装 Edge 15,所以支持它的理由很有限。
欲了解更多信息,请查看我可以使用吗。
一个新世界刚刚开启!
现在您已经了解了如何传递这些事件,您可以用它做更多的事情!如果您想在触摸设备上使用,可以使用该touchmove
事件。也可以尝试使用其他事件!您可以仅使用 JavaScript 来创建复杂的视差效果,仅传递scroll
事件值,其他所有操作都使用 CSS 来实现。
您不仅知道如何使用它,而且还了解为什么要使用它以及它如何提高性能。
文章来源:https://dev.to/thalitadev/step-by-step-guide-pass-your-cursor-position-using-css-variables-c7b