跳到主要内容

css 画多边形

三角形

用 CSS 画三角形可以利用 border 实现。

等边/等腰三角

div.triangle {
width: 0;
height: 0;
border-width: 100px;
border-wtyle:'solid';
border-color: 'transparent transparent green transparent';
}

上面代码我们给 div 元素的宽高都设置成0,把边框设置大一点,就得到了一个四个三角形构成的正方形。如果对其他三条边框的颜色设置成透明的,则就只剩下一个等腰三角形了。

等边三角形的三条边都相等,假设我们要画的等边三角形的边长等于 div 的宽度,我们就可以根据勾股定理算出div的高度。

假如等边三角形的宽度是50,则矩形的高度就等于:

h=250225287h = 2\sqrt{50^2 - 25^2} ≈ 87

<div style={{
width: 0,
height: 0,
borderLeftWidth: 50,
borderRightWidth: 50,
borderTopWidth: 87,
borderBottomWidth: 87,
borderStyle:'solid',
borderColor: 'transparent transparent green transparent',
}}></div>

直角三角形

上面用 border 画出的四个三角形其实就是等腰直角三角形,相邻的两个三角形组成的大三角形也是一个直角三角形。

梯形

梯形也可以根据上面画三角形的方式画出来,只需要指定一下div的宽高即可。需要注意的是,div的宽高需要比border要大,不然中间不会产生空白的方形。

const Rectangle = () => {
return (
<div style={{
width: 150,
height: 150,
borderLeftWidth: 50,
borderRightWidth: 50,
borderTopWidth: 50,
borderBottomWidth: 50,
borderStyle:'solid',
borderColor: 'blue green red purple',
}}></div>
);
}

直角梯形

直角梯形可以在上面的基础上改造,我们只需要把左边框和上边框的宽度设置为0,这样下边框的右边就会变成直角。

<div style={{
width: 150,
height: 150,
borderTopWidth: 0,
borderLeftWidth: 0,
borderStyle:'solid',
borderRightWidth: 50,
borderBottomWidth: 50,
borderColor: 'blue green red purple',
}}></div>

圆和椭圆很好实现,只要把 border-radius 设置成 50% 即可。

div {
width: 150px;
height: 100px;
border-radius: 50%;
}

渐变

使用渐变也是可以画多边形的,比如使用线性渐变画一个平行四边形。

.parallelogram {
width: 360px;
height: 100px;
// -45度倾斜角渐变,红色从0-30%,绿色从30%-70%,紫色从70%-100%
background-image: linear-gradient(-45deg, red 0 30%, green 30% 70%, purple 70% 100%);
}

如果上面代码把红色和紫色渐变都改成transparent,就可以得到一个绿色的平行四边形。同时可以发现,如果把紫色和绿色换成透明色,就可以得到一个红色的直角梯形。

除此之外,也可以使用 transform 中的 skew() 函数或一个平行四边形。

<div style={{
width: 100,
height: 100,
backgroundColor: 'pink',
transform: 'skew(-10deg)'
}}/>

clip-path

clip-path 可以说是 css 多边形的终极方案了,它可以使用 polygon() 画出任意的多边形。语法与 svg 填充规则类似。

这个属性使用裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏。

比如我们有一个蓝色的方形 div:

要把整个 div 裁剪成一个不规则的多边形,就可以使用 clip-path 属性实现。

/* 连接四个点坐标:[(20, 20), (180, 30), (180, 100), (40, 100)] */
clip-path: polygon(20px 20px, 180px 30px, 180px 100px, 40px 100px);

filter

使用 filter 滤镜属性可以做出很多有意思的效果,比如下面的效果,可以把两个圆“融合”在一起。

<div className={styles.filter}></div>

<style>
.filter {
width: 200px;
height: 140px;
position: relative;
filter: contrast(20);
border-radius: 10%;
background-color: #fff;
}
.filter::before {
content: '';
display: inline-block;
width: 70px;
height: 70px;
filter: blur(5px);
border-radius: 50%;
position: absolute;
top: 15%;
left: 40px;
z-index: 1;
background-color: rgb(137, 255, 10);
}
.filter::after {
content: '';
display: inline-block;
width: 100px;
height: 100px;
filter: blur(5px);
border-radius: 50%;
position: absolute;
top: 15%;
left: 80px;
background-color: rgb(108, 245, 54);
}
</style>

上面代码中最主要的代码是给两个伪类设置了 filter: blur(5px) 属性,它会将高斯模糊应用于输入图像。

但发现图形并没有模糊,这是因为父元素设置了这两个属性:

filter: contrast(20);
background-color: #fff;

contrast() 会调整输入图像的对比度,一般来说对比度越大,图像越清晰醒目,色彩也越鲜明艳丽。

shape-outside

shape-outside 定义了一个可以是非矩形的形状,相邻的内联内容应围绕该形状进行包装。

它一般与 float 属性一起使用,用于文字排版。比如:

Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nam autem facere officia saepe, ab minima nesciunt at cum optio voluptates cumque sunt, delectus eos quos neque porro quasi necessitatibus ducimus. Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nostrum dignissimos temporibus a numquam provident iste, voluptatem, corporis debitis sit modi non tenetur iure. Enim quos ratione minima nam dolores fugiat. Neque aliquid inventore recusandae, veritatis autem deserunt error quam in ipsa cupiditate dolores modi. Nulla laboriosam ipsum blanditiis labore officia, magni autem corrupti dolores at pariatur officiis illo, veritatis cupiditate? Ipsam cum deleniti inventore, sunt sed fugit corrupti maiores itaque quaerat reiciendis voluptatum unde accusantium! Maxime, voluptate! Accusantium rerum, iusto blanditiis architecto velit illo at optio earum quo accusamus atque!
<div>
<div className={styles.shapeOutside}></div>
<div>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nam autem facere officia saepe, ab minima nesciunt at cum optio voluptates cumque sunt, delectus eos quos neque porro quasi necessitatibus ducimus.
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Nostrum dignissimos temporibus a numquam provident iste, voluptatem, corporis debitis sit modi non tenetur iure. Enim quos ratione minima nam dolores fugiat.
Neque aliquid inventore recusandae, veritatis autem deserunt error quam in ipsa cupiditate dolores modi. Nulla laboriosam ipsum blanditiis labore officia, magni autem corrupti dolores at pariatur officiis illo, veritatis cupiditate?
Ipsam cum deleniti inventore, sunt sed fugit corrupti maiores itaque quaerat reiciendis voluptatum unde accusantium! Maxime, voluptate! Accusantium rerum, iusto blanditiis architecto velit illo at optio earum quo accusamus atque!
</div>
</div>

<style>
.shapeOutside {
background-color: blueviolet;
height: 160px;
width: 160px;
border-radius: 50%;
/* 设置浮动 */
float: left;
shape-outside: circle(50%);
}
</style>

drop-shadow

drop-shadow 是一个 css 的函数, 这个函数有点类似于 box-shadow 属性。box-shadow 属性在元素的整个框后面创建一个矩形阴影,而 drop-shadow() 过滤器则是创建一个符合图像本身形状 (alpha 通道) 的阴影。

如果给一个带有透明度的 png 图片设置阴影(圆形图片,周围是透明的),使用 box-shadow 属性设置,会发现阴影在方形图片的四周,而不是有色彩的圆形区域的周围。drop-shadow() 可以很好的解决这个问题。

3D 立方体

使用 CSS 是可以画 3D 立方体的,需要利用 3D 变换实现。

1
2
3
4
5
6
<div className={styles.container}>
<div className={clsx(styles.cube, showbf ? styles.showbf : styles.hidebf)}>
<div className={clsx(styles.face, styles.front)}>1</div>
<div className={clsx(styles.face, styles.back)}>2</div>
<div className={clsx(styles.face, styles.right)}>3</div>
<div className={clsx(styles.face, styles.left)}>4</div>
<div className={clsx(styles.face, styles.top)}>5</div>
<div className={clsx(styles.face, styles.bottom)}>6</div>
</div>
</div>

<style>
.container {
width: 150px;
height: 150px;
margin: 75px 0 0 75px;
border: none;
}

.cube {
width: 100%;
height: 100%;
/* 观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果 */
perspective: 550px;
/* 指定观察者的位置 */
perspective-origin: 200% 200%;
/* 指示元素的子元素应位于 3D 空间中 */
transform-style: preserve-3d;
}

.face {
display: block;
position: absolute;
width: 100px;
height: 100px;
border: none;
line-height: 100px;
font-size: 60px;
color: white;
text-align: center;
}

.showbf div {
backface-visibility: visible;
}

.hidebf div {
backface-visibility: hidden;
}

/* Define each face based on direction */
.front {
background: rgba(0, 0, 0, 0.3);
/* 往前移动 50px */
transform: translateZ(50px);
}

.back {
background: rgba(0, 255, 0, 1);
color: black;
transform: rotateY(180deg) translateZ(50px);
}

.right {
background: rgba(196, 0, 0, 0.7);
transform: rotateY(90deg) translateZ(50px);
}

.left {
background: rgba(0, 0, 196, 0.7);
transform: rotateY(-90deg) translateZ(50px);
}

.top {
background: rgba(196, 196, 0, 0.7);
transform: rotateX(90deg) translateZ(50px);
}

.bottom {
background: rgba(196, 0, 196, 0.7);
transform: rotateX(-90deg) translateZ(50px);
}
</style>

需要注意的是:transform 属性中的变换函数执行顺序是从右往左进行运算,比如 .bottom 会先运行 translateZ(50px) 函数,然后在运行 rotateX(-90deg) 函数,这与数学中的矩阵运算相关。

上面代码中所有的面都是先往“前”移动了50px,然后再做的旋转。这是因为默认情况下 transform-origin 的值是 centercenter center 0),即:每个div.face的中心位置,我们要构建一个立方体,需要把叠在一起的div偏离位置,统一都沿z轴方形移动 50px,这时候虽然还都叠在一起,但是transform-origin 的值已经不和div.face的中心点重叠了。

再进行 rotate 旋转变换时就可以得到一个立方体了。

svg

使用 svg 也可以创建出多边形,具体可以参考 MDN文档,API 与 canvas 很像,这里就不再叙述了。