你不知道的 border 和 border-radius

1,655 阅读5分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

作为一名前端,每天都在写 CSS,经常写的两个样式为 border 和 border-radius,相信大家都知道其基本用法:

  • border:设置元素边框
  • border-radius:设置元素圆角

实际上这两个属性的应用场景是非常广泛的,我们有必要对其进行深入的研究和探索。

border

绝大多数时候上下左右四个方向的颜色都是一样的,此时并不能看出来真正区别,可能都没有意识到左上角、右上角、左下角和右下角的边框交界处是什么效果。当我们把边框的宽度设置大一点,四个方向设置不同颜色,就能够非常清晰的看到边框的本质:

当 border 的宽度等于正方形宽度的时候,我们会发现上下左右边框都变成了等腰直角三角形:

那如果只设置部分边框又会怎样呢?例如去掉 border-top 或者只设置 border-right 和 border-bottom,可以先脑补一下,然后再看实际效果:

掌握了这个知识点之后,就可以做小箭头的气泡效果啦,例如对掘金的真情表白:

这里就是利用把顶部和底部的 border 给设置成透明色,仅透出右侧的 border,就形成了向左的箭头。

border 的属性也可以单独设置,顺序依次为上、右、下、左:

border-width: 1px 2px 3px 4px;
border-style: solid dashed dotted solid;
border-color: red orange blue green;

但是很明显不如下面的写法直观:

border-top: 1px solid red;
border-right: 2px dashed orange;
border-bottom: 3px dotted blue;
border-left: 4px solid green;

有一点需要强调,当子元素相对于父元素进行绝对定位时,它的参照原点是父元素的 padding-box,而不是 border-box,如下图所示:

border-radius

该属性用于设置元素的外边框圆角,大部分场景下我们会写类似下面的代码:

border-radius: 50px;

会在元素四个角形成半径为 50px 的圆角效果:

当圆角的半径不断增加,直到等于正方形边长的一半的时候,整个正方形就会裁剪成一个大的圆形,相当于四个角的小圆合成了一个居中的大圆,动画效果如下:

那如果圆角半径超过正方形边长一半的话,浏览器会如何处理呢?其实规范里面有详细的描述:

当任意两个相邻圆角的半径之和超过元素的宽高尺寸时(以 border box 为参照),会按照比例缩小半径的值,直到不会相互重叠为止。

其实 border-radius 的语法比我们想象中的灵活很多,例如:

  • 它不仅可以是 20px,也可以是百分比,比例基于元素的尺寸进行解析(宽度用于解析水平半径,高度用于解析垂直半径)

  • 它是一个简写属性,可以用斜杠 /分隔来单独设置四个拐角的值,例如 border-radius: 20px 50% 10px 20px / 20px 50% 20px 30% 相当于针对每个拐角单独设置水平和垂直半径:

    • border-top-left-radius: 20px左上圆角半径是 20px
    • border-top-right-radius: 50% 右上圆角水平和垂直半径分别是宽度和高度的一半
    • border-bottom-right-radius: 10px 20px 右下圆角的水平和垂直半径分别是 10px 和 20px
    • boder-bottom-left-radius: 20px 30% 左下圆角的水平半径是 20 像素,垂直半径是高度的 30%。
  • 从左上角顺时针顺序应用到每个拐角,如果提供的值少于 4 个,则按照 CSS 常规方式进行重复,即:

    • 1个值表示所有圆角都是这样
    • 2个值表示左上和右下按照前一个值,右上和左下按照后一个值
    • 3个值表示应用在左上、右上、右下的圆角,而左下的圆角的值等于右上圆角的值

我们来看一个案例:

border-radius: 100px 50px / 50px 100px;
/* 等价于下面的写法 */
/* border-radius: 100px 50px 100px 50px / 50px 100px 50px 100px; */

用表格描述如下:

左上角右上角右下角左下角
水平半径100px50px100px50px
垂直半径50px100px50px100px

用图形表示如下:

上图的完整演示代码:

<div class="container">
  <div class="wrapper">
    <div class="box">
    </div>
    <div class="corner top-left"></div>
    <div class="corner top-right"></div>
    <div class="corner bottom-right"></div>
    <div class="corner bottom-left"></div>
  </div>
</div>
.container {
  margin-top: 100px;
  display: flex;
  justify-content: space-around;
  --size: 400px;
  --border-radius-size: 50px;
}

.wrapper {
  position: relative;
}

.box {
  width: var(--size);
  height: var(--size);
  box-sizing: border-box;
  border-radius: calc(var(--border-radius-size)*2) var(--border-radius-size) / var(--border-radius-size) calc(var(--border-radius-size)*2);
  background-color: antiquewhite;
  border: 10px solid gold;
}

.corner {
  position: absolute;
  border: 3px dotted purple;
}

.corner.top-left {
  left: 0;
  top: 0;
  width: calc(var(--border-radius-size)*4);
  height: calc(var(--border-radius-size)*2);
  border-radius: 50%;
}

.corner.top-right {
  top: 0;
  right: 0;
  width: calc(var(--border-radius-size)*2);
  height: calc(var(--border-radius-size)*4);
  border-radius: 100%;
}

.corner.bottom-right {
  bottom: 0;
  right: 0;
  width: calc(var(--border-radius-size)*4);
  height: calc(var(--border-radius-size)*2);
  border-radius: 50%;
}

.corner.bottom-left {
  bottom: 0;
  left: 0;
  width: calc(var(--border-radius-size)*2);
  height: calc(var(--border-radius-size)*4);
  border-radius: 100%;
}

项目实战

用 CSS 画一个半圆

据说 90% 的前端都会用 CSS 画圆,但是只有 10% 的前端会用 CSS 画半圆,对就是下面这个图形:

如果不会画,说明 border-radius 属性还没掌握透,很显然我们只需要先画一个宽度为高度两倍的矩形,然后给左上角和右上角设置单独的圆角即可,代码如下:

.box {
  width: 200px;
  height: 100px;
  box-sizing: border-box;
  background-color: antiquewhite;
  border: 10px solid gold;
  border-radius: 50% 50% 0 0 / 100% 100% 0 0; /* 关键代码 */
}

用 CSS 画一个扇形

如果你已经学会了如何画半圆,那么下面的扇形其实就非常容易了:

思路就是把一个矩形的左上圆角设为 100% 边长,然后旋转 45° 即可,代码如下:

.box {
  width: 100px;
  height: 100px;
  box-sizing: border-box;
  background-color: antiquewhite;
  border: 10px solid gold;
  border-top-left-radius: 100%; /* 或者用 border-radius: 100% 0 0 0 / 100% 0 0 0; */
  transform: rotate(45deg);
}