关于 border-radius 你很可能不知道的一些事
前言
我在试图创建一个胶囊形状的时候遇到了这个问题。
对于一个矩形而言,如果你只是单纯的这么做:
最终你只会得到一个椭圆:

要生成一个合格的胶囊,圆角的水平和垂直半径都得等于盒子的较短边的一半。
dbc94546cd20e7b898b1d83191d11a6.jpg
可是事实上,当你在属性里使用百分数的时候,默认对应的是对应边(也就是水平半径是盒子 width 的一半,垂直半径是 height 的一半)。而如果想要制作胶囊,你想要的是垂直半径和水平半径都是盒子垂直边的一半。
但除非使用变量,你几乎无法做成这件事。我学到了一个比较讨巧的办法是这样做:
如此一来,真的能创建一个完美的胶囊。但是为什么可以?
这个让我对背后的原理滋生了浓厚的兴趣。经过一系列探究,我已经得到了答案。探究用到的案例代码我会放在文末。
基础知识
border-radius
的一个最完整的写法是这样的:
dbc94546cd20e7b898b1d83191d11a6.jpg
1 2 3 4 5
|
border-radius: 10px 20px 30px 40px / 15px 25px 35px 45px;
|
角的次序就是从左上角开始顺时针转一圈。
一个冲突情况
对于一个 400x200 的盒子,如果我把圆角设置成这样:
1
| border-radius: 200px 0px 0px 200px / 150px 0px 0px 150px;
|
你会发现左上角和左下角的垂直半径都超过了盒子的高度,也就是像下图这样:
一个冲突情况
那到最后到底会怎么渲染呢?先看答案:

没错,在这种冲突下,居然达成了某种平衡,使得两个角的垂直半径看起来都像是 height 的一半,也就是 100px。
原理
经过仔细查阅资料,我明白了一个重要的相关原理:
当相邻角的半径之和超过相应边的长度时,浏览器会按比例缩小所有半径值直到相加等于对应边长度,以确保它们能够正确渲染。
也就是说对于一个 400x200 的盒子,如果这样设置:
1
| border-radius: 200px 0px 0px 200px / 300px 0px 0px 300px;
|
那浏览器会这样算:
两个边的垂直半径和 = 300 + 300 = 600
实际的height = 200
得出应该缩小3倍
所以最终的垂直半径都为:
300 ÷ 3 = 100
值得注意的是,水平半径也会发生变化:
最终的水平半径 = 200 ÷ 3
原因在于:
当浏览器调整 border-radius
值时,它会:
- 保持原始的水平:垂直半径比例
- 同比例缩放两个方向的半径
结论
经过上面的探究,就能知道为什么圆角半径设置的很大的时候,能巧妙制作出胶囊了:
浏览器会同比例缩放水平半径和垂直半径,缩放的比例是由盒子的较短边决定的,这是因为在缩小比例的时候,要达到短边的长度,短边需要更大的缩放比。所以最后就发现圆角值能很巧的等于较短边的一半啦。
测试用例
测试的时候调整 .box 的圆角值即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
position: relative;
}
body {
height: 100vh;
background-color: #333;
}
.box {
box-sizing: border-box;
width: 400px;
height: 200px;
top: 1%;
left: 50%;
position: absolute;
transform: translateX(-50%);
background-color: #ab8df7cc;
border: #bdbdbd 2px solid;
border-radius: 200px 0px 0px 200px / 300px 0px 0px 300px;
}
.box2 {
width: 400px;
height: 200px;
display: flex;
flex-wrap: wrap;
top: 1%;
left: 50%;
position: absolute;
transform: translateX(-50%);
background-color: #ab8df748;
}
.grid {
width: 25%;
height: 50%;
box-sizing: border-box;
border: #c9c9c9 1px dashed;
}
</style>
<div class="box"></div>
<div class="box2">
<div class="grid"></div>
<div class="grid"></div>
<div class="grid"></div>
<div class="grid"></div>
<div class="grid"></div>
<div class="grid"></div>
<div class="grid"></div>
<div class="grid"></div>
</div>
</body>
</html>
|