尧图精选

CSS 形状绘制完全指南:40 种纯 CSS 图形实现与选型

🕒 发布时间:2026/9/18 8:45:39 📁 来源:尧图网络
做前端这些年我发现一个挺有意思的现象很多人一提到用 CSS 画形状第一反应就是这玩意儿能画啥不就是矩形加圆角吗但实际上从最简单的三角形、对话框气泡到五角星、心形、波浪线甚至棋格纹理CSS 都能搞定而且不依赖任何图片资源和 SVG。平时接到 UI 稿遇到小箭头、装饰图形我基本都是顺手用 CSS 画加载快、好维护改颜色也只改一行代码。这篇文章就把我这些年积攒下来的 CSS 绘制形状方案做一个系统整理按实现技术分门别类覆盖最常见的 40 种形状。每一种都会给出核心代码和几句原理说明重点讲清楚每种方案背后的思路。内容不会太长篇大论但保证每一条都能直接抄走用。1. 画形状前先想清楚这 5 种技术分别适合什么我最早接触 CSS 画形状的时候也很困惑同样一个三角形网上能找到七八种写法到底该用哪种后来踩了不少坑才明白CSS 画形状本质上就是围绕几个核心属性在做文章只要搞懂每个属性的脾气选型就是一瞬间的事。1.1 五种核心技术的基本盘我把常用的 CSS 绘图手段归纳成五类基本覆盖了所有常见形状技术方案核心属性擅长画的形状缺点border 边框法border-width / border-color / border-style三角形、梯形、箭头、对话框样式老派代码啰嗦border-radius 圆角法border-radius圆、椭圆、胶囊、半圆、叶子只能画曲线相关形状transform 变换法transform: rotate / skew菱形、平行四边形、旋转矩形本质还是矩形底子clip-path 裁剪法clip-path: polygon / circle / ellipse五角星、心形、六边形、任意多边形浏览器兼容性要注意gradient 渐变法 伪元素background / linear-gradient / ::before / ::after波浪、棋格、斜纹、棋盘形状是画出来的背景无法响应交互这里面最关键的一条经验是clip-path 是当前最推荐的方案因为它的思路最直接——把元素当作一张纸直接裁剪出想要的形状不需要像 border 那样靠拼接。后面我会花一整章细讲。1.2 形状库的组成逻辑这 40 种形状并不是随机罗列的我按性质把它们归成几组基础几何三角形、圆形、椭圆、矩形变体符号类箭头、星形、心形、对话框多边形类五边形、六边形、八角星背景纹理类波浪、棋格、斜纹、格子纸混合类胶囊、叶子、切角矩形、半圆这样归类的目的是为了方便查表你拿到一个形状需求先判断它属于什么类型然后直接去对应的章节找方案。比如领导说要一个标签上的小三角你就不用去看圆形的实现而是直接跳到 border 三角形那一节。2. border 边框法用四块颜色拼出三角形和对话框很多人刚学 CSS 时都遇到过这个名场面给一个宽高为 0 的元素设置不同颜色的粗边框结果出现了四个三角形。当时觉得莫名其妙后来才明白这正是 border 绘图的核心原理。2.1 三角形的原理边框其实是四块梯形拼图先看一段最简单的代码.triangle { width: 0; height: 0; border: 50px solid transparent; border-top-color: #ff6b6b; }这段代码会得到一个朝下的红色三角形。原理是当元素的宽高都是 0 时四条边框会收缩交汇在中心点每条边框呈现为一个三角形。只保留一条边框有颜色其余三条设置成 transparent透明剩下的就是纯粹的三角形。这里有个很重要的技巧改变 border-width 就能控制三角形的形状。.triangle-isosceles { width: 0; height: 0; border-left: 40px solid transparent; border-right: 40px solid transparent; border-bottom: 60px solid #ff6b6b; }上面的代码画的是一个底边宽 80px、高 60px 的等腰三角形。border-left 和 border-right 的宽度决定了三角形的底边宽度的一半border-bottom 的宽度决定三角形的高。想画扁三角形就加大左右边框宽度想画高三角形就加大底边框宽度。2.2 方向变换和箭头组合三角形的方向由哪条边不透明决定。记住这个口诀想让三角形朝哪个方向就把哪个方向的 border-color 设为实色。箭头朝上就设置 border-top-color箭头朝下就设置 border-bottom-color以此类推。有了三角形箭头就顺理成章了。最常见的右箭头是一个矩形 一个右三角.arrow-right { width: 60px; height: 40px; background: #ff6b6b; position: relative; } .arrow-right::after { content: ; position: absolute; right: -20px; top: 0; width: 0; height: 0; border-top: 20px solid transparent; border-bottom: 20px solid transparent; border-left: 20px solid #ff6b6b; }这里用到了伪元素这是 CSS 绘图中极其重要的技巧。一个元素本身画主体伪元素画装饰部分两边颜色保持一致拼接出来就是完整的箭头。2.3 对话框气泡和梯形对话框气泡是 border 形状里最有实用价值的一个UI 里经常用在小提示、聊天记录上。经典实现是圆角矩形 小三角尾巴.bubble { width: 200px; height: 60px; background: #4ecdc4; border-radius: 12px; position: relative; } .bubble::after { content: ; position: absolute; bottom: -20px; left: 30px; border: 10px solid transparent; border-top-color: #4ecdc4; }伪元素的小三角通过绝对定位放在气泡下方三角的颜色和气泡背景一致。用 border-radius 和 border 组合就能得到带圆角的气泡主体和锐利的尾巴视觉效果已经很接近图片素材了。梯形则是 border 法的另一个经典应用。给元素设置宽高再配合边框透明色.trapezoid { width: 100px; height: 0; border-bottom: 60px solid #ffe66d; border-left: 20px solid transparent; border-right: 20px solid transparent; }这个实现比较反直觉元素宽度 100px左右边框各 20px 透明最终呈现的梯形上底 100px、下底 140px。它的本质是利用边框之间的斜切角度造出的几何效果。我在实际项目里用它做过价格标签的底座效果挺好。3. border-radius 与 transform圆形、椭圆、胶囊和菱形的组合拳border-radius 这个属性不少人以为只是把方角变圆角用的实际上它是 CSS 绘图中曲线形状的主力军。配合 transform 使用又能做出很多有棱角的形状。3.1 圆形和椭圆把圆角拉满画圆形代码只有一行核心.circle { width: 100px; height: 100px; border-radius: 50%; background: #a29bfe; }原理很简单border-radius: 50% 会让元素四个角的圆角半径等于元素宽高的一半四个圆弧相交正好拼出一个内切圆。这里有一个细节是宽高必须相等才能是正圆宽高不等就会变成椭圆。椭圆就是把宽高设成不一致.ellipse { width: 120px; height: 80px; border-radius: 50%; background: #a29bfe; }这种写法在画鸡蛋和叶子这类形状时特别重要因为它们的本质是多个不同圆心、不同半径的圆弧拼接。3.2 叶子形、胶囊形和半圆叶子形的实现是个很好的技巧它同时用到了 border-radius 的两个值.leaf { width: 80px; height: 160px; background: #00b894; border-radius: 0 50% 0 50%; }这里 border-radius 的四个值分别对应左上、右上、右下、左下。左上角和右下角是 0右上角和左下角是 50%看起来就像一片竖立的叶子。实际项目中这种叶形圆角常用来做花瓣、扇形的装饰元素。胶囊形其实是圆角矩形的一种极致形式应用场景非常广比如标签、进度条、按钮.capsule { width: 200px; height: 60px; border-radius: 30px; /* 高度的一半 */ background: #fd79a8; }或者直接把 border-radius 设成 999px、999em让浏览器自己算。这里的关键是圆角半径大于等于高度的一半时两侧就会变成半圆形成胶囊。半圆也很常用做法是宽高比 2:1然后只保留两个上角为圆角.semicircle { width: 120px; height: 60px; border-radius: 60px 60px 0 0; background: #fab1a0; }3.3 transform 变换从矩形到菱形和平行四边形我会把 transform 归入形状绘制是因为很多看起来不像矩形的形状本质上都是对矩形做了变换。菱形就是最典型的例子.diamond { width: 100px; height: 100px; background: #0984e3; transform: rotate(45deg); margin: 40px; }一个正方形旋转 45 度就是菱形。这里有个实际布局细节旋转后的元素视觉尺寸会变大如果不加 margin 或预留空间很容易与周围元素重叠。我一开始经常被这个问题坑到后来统一在菱形外面包一层容器用 padding 或者 margin 给旋转留出空间。平行四边形则可以通过 skew 倾斜得到.parallelogram { width: 140px; height: 80px; background: #e17055; transform: skew(-20deg); }skew(-20deg) 把元素水平方向倾斜 20 度原本的矩形就变成了平行四边形。这种形状在标签页、卡片装饰里很常见。这里有一个进阶技巧如果平行四边形里面要放文字直接对元素做 skew 会让文字也跟着歪。解决办法是在内部再用一个 counter-skew 的伪元素或子元素反倾斜回来文字就能保持正常显示。这是我实际开发中踩过的坑需要注意。4. clip-path 裁剪法一次性搞定五角星、心形和六边形如果让我只能推荐一种 CSS 绘图方案我会毫不犹豫选 clip-path。它的思路和其他方案完全不同其他方案都是拼clip-path 是裁剪就像拿一把剪刀在元素上剪出一个形状。这种思路写复杂形状时优势特别明显。4.1 polygon 多边形五角星和六边形clip-path 的核心语法是 polygon(x1 y1, x2 y2, x3 y3, ...)括号里传入多边形每个顶点的坐标。坐标可以写具体的像素值也可以写百分比还可以写 calc() 表达式。画一个六边形.hexagon { width: 100px; height: 100px; background: #6c5ce7; clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); }六个顶点的坐标从顶部中间开始顺时针排列顶部偏左 25%、顶部偏右 75%、右边缘中间 100% 50%、底部偏右 75%、底部偏左 25%、左边缘中间 0% 50%。每个顶点之间用逗号分隔最后不需要闭合浏览器会自动连回第一个顶点。五角星稍微复杂一些但核心思路一样就是定义 10 个顶点五个外角点、五个内角点.star { width: 100px; height: 100px; background: #fdcb6e; clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }第一次写这组坐标的时候我看着密密麻麻的数字头痛后来发现不用死记硬背网上有现成的 clip-path 坐标生成器。我的建议是直接用生成器画好形状然后复制坐标到代码里。真正要学的是读坐标的能力——能看懂每个点大致在哪个位置这样才能在现成代码上做微调。4.2 心形、箭头和对话框心形用 clip-path 写也很方便它实际是一个五顶点多边形.heart { width: 100px; height: 100px; background: #ff6b6b; clip-path: polygon(50% 15%, 80% 40%, 85% 70%, 50% 95%, 15% 70%, 20% 40%); }注意这组坐标是从上方中间偏下的位置开始让心窝的位置留出来两侧用圆弧状转折表达心形轮廓。虽然直接用 polygon 画曲线形有点硬但视觉上已经非常接近心形了而且比堆 border-radius 省事得多。clip-path 还有一个 box 版本支持 circle 和 ellipse.half-circle-clip { width: 100px; height: 100px; background: #00cec9; clip-path: circle(50% at 50% 0%); }circle(50% at 50% 0%) 表示圆心在元素的水平中心、垂直顶部半径是元素宽度的 50%这样裁剪出来的就是上半圆。这种写法比 border-radius 组合更直观尤其在需要半圆扇形这类不规则裁剪时非常好用。4.3 clip-path 的几个硬伤clip-path 虽然强大但不是万能的我总结了几条实战中要注意的点裁剪区域外的部分不响应交互。比如一个四方形的按钮裁剪成圆形后只有圆形区域内的点击有效四角被剪掉的区域点击不到。这在做可点击图形时要格外注意。不能直接设置边框。元素加 border 属性后clip-path 会把边框一起裁剪掉形状轮廓看着光秃秃的。需要边框效果时常见做法是给元素加一个带背景色的父元素作为描边底。box-shadow 会被裁剪。给裁剪元素加 box-shadow阴影只在裁剪区域内显示外部阴影会消失。这也是我踩过的大坑最后用 drop-shadow 滤镜解决的。部分属性存在兼容性旧浏览器问题。现代浏览器几乎都支持但如果项目要兼容比较老的环境最好用supports做特性检测不支持的场景准备一个不带裁剪的降级样式。5. 渐变与伪元素波浪、棋格与更多背景纹理前面几章讲的都是闭合图形也就是能放内容、能交互的形状。但 UI 里还有一种需求是背景纹理——波浪分割线、棋盘格、斜纹、纸张格子。这些用 border 和 clip-path 都不好做得靠 gradient 渐变和伪元素。5.1 用 repeating-linear-gradient 画波浪波浪线分割线是我实际开发里很常用的一种装饰。实现思路是在一个高度固定的元素里用多个圆形的 background 重复排列形成波浪的视觉.wave { height: 40px; background: radial-gradient(circle at 20px 20px, #6c5ce7 0 12px, transparent 12px); background-size: 40px 40px; }radial-gradient 画出一个直径为 20px 的圆形色块background-size 设成 40px x 40px 后这个圆形会以 40px 为间距在水平和垂直方向平铺。第一个圆的圆心在 (20px, 20px)恰好位于平铺块的中心加上圆形下方是透明的就形成了半圆形的波浪边。想要更完整的波浪可以用两层渐变叠加一层向上凸、一层向下凹整体效果更接近波浪线。这种平铺单元 背景渐变的思路是画纹理的核心学会一次以后画什么纹路都能推。5.2 棋格、斜纹和格子纸棋格是这类纹理里最典型的一个。核心思路是用两个 linear-gradient 交叉叠加.checkerboard { width: 100px; height: 100px; background: linear-gradient(45deg, #2d3436 25%, transparent 25%, transparent 75%, #2d3436 75%), linear-gradient(45deg, #2d3436 25%, transparent 25%, transparent 75%, #2d3436 75%); background-size: 20px 20px; background-position: 0 0, 10px 10px; }原理稍微有点绕两层完全相同的 45 度斜纹第二层偏移 10px半个平铺单元的大小叠加后正好补上第一层空出来的格子形成棋格。这是我用过的所有纹理方案里最有代表性的一种——两个斜纹交错互相补位就变成了棋格。斜纹更简单单层 linear-gradient 就能解决.stripes { width: 100px; height: 100px; background: repeating-linear-gradient(45deg, #e17055 0 10px, #ffeaa7 10px 20px); }repeating-linear-gradient 会不断重复 45 度方向的渐变段每 10px 换一次颜色形成斜向条纹。5.3 伪元素与渐变组合自由多变的花纹前面提到的波形和棋格都是画在元素自身的背景上。但如果需要在元素内部的某个角落加一个装饰花纹又不想增加 HTML 结构伪元素就派上了用场。比如给卡片右上角加一个斜纹三角装饰.card { width: 300px; height: 200px; background: #fff; position: relative; overflow: hidden; } .card::before { content: ; position: absolute; top: 0; right: 0; width: 50px; height: 50px; background: repeating-linear-gradient(45deg, #6c5ce7 0 5px, #a29bfe 5px 10px); }伪元素的优势是不占 DOM 节点并且可以自由定位。很多看起来复杂的图形拆开看其实就是一个主体元素 一到两个伪元素的组合。我在做项目时有一个习惯先想清楚这个图形由哪几个基础形状组成再给每个形状分配元素。能用伪元素的就不用额外标签页面结构会清爽很多。6. 画形状的选型方法40 种形状背后的通用决策前面按技术分章介绍了各种形状最后我想把选型逻辑单独拉出来说一下。这是我从 40 种形状里总结出的一个通用方法下次不管遇到什么形状需求都可以按照这个思路快速判断。6.1 从需求倒推技术方案拿到一个形状需求时我一般依次问自己三个问题第一问这个形状是符号还是装饰如果是需要用户点击的按钮图标、标签箭头首选 border 和 border-radius 方案因为它们保留了元素的盒模型属性交互和文字排版都正常。如果只是装饰性的背景花纹直接用 gradient 或者伪元素做。第二问形状是直边多边形还是曲线弧形直边多边形三角形、六边形、五角星无脑选 clip-path坐标一写就完事。曲线弧形圆、胶囊、叶子用 border-radius 最省心。混合型比如带圆角的气泡就 border-radius 伪元素组合。第三问这个形状需要动态变化吗如果形状需要响应 hover 切换、动画过渡clip-path 的过渡通常比 border 更平滑因为它本质是对一个区域做连续裁剪。但要注意clip-path 的多边形顶点数量必须一致才能做过渡动画五角星变成六边形是可行的五角星变成圆形就不行。这个三问流程看起来简单但真能省下不少来回改代码的时间。我有段时间每次接到形状相关的 UI 需求都先用这个流程在脑子里过一遍再动手写基本一次成型。6.2 40 种形状速查与避坑清单把刚才讲的所有形状整理成一个速查表方便直接查形状推荐方案核心代码摘要三角形上/下/左/右border 透明色border-top-color 设实色即可梯形border 透明边border-bottom left/right 透明对话框气泡圆角矩形 ::after 三角border-radius 伪元素箭头四方向矩形 ::after 三角position 定位拼接圆形border-radius: 50%宽高相等椭圆border-radius: 50%宽高不等胶囊形border-radius: 999px或等于高度一半半圆border-radius 单边圆角宽高比 2:1叶子border-radius: 0 50% 0 50%开一角的圆角菱形transform: rotate(45deg)预留旋转空间平行四边形transform: skew(-20deg)内部反倾斜保文字五角星clip-path: polygon(10 点)生成器取坐标六边形clip-path: polygon(6 点)上下各三点心形clip-path: polygon(6 点)从上中开始排列箭头裁剪版clip-path: polygon三四个顶点波浪边radial-gradient 平铺background-size 控制波长棋格两层 linear-gradient 叠加第二层偏移半格斜纹repeating-linear-gradient角度 色段宽度格子纸linear-gradient 横竖叠加background-size 控制格距最后说几个我反复踩过的坑集中列出来border 画三角形时border-width 是朝外延伸的。很多人以为 border 画出来的三角是缩在元素内部其实它是朝外扩展的。所以三角形周围一定要留 margin不然会盖住相邻内容。clip-path 剪完的图形没有盒模型边界。外界看到的只有裁剪后的形状但用户代理浏览器计算点击区域时依然以裁剪后的路径为准。做可点击区域前要自己判断裁剪后的热区大小是否符合预期。transform 旋转后元素仍然占据原来的布局空间。一个菱形旋转 45 度后周围的兄弟元素不会自动给它让位旋转后视觉尺寸变大特别容易重叠。我的统一做法是给 transform 元素加一个足够大的 margin或者用父级 padding 兜底。渐变纹理的 background-size 必须和坐标互相配合。我一开始写棋格时background-position 没设偏移结果两层纹理叠在一起完全重合根本看不出棋格效果。偏移半个平铺单元是棋格成立的关键。6.3 实际项目中的应用建议聊了这么多技术和代码最后落到实际开发上我对 CSS 绘图的定位是能用 CSS 画的就绝不引图片能用简单方案的就别上复杂方案。像三角形、圆、胶囊、气泡这类基础形状完全可以直接用 CSS 写几乎没有维护成本改色只动一行。五角星、六边形这类复杂多边形clip-path 也足够轻量没必要为了一个图标引整个图标库。但是一旦形状变得极其复杂比如带纹理渐变、多层阴影、多角度透视的图形CSS 的代码量会急剧膨胀这时候老老实实切图或引 SVG 反而更明智。我自己画形状有一条底线一个 CSS 形状的代码超过 10 行我就停一下想想是不是该换方案了。不是 CSS 画不出来而是超过这个阈值后后续的维护成本比如改尺寸、改比例、适配响应式会指数级上升。画形状的最终目的是服务页面而不是炫技。记得有一次做一个数据可视化大屏需要一排六边形组成的装饰背景。用 clip-path 写了一个六边形类然后重复渲染了三排每排错开半个角度。整个页面加载完全没有任何图片请求性能上没有任何压力跨浏览器表现也稳定。这种无图化带来的轻快感是 CSS 绘图最让人上瘾的地方。如果你还没试过用 clip-path 画多边形强烈建议打开浏览器控制台随便建一个 div把文章里的五角星坐标粘进去看效果——你会发现原来做图形可以这么简单。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →