我正在参加 码上掘金体验活动,详情:show出你的创意代码块
概述
看到这个设计原型时,我相信很多人的 DNA
都被触动了(虽然我未生于那个年代,但被那个年代深深的吸引)。上世纪九十年代,业界还在探索 3D
射击游戏的时候,任天堂首先推出了初代《星际火狐》,可以说《星际火狐》算是最早一批的 3D
效果的飞行射击游戏了。
这个 CSS
实现的飞行器就源于《星际火狐》初代。
飞行器实现
飞行器看起来非常炫酷,你有可能会想这实现起来会有多复杂,哎~,那你就错了,且看我是如何一步一步分解炫酷的飞行器。
飞行器主体可以分为三部分: cockpit
飞行器主体;wing_left
左翼;wing_right
右翼
我们来看一下飞行器的俯视图:
从俯视图(写到这里突然发现也不算是俯视图,大家暂且这么理解着)可以看出,飞行器是由多个不规则的三角形组成的,同时还可以看到一些三维立体感,可见这些三角形发生了偏转。
开始抢答,在前端中看到奇奇怪怪的三角形,你的第一想法是什么? 利用 border 实现。
哎~你别说,我还就没这么用,皮不皮。
CSS3
有个属性叫 clip-path
,这个属性不得了,简直就是多边形的真神。(哦呦,谢天谢地了)
/* polygon 定义多边形等 */
/* polygon 实现的原理是连接指定点,最终显示所有点连接形成的闭合区域 */
clip-path: polygon(<fill-rule>?, [ <length-percentage> <length-percentage> ]#);
clip-path 的原点为左上角
cockpit 实现
cockpit
是飞行器的主舱,这里一定注意别上面看了个俯视图就以为当前部分只有两个三角形构成,我是有底的,有背的。
好的,好的,我知道了,那咱们就来瞅瞅 html
部分。
<div class="cockpit">
<div class="under"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="edge_left"></div>
<div class="edge_right"></div>
</div>
咦,他咋六部分那?我们后面的那两个三角形,一块绘制在主体部分。你看看,年轻人,一定要稳重,你不交代好,我咋能知道。
我们来实现一波 left
和 right
。
clip-path
的原点为左上角,polygon
是基于点连线实现,因此,因此 left
部分我们需要定义三个点,看图说话,左顶点位于最左边的上 1/4
处,因此位置应为 (0, 25%)
。其余点大致类似
.left {
width: 30px;
height: 150px;
background: linear-gradient(0deg, white 0%, #cccccc 100%);
-webkit-clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
}
.right {
width: 30px;
height: 150px;
background: linear-gradient(0deg, #aaaaaa 0%, #888888 100%);
-webkit-clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
}
你看看,这不是像模像样吗?
然后我们把剩下的部分依次进行上述设计,整体造型就成功设计出来了。
给飞行器的组成添加 position: absolute
定位以及 transform-rotate
语法,还是以 cockpit
为例子:
/* 我们以 cockpit 为例子 */
/* 底部 */
.under {
position: absolute;
width: 60px;
height: 150px;
background: linear-gradient(0deg, #666666 0%, #333333 100%);
-webkit-clip-path: polygon(14.5% 23.5%, 85.5% 23.5%, 50% 100%);
clip-path: polygon(14.5% 23.5%, 85.5% 23.5%, 50% 100%);
/* 设置旋转中心 */
transform-origin: 50% 100%;
transform: rotateX(10.7deg) rotateY(180deg);
}
/* 后部 */
.back {
position: absolute;
width: 60px;
height: 150px;
background: radial-gradient(ellipse at center, #2ca4f4 0%, #0d25bf 67%);
-webkit-clip-path: polygon(14.5% 25%, 85.5% 25%, 50% 6%);
clip-path: polygon(14.5% 25%, 85.5% 25%, 50% 6%);
transform-origin: 50% 25%;
transform: translateZ(-21.5px) rotateX(-45deg) rotateY(180deg);
}
/* 左面 */
.left {
width: 30px;
height: 150px;
background: linear-gradient(0deg, white 0%, #cccccc 100%);
-webkit-clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
clip-path: polygon(100% 0%, 0% 25%, 100% 100%);
transform-origin: 100% 0;
transform: rotateY(-45deg);
}
/* 右面 */
.right {
width: 30px;
height: 150px;
background: linear-gradient(0deg, #aaaaaa 0%, #888888 100%);
-webkit-clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
clip-path: polygon(0% 0%, 100% 25%, 0% 100%);
transform-origin: 0 0;
transform: rotateY(45deg);
}
我们来看一下立体造型:
怎么样,炫酷不,fly fly 飞飞飞。
cockpit 实现总结
其实从上面的分析可以发现,整体飞行器实现并不复杂,我们主要使用了下面的方法
clip-path
绘制各种不规则三角形position: absolute
实现图形定位transform-rotate
实现图像旋转实现立体效果
大家一定要学起来啊,这几个属性太强了。
动画效果
飞行器它不会飞那还叫飞行器吗?这部闹着玩呐,来,咱们通过 animation
让他动起来。
如果想飞行效果够炫酷,那必须是三轴同步飞行,因此我给这个飞行器分别添加了 x y z
轴的旋转动画。
/* 绕 x 轴旋转动画 */
@keyframes flyX {
0% {
transform: translateX(0px);
}
25% {
transform: translateX(180px);
}
50% {
transform: translateX(0px);
}
75% {
transform: translateX(-180px);
}
100% {
transform: translateX(0px);
}
}
/* 绕 y 轴旋转动画 */
@keyframes flyY {
0% {
transform: translateY(0px);
}
25% {
transform: translateY(200px);
}
50% {
transform: translateY(0px);
}
75% {
transform: translateY(-200px);
}
100% {
transform: translateY(0px);
}
}
/* 绕 z 轴旋转动画 */
@keyframes flyZ {
0% {
transform: translateZ(0px);
}
25% {
transform: translateZ(150px);
}
50% {
transform: translateZ(0px);
}
75% {
transform: translateZ(-150px);
}
100% {
transform: translateZ(0px);
}
}
然后我们将三个动画分别设置在飞行器的外层,形成下面的 HTML
结构。
<div class="fly_x">
<div class="fly_y">
<div class="fly_z">
<!-- 飞行器主体 -->
<div class="body"></div>
</div>
</div>
</div>
然后分别给 fly_x,fly_y,fly_z
添加动画效果。
.fly_x {
/* 实现 3d 效果 */
transform-style: preserve-3d;
-webkit-animation: flyX 10152ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
animation: flyX 10152ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
}
.fly_y {
transform-style: preserve-3d;
-webkit-animation: flyY 18891ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
animation: flyY 18891ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
}
.fly_z {
transform-style: preserve-3d;
-webkit-animation: flyZ 14259ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
animation: flyZ 14259ms cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite;
}
我们来看一下动画效果:
乍一看还挺炫酷,但看习惯了咋感觉笨笨的。这可不行,我们再给最外层添加一个 Z
轴的旋转,模拟相机效果。
#awing {
position: relative;
transform-style: preserve-3d;
transform: scale(1.5) rotateX(80deg);
-webkit-animation: 10000ms cameraRotate cubic-bezier(0.545, 0.08, 0.52, 0.975)
infinite alternate;
animation: 10000ms cameraRotate cubic-bezier(0.545, 0.08, 0.52, 0.975) infinite
alternate;
}
@keyframes cameraRotate {
0% {
transform: scale(1.5) rotateX(70deg) rotateZ(20deg);
}
100% {
transform: scale(1.5) rotateX(70deg) rotateZ(340deg);
}
}
咋样,现在看起来是不是炫酷多了,但总感觉飞行器还缺点什么,缺点啥呐?
火焰效果
飞行器飞起来没有火焰哪能有感觉,这里实现也有点看点,大家一定想不到。
我们先定义一个火焰 boost
,样式如下:
.boost {
position: absolute;
width: 10px;
height: 50px;
margin-left: -5px;
background: #00aaff;
}
然后我们添加多个 boost
,并且为每个 boost
定制动画效果,我这里举三个例子:
@keyframes boost1 {
0% {
transform: translateZ(-26px) translateY(-59px) translateX(3px) rotateY(
157deg
);
opacity: 0.6;
}
100% {
transform: translateZ(-14px) translateY(-300px) translateX(39px) rotateY(
157deg
);
opacity: 0;
}
}
@keyframes boost2 {
0% {
transform: translateZ(-19px) translateY(-48px) translateX(0px) rotateY(
220deg
);
opacity: 0.6;
}
100% {
transform: translateZ(-12px) translateY(-300px) translateX(-31px) rotateY(
220deg
);
opacity: 0;
}
}
@-webkit-keyframes boost3 {
0% {
transform: translateZ(-21px) translateY(-56px) translateX(7px) rotateY(
64deg
);
opacity: 0.6;
}
100% {
transform: translateZ(-6px) translateY(-300px) translateX(-4px) rotateY(
64deg
);
opacity: 0;
}
}
然后我们来看一下添加火焰后的效果:
怎么样够炫酷吗?这样还不够,我们继续优化一下火焰效果。
filter
CSS
里面有个 filter
属性,filter
属性有下列几种属性值:
blur(px)
: 对图像应用模糊效果。较大的值将产生更多的模糊。contrast(%)
: 调整图像的对比度。0%
将使图像完全变黑。默认值是100%
,代表原始图像grayscale(%)
: 将图像转换为灰阶。0% (0)
是默认值,代表原始图像。100%
将使图像完全变灰(用于黑白图像)- 还有几个属性,就不详细讲了,本项目主要使用前两个属性
给 boost
类名添加下面样式,然后我们来看一下最终结果:
filter: blur(15px) contrast(15);
码上掘金代码是 scss 实现的,文章中是以 css 为角度讲解的。
部分代码实现借鉴大佬。