映射鼠标位置或实现拖拽效果,我们可以在 JavaScript 中做到这一点。但实际上,在CSS中有更加简洁的方法,我们可以在不使用JavaScript 的情况下,仍然可以实现相同的功能!
只使用CSS就可以实现模仿鼠标"点击和拖动"效果,让我们来看看如何获得用户的鼠标位置,并将其映射到 CSS 自定义属性:--positionX 和 --positionY 中。下面是具体实现步骤。
初始化
我们的第一个 demo 将使用 --positionX 和 --positionY 自定义属性来设置元素的宽度和高度。
<div class="content"> <div class="square"></div></div>
*, *::before, *::after { padding: 0; margin: 0 auto; box-sizing: border-box;}body { background-color: black; height: 100vh;}.content { --positionX: 0; --positionY: 0; position: absolute; top: 0; right: 0; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center;}.square { width: 100px; height: 100px; background: white;}
这是我们最初的状态。我们这里有一个了名为 .content 的容器
我们还在内容中添加了两个自定义属性。我们将使用鼠标位置来设置这些属性的值,然后使用它们来设置 .square 元素的宽高。
一旦我们为鼠标位置绘制了自定义属性,我们几乎可以使用它们来做我们想要的任何事情。例如,我们可以使用它们来设置一个绝对定位元素的 top/left、控制 transform 属性、设置 background-position、调整 color,甚至设置伪元素的内容等。我们将在文章的结尾看到一些这样的演示效果及对应的Codepen 项目链接。
grid 网格
目标是在屏幕上创建一个不可见的网格,并使用 :hover 伪类将每个"单元格"映射成我们自定义属性的一组值。此时,当鼠标光标移动到屏幕的右侧时,--positionX 的值将更高:当鼠标向左移动时,它变得更低。对于 --positionY 也是一样的:当光标移动到顶部时,值将更低,当光标移动到底部时,值会更高。
关于我网格大小及网格分块需要注意的地方:实际上我们可以使任何我们可以达到的网格尺寸。它越大,自定义属性值就越准确。但这也意味着我们将有更多网格分块区间,网格分块过多可能会导致性能问题,根据实际项目保持适当的平衡地调整网格大小是非常重要的。
现在,假如我们需要一个10×10网格,所以总共100个网格分块在我们容器中。(在实际开发中可以使用pug等语法快速创建表格,例子中100个空间全部用 div 表示出来了)
<div class="cell"></div><div class="cell"></div><div class="cell"></div><!-- 97 more cells --><div class="content"> <div class="square"></div></div>
由于级联关系,将 .cell 元素放在 .content 元素前面。
我们希望使用 .cell 类来控制 .square,由于CSS的级联关系,一个元素只能控制其子子元素(或子元素的子元素)及位置在它的后面的兄弟元素(或兄弟元素的子元素)
这意味着两件事:
- 每个 .cell 必须先于需要控制的元素(在这个例子中为 .square)。
- 不能把这些 .cell 放在一个容器里,如果我们这样做.content 元素就不再是他们的兄弟元素。
定位单元格
有很多方法可以定位 .cells。比如我们可以使用 position: absolute,并设置它们的 top 和 left 属性;或者我们也可以通过 transform 来转换位置;但最简单的选择其实是使用 display: grid。
body { background-color: #000; height: 100vh; display: grid; grid-template: repeat(10, 1fr) / repeat(10, 1fr);}.cell { width: 100%; height: 100%; border: 1px solid gray; z-index: 2;}
border 只是暂时的,在开发中所以我们可以看到屏幕上的网格,稍后会删除它。
z-index 非常重要,因为我们希望单元格出现在内容顶层。以下是我们目前完成的内容:
<div class="cell"></div><div class="cell"></div><div class="cell"></div><!-- 97 more cells --><div class="content"> <div class="square"></div></div>
```
*, *::before, *::after { padding: 0; margin: 0 auto; box-sizing: border-box;}body { background-color: black; height: 100vh; display: grid; grid-template: repeat(10, 1fr) / repeat(10, 1fr);}.cell { width: 100%; height: 100%; border: 1px solid gray;