CSS 教程 / CSS 边框、圆角与阴影

CSS 边框定义盒子的可见边缘,border-radius 使其角变圆,box-shadow 添加阴影而不增加布局尺寸。阴影仍可能被祖先元素的 overflow 设置裁剪,圆角边框不会自动裁剪每个子元素。

设置边框的宽度、样式和颜色

.card { border: 2px solid #3d6b89; }

border 缩写结合了宽度、样式和颜色。solid 绘制连续线,dashed 绘制虚线,dotted 绘制点线。none 样式即使在存在宽度和颜色时也会抑制预期的边框。当仅需要一个边缘有边框时,使用 border-bottom 或 border-block-end。有关详细信息,请参阅 CSS 盒模型:内容、内边距、边框与外边距。

属性 盒子大小效果 主要用途
border 在 content-box 中,它在外部添加,而在 border-box 中,它包含在指定大小内。 元素的边框
outline 不会增加布局空间 在聚焦元素周围显示轮廓
box-shadow 不会增加布局空间 阴影和视觉深度

在固定 border-box 宽度的情况下,增加边框厚度会减少内部空间,但保持外部宽度。装饰性边框或阴影的作用不同于识别当前键盘目标的聚焦轮廓。保持该指示器可见。参见 MDN:border。

比较圆角的长度值与百分比

.round { border-radius: 12px; }

.circle { width: 80px; height: 80px; border-radius: 50%; }

.oval { width: 160px; height: 80px; border-radius: 50%; }

像 12px 这样的长度值指定了角半径。你可以给四个角不同的值,但先从四个角使用同一值的情况开始比较。如果对宽度和高度相同的盒子应用 50%,它看起来会像一个圆,如果水平和垂直尺寸不同,它会看起来像一个椭圆。百分比的水平半径基于宽度,垂直半径基于高度。

父元素的圆角不会自动裁剪子图像。根据你的目的,在给图像本身设置 border-radius 或从父元素裁切溢出内容之间进行选择。如果给父元素设置 overflow: hidden,子元素的阴影/焦点显示也可能会在边界处被裁剪。下面的对比说明了哪个盒子被裁剪。你可以在 MDN:border-radius 中查看半径计算。

读取阴影值

.shadow { box-shadow: 0 8px 24px 4px rgb(0 0 0 / 16%); }
值 含义 要更改的结果
第一个 0 水平移动 正数向右移动,负数向左移动
第二个 8px 垂直移动 正数向下移动,负数向上移动。
第三个 24px 模糊半径 越接近 0,越清晰;数值越大,越模糊。
第四个 4px 扩展半径 正数增加阴影大小,负数减小阴影大小。
rgb(0 0 0 / 16%) 颜色和不透明度 它与背景的区分程度各不相同。

前两个长度是必需的,模糊和扩散可以省略。模糊半径不能为负值。添加inset是内阴影,默认是外阴影。还有一种方法可以添加多个阴影,但首先通过单独改变一个阴影的移动和大小进行检查。

阴影不会占用布局空间。它不会因为模糊或扩散而推动后面的卡片。大的阴影可能遮挡附近的内容,因此在需要时应通过边距或布局间隙提供实际间距。参见MDN:box-shadow。

找到剪裁阴影的祖先元素

.frame { padding: 12px; overflow: visible; }

.frame.clip { overflow: hidden; }

.frame .card { box-shadow: 0 18px 20px 8px rgb(0 0 0 / 25%); }

最后两张卡片有不同的 .frame 父元素。它们的子元素阴影是相同的,但一个父元素允许可见的溢出,而另一个则会裁剪溢出。阴影超出了父元素的 12px 内边距,因此隐藏溢出的版本会在父元素边界处裁剪它。在诊断被裁剪的阴影时,请检查该祖先元素。参见 CSS 溢出、长文本换行和省略号。

应区分在卡片本身设置 overflow: hidden 与祖先元素裁剪子卡片外阴影这两种情况。这次练习是一个父元素剪切子卡片外围阴影的情况。如果阴影在实际页面上不可见,你应检查的不仅是卡片本身的值,还包括父元素的溢出和边框。

运行示例并比较变化

将以下代码以 UTF-8 格式保存到 borders.html。保存后用浏览器打开。示例包含边框、圆角、外阴影、内阴影、圆形、椭圆及祖先元素裁剪阴影的对比。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Comparing borders, corners, and shadows</title>
  <style>
    * { box-sizing: border-box; }
    body { margin: 24px; color: #333; font: 16px/1.6 sans-serif; background: #f6f8fa; }
    .card { width: 100%; max-width: 320px; margin-block: 24px; padding: 20px; background: white; }
    .border { border: 2px solid #3d6b89; }
    .round { border: 2px solid #3d6b89; border-radius: 12px; }
    .shadow { border-radius: 12px; box-shadow: 0 8px 24px 4px rgb(0 0 0 / 16%); }
    .inset { box-shadow: inset 0 0 12px 2px rgb(0 0 0 / 20%); }
    .shape { width: 80px; height: 80px; margin-block: 16px; border-radius: 50%; background: #6eb898; }
    .oval { width: 160px; }
    .frame { width: 100%; max-width: 320px; padding: 12px; margin-block: 24px; background: #dce8f1; overflow: visible; }
    .frame .card { margin: 0; max-width: none; height: 100px; box-shadow: 0 18px 20px 8px rgb(0 0 0 / 25%); }
    .clip { overflow: hidden; }
  </style>
</head>
<body>
  <h1>Card boundaries and shadows</h1>
  <div class="card border">Card with a border only</div>
  <div class="card round">Border and rounded corners</div>
  <div class="card shadow">Outer shadow</div>
  <div class="card inset">Inset shadow</div>
  <h2>50% Edges: Circles and Ovals</h2><div class="shape" role="img" aria-label="80×80 circle"></div><div class="shape oval" role="img" aria-label="160×80 ellipse"></div>
  <h2>Parent: overflow: visible</h2><div class="frame"><div class="card">Child shadow visible outside the parent</div></div>
  <h2>Parent: overflow: hidden</h2><div class="frame clip"><div class="card">Child shadow clipped at the parent boundary</div></div>
</body>
</html>
  1. 将 .border 的厚度从 2px 改为 8px。在宽窗口中,确保外部宽度保持不变且内部空间减少,然后将其恢复为 2px。
  2. 将 .shape 的宽度从 80px 改为 160px。如果高度保持 80px,请确保圆形变为椭圆形。恢复到原始宽度。
  3. 将 .shadow 的水平偏移改为 20px,垂直偏移改为 -8px。保持模糊为 24px,只比较移动的方向。接着,将模糊改为 0,和锐利的边缘比较,然后再恢复到原来的值。
  4. 将扩散从 4px 改为 -4px。注意阴影的大小是否减小。比较后恢复扩展半径为 4px。再将第二个 .frame 的 overflow 从 hidden 改为 visible,检查父元素外的阴影是否重新出现,最后恢复 hidden。

如果阴影模糊,请检查颜色不透明度和背景对比度;如果只有一侧被裁剪,请检查父元素的边框和溢出设置。如果角落内部的子内容突出,我们也会比较给子元素本身设置圆角的方法。判断时不要以增加效果为主,而是以保持内容清晰和易于操作为基础。