不一样的边框:border-radius和border-image

2,422 阅读11分钟

在开发活动页的时候,经常会遇到一些边框相关的样式,例如轮廓不规则的头像、字数不确定的气泡对话框等(如下图)。这是怎么实现的呢?很简单都是利用我们平时常用的 CSS 属性 border 实现的。

不规则轮廓利用border-radius;气泡对话框是利用border-image实现的,下面我们就分别介绍一下这两个 CSS 属性。

image.png

image.png

border-radius

文章开头的不规则轮廓实现方式当然不止一种。在这里是通过最常用的 border-radius 实现的。

我们通常使用这个属性来实现圆角矩形、圆形等基本形状,那是如何实现这种不规则的形状呢?下面就介绍一下属性值的含义以及实现方式。

image.png

border-radius 是一个组合属性,用来设置矩形区域的四个外边框圆角,包含以下几个属性:

  • border-top-left-radius(下文简称top-left)
  • border-top-right-radius(下文简称top-right)
  • border-bottom-right-radius(下文简称bottom-right)
  • border-bottom-left-radius(下文简称bottom-left)

每个属性最多可以设置两个值,设置一个值为单一半径;设置两个值为额外半径。下面就分别对这两种情况进行介绍。

单一半径

  • 可以设置 1-4 个值,设置规则如下:

    1 个值: 表示所有的角都按照这个值进行圆角化,即 top-left + top-right + bottom-right + bottom-left;

    2 个值: 第一个值表示 top-left + bottom-right,第二个值表示top-right + bottom-left;

    3 个值: 第一个值表示 top-left,第二个值表示 top-right + bottom-left,第三个值表示 bottom-right;

    4 个值: 分别表示 top-left、top-right、bottom-right、bottom-left。

    💡 设置顺序和常用的属性padding``margin类似都是沿着顺时针转的;只不过border-radius是从左上角开始的。

  • 可以混合使用长度和百分比

    使用百分比时,如果元素区域是正方形则圆弧为正圆形,半径为元素宽度的百分比;如果元素区域是长方形则圆弧为椭圆形,椭圆的水平半径为元素区域宽度的百分比,垂直半径为元素区域高度的百分比。

    border-radius: 50%用来制作圆形/椭圆形。水平半径为矩形宽度的一半,垂直半径为矩形高度的一半。

image.png

长度和百分比可以混合使用,例如 border-radius: 45px 30% 30% 45px;

image.png
  • 设置范围为 [0,∞]

    0 表示直角;

    圆弧半径大于一定值后图形将来不再发生变化,下面会详细介绍这种情况。

额外半径

实际上border-radius的每个属性都可以设置两个值,分别表示水平半径和垂直半径。例如 border-top-left-radius:10px; 等同于 border-top-left-radius:10px 10px;

注意:书写公式 border-垂直-水平-radius: 水平 垂直;

所以border-radius的值最多可以设置 8 个,用/分开前后各 4 个。/前的值表示水平半径,/后的值表示垂直半径。这和设置百分比类似,不过可以分别设置独立的值,前后 4 个值的设置规则和单一半径设置规则相同。

border-radius = 
  <length-percentage [0,∞]>{1,4} [ / <length-percentage [0,∞]>{1,4} ]? 

把圆弧辅助线画出来可以看出最后剩余形状就是椭圆形四个角方框四条边重叠的部分。

border-radius: 90px 40px;border-radius: 90px / 40px;是完全不同的。

image.png border-radius: 30% 40% 40% 30% / 30% 30% 40% 40%;

image.png border-radius: 50%形成的是一个圆形,类似的同一个方向的半径之和等于100%就不会留下直线,所有方向都满足这个条件就会形成像开头这种圆润的不规则图形

假设border-radius: a b c d / e f g h; 四个角的半径分别为:

top-left: a e;

top-right: b f;

bottom-right: c g;

bottom-left: d h;

可以得出四个方向的半径之和分别为:水平方向top = a + b; 水平方向bottom = c + d; 垂直方向left = e + h; 垂直方向right = f + g;

border-radius:30% 70% 70% 30% / 30% 30% 70% 70%;代入上述公式,可以得到 👇 圆润的图形。

image.png

曲线重叠问题

这里问大家一个问题,如果半径再大一些会怎么样?

border-radius:90% 70% 70% 30% / 30% 30% 70% 70%;按照这个比例绘制圆弧辅助线会发现和图像边缘不重合(如下图一)。

image.png

这是因为border-radius渲染时有个两个特性:大值特征和等比例特征。下面分别对这两个特征进行详细介绍:

大值特征

border-radius的值很大时,渲染时同一方向相邻半径之和不能超过矩形的宽高,这就是border-radius大值特征。例如:

矩形尺寸 width: 300px; height: 200px; 设置边框圆角 border-radius: 900px 0 0 0 / 900px 0 0 0;

左上角的圆弧水平半径为900px,大于宽度300px;垂直半径为900px,大于高度200px;此时圆弧可以渲染的最大尺寸为200px。

因此相当于设置边框圆角 border-radius: 200px 0 0 0 / 200px 0 0 0;

image.png

上述例子圆弧的水平垂直方向是相等的,便于理解大值特征,如果圆弧两个方向的半径不想等会怎样呢?

此时需要用到border-radius等比例特征

等比例特征

等比例特征是说某个角圆弧的水平半径/垂直半径这个比例是不会变的。例如:

设置边框圆角 border-radius: 900px 0 0 0 / 400px 0 0 0;

左上角的圆弧水平半径为900px,大于宽度300px;垂直半径为400px,大于高度200px。此时圆弧水平半径最大为300px,缩小系数为 300 / 900;垂直半径最大为200px,缩小系数为 200 / 400,根据等比例特征只能系数也较小的值就是 300 / 900 来缩小圆弧。可以得出实际渲染的尺寸为 border-radius: 300px 0 0 0 / 400px/3 0 0 0;

image.png

如果同一方向设置了两个圆弧呢?这里就用到了等比例特征的另外一层含义,同方向的相邻圆弧半径比例不变。

例如设置边框圆角 border-radius: 900px 600px 0 0 / 900px 600px 0 0;

左上角的圆弧水平半径为900px,垂直半径为900px; 右上角的圆弧水平半径为600px,垂直半径为600px;

此时水平方向有两个半径,半径之和为 900px + 600px = 1500px,大于矩形宽度300px;垂直方向左侧半径为600px,大于200px;垂直方向右侧半径为600px,大于200px;根据大值特性此时需要将水平方向半径之和缩小至300px,为保证圆弧比例不变每个圆弧都需要缩小相同的系数,也就是300/1500。可以得出实际渲染的尺寸为 border-radius: 180px 120px 0 0 / 180px 120px 0 0;

image.png

根据上述推算过程可以得出一个通用的计算公式:

f = min(L宽度/S宽度,L高度/S高度),L为容器宽高,S为统一方向相邻半径之和;f 为缩小系数。

所有圆弧的实际渲染的半径都需要乘以缩小系数 f

假设border-radius: a b c d / e f g h;

按照css规范设定的规则可以得出 f = min(width / ( a + b) , width / ( c + d ) , height / (e + h) , height / ( f + g) )

例如 border-radius: 90% 70% 70% 30% / 30% 30% 70% 70%;代入公式 f = min(L宽度/S宽度,L高度/S高度) 可以得出 f = 100% / (90% + 70%) = 0.625

👉 实际上绘制的图形为border-radius: 56.25% 43.75% 43.75% 18.75% / 18.75% 18.75% 43.75% 43.75%;

image.png

border-width

假设边框有了宽度border-width又会出现怎么样的现象呢?

外边框符合上述的规则,内边框的圆弧半径则需要减去边框宽度 =border-radius - border-width,结果大于零为圆角;不大于零则为直角。

image.png

注意:边框圆弧半径水平和垂直方向只要一个方向为零则为直角,例如 border-radius:50px / 0;border-radius:0; 是同样的效果。

Visual Tool

FANCY-BORDER-RADIUS 一个 border-radius 视觉生成器,直观的创建一个有机形状。

BORDER-RADIUS-GENERATOR 一个用来生成border-radius效果的工具。

浏览器兼容性

image.png

border-image

image.png

在一些活动页面中可能会遇到给一段文字增加气泡对话框背景图片,UI会提供一个背景图片的示例,但是我们并不清楚这段文字的长度。同一张图片在不同的尺寸下边角可能会变形失真,单纯的拉伸图片恐怕是不行(👇左图为拉伸的效果,右图为理想效果),那该如何解决呢?如果可以对图片进行部分拉伸,就可以解决上述问题了。

image.png

.9.png

"点九图"是安卓独有的切图格式,这种格式可以使圆角矩形在拉伸放大时不会模糊失真。后缀名为【.9.png】,为了方便记忆称为点九图。

.9.png 相当于把一张png图分成了9个部分(九宫格),分别为4个角,4条边,以及一个中间区域。4个角是不做拉伸,2条水平边和垂直边分别只做水平和垂直拉伸,中间区域同时在水平和垂直两个方向拉伸。

image.png

border-image 属性可以通过设置一些规则,将一副图划分为类似上述 .9.png 的九宫格。

border-image 是一个组合属性,用来设置边框图片,包含以下几个属性:

  • border-image-source:边框图片路径;
  • border-image-slice:边框图片的分割位置;
  • border-image-width:边框图片的宽度;
  • border-image-outset:边框图片向外延伸的尺寸;
  • border-image-repeat:边框图片平铺样式。

border-image-slice

定义四条切线的位置,将 border-image-source 引用的图片资源划分成 9 个区域,四个角(1-4)、四个边(5-8)以及中心区域(9)。

image.png

border-image-slice = 
    [ <number [0,∞]> | <percentage [0,∞]> ]{1,4}  && fill? 
  • 可以设置 1-4 个值,设置规则如下:

    1 个值: 四条切线的位置相同,即 top、right、bottom、left

    2 个值:第一个值表示 topbottom,第二个值表示 leftright

    3 个值:第一个值表示top,第二个值表示leftright,第三个值表示buttom

    4 个值:这四个值则分别对应 toprightbuttomleft

  • 可以混合使用 number 和 percentage

    number: 在位图中的单位为像素点;在矢量图中则是坐标,表示切线的位置。

    percentage: 原始图像的大小百分比表示切线的位置。

  • fill 为可选值,放在末尾

    表示保留图片的中心区域并将其作为背景显示出来,但其会堆叠在 background 之上。它的宽度和高度分别对应顶部和左侧图像切片的宽度和高度。

分析一下文章开头的气泡对话框图片(102  *  79),四个角的圆角为特殊图形不可拉伸,在切割区域的时候要注意保留四个角的特殊图形,拉伸四条边和中间区域来实现自适应的效果。

border-image-slice: 8 34 27 8 fill;切割为👇 下图 9 个区域。

image.png

border-image-repeat

定义 4 个边和中间区域的填充方式。

  • 可以设置 1-2 个值

    1 个值: 设置水平和垂直方向的填充方式;

    2 个值: 分别设置水平和垂直方向填充方式。

  • 可以设置 stretch, repeat, round, space

    stretch拉伸图片以填充边框。

    repeat平铺图片以填充边框。从中间往两端重复,当不能整数次平铺时,不会放大或缩小图像。

    round平铺图像。当不能整数次平铺时,根据情况放大或缩小图像。

    space平铺图像。当不能整数次平铺时,不会放大或缩小图像,会用空白间隙填充在图像周围。

image.png

border-image-width

指定 border-image 的宽度。

border-image-width = 
  [ <length-percentage [0,∞]> | <number [0,∞]> | auto ]{1,4} 
  • 可以设置1、2、3、4个值,设置规则同上述 border-image-slice

  • 支持 number、length、percentage、auto

    number: border-width 的倍数。

    length:具体长度。

    percentage: 元素区域大小的百分比。

    auto: border-image-slice 的大小。

border-image-width 和 border-width

  1. border-image图片填充的区域大小只取决于 border-image-width ,与 border-width 无关。
  2. border-image-width 在未设置时,默认取 border-width 的值。

Visual Tool

BORDER-IMAGE GENERATOR 用于生成 CSS3 border-image 值的工具。

浏览器兼容性

image.png