CSS的视觉效果
记得在第五届中国区的CSS Conf大会上@张鑫旭、@袁川两位老师分享的话题都和视觉以及创意有关的话题,而且在社区中有关于这方面讨论也多,比如说@Lea Verou的《CSS Secrets》一书就有很多介绍CSS用来创建视觉效果的技巧。另外,在社区也有很多关于这方面的介绍,比如CSSArt网站、ASingleDiv网站和CodePen上的SingleDiv等。当然,也有同学私下找我,让我能不能抽空聊聊这方面的话题,那么今天,我们就和大家来聊聊如何使用CSS来实现一些视觉效果,在这里我更倾向于和项目中的一些需求和大家讨论这方面的话题。希望大家对这方面话题感兴趣。
项目中对视觉效果的诉求
对于Web开发人员来说,或者说对于视觉还原(称呼高级一点是UI开发者)来说,在项目中有很多效果(视觉效果)是可以纯CSS代码来实现的,比如像下图这些效果:
上图都是摘自历年来项目中的视觉稿。
看到上图中各视觉元素的效果时,试问一下,你是采用纯CSS的代码来实现呢?还是切出图片运用于项目中呢?如果我来回答该问题的话,那就是用代码来实现。我一向的原则是:
能用代码实现的效果绝不采用图片!
具体原因我就不说了,大家都懂的。那么在CSS中怎么来实现这些效果,或者说用纯代码来更真切的还原视觉效果,即CSS视觉效果。
纯CSS绘图要素
在CSS的世界中我们有一些属性可以用来绘制图形,其中最为常见的有:
border
CSS的border
可以轻易的绘制线条,比如直线,点线等:
border
除了绘制线形之外,还可以绘制一些其他的图形,其中最为熟悉的就是三角形之类的:
正如上例所示,如果元素width
或height
值为非0
时,还可以绘制出别的图形。
box-shadow
估计在很多开发者的认知中,box-shadow
只是用来给元素盒子添加阴影效果,事实上并非如此,借助box-shadow
独有的特性,除了可以绘制阴影之外,还可以绘制一些图形。比如绘制一个3D形状:
但社区中有人提出,box-shadow
对于Web性能有所影响,特别是会减缓滚动速度,因此在绘制3D的效果时,时常会借助::before
和::after
来处理(据说对于性能有所提高):
CSS的伪元素
::before
和::after
在Web中还可以做很多事情,如果你对这方面感兴趣的话,可以阅读《伪元素能帮助我们做些什么》一文。
除此之外,box-shadow
还可以模拟出多个DOM元素,在ASingleDiv网站中提供的示例中就不缺这种效果:
利用该特性,并且配合CSS的animation
就可以创建很多具有创意的Loading效果,比如:
border-radius
对于大多数Web开发者而言,习惯性的给border-radius
设置一个参数,比如border-radius: 50%
绘制一个圆或椭圆。但是,如果我们给border-radius
设置八个参数值时,可以创建不同的形状:
这种特性用于实际案例中也具有独特的视觉效果:
@supremebeing09在他的教程《CSS Border-Radius Can Do That?》(译文)中还专门提供了一个工具,让你更好的控制border-radius
的值,实现不同的效果:
具体的案例可以看看@Louise Flanagan绘制的超级马里奥的脸:
渐变
CSS的渐变属性已经是非常成熟的了,其主要分为线性渐变(linear-gradient()
、repeating-linear-gradient()
)、径向渐变(radial-gradient()
、repeating-radial-gradient()
)以及圆锥渐变(conic-gradient()
、repeating-conic-gradient()
)等。有关于这方面更详细的介绍可以阅读:
- CSS3 Gradient
- 再说CSS3渐变:线性渐变
- 再说CSS3渐变:径向渐变
- 为什么要使用
repeating-linear-gradient
- 你真的理解CSS的
linear-gradient
? - 使用CSS渐变绘图
- conic-gradient
使用CSS的渐变特性可以帮助我们绘制出很多图形,比如@Lea Verou创建的CSS Patterns Gallery:
如果你对这方面感兴趣的话,还可以阅读《51 CSS Background Patterns》一文中提供的各种效果。
另外,时至今日,CSS渐变在实际项目中使用非常的广泛。比如文章开头提展示的一些UI效果,大部分都有渐变的身影。比如进度条的效果,使用repeating-linear-gradient()
就可以很容易的实现:
@rkchauhan提供了一个纯CSS实现的各种不同效果的进度条,共中很多就离不开渐变:
有关于渐变更多的效果还可以点击这里查看,另外,如果你对使用渐变绘制图形过程感兴趣的话,可以阅读《使用CSS渐变绘图》一文,英文原文可以点击这里查看。
除此之外,CSS的渐变特性和background-size
、background-clip
等背景属性结合在一起也能绘制出一些具有创意的图形效果:
使用渐变最难的并不是他的用法,而且对颜色的掌握以及对光线角度的掌握,这方面并不是说掌握CSS就能做的。比如@Bradley Taunt提供的一个案例,使用CSS渐变绘制出一个立体的圆球形:
clip-path
对于绘制图形而言,clip-path
中提供的函数是最灵活的。可以很好的帮助我们绘制出不同的图形:
有关于
clip-path
更详细的介绍,可以阅读《探索CSS Masking模块:Clipping》一文。
clip-path
除了可以实现绘制一些图形之外,还可以实现一些具有创意的效果,比如《响应式网格布局》一文提到的穿叉效果:
clip-path
在动效方面的创意也很丰富,比如@Travis Almand的《Animating with Clip-Path》和@Mikael Ainalem的《Creating Morphing Animations with CSS clip-path》提到的效果:
在布局方面也有独到之处,特别是和CSS的Shape相关属性结合在一起可以实现一些异形布局效果:
transform
CSS的transform
属性中包含了多个功能性函数,比如translate()
、rotate()
、skew()
、scalc()
、translate3d()
、rotate3d()
、scale3d()
等。
目前W3C规范对这方面的描述也是非常的详细,主要的文档规范有:
- CSS Transforms Module Level 1
- CSS Transforms Module Level 2
- CSS 3D Transforms Module Level 3
- FX 2D Transforms 1.0, Part 2: Language
CSS transform
可做的事情非常地多,比如Codepen上的这些案例:
同样的,用来绘制图形也是非常有用的,比如@Louise Flanagan写的这个Demo,就有很多地方使用了rotate
:
另外在构建3D和制作动画,CSS的transform
也很有用。不过这里不花时间阐述,感兴趣的话可以阅读:
overflow
overflow
在图形绘制中所起的作用大都是用来隐藏溢出的部分,即overflow: hidden
使用的多。事实上,CSS的overflow
也是在CSS中也是一个强大的功能模块,早前在《你所不知道的CSS Overflow Module》一文中有做过深入的探讨。
上面这几个属性在CSS绘图世界中用得最为频繁的属性,当然,CSS是非常有意思的,绘制同一个图形可能会有多种不同的姿势。另外,这些技巧只是一些基础知识,如果要真正的实现一些具有创意的效果,那还是需要打开自己的灵感。比如@袁川大大分享的《Generative Art With CSS》:
如果你感兴趣的话,也可以关注<css-doodle>
,你会领略到CSS神奇的另一面,也会感叹到原来CSS离艺术的创作是这么的近:
附文:《一个制作Web图案的组件:css-doodle》。
CSS 绘制动物森林场景
最近动物森林(Animal Crossing)游戏非常的火爆(你玩吗?),但是说,用CSS来绘制一个类似动森中的一个场景,你可能会像为觉得不可思议吧。但是@Tee Diang就做到了:
看上去很复杂,对吧。其实里面用到的技术都是前面和大家聊的部分。我们来看看怎么使用前面聊的技术来绘制。这里并不会完全介绍怎么绘制这样的一个游戏场景,只是会以其中的部分元素为例,目的是告诉大家,其实这也很简单。
我们来看其中几个元素的制作。先来看椰汁树的制作:
<!-- HTML -->
<div class="palm-tree joycon-tree">
<div class="palm-trunk"></div>
<div class="palm-fruit"></div>
<div class="palm-leaves">
<div class="palm-leaf">
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
</div>
<div class="palm-leaf">
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
</div>
<div class="palm-leaf">
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
</div>
<div class="palm-leaf">
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
<div class="edges"></div>
</div>
</div>
</div>
CSS很简单,就是我们平常写的一些属性:
// CSS
.palm-tree {
width: 100px;
height: 200px;
position: relative;
transform: scaleX(-1);
}
.palm-tree::after {
content: "";
position: absolute;
width: 60px;
height: 40px;
background-color: rgba(0, 0, 0, 0.3);
bottom: 0;
z-index: -1;
border-radius: 100%;
left: 40px;
bottom: -10px;
}
.palm-trunk {
position: absolute;
width: 30px;
height: 100px;
background-color: #df916a;
border-radius: 30px;
bottom: 0;
left: 40%;
transform: rotate(-10deg);
background: linear-gradient(135deg, #d67240 25%, transparent 25%),
linear-gradient(225deg, #d67240 25%, transparent 25%) -50px 0,
linear-gradient(315deg, #d67240 25%, transparent 25%) -50px 0,
linear-gradient(45deg, #d67240 25%, transparent 25%);
background-size: 50px 50px;
background-color: #df916a;
border: 1px solid black;
box-shadow: inset 0px 30px 10px #7c2020;
}
.palm-fruit {
position: absolute;
z-index: 2;
}
.palm-fruit::before,
.palm-fruit::after {
content: "";
position: absolute;
background-color: #ffea71;
width: 30px;
height: 30px;
border-radius: 100%;
border: 1px solid brown;
box-shadow: inset 3px -3px goldenrod;
}
.palm-fruit::before {
left: 40px;
top: 90px;
}
.palm-fruit:after {
top: 95px;
left: 20px;
}
.palm-leaves {
position: absolute;
}
.palm-leaf {
position: absolute;
width: 90px;
height: 40px;
background-color: #7abe7a;
border-top-left-radius: 90px;
border-top-right-radius: 90px;
border: 1px solid black;
border-bottom: none;
display: flex;
justify-content: center;
align-items: baseline;
}
.palm-leaf:nth-child(1) {
transform: rotate(-20deg);
left: 30px;
top: 50px;
animation: rotateLeaf1 3s ease infinite;
}
.palm-leaf:nth-child(2) {
transform: rotate(20deg);
left: -40px;
top: 50px;
animation: rotateLeaf2 3s ease infinite;
}
.palm-leaf:nth-child(3) {
transform: rotate(-30deg);
left: -40px;
top: 90px;
width: 80px;
height: 40px;
animation: rotateLeaf3 3s ease infinite;
}
.palm-leaf:nth-child(4) {
transform: rotate(20deg);
left: 40px;
top: 75px;
width: 80px;
height: 40px;
border-top: none;
animation: rotateLeaf2 3s ease infinite;
}
@keyframes rotateLeaf1 {
50% {
transform: rotate(-25deg);
}
}
@keyframes rotateLeaf2 {
50% {
transform: rotate(25deg);
}
}
@keyframes rotateLeaf3 {
50% {
transform: rotate(-35deg);
}
}
.edges {
flex: 1 1 0;
height: 14px;
width: 100%;
margin-top: 29px;
border-radius: 100%;
background-color: #7abe7a;
border-bottom: 2px solid black;
}
我们再来看另一个部分,就是人物部分:
<!-- HTML -->
<div class="isabelle">
<div class="legs"></div>
<div class="arm right-arm"></div>
<div class="dress"></div>
<div class="arm left-arm"></div>
<div class="head-container">
<div class="head">
<div class="right-ear"></div>
<div class="left-ear"></div>
<div class="bangs"></div>
<div class="ponytail"></div>
<div class="face">
<div class="eyes"></div>
<div class="closed"></div>
<div class="cheeks"></div>
<div class="mouth"></div>
<div class="nose"></div>
</div>
</div>
</div>
</div>
对应的CSS:
// CSS
.isabelle {
width: 100px;
height: 150px;
position: relative;
}
.isabelle:after {
content: "";
position: absolute;
width: 65px;
height: 28px;
background-color: rgba(0, 0, 0, 0.2);
z-index: -1;
right: 25px;
border-radius: 100%;
bottom: 13px;
transform: skew(25deg);
}
.head,
.face {
position: absolute;
left: calc(50% - 27px);
width: 58px;
height: 40px;
background-color: #ffe89e;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 15px;
border-top-right-radius: 15px;
border-top-left-radius: 10px;
top: 50px;
border: 1px solid #ff9292;
background-image: radial-gradient(
35px 30px at 70% 90%,
white 60%,
transparent 61%
);
animation: rotateHead 8s ease infinite;
}
@keyframes rotateHead {
50% {
transform: rotate(-10deg);
}
}
@keyframes rotateEar {
50% {
z-index: -1;
transform: scaleX(-1) rotate(10deg);
}
}
.left-ear,
.right-ear,
.right-ear {
position: absolute;
background-color: #ffdc6b;
top: -22px;
}
.left-ear,
.right-ear {
width: 30px;
height: 65px;
border: 1px solid brown;
border-radius: 84% 16% 42% 58% / 79% 9% 91% 21%;
left: -15px;
transform: rotate(10deg);
}
.right-ear {
transform: scaleX(-1) rotate(25deg);
z-index: -1 !important;
left: 30px;
}
.bangs {
position: absolute;
width: 100%;
height: 30px;
left: 1px;
transform: scale(0.95);
z-index: 2;
}
.bangs:before,
.bangs:after {
content: "";
position: absolute;
width: 35px;
height: 30px;
background-color: #ffe89e;
border: 1px solid #ff6565;
top: -25px;
}
.bangs:before {
transform: scaleX(1.2) rotate(-25deg);
z-index: 2;
border-radius: 73% 27% 70% 50% / 88% 29% 71% 52%;
}
.bangs:after {
transform: rotate(10deg);
border-radius: 30% 70% 30% 70% / 30% 77% 53% 70%;
left: 30px;
}
.ponytail {
width: 20px;
height: 10px;
background-color: #ac0000;
position: absolute;
top: -32px;
left: 20px;
border-radius: 100%;
}
.ponytail:before,
.ponytail:after {
content: "";
position: absolute;
background-color: #ffe89e;
border: 1px solid brown;
}
.ponytail:before {
width: 28px;
height: 28px;
border-radius: 100%;
top: -25px;
left: -10px;
}
.ponytail:after {
width: 20px;
height: 20px;
border-radius: 100%;
border-left: none;
border-top: none;
top: -17px;
left: 10px;
}
.face {
top: initial;
animation: none;
}
.nose {
position: absolute;
width: 10px;
height: 5px;
background-color: black;
border-radius: 100%;
left: 65%;
top: 20px;
}
.eyes {
position: absolute;
width: 50px;
left: 20px;
animation: toggleOpen 4s infinite;
}
.eyes:before,
.eyes:after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-top: 3px solid black;
border-top-left-radius: 100px;
border-top-right-radius: 40px;
top: 8px;
background-image: radial-gradient(
1px 2px at 80% 40%,
white 99%,
transparent 100%
),
radial-gradient(3px 5px at 70% 35%, black 99%, transparent 100%);
}
.eyes:after {
width: 10px;
transform: scaleX(-1);
right: 14px;
}
.closed {
position: absolute;
opacity: 0;
left: 45px;
animation: toggleClose 4s infinite;
}
.closed:before,
.closed:after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-bottom: 3px solid black;
border-radius: 100%;
top: 5px;
}
.closed:after {
width: 10px;
right: 14px;
}
.cheeks {
position: absolute;
width: 100%;
}
.cheeks:after {
content: "";
position: absolute;
width: 6px;
height: 2px;
background-color: #ffd038;
border: 1px solid orange;
border-radius: 100%;
left: 15px;
top: 22px;
}
.mouth {
position: absolute;
width: 20px;
height: 8px;
transform: scale(0.7);
background-color: maroon;
border: 1px solid black;
border-bottom-left-radius: 90px;
border-bottom-right-radius: 90px;
left: 30px;
top: 27px;
overflow: hidden;
}
.mouth:before {
content: "";
position: absolute;
width: 9px;
height: 4px;
background-color: pink;
border-radius: 100%;
left: 5px;
top: 5px;
}
.dress {
position: absolute;
width: 45px;
height: 80px;
background-color: #4f4363;
top: 50px;
left: 30px;
background-image: radial-gradient(lavender 30%, transparent 0),
radial-gradient(lavender 30%, transparent 0);
background-size: 30px 30px;
background-position: 0 0, 15px 15px;
clip-path: polygon(20% 0%, 80% 0%, 100% 100%, 0% 100%);
clip-path: polygon(37% 0, 65% 0, 100% 100%, 0% 100%);
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.arm {
position: absolute;
width: 10px;
height: 30px;
background-image: linear-gradient(to bottom, #4f4363 30%, #ffe89e 31%);
border-radius: 30px;
border: 1px solid black;
}
.left-arm {
position: absolute;
left: 24px;
top: 86px;
transform: rotate(45deg);
}
.right-arm {
position: absolute;
left: 55px;
top: 86px;
transform: rotate(25deg);
}
.legs {
width: 20px;
}
.legs:before,
.legs:after {
content: "";
position: absolute;
width: 10px;
height: 30px;
background-color: #ffe89e;
border-radius: 90px;
border: 1px solid black;
transform: rotate(-45deg);
}
.legs:before {
top: 115px;
left: 45px;
}
.legs:after {
top: 110px;
left: 60px;
}
从这两个示例的代码来看,你会发现,这里面并没有什么复杂的代码。
来自于项目中的案例
可能大家觉得上面动森中的示例难以用到实际项目中来,但我想说的是,他们的原理是一致的,正如文章最开头提到的一些示例,完全可以用纯CSS的代码来实现。接下来,我们就来看一些示例。
Ribbon的制作
Ribbon的效果在实际项目是很常见的一种效果,而且有很多不同风格的Ribbon效果。比如在一个卡片的右上角有一个Ribbon,如下图所示:
就该效果而言,有很多种方式来实现,但随着clip-path
的到来,实现这样的效果可以说是非常的简单了。
我想你从上图中就看出左右两者之间的差异。特别是在要实现上图右侧的效果时,那么clip-path
会变得更为灵活。我们来看一个实际效果,比如你有一个卡片:
.card::before {
content: "";
position: absolute;
left: -4px;
top: -4px;
width: 100px;
height: 100px;
border-radius: 12px;
z-index: 9;
clip-path: polygon(0 0, 100% 0, 104% 0, 0% 104%);
background: #ffb202 url('data:image/png;base64,...') no-repeat 14px 14px;
background-size: 32px 32px;
}
当然,除了clip-path
方法之外,还可以采用最古老的方式,那就是使用border
来实现:
.card::before {
content: "";
position: absolute;
left: -4px;
top: -4px;
border: 50px solid #ffb202;
border-right-color: transparent;
border-bottom-color: transparent;
border-radius: 13px;
}
不同的是,如果在给Ribbon添加别的元素,那这种方式就有点困难了,需要另外来处理:
可以说,有了clip-path
,很多Ribbon的效果都可以非常容易的实现。
Badge
最近在一个项目中有一个类似下图这样的需求:
面对这样的效果,估计很多同学第一意愿是用图标来替代这些系列号,但在我的方案中,我采用了另一种姿势,那就是使用CSS的Masking技术,简单地说,使用下图做为mask-image
源:
我们的代码可以这么写:
<!-- HTML -->
<li><span>1</span></li>
//CSS
li {
width: 42px;
height: 42px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
li span {
width: 42px;
height: 42px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
mask: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAAnBAMAAABgRHy1AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVM9DkAAAAPdFJOUwDylNS/BSoc4jZGea5aCCjbjdkAAACqSURBVCjPY2BgSDL8jwQ+GiUwAEHQfzTwKYCBgdUfXfS/KwMDE4bg/08MDPmYov8TGPSxiCow2GMRNWCQxyIqwIBF8P+HUVGqifZjDXV/rDF0H4voAYYILKILGDgxBb8A09lCDNF2oCg7un2fwYmSF9VxH/cxgMFrlJSiDhFkYK1BEjzGAAeL4YKeDEhgI1TQClmQgR2SYHsZUAEnyH3SAQzowsrCZx/AOACyl6ocYYMMjwAAAABJRU5ErkJggg==")
no-repeat center;
mask-size: cover;
background-color: #ff79b7;
font-weight: 500;
font-size: 28px;
line-height: 1;
color: #fff;
z-index: 2;
}
li::after {
content: "";
width: 42px;
height: 42px;
position: absolute;
mask: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAAnBAMAAABgRHy1AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACVM9DkAAAAPdFJOUwDylNS/BSoc4jZGea5aCCjbjdkAAACqSURBVCjPY2BgSDL8jwQ+GiUwAEHQfzTwKYCBgdUfXfS/KwMDE4bg/08MDPmYov8TGPSxiCow2GMRNWCQxyIqwIBF8P+HUVGqifZjDXV/rDF0H4voAYYILKILGDgxBb8A09lCDNF2oCg7un2fwYmSF9VxH/cxgMFrlJSiDhFkYK1BEjzGAAeL4YKeDEhgI1TQClmQgR2SYHsZUAEnyH3SAQzowsrCZx/AOACyl6ocYYMMjwAAAABJRU5ErkJggg==")
no-repeat center;
mask-size: cover;
left: 0;
top: 4px;
z-index: 1;
background-color: #1c4d8e;
}
li:nth-child(1) span {
background-color: #ffe12e;
}
li:nth-child(1)::after {
background-color: #a84700;
}
li:nth-child(2) span {
background-color: #e7e7e7;
}
li:nth-child(2)::after {
background-color: #b0b0b0;
}
li:nth-child(3) span {
background-color: #e1ad5b;
}
li:nth-child(3)::after {
background-color: #985800;
}
效果如下:
Starbursts
在平时开发中,可能会处理像下图这样的徽标效果:
像这样的效果,CSS处量起为也非常的容易:
绘制不规则图形
下图这个效果也是来自于实际项目中:
就上图而言,我想到的最简单的方法就是使用clip-path
,不过需要对坐标点做一点计算:
我们用代码来描述上图的结果:
<!-- HTML -->
<div class="box">
<span>CSS Clipping</span>
</div>
CSS如下:
.box {
width: 220px;
height: 64px;
display: flex;
justify-content: center;
align-items: center;
color: #1c4d8e;
font-size: 24px;
position: relative;
}
.box::before,
.box::after {
content: "";
position: absolute;
}
.box::before {
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #ff79b7;
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 8.12% 100%, 0% 71.87%);
z-index: 1;
}
.box::after {
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
z-index: 2;
background-color: #fff;
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 7% 100%, 0% 69.57%);
}
.box span {
position: relative;
z-index: 3;
}
这个时候只需要改变容器大小,就要以得不同尺寸的结果:
.box2 {
width: 400px;
height: 120px;
}
而且使用transform
还可以来个镜像:
.box3 {
width: 30vw;
height: 30vh;
transform: scaleX(-1);
}
.box3 span {
transform: scaleX(-1);
}
效果如下:
如果你想花过多脑细胞去做数学计算的话,还可以使用开发者工具根据原图绘制:
渐变图形
再来看下面这样的示例:
仔细分析一下,我们可以采用多背景来实现:
我们来看其中一个代码:
.card {
width: 218px;
min-height: 148px;
position: relative;
display: flex;
flex-direction: column;
border-radius: 12px 72px 12px 12px;
border: 1px solid transparent;
font-size: 24px;
padding: 70px 18px 18px;
margin: 10px;
border-color: rgba(184, 112, 0, 0.28);
box-shadow: 0 8px 12px 0 rgba(234, 165, 55, 0.3),
inset 0 1px 3px 0 rgba(255, 255, 255, 0.5);
color: #870000;
background-size: 28px 28px, 49px 49px, 103px 103px, cover;
background-position: calc(100% - 20px) calc(100% - 20px), calc(100% + 10px) calc(100% + 10px), -34px -28px, 0 0;
background-image:
radial-gradient(circle, rgba(255,255, 255, .2), rgba(255,255, 255, .2) 70%, rgba(255,255, 255,0) 70%),
radial-gradient(circle, rgba(255,255, 255, .2), rgba(255,255, 255, .2) 70%, rgba(255,255, 255,0) 70%),
radial-gradient(circle, rgba(255,255, 255, .3), rgba(255,255, 255, .3) 70%, rgba(255,255, 255,0) 70%),
linear-gradient(180deg, #ffe3ae 0%, #ffd34f 100%);
background-repeat: no-repeat;
}
效果如下:
如何快速通过Sketch还原UI
其实到今天为止,随着设计软件越来越强大,我们还原UI视觉稿的事情变得越来越容易,比如说,通过Sketch就可以快速还原。我们来看一个示例,比如我们要还原这样的一个卡片背景:
正确使用软件,可以获取所有元素的信息:
接着开始撸码了。就该卡片UI效果来看,主要有两部分,顶部类似钉子部分和下面卡片主体部分。HTML结构可以像下面这样来构建:
<!-- HTML -->
<div class="card">
<div class="card__nail"></div>
<div class="card__content"></div>
</div>
在Sketch软件中选中对应的图层,可以获取到相应信息:
这些信息都可以为CSS所有,也可以快速复制出CSS:
具体的代码如下:
.card {
position: relative;
}
.card__nail {
width: 13px;
height: 13px;
border-radius: 50%;
background-image: linear-gradient(180deg, #fb9f0e 0%, #ff563e 100%);
box-shadow: 0 2px 0 0 #d03800, 0 2px 7px 0 #b50713;
top: -20px;
left: 50%;
position: absolute;
transform: translate(-50%, 0);
}
.card__nail::before,
.card__nail::after {
content: "";
position: absolute;
z-index: -1;
width: 7px;
height: 50px;
border-radius: 4px;
opacity: 0.5;
transform: scaleX(-1) rotate(70deg);
background-image: linear-gradient(180deg, #faa900 0%, #f27000 100%);
transform-origin: center top;
top: 6px;
left: 0;
}
.card__nail::after {
transform: rotate(70deg);
}
.card__content {
width: 134px;
height: 150px;
border-radius: 8px;
background-image: linear-gradient(to top, #fffab5 0%, #ffffff 39%),
linear-gradient(to bottom, #fff33e, #ffed14);
background-origin: border-box;
background-clip: padding-box, border-box;
box-shadow: 0 6px 0 0 #f27000;
border: 2px solid transparent;
position: relative;
z-index: 2;
}
效果如下:
是不是很简单。
小结
这篇文章主要和大家一起探讨了如何使用CSS来实现视觉效果,主要围绕着如何通过代码实现UI,换句话说,就是绘制图形。在很多情况之下,针对上面的一些实例效果,更多的同学会考虑使用图片,这并不是不好的方式,只不过使用图片除了多了请求,有一定的带宽,而且也需要流量。即使抛开这一切,图片的扩展性和灵活性就是比不过代码的。
在CSS中,绘制图形主要的一些方式,就是采用border
、border-radius
、clip-path
和渐变等组合。如果在美学方面有一定的造诣,还能创作出一些更优秀的作品。最后,希望这篇文章对大家有所帮助。如果你在这方面有更好的建议,欢迎在下面的评论中与我们一起共享。