clip-path:circle() 半径似乎没有正确计算

clip-path:circle() radius doesn't seem to be calculated correctly

每当我尝试使用 CSS circle() 函数进行一些裁剪时,它一直困扰着我,如下所示:

.red {
   width: 200px;
        height: 300px;
        background: red;
        border: 2px solid black;
        clip-path: circle(69%);  /*barely cuts off the corners of the .red div */
}

/*  the full circle will enclose the entire box at around 71% or (sqrt(2)/2 * 100%)
 per Mozilla documentation and not at 100% as one might expect */
<div class='red'></div>

半径似乎从未像我期望的那样被计算出来。在查看 Mozilla MDN 参考资料 (https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape) 后,他们似乎计算如下:





这对我来说似乎不正确。我想他们会计算包围元素矩形(div、img 等)的圆周半径,如下所示:





但事实似乎并非如此。任何人都可以对此有所了解。这是某种错误还是我只是不理解这里的某些内容?

它的定义是这样的,他们从来没有打算计算你显示的半径。也是in the specification.

为了更好地理解,让我们考虑一个正方形。如果您将 50% 视为值

,则可以得到一个完美的圆

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(50%);
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>

背后的思路是考虑下图:

R 是您正在计算的 'c'(绿线),r 是使用的参考(紫线)。您可以很容易地看到 r = R/sqrt(2)R = sqrt(w² + h²)。结合两者会给我们:

r = sqrt(w² + h²)/sqrt(2)

这是您在 MDN 页面中看到的公式。

在正方形内使用此值的 50% 将得到逻辑圆:

 r/2 = sqrt(w² + h²)/(2*sqrt(2)) = sqrt(2*w²)/(2*sqrt(2)) = w/2 (or h/2)

为了覆盖整个正方形,我们需要一个等于 R/2 的值,即 r/sqrt(2) = r/1.41 并且由于 r100%,您将得到 71%你发现了

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(calc(100% / 1.44)); /* a little bogger  than 1.4 to better see*/
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>

相同的逻辑适用于宽度和高度不同但参考保持不变的非正方形:

r = sqrt(w² + h²)/sqrt(2)

从上面我们可以得出结论,71% 是一个神奇的值,无论形状如何,它都会产生相同的输出,因为它依赖于包围元素矩形的圆周半径 50%(或任何其他值)将给出不同的结果:

.red {
  width: 200px;
  height: 200px;
  background: red;
  box-shadow:0 0 0 100px yellow;
  display:inline-block;
  clip-path: circle(71%); 
  margin: 70px;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

使用50%

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(50%); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

我们也可能认为任何大于 71% 的值都是无用的,因为我们总是会给出一个比我们的元素大的圆。这是事实,但我们不应该忘记我们也有立场。

使用 100%200% 甚至 300%!

的输出示例

.red {
  width: 200px;
  height: 200px;
  background: red;
  border:2px solid;
  box-sizing:border-box;
}
<div class='red' style="clip-path: circle(100% at  0    50%)"></div>

<div class='red' style="clip-path: circle(200% at -100% 50%)"></div>

<div class='red' style="clip-path: circle(300% at -200% 50%)"></div>


我会考虑一个不同的 属性 来更好地消除混淆 radial-gradient

.box {
  width:200px;
  height:200px;
  border:1px solid;
  background:radial-gradient(circle 50%, red ,blue);
}
<div class="box">

</div>

下面的代码是用来定义一个半径等于 50% 的圆,但它是无效的,因为我们不知道引用:

Note: Percentages are not allowed here; they can only be used to specify the size of an elliptical gradient, not a circular one. This restriction exists because there is are multiple reasonable answers as to which dimension the percentage should be relative to. A future level of this module may provide the ability to size circles with percentages, perhaps with more explicit controls over which dimension is used.ref

我们正在处理矩形形状,因此我们可以使用您正在计算的高度、宽度、半径等。有很多选项,所以他们只是决定使其无效,但对于 clip-path 他们做了一个决定,定义了percetange的使用参考。

顺便说一下,考虑 closest-side/farthest-side.

这样的值,您可以更好地控制自己的圈子

下面总是给我们圆圈接触最近的边(与带背景的 contain 相同)

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path:circle(closest-side); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

下面总是给我们最远边的圆圈(与带背景的 cover 相同)

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path:circle(farthest-side); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>


结合位置,它们可以给出一些有趣的结果:

.red {
  width: 200px;
  height: 200px;
  background: red;
  border:2px solid;
  box-sizing:border-box;
  transition:1s all;
}
<div class='red' style="clip-path:circle(farthest-side at left); "></div>
<div class='red' style="clip-path:circle(closest-side at 10% 10%); "></div>
<div class='red' style="clip-path:circle(farthest-side at top left); "></div>
<div class='red' style="clip-path:circle(closest-side at 40% 50%); "></div>