- 原文地址:codrops
- 原文作者:Nick Pettit
当使用 3D 转换来对元素进行格式化的时候,您可能会注意到它们没有任何阴影并且看起来非常平坦。 在现实生活中,物体会阻挡光线并产生阴影。 物体表面可能是哑光,反光,或者介于两者之间。所以,我们可以做得更好。
如果你需要将光线投射到复杂的几何体上,可以选择Photon等引擎,但它们处理器非常复杂。 在本文中,我将向您展示一个可以应用于只有几个面的元素的解决方案。 我们的例子将是一个带有光泽海报的3D电影画廊,当海报旋转时,两侧将包含电影的相关介绍。
HTML结构
我们的页面将有几个不同的部分。 首先,我们需要一个简单的父元素来居中页面上的所有内容。 接下来,我们将创建一个包含所有3D海报的无序列表。 我们给ul添加类“stage”,给每个li添加类“scene”。 在我们的CSS中,ul将充当所有li元素的容器,每个li元素会设置perspective属性用于构成透视图。
<div class="wrapper">
<ul class="stage">
<li class="scene"></li>
<li class="scene"></li>
<li class="scene"></li>
</ul>
</div>
复制代码
对于每个li,我们需要添加相当多的子元素。 这将包含我们的电影海报以及每部电影的所有相关介绍。 在一个更强大的电影库中,这可以使用一些后端代码动态完成。 出于本示例的目的,我们将保持简单。
<li class="scene">
<div class="movie">
<div class="poster"></div>
<div class="info">
<header>
<h1>It's a Wonderful Life</h1>
<span class="year">1946</span>
<span class="rating">PG</span>
<span class="duration">130 minutes</span>
</header>
<p>
In Bedford Falls, New York on Christmas Eve, George Bailey is deeply troubled. Prayers for his well-being from friends and family reach Heaven. Clarence Odbody, Angel Second Class, is assigned to visit Earth to save George, thereby earning his wings. Franklin and Joseph, the head angels, review George's life with Clarence.
</p>
</div>
</div>
</li>
复制代码
我们的画廊将包含至少两部电影。 元数据有点冗长,还有一些您需要的图像资源,但所有内容都包含在下载的代码中。 让我们开始写相关的CSS部分。
CSS样式
请注意,示例CSS不包含任何浏览器前缀,但您可以在下载的文件中找到它们。
首先,让我们做一些基本的操作。 我们需要将我们的父元素居中,然后删除默认的列表样式。
.wrapper {
margin: 0 auto 100px auto;
max-width: 960px;
}
.stage {
list-style: none;
padding: 0;
}
复制代码
接下来,我们将给.scene类设置明确的宽度和高度(与我们的海报相同)。 如果您想在高分辨率显示器上有更好的视觉效果,那么您可以使用两倍大的图像。
每个.scene类之间将提供足够大的外边距,使得它们不会彼此重叠。 然后我们将设置所有列表项浮动到左侧,以便它们在一行中彼此相邻排列。 这类似于创建大多数网站的导航条的方式。
最后,我们将添加perspective属性。 这将允许我们在嵌套元素中创建3D场景,1000px的值将为对象提供相当大的景深。 较低的值会有点过于戏剧化,但您可以尝试这一点,看看多大的值最适合您。
.scene {
width: 260px;
height: 400px;
margin: 30px;
float: left;
perspective: 1000px;
}
复制代码
类似.scene类,我们还需要在.movie类类上设置明确的宽度和高度。 这将有助于每张海报在转换时看起来都是正确的。 接下来,我们将transform-style设置为preserve-3d,以便我们可以在3D空间中转换元素。 最后,我们将沿Z轴将其平移-130像素。 这将使海报有更多的空间来移动。
.movie {
width: 260px;
height: 400px;
transform-style: preserve-3d;
transform: translateZ(-130px);
transition: transform 350ms;
}
复制代码
这是转换开始的地方。我们给.movie类添加一个transition。 设置时间为350毫秒,但如果你想要一个更戏剧性的效果,可以设置较小的值。
然后当鼠标悬停在.movie类时将开始转换。 这将沿Y轴旋转3D海报,然后沿Z轴将其移向屏幕。 您可以将海报旋转整整90度,但我更喜欢稍微偏移以保持3D效果。
.movie:hover {
transform: rotateY(-78deg) translateZ(20px);
}
复制代码
敏锐的程序员会注意到,虽然我们已经平移了每个li,但我们实际上从未实际旋转任何会产生几何图形并构建对象的元素。 我们现在创建每个3D海报。 每个.poster和.info都需要绝对定位,否则它们会互相推开。 我们不希望这样,因为我们将使用变换来定位它们。 接下来,我们需要在两个类上设置显式维度,以便双方中的每一个都完全相同。
.movie .poster,
.movie .info {
position: absolute;
width: 260px;
height: 400px;
background-color: #fff;
backface-visibility: hidden;
}
复制代码
随着我们海报的几何形状准备就绪,我们可以将它们变换到位。 .poster只需沿Z轴移动130px(因为记住,我们将.movie移回了这个数量)。 背景大小已设置为cover,以便在我们应用海报背景时,它们将填充几何体。 无论如何它们都会正确,因为它们的尺寸正确,所以这实际上只是一种预防措施。
.info需要平移与.poster相同的数量,但也需要旋转。 我们想要形成一个方框,所以我们将它旋转90度。 我在转换后添加了一些样式,但这主要是出于审美原因。
.movie .poster {
transform: translateZ(130px);
background-size: cover;
background-repeat: no-repeat;
}
.movie .info {
transform: rotateY(90deg) translateZ(130px);
border: 1px solid #B8B5B5;
font-size: 0.75em;
}
复制代码
我们将使用伪元素::after创建另一个盒子阴影:
.movie::after {
content: '';
width: 260px;
height: 260px;
position: absolute;
bottom: 0;
box-shadow: 0 30px 50px rgba(0,0,0,0.3);
transform-origin: 100% 100%;
transform: rotateX(90deg) translateY(130px);
transition: box-shadow 350ms;
}
.movie:hover::after {
box-shadow: 20px -5px 50px rgba(0,0,0,0.3);
}
复制代码
在CSS中,我们继续设置.info类中包含的子元素的样式。 这些都与此演示无关,因为它主要只是格式化一些文本和图像。 真正的魔法发生在以后。
.info header {
color: #FFF;
padding: 7px 10px;
font-weight: bold;
height: 195px;
background-size: contain;
background-repeat: no-repeat;
text-shadow: 0px 1px 1px rgba(0,0,0,1);
}
.info header h1 {
margin: 0 0 2px;
font-size: 1.4em;
}
.info header .rating {
border: 1px solid #FFF;
padding: 0px 3px;
}
.info p {
padding: 1.2em 1.4em;
margin: 2px 0 0;
font-weight: 700;
color: #666;
line-height: 1.4em;
border-top: 10px solid #555;
}
复制代码
这是我们使用box-shadow属性创建伪照明的地方。 对于.poster类,我们添加一个内阴影,其X和Y偏移为0px。 模糊半径将设置为40px,阴影设置为rgba(255,255,255,0)(白色“阴影”设置为100%透明度)。 请记住,有一个过渡应用于.movie的所有子项,所以如果我们为阴影设置一个起始状态,我们就可以使用:hover对其进行动画处理。
如果我们将鼠标悬停在.movie上,它将重置.poster的box-shadow值,并通过转换为它们设置动画。 在这个新状态下,海报的X偏移为300px,不透明度为0.8。 这将有效地将盒子阴影移动到海报顶部,沿着边缘有一些模糊。 透明度将有助于使海报图像凝聚阴影,这将使海报看起来像有光泽的。
.movie .poster,
.movie .info,
.movie .info header {
transition: box-shadow 350ms;
}
.movie .poster {
box-shadow: inset 0px 0px 40px rgba(255,255,255,0);
}
.movie:hover .poster {
box-shadow: inset 300px 0px 40px rgba(255,255,255,0.8);
}
复制代码
就像海报一样,我们也希望在盒子的另一侧涂上阴影。 对于.info面板,我们希望当元素向前旋转时暗阴影消失,然后当纸张纹理缩回到每个3D海报之间的间隙时再重新出现。 在我们的页面上,左侧有光泽的海报,右侧有阴影,看起来会像有一束光从左侧照在页面上。
.movie .info,
.movie .info header {
box-shadow: inset -300px 0px 40px rgba(0,0,0,0.5);
}
.movie:hover .info,
.movie:hover .info header {
box-shadow: inset 0px 0px 40px rgba(0,0,0,0);
}
复制代码
最后,我们需要将海报图像和静态图像添加到每部电影中。 我使用:nth-child伪类完成了这个,但同样,这可能会在动态网站的其他地方完成。
.scene:nth-child(1) .movie .poster {
background-image: url(../img/poster01.jpg);
}
.scene:nth-child(2) .poster {
background-image: url(../img/poster02.jpg);
}
.scene:nth-child(3) .poster {
background-image: url(../img/poster03.jpg);
}
.scene:nth-child(1) .info header {
background-image: url(../img/still01.jpg);
}
.scene:nth-child(2) .info header {
background-image: url(../img/still02.jpg);
}
.scene:nth-child(3) .info header {
background-image: url(../img/still03.jpg);
}
复制代码
您会注意到我们在演示中使用了Modernizr来检测对3D变换的支持,并为不支持它的浏览器提供简单的回退版本。
正如我在介绍中所建议的那样,这种技术可以应用于简单的几何体。 有人可能想知道为什么我没有使用渐变来在海报图像上创建一个更受控制的阴影。 在本文诞生的时候,转换不能应用于渐变,所以虽然这可能适用于静态几何,但一旦元素设置了动画效果,幻象就会被打破。
如果您对此技术有任何问题,意见或改进,我很乐意在评论中听到它们!