背景
最近接了一个需求,产品让在页面上加一个按钮,我(不假思索):"好的!简单!"。
设计:"好的,按钮样式如下:"
我:"?"
作为一个前端摆子,我肯定不会思考怎么实现不规则图形的,于是我跑去和设计要了切图,设计:"诺~"
把图形当做背景图片就好了嘛,三分钟写完。
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>购买按钮</title>
</head>
<style>
body {
padding: 100px;
}
.button-container {
position: relative;
}
button {
border: none;
padding: 8px 16px;
background: #000000;
color: #fff;
border-radius: 5px;
font-size: 26px;
font-weight: bold;
}
.bubble {
position: absolute;
top: -22px;
left: 70px;
font-weight: bold;
font-size: 12px;
color: #ffffff;
padding: 4px 10px 7px;
background: url(./src/assets/qipao.png);
background-size: contain; /* cover */
}
</style>
<body>
<div class="button-container">
<div class="bubble">先抢先得,仅剩48件</div>
<button>立即购买</button>
</div>
</body>
</html>
不过我好像忘记了一件事情,文字是不固定长度的,而我写出来的样式是这样,这样,这样的......
(以上分别设置了 background-size: initial;
,background-size: contain;
和 background-size: cover;
既然 background
不能用,动了动脑子,我想出了好办法,拿一个图片当做背景图,然后指定和文字相同的宽高就好了!
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>购买按钮</title>
</head>
<style>
body { padding: 100px; } .button-container { position: relative; } button {
border: none; padding: 8px 16px; background: #000000; color: #fff;
border-radius: 5px; font-size: 26px; font-weight: bold; } .bubble { position:
absolute; top: -22px; left: 70px; font-weight: bold; font-size: 12px; color:
#ffffff; padding: 4px 10px 7px; background-size: contain; background-size:
cover; }
</style>
<body>
<div class="button-container">
<div class="bubble">
<img src="./src/assets/qipao.png" style="position: absolute; left: 0; top: 0; width: 100%; height: 100%;" />
<span style="position: relative;">先抢先得,仅剩48件</span>
</div>
<button>立即购买</button>
</div>
</body>
</html>
结果是这样的,乍一看好像还凑合,不过当文字边长时,就彻底变形了。。。
可怜的小饼干已经在抓狂了T^T
点九图
不过还好,搜到了点九图这个东西(参考 点九切图你知道怎么切吗?)
点九图(9 patch image) ,是Android开发中用到的一种特殊格式的图片,文件名以" .9.png "命名。这种图片能告诉开发,图像哪一部分可以被拉伸,哪一部分不能被拉伸需要保持原有比例。运用点九图可以保证图片在不模糊变形的前提下做到自适应。点九图常用于对话框和聊天气泡背景图片中。
如图为一个点九图,可以比较明显的看到上下左右分别有一个像素的黑色线段。简单来说,序号1和2表示了可以拉伸的区域 ,序号3和4表示了显示内容区域。
当设定了按钮实际应用的宽和高之后,横向会拉伸1区域的像素,纵向会拉伸2区域的像素。而显示内容区域表示了需要展示文字的区域。
看看!这个正是我想要的吗!不过人家是安卓的,和前端又有什么关系?!
CSS 实现点九图 - border-image
咱就是说有什么事情不能问问神奇的 ChatGPT 呢
OK,让我们来学一下 border-image
。
border-image
border-image
的默认值为 border-image: none 100% / 1 0 stretch
,拆分成子属性为:
css
border-image-source: none;
border-image-slice: 100%;
border-image-width: 1;
border-image-outset: 0;
border-image-repeat: stretch;
接下来分别说下子属性的作用,先通过表格简单总结,后面分开来说。
属性 | 作用 | 默认值 |
---|---|---|
border-image-source | 指定边框图片的 URL 或者渐变值。 | none |
border-image-slice | 指定边框图片的裁切方式 | 100% |
border-image-width | 指定边框图片的宽度。 | 1 |
border-image-outset | 指定边框图片的偏移量 | 0 |
border-image-repeat | 指定边框图片的重复方式 | stretch |
border-image-source
border-image-source
属性用于指定边框图片的 URL 或者渐变值。
border-image-source
属性接受一个 URL 值或者一个渐变值,表示边框图片的来源。如果使用 URL 值,则可以指定一个图片文件的 URL,例如:
css
border-image-source: url(border.png);
如果使用渐变值,则可以使用 linear-gradient()
或者 radial-gradient()
函数来定义一个渐变,例如:
css
border-image-source: linear-gradient(to right, red, yellow);
需要注意的是,border-image-source
属性必须与 border-image-slice
属性一起使用,否则边框图片不会被显示。
border-image-width
border-image-width
属性用于指定边框图片的宽度,可以使用长度值、百分比值或者数字值来指定。如果使用长度值或百分比值,则表示边框图片的宽度;如果使用数字值,则表示边框图片的宽度为边框宽度的倍数。
例如,以下代码将边框图片的宽度设置为 20 像素:
css
border-image-width: 20px;
如果边框图片的宽度小于边框区域的宽度,则边框图片将被拉伸以填充整个边框区域;如果边框图片的宽度大于边框区域的宽度,则边框图片将被裁切以适应边框区域。因此,可以通过设置 border-image-width
属性来控制边框图片的大小。
需要注意的是,border-image-width
属性必须与 border-image-source
属性一起使用,否则边框图片不会被显示。
border-image-slice
border-image-slice
属性用于指定边框图片的裁切方式,即指定边框图片的哪一部分用于绘制边框,哪一部分用于填充边框内部。
border-image-slice
属性接受一个或四个值,分别表示图片裁切的上、右、下、左四个方向的值。如果只指定一个值,则表示四个方向的值都相同;如果指定两个值,则第一个值表示上下方向的值,第二个值表示左右方向的值;如果指定三个值,则第一个值表示上方的值,第二个值表示左右方向的值,第三个值表示下方的值;如果指定四个值,则分别表示上、右、下、左四个方向的值。
border-image-slice
可以指定为百分比或者数值,数值单位为像素。
假设我设置 border-image-slice: 10% 20% 30% 40%;
,那么图形将以如下的方式被分割成 9 份,然后 1,3,7,9 会被放置在边框的四个角,2,6,8,4 在四个边,如果长度不够会被拉伸(border-image-repeat:stretch
情况下),如果设置 fill 则中间部分5也会在新的背景中展示。
然后举个例子,先找一个比较经典的图片:
html
<!DOCTYPE html>
<html lang="en">
<style>
body { padding: 100px; --width: 20px; }
.box { width: 100px; height: 100px; box-sizing: border-box; position: relative; box-shadow: 0px 0px 0px 1px #000; }
.inner1 { position: absolute; top: 0; bottom: 0; left: var(--width); right: var(--width); border-style: solid; border-width: 0 1px 0px 1px; }
.inner2 { position: absolute; top: var(--width); bottom: var(--width); left: 0; right: 0; border-style: solid; border-width: 1px 0px 1px 0; }
.box {
border-image-source: url(./src/assets/border.png);
border-image-slice: 100%;
border-image-width: var(--width);
border-image-outset: 0;
border-image-repeat: stretch;
}
</style>
<body>
<div class="box">
<div class="inner1"></div>
<div class="inner2"></div>
</div>
</body>
</html>
展示效果
通过两个 div 设置了辅助线,为了清楚得看到 border-image 所占宽度。
上面是默认值 100% 的效果,下面尝试调整 border-image-slice
的值。
样式 | 效果 |
---|---|
border-image-slice: 60% |
|
border-image-slice: 50% |
|
border-image-slice: 40% |
|
border-image-slice: 10% |
可以看到,当 border-image-slice
大于 50% 的时候,只有四个角有图形,四个边框是没有图形的。这也很合理,因为按照上面的切割方式,当 left > right 时,中间是没有图形的。
再尝试下四个方向不同的大小。以及添加 fill
的样式。
样式 | 效果 |
---|---|
border-image-slice: 33% 100% 33% 50%; |
|
border-image-slice: 30% 20% fill |
border-image-repeat
border-image-repeat
属性用于指定边框图片的重复方式,即指定边框图片在边框区域内的重复方式。
border-image-repeat
属性接受一个或两个值,分别表示图片在水平方向和垂直方向的重复方式。如果只指定一个值,则表示水平和垂直方向的重复方式相同。
border-image-repeat
属性的值可以是以下几种:
-
stretch
:默认值,表示边框图片将被拉伸以填充整个边框区域。 -
repeat
:表示边框图片将在边框区域内平铺重复。 -
round
:表示边框图片将在边框区域内平铺重复,如果图片大小不能完全填充边框区域,则会自动缩小或放大图片,直到完全填充边框区域。 -
space
:表示边框图片将在边框区域内平铺重复,如果图片大小不能完全填充边框区域,则会在图片之间留出等间距的空白。
这个乍一看不是很好理解,可以通过例子来看下。
当我们设置 border-image-slice: 30% fill;border-image-repeat: stretch;
时,中间的图形会被拉伸为如下效果。
当我们设置为 border-image-repeat: repeat;
可以看到同样的图案没有被拉伸,而是被平铺重复。
border-image-repeat: round;
还是会被重复,但是这种情况下会适当拉伸或缩小,让图形刚好重复倍数个。
最后 border-image-repeat: space;
不会被拉伸或缩小,只让图形刚好重复倍数个,剩余的空间在重复图形间留下空白。
border-image-outset
border-image-outset
属性用于指定边框图片的偏移量,即指定边框图片与边框区域的距离。
border-image-outset
属性接受一个或四个值,分别表示图片偏移的上、右、下、左四个方向的值。如果只指定一个值,则表示四个方向的值都相同;如果指定两个值,则第一个值表示上下方向的值,第二个值表示左右方向的值;如果指定三个值,则第一个值表示上方的值,第二个值表示左右方向的值,第三个值表示下方的值;如果指定四个值,则分别表示上、右、下、左四个方向的值。
例如,以下代码将边框图片的偏移量设置为 10 像素:
css
border-image-slice: 100%;
border-image-outset: 10px;
border-image-repeat: stretch;
回到最初的例子
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>
body {
padding: 100px;
}
.button-container {
position: relative;
}
button {
border: none;
padding: 8px 16px;
background: #000000;
color: #fff;
border-radius: 5px;
font-size: 26px;
font-weight: bold;
}
.bubble {
position: absolute;
top: -22px;
left: 70px;
font-weight: bold;
font-size: 12px;
color: #ffffff;
padding: 4px 10px 7px;
border-image-source: url(./src/assets/qipao.png);
border-image-slice: 26 fill;
border-image-width: 50px;
border-image-slice: 27 35 32 37;
}
</style>
<body>
<div class="button-container">
<div class="bubble">先抢先得,仅剩48888888件</div>
<button>立即购买</button>
</div>
</body>
</html>
可以看到现在文字再长图形也不会变形了。