[译] 使用CSS制作球体

5,068 阅读12分钟

原文链接:cssanimation.rocks/spheres/

使用border-radius属性,我们可以实现带圆角的形状和圆形。可以添加一些渐变效果来使他们变成圆球。让我们尝试一下,并且可以添加一些动画效果来赋予他们活力。

平面设计

我们可以通过两种方式用css来制作圆球。

第一种方式是通过使用大量元素来创建一个真正的3D球体。这种方式存在的缺点就是需要浏览器渲染许多元素,从而可能会影响性能。由于一个平滑的球体需要用到很多元素,所以看起来有点粗糙[应该是想表达想画一个平滑球体,需要特别多的元素来填补,不然看起来不光滑?]

相反地我会尝试第二种方式,利用css渐变来添加阴影,以及在一个单元素上添加3D效果。

例子和源码

所有在文章中提到的例子可以通过我的codepen账户找到,或者在文章中每个事例中选择“Edit on Codepen”查看源码。

在代码示例中,我没有添加任何浏览器前缀[css前缀]。我推荐使用像Autoprefixer这样的给工具,或者根据自己的需要添加相应的前缀。

基本形状

在添加细节前,我们先创建一个最基本的圆形。

从HTML开始:

<figure class="circle"></figure>

这里我们使用figure元素,但你也可以使用其他元素。figure是HTML5中用于表示图像或图表的元素,它是内容的一部分,可以在不影响内容含义的情况下删除。

通过figure元素来创建一个圆,我会给它设置宽高,并且设置border-radius为50%。任何形状只要设置border-radius超过50%,都会变成圆形。

.circle {
  display: block;
  background: black;
  border-radius: 50%;
  height: 300px;
  width: 300px;
  margin: 0;
}

一个圆形的展示。

See the Pen Spheres tutorial: 1. Circle by Donovan Hutchinson (@donovanh) on CodePen.

现在我们有了一个最基础的圆形,我们可以开始美化它,让它看起来更像个球形。

Shading 101

大部分3D球体教程所做的第一件事就是添加一个简单的径向渐变,稍微位置向上以及靠圆心的左侧。

我们可以通过css来做到这一点:

.circle {
  display: block;
  background: black;
  border-radius: 50%;
  height: 300px;
  width: 300px;
  margin: 0;
  background: radial-gradient(circle at 100px 100px, #5cabff, #000);
}

你应该可以看到像这样的效果:

See the Pen Spheres tutorial: 1.b Circle + basic shading by Donovan Hutchinson (@donovanh) on CodePen.

径向渐变

radial-gradient属性需要配置一些参数。第一个参数是渐变开始的中心位置。根据*shape* at *position*这种格式。在上个例子中,渐变形状是circle,它的中心位置离左侧100px,离顶部100px。

接下来是设置一系列颜色。你可以指定两种颜色以上,但必须在每个颜色之间添加一个距离,可以让渐变知道何时将每个颜色过渡到它的下个颜色。

在这个例子中指定了两种颜色,这让浏览器默认第一个颜色从0%开始,第二个颜色为100%结束,在这两个颜色间绘制过渡效果。假如我们想改变渐变中的其他步骤,可以指定距离,用像素或者百分比来表示,在接下来的描述中可以看到。

我们有一个看起来有点像3D的东西,看起来很棒,但让我们尝试着让它看起来更好一些。

Shadows & 3D

根据你应用于曲面的着色阴影,可以创建出不同的外观效果。首先,让我们设置一个场景来将球放在里面。

在这里我们将用到更多的HTML元素:

<section class="stage">
  <figure class="ball"><span class="shadow"></span></figure>
</section>

类名为ball的标签里面包含了用来创建阴影效果span标签,而它被的父元素是stagediv。当我们想要设置perspective和定位阴影时, 父元素stagediv很有用,因为可以看起来更像是3D效果。

stage以及shadow添加样式。

.stage {
  width: 300px;
  height: 300px;
  display: inline-block;
  margin: 20px;
  perspective: 1200px;
  perspective-origin: 50% 50%;
}
.ball .shadow {
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0) 50%);
  transform: rotateX(90deg) translateZ(-150px);
  z-index: -1;
}

注意,在上面示例中我没有添加相对于的css前缀,但在codepen示例中是包含的。在上面示例中我给stagediv设置perspective: 1200pxperspective属性使具有三维位置变换的元素产生透视效果[大概意思应该是这个]。

shadow设置径向渐变radial gradient,然后使用transform属性来对其定位。在3D空间里,transform属性包括旋转[rorate]、缩放[scale]、移动[move]和倾斜[skew]。让shadow在x轴上旋转90度,z轴上向下偏移150px。

由于我们在stage容器设置了perspective属性,所以shadow看起来像是一个拉伸的椭圆形,感觉像圆球的影子。

See the Pen Spheres tutorial: 2 Basic plus shadow by Donovan Hutchinson (@donovanh) on CodePen.

它现在看起来比之前要好一点了,让我们为它添加更多的底纹效果。

Multiple shaders

现实中很少会看到只有一个角度发光的物体,因为光会反射到其他表面上,最终各种光源混合在一起。为了让这个球看起来更加真实,我们使用伪元素添加两个渐变,让它看起来更有光泽。

.ball {
  display: inline-block;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 50%;
  position: relative;
  background: radial-gradient(circle at 50% 120%, #81e8f6, #76deef 10%, #055194 80%, #062745 100%);
}
.ball:before {
  content: "";
  position: absolute;
  top: 1%;
  left: 5%;
  width: 90%;
  height: 90%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 0px, #ffffff, rgba(255, 255, 255, 0) 58%);
  filter: blur(5px);
  z-index: 2;
}

这里我们设置了两个稍微复杂的渐变。

第一个渐变是一种弱光效果应用在ball元素上,渐变的中心为50%、120%,使中心位置离开球表面。我这样做是使最后的颜色过渡看起来不要太生硬,从而展现出更加平滑的渐变效果。

第二个渐变是位于球体顶部的高亮效果,宽高都为球体的90%。它位于球体顶部的中心,向外渐渐扩散,直到消失。

我使用了before伪元素,而不是创建一个新元素去盖在球体上方。

由于单纯使用该渐变会看起来比较生硬,所以我利用了blur效果去对其进行柔化,但目前该属性只有chrome和safari支持,但在未来其他浏览器中,它可能会发挥更大的作用。

以上两个渐变的设置让球拥有更好的视觉效果:

See the Pen Spheres tutorial: 3 Better shading by Donovan Hutchinson (@donovanh) on CodePen.

Shinier

现在球看起来效果非常柔和,所以接下来我们添加一些光泽,让它看起来更像一个斯诺克球。

为达到这个效果,我们同样添加柔和的光线,但要将顶部的高光效果调整的更小以及更锐利。我们需要使用两个伪选择器覆盖在球颜色上,一个底部的高光渐变,一个反射光效果渐变。

.ball {
  display: inline-block;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 50%;
  position: relative;
  background: radial-gradient(circle at 50% 120%, #323232, #0a0a0a 80%, #000000 100%);
}
.ball:before {
  content: "";
  position: absolute;
  background: radial-gradient(circle at 50% 120%, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 70%);
  border-radius: 50%;
  bottom: 2.5%;
  left: 5%;
  opacity: 0.6;
  height: 100%;
  width: 90%;
  filter: blur(5px);
  z-index: 2;
}
.ball:after {
  content: "";
  width: 100%;
  height: 100%;
  position: absolute;
  top: 5%;
  left: 10%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8) 14%, rgba(255, 255, 255, 0) 24%);
  transform: translateX(-80px) translateY(-90px) skewX(-20deg);
  filter: blur(10px);
}

这里我们设置微弱的渐变效果应用在球上面,before伪元素包含一个较亮的高光,它也从球的底部开始,并产生来自表面的反射光的效果。

这里加了个新的伪元素after,它是一个圆形渐变效果,从中心位置50% 50%渐变,并在24%左右的标记处渐变为透明。这个渐变产生了白色反光的效果,但为了让它看起来更像是一个反射光,我们设置了transform来调整它的位置。

设置transform属性,往左移动80px,往上移动90px,并且设置了倾斜效果,往x轴倾斜拉伸,使其看起来更像是球反射出的光泽。

See the Pen Spheres tutorial: 4 Shinier by Donovan Hutchinson (@donovanh) on CodePen.

8-ball

让我们继续添加数字8,看起来更像是一个台球。

我们需要一个额外的元素来增加数字8,以及设置其样式。

<section class="stage">
  <figure class="ball">
    <span class="shadow"></span>
    <span class="eight"></span>
  </figure>
</section>

.ball .eight {
  width: 110px;
  height: 110px;
  margin: 30%;
  background: white;
  border-radius: 50%;
  transform: translateX(68px) translateY(-60px) skewX(15deg) skewY(2deg);
  position: absolute;
}
.ball .eight:before {
  content: "8";
  display: block;
  position: absolute;
  text-align: center;
  height: 80px;
  width: 100px;
  left: 50px;
  margin-left: -40px;
  top: 44px;
  margin-top: -40px;
  color: black;
  font-family: Arial;
  font-size: 90px;
  line-height: 104px;
}

再次利用border-radius创建圆eight,并设置transdform属性将该元素定位在右上角。这里我使用before伪元素将数字8添加到content,然后以类似的方式来调整该数字的位置。

一个带光泽的8号台球。

See the Pen Spheres tutorial: 4.b 8-ball by Donovan Hutchinson (@donovanh) on CodePen.

Got my eye on you

css的transform的一大优点就是可以被应用在动画上面,将csskeyframes关键帧用于动画,可以将一系列元素变换作为动画应用在元素上。我将制作一个会动的眼球。

首先是调整示例8-ball中使用的一些颜色,细微的调整让它看起来更像是个眼睛。HTML代码:

<section class="stage">
  <figure class="ball">
    <span class="shadow"></span>
    <span class="iris"></span>
  </figure>
</section>

除了虹膜和瞳孔样式之外,其他css样式大部分类似于示例8-ball。

.iris {
  width: 40%;
  height: 40%;
  margin: 30%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, #208ab4 0%, #6fbfff 30%, #4381b2 100%);
  transform: translateX(68px) translateY(-60px) skewX(15deg) skewY(2deg);
  position: absolute;
  animation: move-eye-skew 5s ease-out infinite;
}
.iris:before {
  content: "";
  display: block;
  position: absolute;
  width: 37.5%;
  height: 37.5%;
  border-radius: 50%;
  top: 31.25%;
  left: 31.25%;
  background: black;
}
.iris:after {
  content: "";
  display: block;
  position: absolute;
  width: 31.25%;
  height: 31.25%;
  border-radius: 50%;
  top: 18.75%;
  left: 18.75%;
  background: rgba(255, 255, 255, 0.2);
}

蓝色渐变形成虹膜的彩色部分,而瞳孔和高光效果使用伪元素进行创建,我还将动画属性animation应用到iris元素,设置如下:

animation: animation-name 5s ease-out infinite;

在该例子中,设置了一个名为“animation-name”的动画,时间设置为5秒,无限循环,并设置其缓动效果为ease-outease-out指动画在快结束时速度变慢,从而达到更加自然的效果。

在没有创建动画情况下,我们看到一个不会动的眼球。

See the Pen Spheres tutorial: 5 Eyeball by Donovan Hutchinson (@donovanh) on CodePen.

让我们创建关键帧keyframes来描述眼球应该如何移动。

@keyframes move-eye-skew {
  0% {
    transform: none;
  }
  20% {
    transform: translateX(-68px) translateY(30px) skewX(15deg) skewY(-10deg) scale(0.95);
  }
  25%, 44% {
    transform: none;
  }
  50%, 60% {
    transform: translateX(68px) translateY(-40px) skewX(5deg) skewY(2deg) scaleX(0.95);
  }
  66%, 100% {
    transform: none;
  }
}

css中的动画关键帧刚开始用起来可能会比较难,你正在做的是用一系列场景来展示元素的各个状态,每个状态对应一个百分比。在该示例中,iristransform: none开始,在20%时,它设置了iris向左移动倾斜。浏览器会自动计算0~20%之间的差距,从而在两者之间进行平滑的过渡。

就像前面说的,完成关键帧中设置的一系列场景需要5秒。

不要忘记设置样式需要的前缀,因为有些浏览器存在兼容css样式问题。

See the Pen Spheres tutorial: 5b Eyeball (animated) by Donovan Hutchinson (@donovanh) on CodePen.

Bubbles

动画和颜色渐变可以产生各种有趣多变的效果,比如气泡?

创建气泡的外观与前面的例子类似,在主色调中将透明度调高,并使用俩个伪元素来增加光泽。

设置动画使气泡动起来。

@keyframes bubble-anim {
  0% {
    transform: scale(1);
  }
  20% {
    transform: scaleY(0.95) scaleX(1.05);
  }
  48% {
    transform: scaleY(1.1) scaleX(0.9);
  }
  68% {
    transform: scaleY(0.98) scaleX(1.02);
  }
  80% {
    transform: scaleY(1.02) scaleX(0.98);
  }
  97%, 100% {
    transform: scale(1);
  }
}

动画适用于整个气泡以及伪元素。

See the Pen Spheres tutorial: 6 Bubble (animated) by Donovan Hutchinson (@donovanh) on CodePen.

Using images

到目前为止,所有球都是在不使用任何图像的情况下创建的。背景图像可以添加更多的细节,并且仍然可以利用伪元素中的css着色。

hop.ie/balls/image…

添加些css渐变效果可以达到深度错觉。

See the Pen Spheres tutorial: 7 Tennis ball by Donovan Hutchinson (@donovanh) on CodePen.

Around the world

动画可以应用于背景图像的位置,使用它我们可以实现旋转地球仪效果。

下面的平面图像在顶部和底部位置稍做拉伸用来作为背景图像。

hop.ie/balls/image…

通过添加阴影和动画,可以创建出3D效果的地球仪,可以在Codepen查看其运行结果。由于该示例的性能问题,我这里设置为默认显示HTML。

ps: 非常感谢Sidoruk Sergey(@Sidoruk_SV)优化这个示例,看起来很棒。

See the Pen Globe by Donovan Hutchinson (@donovanh) on CodePen.

Resources

如果你想了解更多信息,请参考一些有关radial gradients的资料。

想要找更多3D例子?查看Portal CSS获取更多。

Feedback

所有的示例都可以在我的codepen找到。非常感谢Chris和团队提供的出色资源。

如果您对上述内容有任何疑问,请通过电子邮件Twitter与我们联系。