目录
原始视频
前言
约定
准备工作
消失的点
No vectors, Victor
图形转换
transform-origin 属性
让我们开始吧
关于影子
红和蓝
传送门的光
关于人物
创建人物
第一个人物
举起手来
整体设置
动画
关键帧动画
浏览器兼容性   
源码下载
首页 web前端 html教程 CSS传送门_html/css_WEB-ITnose

CSS传送门_html/css_WEB-ITnose

Jun 24, 2016 am 11:16 AM

你不一定必须使用javascript才能在浏览器端构建惊心动魄的3D效果的项目。在这篇文章中,我将介绍一种纯CSS实现的复杂的动画效果。

传送门在线演示地址,Github源码地址

原始视频

视频展示了3D动画场景的构建,美化及动画效果。这篇文章我们将使用CSS3重绘这个传送门视频。重点介绍人物从一个门穿到另一个门的过程。下面是原始视频:

这个视频在第一次发布的时候,就深深的印在了我的脑海中。传送门(创始人 Narbacular Drop )介绍了一种有趣的3D平台解谜游戏。

在视频中,我们看到这个游戏获得战利品的方式,不同于以往的游戏。文章里,我将尝试看能否只使用HTML和CSS来重现这个场景。

下面的图片就是我们打算要创造的场景。

前言

推荐你使用prefix free 或者 SASS来构建 CSS,可以避免在编写CSS的时候,重复的编写前缀。另外,要注意一下,在不同的浏览器中,兼容性前缀的问题。完整的源码,CSS、SASS还有HTML,都可以在Github上找到。

约定

我们的项目是在Chrome来进行开发和测试的,并不兼容Internet Explorer浏览器。代码中包含的一些有趣的3D动画技术并不是现在的主流,但对于未来的前端开发有着它不可忽视的意义。

准备工作

我们先在HTML中创建一个容器,来告诉浏览器我们想把我们的3D场景的内容放在这里。

<article class="container"></article>
登录后复制

在这里我们使用了HTML5中的article标签,来表示这是独立的一段内容。
我们要提到的第一个属性是 perspective。这个属性的值用像素值来表示3D场景的景深。通常的设定范围是800px到1200px。

这个场景给我们感觉很像是一个大房子,我们设置他的perspective值为 2600px,忽略前缀,写法如下:

article.container { perspective: 2600px;}
登录后复制

消失的点

这个容器有一个Z轴景深,我们需要决定一下它的透视点。通过设置perspective-origin属性,来设置我们的消失点,决定我们是从上向下看,还是从某一边看去。

.container { perspective-origin: 50% -1400px;}
登录后复制

perspective-origin这个属性可以设置两个值,水平和垂直方向。这里我们设置了水平方向为50%,垂直方向向上1400像素。相当于我们是在物体上方从下看。

我是使用Chrome浏览器的检查元素和肉眼来调整和决定这个值的。当你设置了你想要的场景画面,你的值可能会比这个数值要高或者低。这决定于你想要表达的效果。另外,需要谨记,这个值会影响动画效果和其他一些有趣的视觉角度转换(perspective-change effects)。

No vectors, Victor

HTML中的对象是很普通的HTML元素,他们是矩形的,有宽和高。这就意味着你所创建3D对象,需要把这些矩形放在该有的位置上。这种方式不同于由点到线,再到图形的方法。换种说法,也就是说,我们无法使用圆,立方体来画。

3D场景中HTML元素的摆放需要用到 transform 属性。

图形转换

transform可以实现对HTML元素的一系列的调整。比如,移动元素,旋转角度, 倾斜或放大缩小。这些变形可以叠加使用。

.example { transform: rotateY(45deg) translateZ(-100px);}
登录后复制

这段代码的意思是将元素沿着Y轴顺时针旋转45度,沿Z轴向后100像素。效果如图:

transform-origin 属性

当你想旋转元素的时候,需要设置一个起始点,我们用 transform-origin属性来实现,可以传三个参数,分别是X轴,Y轴,Z轴。

.default-origin { transform-origin: 50% 50% 0;}
登录后复制

目前的例子里,我没有特别设置,保留了原有的默认值,但我们需要知道有这么个属性。

让我们开始吧

结合效果图,我们拼合属于我们自己的3D杰作。先用HTML和CSS来构建我们的3D对象。我们有必要花一分钟的时间来理解一下我们这种方法和其他3D软件的区别。

<section class="stage">  <div class="shadow"></div>  <div class="back-left"></div>  <div class="back-right"></div>  <div class="platform-left"><span></span></div>  <div class="platform-right"><span></span></div>  <div class="pit-left"></div>  <div class="pit-right"></div>  <div class="pit-back"></div></section>
登录后复制

stage用来装所有的元素,div表示整体中的某一部分结构,将场景中的墙,平台,凹陷的地方,以及阴影部分,拼成我们想要的。
当我开始构建这个图形的时候,我尝试把墙直接放在平台上,通过旋转来调整他的位置,可是图形看上去是等距的。更简单一点的方法实现就是,先放置每一个部分,然后将整体倾斜45度。

带着这个想法,HTML就变成了下面这种平面图。

如图所示,左后与左侧对齐,右后与右侧对齐。为了达到这个效果,稍后我们整体旋转45度。

.stage div { position: absolute; transform-style: preserve-3d;}
登录后复制
登录后复制

在使用变形之前,我们先给div添加公共的属性。

.stage div { position: absolute; transform-style: preserve-3d;}
登录后复制
登录后复制

每个div都设置为绝对定位,事先将transform-style设置为 3D 视图。

接下来我们就可以单独设置div的大小和位置了。

.stage .back-left { background-color: #6b522b; border-left: 6px solid #574625; border-top: 6px solid #8a683d; height: 120px; transform: rotateY(90deg) translateX(-256px); width: 500px;}
登录后复制

以上的规则描述了3D场景中的一个500像素宽,120像素高的浅棕色的一面墙。div沿着Y轴旋转90度,沿着X轴向后推,通过6像素的边框创造一个有景深的错觉。

back-right也设置类似的属性。

.stage .back-right { background-color: #9c7442; border-right: 6px solid #78552c; border-top: 6px solid #b5854a; height: 120px; transform: translateX(253px) translateZ(3px); width: 446px;}
登录后复制

这个div要更小一点,像视频中的那样,不那么方。

接下来,加一些平台,和凹陷。

.stage .platform-left { background-color: #bcb3a8; border-bottom: 6px solid #857964; height: 220px; transform: rotateX(90deg) translateY(396px) translateX(253px) translateZ(-13px); width: 446px;}.stage .platform-right { background-color: #bcb3a8; border-bottom: 6px solid #847660; border-right: 6px solid #554c3d; height: 164px; transform: rotateX(90deg) translateY(88px) translateX(253px) translateZ(-41px); width: 446px;}.stage .pit-left { background-color: #4d4233; height: 800px; transform: translate3D(254px, 125px, 285px); width: 447px;}.stage .pit-right { background-color: #847660; height: 800px; top: -1400px; transform: translate3D(254px, 125px, 173px); width: 451px;}.stage .pit-back { background-color: #6b522b; height: 220px; transform: rotateY(90deg) translate3D(-200px, 87px, 168px); width: 170px;}
登录后复制

目前我们的图形如下:

目前和目标图形不一样,我们还需要把它旋转一下,给section增加一个transform的属性。

.stage { margin: 0 auto; transform-style: preserve-3d; transform: rotateY(-45deg); width: 460px;}
登录后复制

效果如下:

你可能注意到了边框有一个很漂亮的景深的效果,特别是在边角的地方,颜色不同,有45度的旋转。
因为我们是斜45度看过去的,所以这个效果是很可能出现的。有个别的角落看着有出入,但考虑到我们直接用的边框,没有引用图片,有这个瑕疵,是可以忍受的。

关于影子

视频里,平台下面有一个很漂亮的阴影。我们可以使用CSS的属性 box-shadow 来实现。

.stage .shadow { background-color: transparent; box-shadow: -600px 0 50px #afa79f; height: 550px; transform: rotateX(90deg) translateZ(-166px) translateX(550px); width: 550px;}
登录后复制

给div加了一个盒阴影,阴影本身是透明的,与实体偏离600像素,整体偏离了stage,所以是可见的。效果如下:

红和蓝

接下来我们添加一些装饰和鲜艳的门。

两个入口使用HTML来表示。

<div class="portal red"></div><div class="portal blue"></div>
登录后复制

两个div,一个表示红色的门,一个表示蓝色的门。两个都分别设置一些过渡色来实现发光的效果。
因为只用了一个div元素,所以我们可以尝试使用CSS伪类来实现整体效果。

第一步,先创建一个门的形状。

.stage .portal { background-color: black; border-radius: 44px/62px; box-shadow: 0 0 15px 4px white; height: 72px; width: 48px;}
登录后复制

用 border-radius 属性实现椭圆形,白色阴影实现发光的效果。同时我们给伪类也定义相同的大小
和边框。

.stage .portal:before { border-radius: 44px/62px; border: 4px solid white; content: ""; display: block; height: 72px; margin-left: -4px margin-top: -4px; width: 48px;}
登录后复制

门的整体效果已经设置完了,之后我们需要分别设置蓝色的门和红色的门。

首先,红色的门:

.stage .portal.red { background: radial-gradient(#000000, #000000 50%, #ff4640 70%); border: 7px solid #ff4640; transform: translate3D(223px, 25px, 385px) rotateY(90deg) skewX(5deg);}.stage .portal.blue { background: radial-gradient(#000000, #000000 50%, #258aff 70%); border: 7px solid #258aff; transform: translate3D(586px, 25px, 4px) skewX(-5deg);}
登录后复制

红色的门,我们给了一个放射性渐变的颜色和一个红色边框。通过transform将其放置到左侧墙上。蓝色的门类似,放置到右侧墙上。测试的时候,两个看起来都有一些错位,所以我给他们加了5度的倾斜。

传送门的光

早先,我们就在两个平台里分别放了一个span标签。我们可以利用这个span来定义每个门下面的照射到平台上的光。

.stage .platform-left span { background: radial-gradient(left, #f3cac8, #c8b8ad 70px, #bcb3a8 90px); display: block; height: 200px; left: 0; position: absolute; width: 120px;}.stage .platform-right span { background: radial-gradient(top, #cdebe8, #c2cbc1 40px, #bcb3a8 60px); display: block; height: 60px; left: 280px; position: absolute; width: 150px;}
登录后复制

两个span都被绝对定位在门下方,一个红色光,一个蓝色光。其实伪元素也可以实现这个效果,
但是伪元素对动画的支持不好。

在右侧的墙上,需要一个门表示退出。你可能想像不到我们用边框就实现了这个效果。一个的div和有颜色的边框做了一个内凹的效果。

门的HTML放在stage 里。

<div class="door"></div>
登录后复制

给门设置几个边框,然后定位到右墙上。

.stage .door { background: #efe8dd; border-bottom: 6px solid #bcb3a8; border-left: 7px solid #78552e; height: 85px; transform: translate3D(450px, 34px, 4px); width: 65px;}
登录后复制

下边框和左边框与平面和右面墙重合,有一种景深的感觉。不设置上边框,左边框立在左侧,展示的效果也很好。

关于人物

有了传送门之后,我们需要有一个人物可以从一边到达另一边。第一步,先画一个人物。

刚开始的时候,我尝试了让一个人物从传送门进去,然后动画停止,立即从另一边继续。但当我让人物停止,在传送门之间移动的时候,会有闪烁。为了解决这个问题,我使用了2个人物,分别让他们移动。

创建人物

人物主要两部分组成,头部和身体。腿是用身体的伪类创建的。同理,创建一个人物的影子。

<div class="dude one">  <figure class="head"></figure>  <figure class="body"></figure>  <div class="dude-shadow one">    <figure class="head"></figure>    <figure class="body"></figure>  </div></div>
登录后复制

因为影子是人物的一部分,所以要同时移动。CSS如下:

.dude, .dude-shadow { height: 100px; width: 30px;}.dude figure, .dude-shadow figure { background-color: black; display: block; position: absolute;}.dude figure.head, .dude-shadow figure.head { border-radius: 22px; height: 20px; left: 3px; top: 0; width: 20px;}.dude figure.body, .dude-shadow figure.body { border-radius: 30px 30px 0 0; height: 30px; top: 21px; width: 26px;}.dude figure.body:before, .dude figure.body:after, .dude-shadow figure.body:before, .dude-shadow figure.body:after { background-color: black; content: ""; height: 15px; position: absolute; top: 30px; width: 9px;}.dude figure.body:before, .dude-shadow figure.body:before { left: 3px;}.dude figure.body:after, .dude-shadow figure.body:after { left: 14px;}
登录后复制

我们用这些样式来描述人物和影子。每个部分是绝对定位,border-radius 来设置圆角。腿用伪元素来定义,然后分别定义位置。

第一个人物

人物构建好了之后,将其定位到开始的位置。

.stage .dude.one { transform: translate3D(514px, 50px, 375px) rotateY(78deg);}.stage .dude-shadow.one { opacity: 0.1; transform: translateX(-12px) rotateX(90deg) translateY(8px);}
登录后复制

CSS 位置的变换既包含人物本身,也包含人物的影子,人物的透明度设置为0.1, 而不是设置成灰色,
这样做的好处是允许你看见影子后面的背景细节。

第一个人物现在在初始位置,参考视频,我们将人物旋转了一个相同的角度。稍后我们会加一些特效让他穿过传送门。

举起手来

第二个人物有更多的细节,手, 这个想法是人物穿越传送门时产生的,象征着他们举起手来庆祝。

以下是HTML代码:

<div class="dude two">    <figure class="head"></figure>    <figure class="body"></figure>    <figure class="arm left"></figure>    <figure class="arm right"></figure>    <div class="dude-shadow two">        <figure class="head"></figure>        <figure class="body"></figure>        <figure class="arm left"></figure>        <figure class="arm right"></figure>    </div></div>
登录后复制

第二个人物开始是透明的动画效果,然后在第一个人物动画效果开始的中途穿过传送门(第一个人物到达传送门),设置第二个人物定位在传送门。

.stage .dude.two { transform: translate3D(610px, 40px, 10px) rotateY(15deg);}.stage .dude.two figure.arm { background: black; height: 8px; position: absolute; top: 20px; width: 20px;}.stage .dude.two figure.arm.left { left: -13px; transform: rotateZ(40deg);}.stage .dude.two figure.arm.right { right: -10px; transform: rotateZ(-40deg);}.stage .dude-shadow.two { opacity: 0.1; transform: translateY(12px) translateX(-16px) translateZ(-6px) rotateZ(-90deg) rotateY(90deg) rotateZ(50deg) skewX(30deg) scaleX(0.8);}
登录后复制

第二个人物将会赋予他手, 手一开始是消失的,但是稍后会出现。

整体设置

当人物和背景都在出现在相应的位置, 这个场景已经准备好开始一些动画效果

让我们看看是怎么实现让它看起来像一个小人从第一个传送门到达第二个门。

动画

如果你看了示例,您会看到几个动画。但我将重点放在人物穿过门的动画,没有讲述所有的动画实现。

关键帧动画

通过使用keyframes来实现HTML的关键帧动画。然后用animation来执行一系列的关键帧动画。
第一件事是让人物从左边的传送门进入。下面是第一组关键帧:

@keyframes move-dude-one {  /* Character flies into scene */  0% { transform: translate3D(514px, -10px, 375px) rotateY(78deg) scaleY(2); }  /* Waits a moment */  1%, 18% { opacity: 1; transform: translate3D(514px, 50px, 375px) rotateY(78deg) scaleY(1); }  /* Moves toward the portal */  34%, 39% { opacity: 1; transform: translate3D(284px, 40px, 375px) rotateY(78deg); }  /* Pauses, them jumps in */  41%, 42% { opacity: 1; transform: translate3D(234px, 40px, 375px) rotateY(78deg); }  /* Vanishes */  43%, 100% { opacity: 0; transform: translate3D(234px, 40px, 375px) rotateY(78deg); }}/* Note: Use prefixes, such as @-webkit-keyframes, @-moz-keyframes, etc! */
登录后复制

关键帧是一系列的步骤,使用百分比来描述。百分比的设置会涉及到动画的时间。那么,如果一个动画持续10秒,10%设置为1秒。90%设置为9秒。

为了让人物完美的穿过传送门,我们每隔10秒设置一个动画。关于每个阶段的动画,我在代码中写了注释。
每个阶段都用了transform属性来设置人物的位置和角度。43%的时候,动画将人物的不透明度设置为0。这时将第一个人物在传送门消失。第二个人物出现。在我们这么做之前,让我们先把第一个动画加到第一个人物上:

.dude.one { animation: move-dude-one 10s linear infinite; opacity: 0;}
登录后复制

将animation属性应用到了due one元素上。设置了动画名称,动画时长10s,无限循环播放。为了确保角色在动画开始之前是隐藏的,不透明度设置成0。

完成之后,让我们为第二个人物进行相应的设置:

@keyframes move-dude-two {  /* Dude be invisible */  0%, 42% { opacity: 0; transform: translate3D(610px, 40px, 10px) rotateY(15deg); }  /* Apparato! */  42.5% { display: block; opacity: 1; transform: translate3D(610px, 40px, 10px) rotateY(15deg); }  /* Move onto the platform */  46%, 75% { opacity: 1; transform: translate3D(610px, 40px, 120px) rotateY(15deg); }  /* Stand there for a bit */  76%, 97% { opacity: 0; transform: translate3D(610px, -10px, 120px) rotateY(15deg) scaleY(2); }  /* Fly up into the sky! */  98%, 100% { opacity: 0; transform: translate3D(610px, -10px, 120px) rotateY(15deg) scaleY(2); }}@keyframes arms {  /* No arms */  0%, 53% { opacity: 0; }  /* Yes arms! */  54%, 100% { opacity: 1; }}
登录后复制

按计划,动画在42%的时候开始。这个人物穿过传送门,站了一会儿,然后飞向天空。
第二组关键帧动画描述它的手。手开始是看不见的,然后举了起来。      

我们给第二个人物添加了如下的动画:

.dude.two { animation: move-dude-two 10s linear infinite; opacity: 0;}.dude.two figure.arm { animation: arms 10s linear infinite; opacity: 0;}
登录后复制

两个动画设置完了,由于需要很好的配合第一个动画,都设置了持续10秒,无限循环。
如果你还没有完成,可以在主流浏览器中打开演示示例做参考,不过最好不要是Internet Explorer浏览器。

浏览器兼容性   

谈到浏览器兼容性的时候,需要注意的是,目前这个示例不兼容Internet Explorer。
Firefox有点瑕疵,但也还可以。Safari(苹果对webkit支持补丁之后)和chrome几乎是100%支持的。
抛开浏览器,在不同设备之间的展示效果。测试结果显示,iphone上的Safari比PC上的chrome效果要好。因为3D transforms的CSS属性,需要依赖于图形硬件。

源码下载

查看在线门户CSS演示或从Github下载源代码。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

HTML容易为初学者学习吗? HTML容易为初学者学习吗? Apr 07, 2025 am 12:11 AM

HTML适合初学者学习,因为它简单易学且能快速看到成果。1)HTML的学习曲线平缓,易于上手。2)只需掌握基本标签即可开始创建网页。3)灵活性高,可与CSS和JavaScript结合使用。4)丰富的学习资源和现代工具支持学习过程。

HTML,CSS和JavaScript的角色:核心职责 HTML,CSS和JavaScript的角色:核心职责 Apr 08, 2025 pm 07:05 PM

HTML定义网页结构,CSS负责样式和布局,JavaScript赋予动态交互。三者在网页开发中各司其职,共同构建丰富多彩的网站。

HTML中起始标签的示例是什么? HTML中起始标签的示例是什么? Apr 06, 2025 am 12:04 AM

AnexampleOfAstartingTaginHtmlis,beginSaparagraph.startingTagSareEssentialInhtmlastheyInitiateEllements,defiteTheeTheErtypes,andarecrucialforsstructuringwebpages wepages webpages andConstructingthedom。

了解HTML,CSS和JavaScript:初学者指南 了解HTML,CSS和JavaScript:初学者指南 Apr 12, 2025 am 12:02 AM

WebDevelovermentReliesonHtml,CSS和JavaScript:1)HTMLStructuresContent,2)CSSStyleSIT和3)JavaScriptAddSstractivity,形成thebasisofmodernWebemodernWebExexperiences。

网页批注如何实现Y轴位置的自适应布局? 网页批注如何实现Y轴位置的自适应布局? Apr 04, 2025 pm 11:30 PM

网页批注功能的Y轴位置自适应算法本文将探讨如何实现类似Word文档的批注功能,特别是如何处理批注之间的间�...

Gitee Pages静态网站部署失败:单个文件404错误如何排查和解决? Gitee Pages静态网站部署失败:单个文件404错误如何排查和解决? Apr 04, 2025 pm 11:54 PM

GiteePages静态网站部署失败:404错误排查与解决在使用Gitee...

如何用CSS3和JavaScript实现图片点击后周围图片散开并放大效果? 如何用CSS3和JavaScript实现图片点击后周围图片散开并放大效果? Apr 05, 2025 am 06:15 AM

实现图片点击后周围图片散开并放大效果许多网页设计中,需要实现一种交互效果:点击某张图片,使其周围的...

HTML,CSS和JavaScript:Web开发人员的基本工具 HTML,CSS和JavaScript:Web开发人员的基本工具 Apr 09, 2025 am 12:12 AM

HTML、CSS和JavaScript是Web开发的三大支柱。1.HTML定义网页结构,使用标签如、等。2.CSS控制网页样式,使用选择器和属性如color、font-size等。3.JavaScript实现动态效果和交互,通过事件监听和DOM操作。

See all articles