在具有渐变背景的元素上应用透明边框时出现奇怪的效果。

76
当在具有线性渐变背景的元素上应用透明边框时,会产生奇怪的效果。

enter image description here

注意元素的左侧和右侧没有正确的颜色(它们被某种方式交换了),并且看起来异常平坦。 HTML
<div class="colors">
</div>

CSS(层叠样式表)
.colors {
    width: 100px;
    border: 10px solid rgba(0,0,0,0.2);
    height: 50px;
    background: linear-gradient(to right, 
        #78C5D6,
        #459BA8,
        #79C267,
        #C5D647,
        #F5D63D,
        #F08B33,
        #E868A2,
        #BE61A5);
}

为什么这个元素的左右两侧显示出了奇怪的效果,我该怎么办?
这是 JSFiddle 的链接:http://jsfiddle.net/fzndodgx/3/

这不就是因为边框与内容框分离了吗?即背景。 - bitten
一个解决方案是使用第二个 div 并使用 ::after:http://jsfiddle.net/a1h2yh11/ - Denys Séguret
7个回答

53
那是因为 gradient 的起始点和结束点在 padding-box 的边缘,而 border 则渲染在 padding-box 外部,所以边框看起来很奇怪,因为 background 在每个边框外部重复出现,以覆盖 border-boxbox-shadow: inset 渲染在 padding-box 内部(就像背景一样),并且在视觉上产生与 border 相同的效果,因此您可以尝试使用它来替换 border
box-shadow: inset 0 0 0 10px rgba(0,0,0,0.2);
padding: 10px;

box-shadow属性不占用空间,因此需要相应增加填充。

padding-boxborder-box的示意图: enter image description here

演示http://jsfiddle.net/ilpo/fzndodgx/5/


9
背景会重复 - 这就是它超出填充框的边界并重新开始的原因 - 因此看起来好像发生了反转。 - Geoff Atkins
6
我认为你在其他回答已经涉及的内容后很久才将其添加到自己的答案中并不好。至少你可以在编辑时提到其他答案。 - Harry
3
因为复制粘贴其他帖子的答案而被踩了。不要试图将别人的工作归功于自己。 - Mr_Green
4
把这称作复制粘贴有些牵强,而且这位用户并没有用新答案替换他原先的回答。无论如何,哈利的回答仍然提供了他解决问题的说明,因此它比这个答案更好。 - BoltClock
2
抱歉,在进行编辑之前我没有仔细阅读他的长篇回答,也没有意识到已经提出了这个解决方案。如果需要的话,我可以删除我的编辑部分。 - Okku
显示剩余4条评论

51

解决方案

修复此问题的最简单方法是将 background-origin 属性的值设置为 border-box

.colors {
  width: 100px;
  border: 10px solid rgba(0, 0, 0, 0.2);
  height: 50px;
  background: linear-gradient(to right, #78C5D6, #459BA8, #79C267, #C5D647, #F5D63D, #F08B33, #E868A2, #BE61A5);
  background-origin: border-box;
}
<div class="colors"></div>


问题原因

以下是决定背景渐变如何显示的相关background属性:

  • background-origin - 默认值为padding-box。这意味着背景实际上是相对于内边距框定位的,所以从border之后开始。
  • background-repeat - 默认值为repeat。这意味着图像应该重复多少次以覆盖整个背景绘制区域。
  • background-clip - 默认值为border-box。这意味着图像还应该出现在盒子边框占据的区域下面。

现在结合所有三个属性,我们可以看到必须尽可能地重复边框,使其即使在边框下方也存在,并且它的起始位置在盒子的边框之后。这意味着必须循环地重复背景,以便填充左侧边框下面的区域。因此,左边框的颜色与渐变的右端相同,反之亦然。

将其更改为border-box后,我们正在使背景相对于边框框定位。这种设置还会影响背景图像的大小,其原因在下面详细描述。


box-sizing:border-box为什么不起作用?

box-sizing设置为border-box不会带来任何变化,因为该属性仅影响盒子的大小。它绝对不会影响以下内容:

  • 渐变图片的大小(实际计算逻辑在下面描述)
  • 渐变图片的起始点(或位置)
  • 背景图片的重复

如何计算渐变的大小?

根据W3C规范,当没有提供显式大小时(默认值为auto),将计算图像的尺寸如下所示:

如果图像既没有固有宽度也没有固有高度,则其大小如“contain”一样确定

注意它谈论的是图像的大小而不是盒子的大小。 实质上,无论盒子的大小如何,当图像本身没有内在高度(这与CSS渐变不同)时,背景图像的大小都将基于关键字contain 的定义计算。 contain的定义如下:
缩放图像,同时保留其内在纵横比(如果有),使其宽度和高度都适合于背景定位区域内的最大尺寸。 背景定位区域的定义如下(在background-origin属性定义下):
对于呈现为单个框的元素,指定了背景定位区域
因此,当图像没有内在高度(在这种情况下也没有background-size)时,图像的大小将等于background-origin值的大小(在我们的例子中为padding-box)。
这就是为什么即使将box-sizing设置为border-box也没有效果的原因。
如果您将background-size明确设置为箱子的尺寸,则会注意到问题在右侧得到解决,但在左侧没有解决。这是因为现在图像足够大,不会在右边框下重复,但其起始点仍在左边框之后。

.colors {
  width: 100px;
  border: 10px solid rgba(0, 0, 0, 0.2);
  height: 50px;
  background: linear-gradient(to right, #78C5D6, #459BA8, #79C267, #C5D647, #F5D63D, #F08B33, #E868A2, #BE61A5);
  background-size: 110px 60px;
}
.colors-2 {
  width: 100px;
  border: 10px solid rgba(0, 0, 0, 0.2);
  height: 50px;
  background: linear-gradient(to right, #78C5D6, #459BA8, #79C267, #C5D647, #F5D63D, #F08B33, #E868A2, #BE61A5);
  box-sizing: border-box;
  background-size: 100px 50px;
}
<div class="colors">
</div>
<div class="colors-2">
</div>


1
可能的不同解决方案的解释很好。 - Afonso Matos
2
@afonsomatos:这个答案所涵盖的方法不是一个变通方法,而是你问题的正确解决方案 :) - Harry

13
元素的背景在边框下方会重复。背景仅在元素的“body”中运行,在边框下面是扩展,开始发生重复。
请参见带有边框no-repeat此示例
更新
通过调整背景的位置和大小可以扩展背景,然后调整其位置。
请查看此fiddle
或者查看片段:
.colors {
  padding: 10px;
  width: 100px;
  border: 10px solid rgba(0, 0, 0, 0.2);
  height: 50px;
  background: linear-gradient(to right, #78C5D6, #459BA8, #79C267, #C5D647, #F5D63D, #F08B33, #E868A2, #BE61A5);
  background-size: 117%;
  background-position-x: 130px;
}
<div class="colors"></div>


5

其他答案已经展示了如何解决这个问题,但是我想指出,如果你增加border-width,就会发现背景实际上是重复的。

.colors {
    width: 100px;
    border: 100px solid rgba(0,0,0,0.2);
    height: 50px;
    background: linear-gradient(to right, 
        #78C5D6,
        #459BA8,
        #79C267,
        #C5D647,
        #F5D63D,
        #F08B33,
        #E868A2,
        #BE61A5);
}

将产生以下结果: 这里是图片描述

@mflodin + 1 它确实变得更加明显 - Afonso Matos

4
渐变色的起点根据默认CSS框模型的行为位于填充框内部,因此直到渐变色的起始和结束颜色一直延伸到无限远处,其中边框也会出现。
这种渐变色的规则同样适用于这个渐变色(NSFW):
它从起始值(紫色)向左方无限延伸,并且从结束值(橙色)向右方无限延伸。它可以沿着这个渐变色向上无限延伸,因此也是如此。
这就是我对此出现的原因的理解,解决方法是使用不同的框模型。

12
为什么你把梯度标记为不适宜在工作场合浏览的内容? - Woodrow Barlow
4
因为它非常丑陋 >.> - bitten
14
我的老板抓到我在看这个渐变色,现在我必须与人力资源部门会面。谢了,Aaron。 - Sterling Archer
1
@WoodrowBarlow Stackoverflow看起来足够商业化和严肃,可以随意浏览(除非您已经激活了基于标签的线程突出显示)。如果直接问到,您总是可以说:“我在这里寻找问题X的解决方案”。大而色彩鲜艳的图片会破坏这种印象。 - ASA

4
background-origin属性的默认值是padding-box,这意味着背景相对于填充框进行定位和缩放。
由于background-clip属性的默认值为border-box,因此背景也会向下延伸到边框以下。它只是在边框下面重复自身。这就是为什么你会看到背景的右侧在左边界下面,反之亦然。
所以,只需要更改原点即可:

.colors {
  width: 100px;
  border: 10px solid rgba(0, 0, 0, 0.2);
  height: 50px;
  background: linear-gradient(to right, #78C5D6, #459BA8, #79C267, #C5D647, #F5D63D, #F08B33, #E868A2, #BE61A5);
  background-origin: border-box;
}
<div class="colors"></div>

或者您可以调整背景大小和位置:将背景大小增加20px,并将其定位在-10px -10px处:

.colors {
  width: 100px;
  border: 10px solid rgba(0, 0, 0, 0.2);
  height: 50px;
  background: linear-gradient(to right, #78C5D6, #459BA8, #79C267, #C5D647, #F5D63D, #F08B33, #E868A2, #BE61A5);
  background-position: -10px -10px;
  background-size: calc(100% + 20px) calc(100% + 20px);
}
<div class="colors"></div>


3

如果您不想使用box-shadow,可以使用border-image并调整渐变颜色:http://jsfiddle.net/9pcuj8bw/5/

.colors {
    width:100px;
    height: 50px;
    background: linear-gradient(to right, 
        #78C5D6,
        #459BA8,
        #79C267,
        #C5D647,
        #F5D63D,
        #F08B33,
        #E868A2,
        #BE61A5) no-repeat;
    border: 10px solid;
    border-image: linear-gradient(to right, 
        #0bc3b8,
        #068e8c,
        #f8c617,
        #ea5f24,
        #b2492c) 1;
}
<div class="colors"></div>

请注意:此方法不适用于IE10或更低版本浏览器:http://caniuse.com/#feat=border-image


你的意思是,“这在IE10上不起作用” - 它在所有其他浏览器(Firefox,Chrome等)上都可以正常工作。 - Kobi
1
这不是最佳解决方案,也没有达到想要的效果。 - Afonso Matos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接