图片边框
原文出处:http://www.w3cplus.com/css3/css-secrets/continuous-image-borders.html
问题
有时候,我们想将一些图案或图片添加为边框,而不是背景。比如,在下图中所示的元素就拥有一个装饰性的边框,边框内是一个被限制在边框区域的图片。此外,我们还希望图片可以覆盖整个边框区域。那么我们怎样使用 CSS 达到这一目的呢?
图注:图片被用来装饰各种高度的边框
此时,也许在你的内心会响起一个响亮的声音:“border-image,border-image,我们可以使用 border-image
,它可以完美的解决这个问题!”年轻人,做事不要太急躁。让我们重新回忆一下 border-image
的解析机制:它实际上将背景分成了九块,然后分别将各个块作用到了元素的边角上。下图就是一个视觉原理图。
图注:border-image
的快速入门。上面:分割后的图片;虚线框内的就是分割后的碎片;中间:border-image: 33.34% url(...) stretch;
下面: border-image: 33.34% url(...) round;
,在线示例链接
那我们是否可以将图片切分成块,然后使用 border-image
模拟出下图这样的效果呢?
实际上,即使我们精确计算出了元素的尺寸和边框宽度,仍然无法达到自动适配多种尺寸的目的。问题的核心就是,我们并不是让边角具有某种特定的图形,而且即使添加上了图形,当元素尺寸变化时,图形也会发生形变。如果你稍微尝试一下,就会理解使用border-image
是无法实现效果的,那么我们应该怎么办呢?
解决这个问题最简单的方法就是使用两个 HTML 标签:一个标签使用目标图片作为北京,两一个使用白色作为背景并覆盖在前一个标签上面:
<div class="something-meaningful">
<div>
I have a nice stone art border,
don’t I look pretty?
</div>
</div>
.something-meaningful {
background: url(stone-art.jpg);
background-size: cover;
padding: 1em;
}
.something-meaningful > div {
background: white;
padding: 1em;
}
这种方法确实实现了下图的效果:
但是它却需要添加额外的 HTML 标签。这只能算是一种折中的办法:它不仅仅混合了表现和样式,而是在某些情况下必须修改 HTML 结构。那么我们是否可以只用一层标签就实现这个效果呢?
解决方案
值得庆幸的是,CSS 的渐变以及在 Backgrounds & Borders Level 3 中扩展后的 background
属性可以帮助我们实现这一个效果,而且是只用一个标签。这种方法的核心就是使用纯色覆盖背景图片。不过,为了让第二章图片装饰到边框上,我们需要为backgroud-clip
属性配置不同的属性值。最后一件事就是让最底下的图层只有一种颜色,所以我们需要通过 CSS 渐变模拟一个纯白色背景。
我们最初实现这个方法的代码就像下面一样:
padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white, white),
url(stone-art.jpg);
background-size: cover;
background-clip: padding-box, border-box;
图注:第一次的尝试非常接近理想效果。
正如上图所示,效果非常接近我们的目标了,唯一的不足是多了一些重复的部分。其中的原因就是 backgroud-origin
属性的默认值为 padding-box
,因此,图片会定位到内边距盒模型的左上角,剩余的部分就会不断平铺这一图片。为了矫正这一效果,我们需要将 background-origin
的属性值修改为 border-box
:
padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white, white),
url(stone-art.jpg);
background-size: cover;
background-clip: padding-box, border-box;
background-origin: border-box;
这些新属性也可以统一使用 background
简写语法来声明,从而让我们的代码更加简洁优雅:
padding: 1em;
border: 1em solid transparent;
background:
linear-gradient(white, white) padding-box,
url(stone-art.jpg) border-box 0 / cover;
当然,我们也可以将这一技巧应用到和渐变相关的背景图案上。比如,看一看下面的这些代码,我们可以用它来生成信封风格的边框:
padding: 1em;
border: 1em solid transparent;
background: linear-gradient(white, white) padding-box,
repeating-linear-gradient(-45deg,
red 0, red 12.5%,
transparent 0, transparent 25%,
#58a 0, #58a 37.5%,
transparent 0, transparent 50%)
0 / 5em 5em;
最终结果如图所示:
图注:我们实现的怀旧信封边框
现在,你可以使用 background-size
随意修改条纹的宽度,也可以使用 border
随意修改边框的宽度。不同于前一个示例,这种效果是可以使用 border-image
来实现的:
padding: 1em;
border: 16px solid transparent;
border-image: 16 repeating-linear-gradient(-45deg,
red 0, red 1em,
transparent 0, transparent 2em,
#58a 0, #58a 3em,
transparent 0, transparent 4em);
不过,使用 border-image
会遇到几个问题:
- 每次修改
border-width
的时候,同时需要修改border-image-slice
- 因为不能在
border-image-slice
中使用类似em
的单位,所以我们只能对边框宽度使用像素单位 - 条纹的宽度需要硬编码到颜色过渡点上,那么当需求变化时就需要修改四个地方的代码
这种技巧的另一种有趣应用就是创建一个类似选区的边框(marching ants borders)。选区型边框(译者:之所以称之为选区型,是因为效果非常类似 ps 中选区边框的效果,更容易理解)是虚线边框,而且虚线是实时滚动的,非常类似行进中的蚂蚁(当然,这需要一定的想象力将虚线想象为蚂蚁)。这在 GUI 中几乎是不可想象的效果。图像编辑软件通常使用这种边框来表示这是一块被选中的区域,简称选区。
图注:选区型边框在 Adobe Photoshop 中被用来标志被选中的地方
为了创建这种边框,我们将要使用前面创建信封边框的技巧。首先是将条纹更改为黑白两色,并且将边框调整为 1px
的宽度(你注意到现在条纹是怎样变化为虚线边框的了吧?),然后适当修改一个 background-size
,最后为 background-size
添加动画效果(从初始值增加到 100%
):
@keyframes ants { to { background-position: 100% } }
.marching-ants {
padding: 1em;
border: 1px solid transparent;
background:
linear-gradient(white, white) padding-box,
repeating-linear-gradient(-45deg,
black 0, black 25%, white 0, white 50%
) 0 / .6em .6em;
animation: ants 12s linear infinite;
}
现在,你可以从下图中看到一个静态的效果。
图注:在纸上显示选区型边框是不可能的,可以访问在线示例进行查看——非常有意思!
显然,这种技巧不仅仅对选区型边框有用,只需修改一下边框颜色和虚线之间的间距,就可以用来创建各种自定义的虚线边框。
目前,如果想要使用 border-image
属性实现类似的效果,那么就只能使用 border-image-source
添加 GIF 来模拟了,详情见 Marching ants animated selection rectangle in CSS。当浏览器广泛支持渐变效果之后,我们就可以用渐变来创建这种效果了,而且代码会更加简练优雅。
图注:顶部剪切过得边框,用来模拟传统书籍中的脚注
不过,border-image
也是非常强大的属性,甚至有时比渐变更强大。比如,假设我们需要一个裁剪过的顶部边框,就像常见的脚注样式。那么只需要使用 border-image
和垂直渐变就可以实现,其中裁剪的长度可以硬编码实现。边框的宽度则有 border-width
来控制。代码就像是这样:
border-top: .2em solid transparent;
border-image: 100% 0 0 linear-gradient( 90deg,
padding-top: 1em;
currentColor 4em,
transparent 0);
最终结果如上图所示。此外,因为我们在这里使用 em
单位,所以整体效果就能随字体大小而变化;因为使用了currentColor
,所以它也可以随字体颜色而改变颜色。
总结
在CSS2.1的时代要实现图片边框效果是一种奢侈的想法,但在CSS3中虽然增加了border-image
属性实现图片边框,但依旧受到诸多的限制性,其中最大的限制就是浏览器对其支持度。在这一节中,我们介绍了使用多背景,以及配合background-clip
、background-origin
属性模拟出图片边框效果。
更多建议: