用CSS画图——从三角形到吃豆人

今天在搬砖的时候看到设计稿上有一个三角形的矢量箭头设计师没有给,就想着去问设计师要一下。这时候旁边的大佬说:“不就一个三角形么还要问设计师拿?来来来我几行代码给你写出来····”

从三角形开始

这貌似是一个老生常谈的话题了,之前的面经上偶尔还会出现这道问题,不知道现在的面试还会不会问这个。主要是利用CSSborder-raduis这个属性,我们先来看看下面这个例子

<style>
    .box1 {
        width: 0px;
        height: 0px;
        border: 50px solid;
        border-left-color: blue;
        border-right-color: yellow;
        border-bottom-color: green;
        border-top-color: red;
    }
</style>
<div class="box1"></div>
复制代码

image.png

在浏览器上渲染出来是这个样子的,图中的4个等腰直角三角形的直角边长是50px,斜边长是100px。容易想到的是,我们只要把其中任意三个三角形隐藏掉,就可以得到一个等腰直角三角形。比如我希望得到一个直角向下的三角形,可以加上以下几行。得到一个三角形之后,再加上transform: rotate(?deg)旋转属性就可以得到任意方向的三角形。

.box1{
    border-left-color: transparent;
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-top-color: red;
}
复制代码

image.png

image.png

在现代工程项目中还可以利用less/sass等预处理语言的能力封装起来,颜色,方向作为参数,这里就不再赘述了。

气泡框

现在有了三角形之后,我们就可以来做一个聊天消息中常见的气泡框。将三角形跟一个矩形结合起来即可。

<style>
    .box {
        width: 200px;
        height: 100px;
        position: relative;
        background: red;
        border-radius: 10px;
    }

    .box::before {
        content: '';
        width: 0px;
        height: 0px;
        border: 20px solid;
        border-left-color: transparent;
        border-right-color: transparent;
        border-bottom-color: transparent;
        border-top-color: red;
        position: absolute;
        top: 100%;
        left: 50%;
    }
</style>
<div class="box"></div>
复制代码

image.png

镂空三角形

如果想实现一个镂空的三角形,最容易想到的方法应该是将两个三角形叠加起来,用一个去遮住另一个。

<style>
    .box {
        width: 200px;
        height: 200px;
        position: relative;
    }

    .box::before {
        content: '';
        width: 0px;
        height: 0px;
        border: 20px solid;
        border-left-color: transparent;
        border-right-color: transparent;
        border-bottom-color: transparent;
        border-top-color: red;
        position: absolute;
    }

    .box::after {
        content: '';
        width: 0px;
        height: 0px;
        border: 20px solid;
        border-left-color: transparent;
        border-right-color: transparent;
        border-bottom-color: transparent;
        border-top-color: white;
        top: -2px;
        position: absolute;
    }
</style>
<div class="box"></div>
复制代码

image.png

五角星

五角星的是利用三个三角形旋转叠加而成

.box {
    position: relative;
    width: 0px;
    height: 0px;
    border-left: transparent 20px solid;
    border-right: transparent 20px solid;
    border-bottom: transparent 20px solid;
    border-top: red 15px solid;
}

.box::before {
    content: '';
    width: 0px;
    height: 0px;
    border-left: transparent 20px solid;
    border-right: transparent 20px solid;
    border-bottom: transparent 20px solid;
    border-top: red 15px solid;
    position: absolute;
    top: -23px;
    left: -10px;
    transform: rotate(286deg);

}

.box::after {
    content: '';
    width: 0px;
    height: 0px;
    border-left: transparent 20px solid;
    border-right: transparent 20px solid;
    border-bottom: transparent 20px solid;
    border-top: red 15px solid;
    position: absolute;
    top: -22px;
    left: -31px;
    transform: rotate(71deg);
}
复制代码

image.png

六角星

六角星就是两个三角形叠起来即可

.box {
    position: relative;

}

.box::before {
    content: '';
    width: 0px;
    height: 0px;
    border-left: transparent 30px solid;
    border-right: transparent 30px solid;
    border-bottom: transparent 52px solid;
    border-top: red 52px solid;
    position: absolute;


}

.box::after {
    content: '';
    width: 0px;
    height: 0px;
    border-left: transparent 30px solid;
    border-right: transparent 30px solid;
    border-bottom: transparent 52px solid;
    border-top: red 52px solid;
    position: absolute;
    transform: rotate(180deg);
    top: -36px;
}
<div class="box"></div>
复制代码

image.png

梯形

这个是我面试字节的时候被问到过的一个题目,原问题大概是画一个等腰梯形,上底是10px,下底是20px,高是5px

我们在上面画三角形的时候把盒子的宽高都设置成了0,这次我们把盒子宽高设置一下试试会发生什么效果。

<style>
    .box {
        width: 10px;
        height: 10px;
        border: 5px solid;
        border-left-color: black;
        border-right-color: green;
        border-bottom-color: blue;
        border-top-color: red;
    }
</style>
<div class="box"></div>

复制代码

image.png

从图中我们可以很容易得知只要把其他三条边框变成透明,就可以得到面试题的答案。

image.png

六边形

在拥有了一个梯形之后,六边形便是两个梯形叠在一起

.box {
    width: 10px;
    height: 10px;
    border: 5px solid;
    border-left-color: transparent;
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-top-color: red;
    position: relative;
}

.box::after {
    content: '';
    width: 10px;
    height: 10px;
    border: 5px solid;
    border-left-color: transparent;
    border-right-color: transparent;
    border-bottom-color: red;
    border-top-color: transparent;
    position: absolute;
    left: -50%;
    top: -250%;
}
复制代码

image.png

八边形

同样的,八边形就是两个梯形叠加一个矩形

.box {
    width: 20px;
    height: 10px;
    background: red;
    position: relative;
}

.box::before {
    content: '';
    width: 10px;
    height: 10px;
    border: 5px solid;
    border-left-color: transparent;
    border-right-color: transparent;
    border-bottom-color: red;
    border-top-color: transparent;
    position: absolute;
    top: 100%;
    transform: rotate(180deg);
}

.box::after {
    content: '';
    width: 10px;
    height: 10px;
    border: 5px solid;
    border-left-color: transparent;
    border-right-color: transparent;
    border-bottom-color: red;
    border-top-color: transparent;
    position: absolute;
    top: -200%;
}

复制代码

image.png

扇形

我们可以在上述代码中加上border-radius属性,就可以得到一个90度的扇形;两个扇形叠加再一起可以得到一个圆环。

<style>
    .box {
        width: 0;
        height: 0;
        border: 50px solid;
        border-radius: 100%;
        border-left-color: black;
        border-right-color: transparent;
        border-bottom-color: transparent;
        border-top-color: transparent;
    }

    .circle::after {
        content: '';
        width: 0;
        height: 0;
        border: 45px solid;
        border-radius: 100%;
        border-left-color: green;
        border-right-color: transparent;
        border-bottom-color: transparent;
        border-top-color: transparent;
    }
</style>
<div class="box"></div>
<div class="box circle"></div>

复制代码

image.png

心形

心形是两个半圆叠加一个菱形,可以参考如下代码

<style>
.box {
    width: 100px;
    height: 100px;
    background: red;
    position: relative;
    transform: rotate(45deg);
}

.box::before {
    content: '';
    width: 0;
    height: 0;
    border: 50px solid;
    border-radius: 100%;
    border-left-color: red;
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-top-color: red;
    position: absolute;
    left: -50px;
    transform: rotate(-45deg);
}

.box::after {
    content: '';
    width: 0;
    height: 0;
    border: 50px solid;
    border-radius: 100%;
    border-left-color: transparent;
    border-right-color: red;
    border-bottom-color: red;
    border-top-color: transparent;
    position: absolute;
    top: -50px;
    transform: rotate(-135deg);
}
</style>
复制代码

image.png

吃豆人

吃豆人则是隐藏掉1/4圆即可

.box {
    width: 0;
    height: 0;
    border: 50px solid;
    border-radius: 100%;
    border-left-color: red;
    border-right-color: transparent;
    border-bottom-color: red;
    border-top-color: red;
    position: relative;
}
复制代码

image.png

网格背景

linear-gradient()  函数用于创建一个表示两种或多种颜色线性渐变的图片。其结果属于<gradient>数据类型,是一种特别的<image>数据类型。

一句话:沿着一条线进行渐变

在了解这个属性之后,最让我觉得神奇的不是它可以实现很花的效果,而是我们可以利用它做“循环”。这个循环打了引号,或许叫做重复比较合适。下面我们就用这个属性来实现一个网格效果。

.box {
    background-image: linear-gradient(to right, #000 1px, transparent 1px),
        linear-gradient(to bottom, #000 1px, transparent 1px);
    background-size: 10px 10px;
    background-repeat: repeat;
    width: 500px;
    height: 500px;
}
复制代码

linear-gradient(to right, #000 1px, transparent 1px) 产生一条竖直的线,配合background-sizebackground-repeat就可以实现“循环”(当然你也可以使用repeat-linear-gradient),进而实现上述的表格效果。

image.png

柱状图

除此之外,竖直方向上的渐变让我们十分容易地去构造一个柱状图。具体代码如下:

.container {
    display: flex;
}

.container div {
    width: 40px;
    height: 200px;
    margin: 20px;
}

.box1 {
    background-image: linear-gradient(to bottom, transparent 40px, red 40px)
}

.box2 {
    background-image: linear-gradient(to bottom, transparent 80px, red 80px)
}

.box3 {
    background-image: linear-gradient(to bottom, transparent 120px, red 120px)
}

<div class="container">
    <div class="box1"></div>
    <div class="box2"></div>
    <div class="box3"></div>
</div>
复制代码

image.png

任意角度扇形

上面我们利用border实现了一个十分局限的扇形,现在我们尝试去画一个任意角度的扇形。

0-180°扇形

主要的思路是用一个半圆配合盒子的overflow:hidden属性,来实现一个0-180°的扇形

.box {
    position: relative;
    width: 100px;
    height: 200px;
    overflow: hidden;
}

.box::before {
    content: '';
    border: 100px solid;
    border-radius: 100%;
    border-left-color: transparent;
    border-right-color: red;
    border-top-color: red;
    border-bottom-color: transparent;
    position: absolute;
    transform: rotate(45deg);
    left: -100%;
}
<div class="box"></div>

复制代码

image.png

由上图可以看到,盒子与伪元素已经完全贴合,那只要这个时候伪元素再进行旋转,就会被盒子的overflow:hidden属性挡掉。

image.png

180-360°扇形

主要的思路是利用两个半圆,通过旋转叠加来实现。

.box {
    position: relative;
}

.box::before {
    content: '';
    border: 100px solid;
    border-radius: 100%;
    border-left-color: transparent;
    border-right-color: red;
    border-top-color: red;
    border-bottom-color: transparent;
    position: absolute;
    transform: rotate(45deg);
}

.box::after {
    content: '';
    border: 100px solid;
    border-radius: 100%;
    border-left-color: red;
    border-right-color: transparent;
    border-top-color: transparent;
    border-bottom-color: red;
    position: absolute;
    transform: rotate(45deg);
}
<div class="box"></div>

复制代码

好了,通过上述代码我们成功画出了一个圆形(好像有什么地方不对,为什么画一个圆形要这么多代码)

image.png

但是,只要我们将任意一个半圆的旋转角度改变,就可以得到任意的180-360°的扇形。

image.png

饼图

现在我们已经有了0-360°的扇形,讲道理可以利用这些扇形叠加来叠加去来画出一个扇形。但其实不用这么麻烦,CSS中有一个属性叫做圆锥渐变:conic-gradient()。使用它来画一个饼图代码如下:

.box {
    position: relative;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: conic-gradient(red 60deg, blue 60deg 130deg, black 130deg 200deg, yellow 200deg);
}
复制代码

image.png

此外,任意角度的扇形也是信手拈来

.box {
    position: relative;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: conic-gradient(red 37deg, transparent 37deg);
}
复制代码

image.png

吃豆人升级版

上面我们实现了一个张着嘴巴不会动的吃豆人,也没有豆子吃。现在我们把这两件事情来补上。

动起来

先来实现一个会动的吃豆人,主要的思路还是用两个半圆,每个半圆旋转45°,这样就可以画出一个90°的口子,再加上动画,让这个口子张开闭合。

.box {
    transform: rotate(90deg);
    width: 200px;
    height: 200px;
    position: relative;
}

.left {
    content: '';
    border: 100px solid;
    border-radius: 100%;
    border-left-color: transparent;
    border-right-color: red;
    border-top-color: red;
    border-bottom-color: transparent;
    position: absolute;
    transform: rotate(90deg);
    animation: left .5s linear infinite ;
}

.right {
    content: '';
    border: 100px solid;
    border-radius: 100%;
    border-left-color: red;
    border-right-color: transparent;
    border-top-color: transparent;
    border-bottom-color: red;
    position: absolute;
    transform: rotate(0deg);
    animation: right .5s linear infinite ;

}

@keyframes left {
    0% {
        transform: rotate(90deg);
    }

    50% {
        transform: rotate(45deg);
    }

    100% {
        transform: rotate(90deg);
    }
}

@keyframes right {
    0% {
        transform: rotate(0deg);
    }

    50% {
        transform: rotate(45deg);
    }

    100% {
        transform: rotate(0deg);
    }
}

<div class="box">
    <div class="left"></div>
    <div class="right"></div>
</div>
复制代码

Animation.gif

吃豆子

好的,帅气的大嘴已经动了起来。现在我想提一个问题,如果让你不用JavaScript,只给你一个dom元素和CSS,让你画N个正方形,你会怎么做呢?

片刻的思索过后,你可以会想起上面我提过渐变可以用来做“循环”。是的,我这里使用到了径向渐变来实现上面的需求,别忘了配合background-repeat,当然,你也可以使用repeat-radial-gradient。 渐变除了兼容性不好没什么缺点(手动狗头)

radial-gradient() CSS函数创建了一个图像,该图像是由从原点发出的两种或者多种颜色之间的逐步过渡组成。它的形状可以是圆形(circle)或椭圆形(ellipse)。这个方法得到的是一个CSS<gradient>数据类型的对象,其是 <image> 的一种。

.bean {
    width: 100px;
    height: 20px;
    background-repeat: repeat-x;
    background-size: 20px 20px;
    background-image: radial-gradient(circle at center, red 4px, #fff 4px 20px);
}
<div class="bean">
复制代码

image.png

现在我们如法炮制地加上动画,让豆子动起来

.bean {
    width: 100px;
    height: 20px;
    background-repeat: repeat-x;
    background-size: 20px 20px;
    background-image: radial-gradient(circle at center, red 4px, transparent 4px 20px);
    overflow: hidden;
    position: relative;
    animation: bean 1s linear infinite;
}

@keyframes bean {
    0% {
        left: 0px;
    }

    100% {
        left: -100px;
    }
}
<div class="bean"></div>
复制代码

Animation.gif

剩下的就只要让豆子冲向吃豆人的嘴巴就好了~

Animation.gif

最后

CSS 还是可以用来画一些简单的图形的,不过在工程上该找设计师还是找设计师吧,毕竟各个属性在各种浏览器的兼容性还是不太一样的。最让你印象深刻的CSS属性是什么呢?

Supongo que te gusta

Origin juejin.im/post/7076036726942564366
Recomendado
Clasificación