你将要创建的内容
在本教程中,我们将使用 css3 透视属性创建一个交互式元素,以提供三维感。本教程还将教您如何使用 jquery 和鼠标事件来获取javascript中的元素位置以及如何操作 CSS 属性。
透视属性的 html 结构
我们需要一个父子关系才能使透视属性正常工作。让我们首先创建 HTML 结构,然后继续 CSS 样式。
<div id="mainWrapper"> <div id="cardsWrapper"> <div class="card"> <div class="image first"> <div class="screen"></div> <div class="text"> <p>Mountain</p> <p>5 Days</p> </div> </div> </div> <div class="card"> <div class="image second"> <div class="screen"></div> <div class="text"> <p>Island</p> <p>2 Days</p> </div> </div> </div> </div> </div>
在这里,我们将两个 card
元素包装到一个 id 为 的 div 中 cardsWrapper
。此外,它 cardsWrapper
被包装到另一个 div 中,以便能够轻松地操纵其在视口中的位置。
每个具有类 of 的元素card
都有一个 image
元素,该元素包含 screen
和 text
元素。结构暂时有点模糊,但我会在接下来的相关章节中解释每个元素的用法。
让我们使用以下 CSS 样式来定位我们的元素。
#mainWrapper{ display: flex; justify-content: center; align-items: center; height: 350px; } #cardsWrapper{ display: flex; justify-content: space-between; width: 700px; } .card{ width: 300px; height: 175px; background-color: red; } .image{ width: 100%; height: 100%; background-color: red; }
使用透视属性
该perspective
属性是您必须在父 div 中设置的内容,其中包含您要使用透视感进行转换的 div。想象一下父 div 是您的世界,它具有您正在体验的特定视角值。
让我们将 perspective
属性添加到我们的父 div,即card
. 我们选择 card
元素作为父元素,而不是 cardsWrapper
,因为我们希望对每个卡片元素都有单独的透视效果。
调整 CSS card
如下。
.card{ width: 300px; height: 175px; background-color: red; perspective: 500px; }
现在尝试为 transform
图像元素添加一个属性以查看透视效果。
.image{ width: 100%; height: 100%; background-color: red; transform: rotateX(30deg); }
由于 image
是 的直接子代 card
,因此受透视图的影响。但是,如果您尝试将 transform
属性添加到 的任何子级 image
,这将不起作用。
为了使这些子元素相对于它们的父 image
元素(本示例中的元素)进行转换,您应该 transform-style: preserve-3d
在父元素上使用。
.image{ width: 100%; height: 100%; transform-style: preserve-3d; transform: rotateX(30deg); }
现在我们在透视属性中有足够的背景知识,并准备继续为其他元素设置样式。
不要忘记 transform: rotateX(30deg)
从图像元素中删除 。
设计卡片样式
我们有一个image
元素,在它之上我们有一个名为 的元素 screen
,然后是 text
. 由于我们在这里使用透视,您可以将这些元素中的每一个视为单独的层。
现在我们将背景图像添加到我们的 image
div 中,然后设置 screen
和 text
元素的样式。
让我们使用以下 CSS 样式为每个卡片对象添加背景图像。
.image.first{ background-image: url("https://c1.staticflickr.com/1/343/31652757460_b2b5794a51_n.jpg"); } .image.second{ background-image: url("https://c2.staticflickr.com/2/1506/25121644830_2d768ef51a_n.jpg"); }
现在我们将为 screen
元素设置样式。
由于我们希望 screen
元素的大小与其父元素完全相同 image
,因此我们使用 100% 的宽度和高度值以及带有 alpha 通道的灰黑色背景色。
导入部分是 transform: translateZ(30px) scale(0.940)
.
所以这里我们只是将 screen
Z 轴上的元素平移 20px。这使它悬停在 image
元素上。由于它是朝向我们的,由于透视规则,它的尺寸会更大。因此,我们将其缩小以匹配父元素的大小。如果您使用不同的平移值,则比例值会有所不同。同样,为父元素定义不同的高度和宽度大小将导致需要不同的缩放值。
.screen{ background-color: rgba(0, 0, 0, 0.22); width: 100%; height: 100%; transform: translateZ(30px) scale(0.940); }
为了了解这里发生了什么,只需将以 image
下行添加到 CSS 规则中,围绕 X 和 Y 轴旋转您的元素:
transform: rotateX(30deg) rotateY(30deg)
现在本节的最后一部分是对 text
元素进行样式设置,这非常简单。
我们基本上对元素使用相同的变换设置, text
以使其与元素处于同一级别 screen
。CSS的其余部分只是简单的样式。您可以按照自己喜欢的方式对其进行调整。
.text{ position: absolute; bottom: 25px; left: 30px; color: white; transform: translateZ(30px) scale(0.940); } .text p{ cursor: default; padding: 0; margin: 0; } .text p:first-of-type{ font-size: 2em; margin-bottom: 5px; } .text p:last-of-type{ font-size: 1em; }
这是手动旋转的最终结果,看看效果。
在继续之前,请从您的 CSS 中删除旋转规则,因为我们将根据光标位置自动控制旋转。
现在我们将编写一些 jQuery代码以使这些卡片具有交互性。
让我们开始吧!
添加与 jQuery 的交互
让我们从基本的 jQuery 代码开始。
(function($){ })(jQuery);
我们将在这个函数中编写所有内容。这将允许 jQuery 等到dom准备好。
由于我们有兴趣与我们的 card
元素进行交互,因此我们需要选择它。
(function($){ var card = $(".card"); })(jQuery);
下一步是在卡片元素上注册光标位置。为此,我们将使用内置 mousemove
事件。
(function($){ var card = $(".card"); card.on('mousemove', function (e) {}); })(jQuery);
现在我们需要跟踪光标位置。获得正确的值有点棘手。
(function($){ var card = $(".card"); card.on('mousemove', function (e) { var x = e.clientX - $(this).offset().left + $(window).scrollLeft(); var y = e.clientY - $(this).offset().top + $(window).scrollTop(); }); })(jQuery);
在这里, e.clientX
并 e.clientY
返回视口内的光标位置。然而,由于每个 card
对象都是相对于视口定位的,我们需要通过提取左侧和顶部偏移值来补偿这一点。
最后要考虑的也是最重要的事情是对窗口滚动的补偿。因此,由于您的光标位置是相对于您的视口注册的,但偏移值是固定的,因此当您滚动时,您的对象会根据您滚动的方向更靠近视口的顶部或左侧。
结果,我们到视口顶部或左侧的相对距离会更小。然而,由于偏移值是固定的,我们需要对此进行补偿,这是通过 $(window).scrollLeft()
and 来完成的$(window).scrollTop()
。因此,通过将这些值添加到相应的变量中,我们只是补偿了我们滚动的量。因此,当您将鼠标悬停在任何 card
元素上时,您的 X 位置将介于 0 到卡片的宽度(定义为 300 像素)之间。同样,Y 位置的范围是从 0 到卡片的高度,即 175 像素。
下一步是将光标位置映射到一个新范围,这将是我们希望以度为单位应用的旋转量,这样当您的光标站在卡片元素的中间时,它看起来只是平坦的,但是当你移动到左/右或上/下时,你会得到一个旋转效果,就好像卡片跟随光标一样。
这是映射函数结果的快速说明。
function map(x, in_min, in_max, out_min, out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
在这个函数中, in_min
和 in_max
参数分别是输入值的最小值和最大值,分别对应 card
元素的宽度和高度。 out_min
是输入将被映射的最小值和 out_max
最大值。
让我们将这个地图函数与我们的 X 和 Y 光标位置一起使用。
(function($){ var card = $(".card"); card.on('mousemove', function (e) { var x = e.clientX - $(this).offset().left + $(window).scrollLeft(); var y = e.clientY - $(this).offset().top + $(window).scrollTop(); var rY = map(x, 0, $(this).width(), -17, 17); var rX = map(y, 0, $(this).height(), -17, 17); }); function map(x, in_min, in_max, out_min, out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } })(jQuery);
现在我们的映射值是 rX
and rY
。
下一步是 image
通过使用映射值作为旋转值来为元素设置 CSS 规则。
(function($){ var card = $(".card"); card.on('mousemove', function (e) { var x = e.clientX - $(this).offset().left + $(window).scrollLeft(); var y = e.clientY - $(this).offset().top + $(window).scrollTop(); var rY = map(x, 0, $(this).width(), -17, 17); var rX = map(y, 0, $(this).height(), -17, 17); $(this).children(".image").css("transform", "rotateY(" + rY + "deg)" + " " + "rotateX(" + -rX + "deg)"); }); function map(x, in_min, in_max, out_min, out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } })(jQuery);
这里我们选择了 card
名为 的元素的子元素 image
,然后设置 CSS 规则来分别绕 X 和 Y 轴旋转这个元素 rX
和 rY
度数。
您将意识到卡片元素在各自的视角中跟随光标。但是,当光标离开卡片元素时,它们会保持其方向。此外,他们会对光标在卡片元素上的存在做出突然的反应。所以我们还需要处理鼠标进入和离开卡片元素的那些情况。
为了处理这些问题,我们需要使用 mouseenter
和 mouseleave
事件。
当鼠标进入 card
元素的区域时,我们给元素添加一个过渡 CSS 规则 image
。这将使 image
元素的“凝视”平滑过渡。
card.on('mouseenter', function () { $(this).children(".image").css({ transition: "all " + 0.05 + "s" + " linear" }); });
同样,我们需要处理 mouseleave
事件。
在这里,我还添加了另一个具有不同时序的过渡 CSS 规则,当鼠标离开 card
元素时,它可以更平滑地过渡到初始位置。
我还添加了变换 CSS 规则以重置 card
元素的旋转。
card.on('mouseleave', function () { $(this).children(".image").css({ transition: "all " + 0.2 + "s" + " linear" }); $(this).children(".image").css("transform", "rotateY(" + 0 + "deg)" + " " + "rotateX(" + 0 + "deg)"); });
所以我们最终的 jQuery 代码如下所示:
(function($){ var card = $(".card"); card.on('mousemove', function (e) { var x = e.clientX - $(this).offset().left + $(window).scrollLeft(); var y = e.clientY - $(this).offset().top + $(window).scrollTop(); var rY = map(x, 0, $(this).width(), -17, 17); var rX = map(y, 0, $(this).height(), -17, 17); $(this).children(".image").css("transform", "rotateY(" + rY + "deg)" + " " + "rotateX(" + -rX + "deg)"); }); card.on('mouseenter', function () { $(this).children(".image").css({ transition: "all " + 0.05 + "s" + " linear", }); }); card.on('mouseleave', function () { $(this).children(".image").css({ transition: "all " + 0.2 + "s" + " linear", }); $(this).children(".image").css("transform", "rotateY(" + 0 + "deg)" + " " + "rotateX(" + 0 + "deg)"); }); function map(x, in_min, in_max, out_min, out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } })(jQuery);
这是最终结果。我还在元素上使用了不同的无衬线字体 text
以使其看起来更好。
结论
在本教程中,我们学习了如何使用透视属性和所需的 HTML 结构使其正常工作。此外,我们还介绍了如何在鼠标悬停在特定 HTML 元素上时注册鼠标光标位置。
最重要的是,我们通过使用 jQuery 向 HTML 元素添加 CSS 规则来使用 mousemove
、 mouseenter
和 mouseleave
事件来引入交互性。