CSS 实现圆环

7,257 阅读7分钟

近期,笔试遇到一个题目,让我用纯css实现3/4圆环。虽然看过很多相关例题,但是到自己动手来写的时候,还是无法实现。此文将介绍一些实现圆环的方法。

一、圆环

要实现圆环,那么首先肯定要实现一个圆。最简单的方法就是通过设置border-radius: 50%来实现。如下代码:

// html
<div class="circle"></div>

// css
.circle {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    background-color: #afb4db;
}

image.png

1.1 border 属性实现圆环

从某个角度来看,圆环就是圆的边框。那么想要实现圆环,就可以使用border属性来实现。

<div class="circle"></div>

// css
.circle {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    background-color: #fff;
    border: 10px solid #afb4db;
}

image.png

如上代码所示,background-color 设置的内容区和padding的颜色,而边框颜色是由border属性设置,对边框和内部设置不同的颜色,一个圆环也就显现出来了。

由于设置了border改变了盒子的实际大小,盒子所占空间需要重新计算,所以在进行布局的时候需要注意。如果不想border改变盒子实际大小,可以设置box-sizing: border-box

1.2 两个圆嵌套实现

将圆环拆开来看,其实就是一个外圆和一个内圆嵌套组成,只要我们给外圆和内圆设置不同的背景色即可形成圆环。具体通过父子元素嵌套实现。

// html
<div class="outer-circle">
    <div class="inner-circle"></div>
</div>

第一种方法,我们可以设置子元素宽高小于父元素宽高,然后通过定位position使得子元素与父元素中心重合。

.outer-circle {
    position: relative;
    width: 200px;
    height: 200px;
    border-radius: 50%;
    background-color: #afb4db;
}
.inner-circle {
    position: absolute;
    top: 10px;
    left: 10px;
    width: 180px;
    height: 180px;
    border-radius: 50%;
    background-color: #fff;
}

image.png

第二种方式,则是设置子元素宽高width: 100%, height: 100%占满父元素内容区,然后设置父元素padding即可。

.outer-circle {
    width: 200px;
    height: 200px;
    padding: 10px;
    border-radius: 50%;
    background-color: #afb4db;
}
.inner-circle {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: #fff;
}

image.png

两种代码中实现的圆环宽度相同,但是圆环的半径不同。第一种实现方式中圆环半径为100px - 10px = 90px,而第二种方式圆环半径就是100px

1.3 伪元素实现

通过伪元素实现,其实思想与1.2中大致相同,即用一个元素遮挡另一个元素的中心部分。

// html
<div class="circle"></div>

// css
.circle {
    width: 200px;
    height: 200px;
    border-radius: 50%;
    background-color: #afb4db;
}
.circle::after {
    content: '';
    position: relative;
    top: 10px;
    left: 10px;
    display: block;
    width: 180px;
    height: 180px;
    border-radius: 50%;
    background-color: #fff;
}

image.png

1.4 svg 实现

除了使用CSS的一些属性来实现圆环,我们也可以使用svg直接绘制一个圆环。

<div class="circle">
    <svg width="200" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
        <circle cx="100" cy="100" r="90" stroke="#afb4db" fill="transparent" stroke-width="10"/>
    </svg>
</div>

image.png

上述代码中相关属性介绍如下:

  • cx:圆心 X 轴坐标
  • cy:圆心 Y 轴坐标
  • r:半径(内圆)
  • stroke:边界颜色
  • fill:填充色
  • stroke-width边界宽度

1.5 canvas 实现

svg能够实现,那么canvas也就一定能够实现,只不过canvas需要在JavaScript中绘制。

<div class="container">
    <canvas id="circle" width="200px" height="200px"></canvas>
</div>

<script>
    const canvas = document.getElementById('circle');
    if (!canvas.getContext('2d')) {
        console.log('浏览器不支持Canvas');
    }
    const ctx = canvas.getContext('2d');
    ctx.strokeStyle = '#afb4db';  // 边界颜色
    ctx.lineWidth = 10;  // 边界宽度
    ctx.beginPath();  // 路径开始
    ctx.arc(100, 100, 90, 0, Math.PI * 2, true);  // 绘制路径
    ctx.stroke();
</script>

image.png

以上就是个人总结的几种实现圆环的方法,但实现圆环的方法不仅这些,当然还有很多,希望大家指出。

二、不完整的圆环

第一节中我们知道了几种实现圆环的方法,那么例如1/4圆环、3/4圆环这种不完整的圆环怎么实现呢?

2.1 border + transform 实现

如1.1所示,我们可以通过设置border来实现圆环。但是我们不仅可以通过border设置所有边界的属性,也可以通过border-topborder-rightborder-bottomborder-left分别设置每个边界的样式。所以当我们设置某个边界的颜色与背景色相同时,那么也就实现了一个不完整的圆环。如下代码:

.circle {
    width: 100px;
    height: 100px;
    margin-right: 20px;
    border-radius: 50%;
    background-color: #fff;
    border: 10px solid #afb4db;
    border-top: 10px solid #fff;
}

image.png

如上图所示,缺口的位置似乎并不满足我们的要求,那么可以通过transform: rotate(deg)旋转一定角度来实现。代码如下:

// html
<div class="container">
    <div class="circle"></div>
    <div class="circle one-four"></div>
    <div class="circle two-four"></div>
    <div class="circle three-four"></div>
</div>

// css
.circle {
    width: 100px;
    height: 100px;
    margin-right: 20px;
    border-radius: 50%;
    background-color: #fff;
    border: 10px solid #afb4db;
    float: left;
}
.one-four {
    border-top: 10px solid #fff;
    transform: rotate(45deg);
}

.two-four {
    border-top: 10px solid #fff;
    border-right: 10px solid #fff;
    transform: rotate(45deg);
}

.three-four {
    border-top: 10px solid #fff;
    border-right: 10px solid #fff;
    border-bottom: 10px solid #fff;
    transform: rotate(45deg);
}

image.png

这种方法还是有很大限制的,它只能实现1/4,1/2,3/4 圆环,那如果我们需要实现一个80%的圆环这种方法就失效了。

2.2 clip-path 裁剪

看了很多资料,发现对于这种实现不完整圆或不完整圆环的需求,大部分都是通过 clip-path属性来实现的。那么下面我们先简单介绍一下clip-path属性。

(1)clip-path 属性

clip-path 属性使用裁剪方式创建元素的可显示区域

本文就以如下例子简单介绍一下几种常用的属性值:

// html
<div class="container">
        <div class="clip"></div>
    </div>

// css
.container {
    width: 200px;
    height: 200px;
    background-color: #afb4db;
}
.clip {
    width: 100%;
    height: 100%;
    background: url("./pupu.png") no-repeat;
    background-size: 100% 100%;
}

image.png

inset:矩形裁剪

定义一个 inset 矩形。

语法

clip-path: inset(top left bottom right round border-radius);
  • 前四个值代表了从参考框向内的上、右、下和左的偏移量,定义了嵌入矩形的边缘位置。
    • 当设置为百分比时,上下偏移量对应高,左右偏移量对应宽
  • 可选参数 border-radius,定义了矩形的圆角弧度

如下代码:

clip-path: inset(40px 20% 10px 20px round 10px);

image.png

circle:圆形裁剪

定义一个圆形(使用一个半径和一个圆心位置)

语法

clip-path: circle(r at x y);
  • r:圆形半径。其值可以为以下四种:
    • length:例如10px, 2rem等
    • 百分比:(width * 百分比 + height * 百分比) / 2
    • closest-side:宽高中较短者的一半
    • farthest-side:宽高中较长者的一半
  • x, y:圆心坐标,默认为盒子中心位置。以左上角为原点。
    • length:例如 x = 10px, y = 10px,那么圆心就在(10px, 10px)处
    • 百分比:x对应宽,y对应高
    • x 还可以设置为 leftright,代表左右边界(对应百分比就是 0% 和 100%)
    • y 还可以设置为 topbottom,代表上下边界(对应百分比就是 0% 和 100%) 如下代码:
clip-path: circle(50px at 100px 40%);

image.png

ellipse裁剪

定义一个椭圆(使用两个半径和一个圆心位置)。

语法

clip-path: ellipse(rx ry at x y);
  • rx,ry:长轴和短轴半径。其值可以为以下四种:
    • length:例如10px, 2rem等
    • 百分比:rx对应宽, ry对应高
    • closest-side:宽高中较短者的一半
    • farthest-side:宽高中较长者的一半

如下代码:

clip-path: ellipse(50px 30% at 100px 40%)

image.png

polygon裁剪

定义一个多边形(使用一个 SVG 填充规则和一组顶点)。

具体语法可见 svg如何绘制多边形

如下代码:

clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);

image.png

path 裁剪

定义一个任意形状(使用一个可选的 SVG 填充规则和一个 SVG 路径定义)。

具体语法可见 svg路径

如下代码:

clip-path: path("M 10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80");

image.png

(2)clip-path 实现不完整圆环

通过如上的介绍,我们可以使用polygon或者path来裁剪,进而获得部分圆环。如下代码:

// html
<div class="circle"></div>

// css
.circle {
    width: 100px;
    height: 100px;
    margin-right: 20px;
    border-radius: 50%;
    background-color: #fff;
    border: 10px solid #afb4db;
    clip-path: polygon(50% 50%, 100% 0, 50% 0);
}
// 

image.png