CSS 实现点9图

本文旨在探讨以下几个问题

1. 什么是点9图?

点9图,我们可以将其理解为图片的一种缩放,即将一张图片,按九宫格的方式拆分为9个部分。如下图:

点9图的重点在于 4角,4边,1中心区域.

图片在拆分使用时,①③⑥⑧四个角保持不变,②④⑤⑦四边进行拉伸或重复,⑨中心用来填充剩余部分。

注:点9图是安卓的一种特殊图片形式,文件扩展名为.9.png,常用于聊天气泡背景图等场景。

2. 为什么要使用点9图?

按照UI提供的素材,如果我们单纯的进行等比例缩放,遇到一些边角像素比较复杂(不规则)的情况,进行等比例拉伸时,很可能会造成拉伸变形,如下图所示:

UI提供的聊天消息气泡图

将图片设置背景等比例拉伸后的样子,是不是很丑!

我们真正想要的样子是这样的,这就是通过使用点9图的方式产生的效果

使用点9图的意义,就在于:可以将图片四角不规则的部分截取保持大小不变,只对其可缩放的四边进行拉伸或重复,进而达到等比放大,又不会造成图片变形的效果。

3. CSS 如何实现点9图?

Andriod 中是原生支持 .9.png 这种图片形式的,但是 web 没有采用这种形式。

web 可以通过 CSS 来达到与点9图一样的效果。

那就是 border-image-slice,即通过边框截取的形式处理图片。

border-image-slice 属性会将图片分割为9个区域:四个角(①②③④),四个边以(⑤⑥⑦⑧)及中心区域(⑨)。四条切片线,从它们各自的侧面设置给定距离,控制区域的大小。

border-image-slice 拆分区域

①②③④是四个角区域,用来形成最终边界图像的角点

⑤⑥⑦⑧是四个边区域,通过拉伸/重复来匹配元素的尺寸。

⑨是中心区域,默认情况下会被舍弃,就好像一个图片中间被镂空了一样,如果对 border-image-slice 设置了 fill 属性的话(fill属性可以在任何位置),中心区域将会作为背景图像被缩放(等价于 background-image),以匹配元素的背景尺寸。

border-image-slice 使用形式

boder-image-slice: number|%|fill,使用实例如下:

1
border-image-slice: 7 12 14 5 fill;

7、12、14、5分别表示 top区域高度right区域宽度bottom区域高度left区域宽度

top、right、bottom、right 的值都可以是 number / percentagenumber 时表示 px 值,percentage 是 图片的 height 或者 width 的比例。

注: fill 可以出现在任何位置,如:

1
border-image-slice: 7 fill 12 14 5;

border-image-slice 是负责截取图片的,border-image-repeat, border-image-width, border-image-outset 则定义这些被截取的图片将如何使用,下面会详细说明这些属性。

完整使用案例

以下面UI提供的消息框图片为例,如图:

采用点9图的方式,实现的效果如下图:

可以看到,即使图片被缩放很大,也并没有失真

具体CSS代码实现

1
2
3
4
5
6
7
8
.message-cell-content {
/*border: 10px solid #000; // 如果不存在border-image-outset,则设置边框宽度,用来给 border-image 提供一个容器*/
border-image-source: url(data:image/png;base64,...); // 图片路径
border-image-slice: 10 10 10 10 fill; // 每个区域截取宽度为 10px
border-image-width: 10px 10px 10px 10px; // 设置各个区域的图片宽度
border-image-repeat: repeat; // 图片重复或拉伸模式
border-image-outset: 10px 10px 10px 10px; //
}

以上五行代码就可以完整的实现点9图效果。

想要的效果实现了,就开始解释一下border-image-repeat, border-image-width, border-image-outset 三者的用法。

border-image-repeat

1
border-image-repeat:stretch | repeat | round | space;

stretch 拉伸图片以填充边框,强调边框拉伸。

repeat 平铺图片以填充边框,强调边框重复填充(建议使用此方式保持高清效果)。

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

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

只要记住,该属性主要是负责边框的缩放形式即可。

border-image-width

定义图像边框宽度。假如 border-image-width 大于已指定的 border-width,那么它将向内部(padding/content)扩展。所以在定义时,如果存在border-width,则跟其值设置一致,防止占用 padding/content 空间。

border-image-outset

定义边框图像可超出边框盒的大小。即,如果不想让 border-image 占用 border 空间的话,可以设置 border-image-outset 使其向 border 外部扩展。其属性值跟 border-image-slice 是对应的。

总结,CSS提供的点9图方式,还是很简洁的,只需要几行代码就能实现。重要的是理解 border-image-slice 是如何切割图片和其他几个属性是如何使用切割好的图片的。

参考资料:

[1] MDN:border-image-slice

[2] Web端的“点九图”