聊聊 Web 中的圆

熟悉 CSS 的同学都知道,使用 CSS 可以绘制一些图形,在业内有很多这方面的案例,比如使用 CSS 绘制不同的纹理CSS 绘制 Icons使用一个div 绘制不同的图形等等。而在 Web 的实际开发中也经常会碰到一些图形的运用,比如我们今天要聊的圆(比如圆形容器,圆形缩略图,圆形按钮)。通常情况下,我们可以使用 CSS 或 SVG 来绘制圆,但在实际使用过程中还是会碰到一些棘手的问题。如果你对这方面感兴趣的话,那么接着阅读下面的内容,你一定会有所收获。

绘制圆的技术方案

在 Web 中,我们可以使用 CSS 和 SVG 等技术手段来绘制圆,大家常见的技术方案主要有:

上面这些技术方案都可以绘制出圆形,每种技术都有其优缺点。接下来我们来看看这些技术是如何绘制出圆,能运用于什么样的场景等。

CSS 的 border-radius

在 CSS 中绘制圆最常见的技术方案应该是border-radius。不过使用border-radius绘制圆有一个前提条件,那就是容器的 width height 必须相等,而且半径的值是其 width (或 height )的 50% (设置 100% 同样等效) 。比如下面这个示例:

CSS 复制代码
.circle {
    width: 50vh;
    height: 50vh;
    border-radius: 50%; /*也可以是设置100%*/
    background-color: #2a394f;
}

Demo 地址:codepen.io/airen/full/...

CSS的border-radius属性绘制圆除了设置50%(或100%)之外还可以设置一个超大值(一般只要大小于容器宽度即可)。该特性用于制作类似药丸形状按钮非常有效,比如:

CSS 复制代码
.button {
    width: 100vh;
    min-height: 25vh;
    border-radius: 100vw;
    background-color: #2a394f;
}

Demo 地址:codepen.io/airen/full/...

实现类似药丸形状按钮时,如果你不知道按钮高度时,可以设置一个任意大的值,比如100vw,甚至是更大的一个值,这样会更安全。

CSS的border-radius同时也会影响到元素的borderbox-shadow以及元素的可触摸(可点击)区域:

Demo 地址:codepen.io/airen/full/...

上面的示例我们使用的是vh单位(视窗单位),当你改变视窗大小的时候,可以看到圆的大小也随之改变。看上去实现了响应式的圆。其实在CSS中我们还可以利用宽高比的技术方案来实现CSS绘制响应式的圆,只不过需要注意的是宽高比应该采用的 1:1 的比例

使用border-radius除了绘制圆形之外,我们还可以绘制椭圆,扇形,半圆等等:

CSS 复制代码
.circle {
    width: 40vh;
    height: 40vh;
    border-radius: 100vw;
    background-color: #2a394f;
}

.ellipse {
    height: 20vh;
    border-radius: 50% / 50%;
}

.circle__half {
    border-radius: 20vh 20vh 0 0;
    height: 20vh;
}

.quarter-circle-top-left{
    border-radius: 0 0 40vh 0;
}
.quarter-circle-top-right{
     border-radius: 0 0 0 40vh;
}
.quarter-circle-bottom-left{
     border-radius: 0 40vh 0 0;
}
.quarter-circle-bottom-right{
     border-radius: 40vh 0 0 0;
}

Demo 地址:codepen.io/airen/full/...

在使用border-radius绘制圆形时,有的时候在一些浏览器中会有一些锯齿的边缘。比如下面这个示例,对比左右两个圆的效果,仔细看哟:

Demo 地址:codepen.io/airen/full/...

CSS的radial-gradient

第一次让我领略到 CSS 渐变的强大之处那就是使用CSS渐变绘制的背景纹理

URL:projects.verou.me/css3pattern...

正如上图所示,我们可以使用radial-gradient来绘制圆形,通过background-image填充到元素中。

CSS 复制代码
.circle {
    background-image: radial-gradient(circle, #d9456f, #d9456f 66%, transparent 66%);
    height: 50vh;
    width: 50vh;
}

Demo 地址:codepen.io/airen/full/...

使用径向渐变配合background-size属性,我们可以做一些特殊的效果,比如下面这样的一个效果:

Demo 地址:codepen.io/airen/full/...

使用CSS渐变除了可以绘制圆,还可以绘制其他的一些图形,前面向大家展示过相关的示例。但径向渐变绘制的圆会因为浏览器的不同,圆圈的边缘可能会有锯齿状或模糊的形状(和border-radius有相似之处)。

除此之外,我们还可以使用repeating-radial-gradient()绘制循环的圆:

还可以使用最新的渐变属性conic-gradient()实现下面示例的效果:

Demo 地址:codepen.io/RockStarwin...

如果将repeating-radial-gradient()conic-gradient()和CSS的animation结合起来,还可以实现一些有趣的动效:

Demo 地址:codepen.io/RockStarwin...

CSS中的circle()函数

如今的CSS也有一些函数特性,其中circle()就是图形函数中的一个,可以用来绘制圆。该函数主要用于CSS的shape-outsideshape-insideclip-path几个属性中。目前可能用于clip-path属性要多于shape-outside。其语法很简单:

scss 复制代码
circle() = circle( [<shape-radius>]? [at <position>]? )

其中<shape-radius>可取值:

xml 复制代码
<shape-radius> = <length> | <percentage> | closest-side | farthest-side

其中closest-side是默认值,另外<position>可取值:

css 复制代码
<position> = [    [ left | center | right | top | bottom | <length-percentage> ]
    |
    [ left | center | right | <length-percentage> ]
    [ top | center | bottom | <length-percentage> ]
    |
    [ center | [ left | right ] <length-percentage>? ] &&
    [ center | [ top | bottom ] <length-percentage>? ]
]

常见的使用方式:

scss 复制代码
circle()
circle(100px at 30% 50%)
circle(farthest-side at 25% 25%);
circle(10em at 500px 300px);

其中circle()<shape-radius>取值为closest-sidefarthest-side需要特意拿出来,我用下图来向大家解释,会更一目了然:

前面提到过了,circle()函数可以运用于CSS的clip-pathshape-outside(或者未来的shape-inside)属性上。我们先来看一下被运用于clip-path属性上的效果:

Demo 地址:codepen.io/airen/full/...

clip-path除了可以绘制一些基本图形之外,而且将其运用于CSS的Masking和Clipping中的话,可以轻易地帮助你实现很多实际需求。

circle()另外还可以运用于CSS Shapes中的shape-outsideshape-inside中,实现一些打破规则布局的效果,比如下图:

比如下图的效果就是circle()被运用于shape-outside中的一个布局效果:

Demo 地址:codepen.io/airen/full/...

CSS Shapes现代Web布局中与常规布局中唯一与众不同的一种方式,该布局可以打破常规的矩形布局风格,可以实现流水式的布局效果,即打破常规规则布局效果。如果你对这方面的知识感兴趣的话,可以点击这里进行了解。

SVG的<circle>

SVG中的 <circle> 元素是绘制基本图形的其中之一。使用该元素可以轻易的绘制出一个圆形:

XML 复制代码
<svg viewBox="0 0 80 80" width="80" height="80">
    <circle class="circle" cx="40" cy="40" r="30"/>
</svg>
CSS 复制代码
.circle {
    fill: #f90;
    stroke: red;
    stroke-width: 5;
}

效果如下:

Demo 地址:codepen.io/airen/full/...

圆在Web中的运用场景

在Web中��圆的使用场景还是蛮多的,估计大家最为熟悉的应该是用户头像制作成圆形。实现这样的效果,最简单的方式之一就是在<img>上使用border-radius

CSS 复制代码
.circle {
    background: rgba(15, 28, 63, 0.125);
    border-radius: 50%;
    height: 50vmin;
    object-fit: cover;
    width: 50vmin;
}

Demo 地址:codepen.io/airen/full/...

该方法虽然简单,但对于响应式方面就差强人意。尽管使用了object-fit:cover来防止非正方形图形失真。

其实实现上面示例的效果,除了使用CSS的属性之外,还可以使用SVG来实现,比如下面这个示例:

XML 复制代码
<svg viewBox="0 0 300 300" width="300" height="300">
  <defs>
    <circle id="circle" cx="150" cy="150" r="149" vector-effect="non-scaling-stroke"/>
    <clipPath id="circle-clip">
      <use xlink:href="#circle"/>
    </clipPath>
  </defs>
  <g clip-path="url(#circle-clip)">
    <image xlink:href="https://avatars0.githubusercontent.com/u/368462?s=460&v=4" width="100%" height="100%" preserveAspectRatio="xMidYMid slice"/>
    <use xlink:href="#circle" fill="none" stroke="#0F1C3F" stroke-width="2" opacity="0.25"/>
  </g>
</svg>

Demo 地址:codepen.io/airen/full/...

上面看到的是一些最基本的效果,其实我们还可以实现一些动效,比如下面这个loading的动效:

Demo 地址:codepen.io/airen/full/...

而SVG制作圆的使用场景也很多,比如在很多图表的运用场景就特别的明显。另外在实现一些圆形进度条,使用SVG会更容易。比如下面这个示例效果:

Demo 地址:codepen.io/sergiopeder...

上面我们看到的是使用SVG绘制圆,或者说实现圆形进度条效果。其实在SVG中,使用<textPath><circle>或者SVG的<path>还可以实现圆形文本环绕的效果

Demo 地址:codepen.io/jwkevinc/fu...

使用clip-path除了可以在Masking和Clipping的场景运用之外,还可以实现一些其他效果,比如类似支付宝芝麻信用效果:

Demo 地址:codepen.io/airen/full/...

前面提到过,circle()函数除了可运用于clip-path属性中之外,还可以运用于shape-outsideshape-inside属性中实现一些不规则的布局效果。比如说文本围绕圆形边缘布局或文本在圆形内布局。其中shape-outside在一些主流浏览器中能看到效果,但是shape-inside支持的浏览器有限。如果我们要实现文本在一个圆内排列这样的效果,可以借助shape-outside来模拟。比如下面这个示例:

Demo 地址:codepen.io/airen/full/...

小结

这篇文章都是聊圆的事情。正如文章中和大家所聊的内容,实现CSS的技术方案有很多种,不同的技术方案可以运用于不同的场景而且每一种实现方案都有其自己的局限性,也有自己的优势。并且可运用的场景也特别多的,大家应该根据自己所需来选择相应的方案。另外,可能上文中还有很多我遗漏的没有想到的方案,如果你在这方面有经验,或者有相应的使用场景,欢迎在下面的评论中与我们一起分享。


如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程:

相关推荐
fruge4 分钟前
纯css制作声波扩散动画、js+css3波纹催眠动画特效、【css3动画】圆波扩散效果、雷达光波效果完整代码
javascript·css·css3
neter.asia13 分钟前
vue中如何关闭eslint检测?
前端·javascript·vue.js
~甲壳虫14 分钟前
说说webpack中常见的Plugin?解决了什么问题?
前端·webpack·node.js
光影少年33 分钟前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js
As977_34 分钟前
前端学习Day12 CSS盒子的定位(相对定位篇“附练习”)
前端·css·学习
susu108301891136 分钟前
vue3 css的样式如果background没有,如何覆盖有background的样式
前端·css
Ocean☾37 分钟前
前端基础-html-注册界面
前端·算法·html
Dragon Wu40 分钟前
前端 Canvas 绘画 总结
前端
CodeToGym44 分钟前
Webpack性能优化指南:从构建到部署的全方位策略
前端·webpack·性能优化
~甲壳虫1 小时前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js