内凹圆角

问题

有些时候,我们只希望容器的内部边框是圆角的,但是外部轮廓线要是矩形的,如下图所示:

图1注:一个具有轮廓线的容器,而它的圆角只在容器的内部

目前,这个有趣的设计用得还不是很多。使用两个元素实现这种效果就太平庸了:

  1. <div class="something-meaningful"><div>
  2. I have a nice subtle inner rounding,
  3. don’t I look pretty?
  4. </div></div>
  5. .something-meaningful {
  6. background: #655;
  7. padding: .8em;
  8. }
  9. .something-meaningful > div {
  10. background: tan;
  11. border-radius: .8em;
  12. padding: 1em;
  13. }

这么做的效果还不错,但会强迫我们使用两层标签,而实际上我们只需要一层。那么是否有方法只使用一层就实现这种效果呢?

解决方案

之前使用两层标签的解决方案很灵活,可以让我们充分利用 background 的特性。比如,我们希望边框不只是纯色的,也有可能是带有噪点的纹理,那么使用上面的方法很简单就可以做到。不过,当我们的边框只是纯色时,有一种方法可以只使用一层元素实现相同的效果,下面就是代码:

  1. background: tan;
  2. border-radius: .8em;
  3. padding: 1em;
  4. box-shadow: 0 0 0 .6em #655;
  5. outline: .6em solid #655;

你能猜到这段代码的效果吗?它所表现的效果:

图2注:为一个圆角元素添加轮廓线

在这里我们将会充分利用 outline 不受元素的圆角影响,而元素的阴影受圆角影响的特性来完成这一效果。因此,如果我们将outline 置于图层顶部,那么 box-shadow 就会弥补 outline 在角落上的空隙:

图3注:使用 box-shadow 属性包围圆角,并且不设置任何偏移和模糊效果

所以组合使用它们就可以实现最终的效果。下图中的阴影和 outline 被设置成了不同的颜色,这是为了让大家看的更明白。

图4注:这里的轮廓线之所以使用黑色,阴影之所以使用洋红色,是为了让大家看清其中的原理;值得注意的是轮廓线在所有图层的最上方

注意,我们无需让阴影的范围等于 outline 的宽度,只需让阴影足以覆盖间隙即可。实际上,如果让 outline 的宽度和阴影的范围相同,在某些浏览器中会发生一些渲染问题,所以我建议使用比 outline 稍小一些的阴影。这也提出了新的问题:弥补间隙的最小阴影应该是多少?

为了回答这个问题,我们需要使用学校里学到的勾股定理来计算直角三角形的各边变长。勾股定理指出,最长边等于其他两边的平方和,由此可知,如果这两条边都等于 a,那么最长边就等于

你可能会惊讶中学学到的理论竟然和我们的内部圆角效果相关,那么你可以查看一下图:

图5注:如果边框半径是r,那么圆心到罗廓线边角的最长距离就是

它很好地解释了勾股定理是如何应用到这里的。在我们的这个示例中,border-radius.8em,所以最小的阴影范围是.34em 的阴影范围。为了避免重复计算,你可以直接取圆角半径的一半,这样就已经足够用了

请注意,这种计算方法并不是没有限制的:对于这里要实现的效果,我们阴影半径必须比 outline 的宽度要小,同时还要大于r 表示 border-radius)。这意味着如果 outline 的宽度小于