转转品牌升级后更新了全新的Logo,今天我们用纯CSS来实现转转的新Logo,为了有一定的挑战性,这里我们只使用一个标签实现,将最大化的使用CSS能力完成Logo的绘制与动画效果。
新logo保留了原本logo里转转熊的轮廓,两个熊耳是两个卫星围绕熊头旋转,是"循环"的意思。中间倾斜的转转首字母"Z",既像二手质检的印章,又像N------NEW的首字母,代表着全新的二手生活方式。
以上是我们要还原的Logo效果动图,现阶段使用方式主要是gif和lottie
SVG两种方式。因为我们的目的是使用单标签实现所有的功能点,对于一些细节部分有所取舍,并不是百分百还原,也并不代表使用CSS的成本和效果是最好的,仅表达CSS的强大能力。接下来分析我们要核心实现的功能点:
- 开始动画时中心的大圆以及2个围绕的小圆都有放大的效果
- 动画开始后2个小圆围绕中心的椭圆旋转
- 字母 Z 由大变小覆盖在中心的椭圆
- 字母 Z 出现时中心的椭圆由红色边框圆变成实心红色圆
- 仔细观察这个字母 Z 并不是普通的字符
基于上述分析接下来开始核心的代码拆解实现,在开始前先定义一些变量方便后续使用:
css
:root {
/* 主题色 */
--mainColor: #ff483c;
/* 字体颜色 */
--fontColor: #fff;
/* 字体宽度 */
--zWidth: 260px;
/* 中心椭圆宽高比 */
--parentScaleY: 0.9;
/* 子元素抵消比例 */
--childScaleY: calc(1 / var(--parentScaleY))
}
2个小圆旋转动画
如果是围绕一个正圆的旋转那么实现就简单很多了,但是这里是一个椭圆,纯CSS应该怎么做呢?根据小编目前的了解大概有以下几种方式都可以实现,但是对应的效果有所区别:
- 使用
transform-style: preserve-3d;
开启3D模式,但是对应的小圆在旋转角度存在视角消失的情况,需要额外处理 - 使用
cubic-bezier
贝塞尔曲线执行动画可以达到椭圆曲线的效果,但是存在动画开始停止不可控的情况 - 使用
rotate
0-360deg旋转,对应子元素需要设置反向旋转来抵消父级的旋转带来的影响
对比各种情况最终使用第三个方案即可满足条件且实现成本较低,首先画出一个椭圆的边框效果,设置scaleY
和border-radius
将一个正方形变成椭圆形,核心代码如下:
css
width: 570px;
aspect-ratio: 1;
border-radius: 50%;
border: 10px solid var(--mainColor);
transform: scaleY(var(--parentScaleY));
然后给这个大圆添加旋转的动画,将整体旋转360度,这时还没有添加其他的元素,所以界面没有变化。
css
@keyframes circle {
0% {
transform: scaleY(var(--parentScaleY)) rotate(0);
}
100% {
transform: scaleY(var(--parentScaleY)) rotate(360deg);
}
}
设置大圆的动画执行相关参数。
css
animation: circle 1s 1 cubic-bezier(.5,.08,.52,.93) forwards;
边框上面的两个圈基于伪元素实现,绘制一个圆并使用定位将小圆定位于大圆的顶部两端。然后设置动画,这里需要注意的是需要设置反向旋转来抵消父级的旋转。
css
@keyframes mini-circle {
0%{
transform: rotate(0deg) scaleY(var(--childScaleY));
}
100%{
transform: rotate(-360deg) scaleY(var(--childScaleY));
}
}
这里为了方便查看将椭圆的参数调大进行对比,可以看到设置抵消后的区别一个圆被压缩了另一个保持了正常的圆形:
未设置抵消
已设置抵消
这里为了更好的利用元素的使用,这里将两个圆的绘制进一步优化到一个伪元素中,核心使用径向渐变背景实现,在同一个 background
中绘制两个纯色圆形,两个圆除了绘制的位置不同其他都是一样。代码如下:
css
background:
radial-gradient(circle 65px at 31% 24.5%,var(--mainColor) 0% 100%, transparent),
radial-gradient(circle 65px at 72% 24.5%, var(--mainColor) 0% 100%, transparent);
到此这部分的内容基本功能完成,实际效果如下:
Z 字母
接下来使用另一个伪元素实现 Z 字母的效果,仔细观察 Z 字母的两个拐角都是锐角效果,并不是日常字母有拐角的效果。
基于当前的样式我们可以用3段矩形拼接完成效果,上下各一段,中间一段增加旋转角度,但是只用一个伪元素如何绘制三个矩形呢,还是用到CSS渐变,这次需要用到linear-gradient
线性渐变,顶部和底部正常从上往下绘制,中间的部分需要绘制线条的旋转角度,除开需要显示的颜色其他部分用#0000
透明色,为了方便看效果对三个矩形更换了不同的颜色,代码如下:
css
background:
linear-gradient(#f00 25%, #0000 25%),
linear-gradient(#0000 75%, #29eb9a 25%),
linear-gradient(124deg, #0000 40%, #000 40% 60%, #0000 60%);
绘制的效果如下:
可以看到目前的效果还不能满足需求,两端都出现了多余的部分,需要进一步优化将其隐藏。这时候需要用到background-size
与background-position
,通过background-size
设置绘制内容的大小,通过设置background-position
设置绘制内容的起点位置,因为设置了一定的空隙部分需要增加no-repeat
不重复,增加以下代码:
css
background-size: 80% var(--w), 80% var(--w), 100% 100%;
background-position: 0 0, 100% 0;
background-repeat: no-repeat;
此时基本符合预期的效果,但实际设计图左下角的锐角部分有超出正常矩形一部分。
所以需要对刚刚设置的size
和position
部分改进,将第一个矩形左侧空出16
px:
css
background-size: 74% var(--w), 80% var(--w), 100% 100%;
background-position: 16px 0, 100% 0;
因为空出了左侧一部分距离,导致整个内容不再是一个正方形,所以需要设置 scaleX
还原宽度将图像还原到正方形。
对于刚刚设置的background
相关属性可以在代码层进一步优化,使用简写将代码合并到一行:
css
background:
linear-gradient(var(--fontColor) 25%, #0000 25%) 16px 0 / 74% var(--zWidth) no-repeat,
linear-gradient(#0000 75%, var(--fontColor) 25%) 100% 0 / 80% var(--zWidth) no-repeat,
linear-gradient(124deg, #0000 40%, var(--fontColor) 40% 60%, #0000 60%) 0 0 / 100% 100% no-repeat;
然后继续给这个 Z 添加动画效果,默认设置 opacity: 0
隐藏,因为 Z 是小圆动画执行结束才出现的,所以还需增加动画的延迟执行时间,增加动画相关代码:
css
animation: z 0.3s 1s 1 ease-in-out forwards;
opacity: 0;
设置动画将内容从1.5倍缩小到正常并设置旋转角度,返抵消以及平移到Logo正中心。这里因为初始增加了1.5的放大所以设置返抵消相关参数有所不同,在设置scaleY
的同时还设置了skew
进一步还原尺寸。
css
@keyframes z {
0% {
transform: rotate(-45deg) scale(1.5) translate(0, -50%) skew(-13deg, 8deg);
opacity: 1;
}
100% {
transform: rotate(-42deg) scaleY(var(--childScaleY)) translate(-4%, -64%) skew(-13deg, 8deg);
opacity: 1;
}
}
完成后的 Z 字母动画效果:
其他细节
开始动画时中心的椭圆以及2个围绕的小圆都有放大的效果,所以需要对前面动画关键帧的定义继续完善。
小圆部分执行动画的前10%也增加scale(0.5)
。
css
@keyframes mini-circle {
0%{
transform: rotate(0) scale(0.5);
}
10%{
transform: rotate(0) scaleY(var(--childScaleY));
}
}
大圆执行动画的前10%部分增加scale(0.8)
。大圆部分还有一个效果是字母 Z 出现的时候中心的椭圆由边框圆变成实心圆,所以是在动画结束前增加对背景色的变化,代码如下:
css
@keyframes circle {
0% {
transform: scale(0.8) rotate(0);
}
10% {
transform: scaleY(var(--parentScaleY)) rotate(0);
}
80% {
background-color: var(--fontColor);
}
100% {
background-color: var(--mainColor);
transform: scaleY(var(--parentScaleY)) rotate(360deg);
}
}
最后
到此我们整个代码实现过程就结束了,基于一个标签实现了转转的Logo的绘制及动画效果。当然这只是对其主要的功能还原,如需完整还原细节还需要进一步优化。
CSS的确是足够强大且对很多复杂的图形效果都能实现,这里我们主要是使用渐变背景实现图案的绘制,除了渐变还可以使用CSS阴影也能达到类似的效果。使用CSS对比使用SVG或GIF在资源体积上有很大的提升,本次实现的Logo使用lottie
的json
需要100KB左右,使用GIF大约需要27KB左右,但是纯CSS实现仅1KB不到即可完成,但是对于较为复杂的场景对应的代码也提升了不少的复杂度,大家要根据实际的情况使用,感兴趣的同学欢迎留言交流。
> 转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。
> 关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~