为什么CSS不支持负内边距?

149

我经常看到负填充的前景可以帮助某些页面元素的 CSS 开发变得更好、更容易。然而,在 W3C CSS 中没有提供负填充的规定。这是什么原因呢?有什么阻碍该属性被用作此类目的的问题吗?谢谢您的回答。

更新:

例如,假设您使用了一个具有 20px 垂直间距的字体,并且希望在某个链接出现时将虚线边框应用于字体底部。在这种情况下,您会发现样式看起来很糟糕,因为虚线边框会出现在指定单词的下方 20px。如果您使用负边距,它将不起作用,因为边距会改变边框外的区域。在这种情况下,使用负填充可能会有所帮助。


30
因为使用负填充没有意义。 - Petah
1
这与由Frontpage生成的HTML中看到的内容相同。它有点可行,但在验证时会抛出大量错误。负填充不是规范的一部分,但仍受浏览器支持。 - Linus Kleen
9
很多人希望有一个例子。这是我的例子,也是为什么我非常喜欢负边距的原因。使用border-image功能,您可能希望让图像边框略微重叠文字(例如,如果您正在制作一个突出显示的光泽气泡,在网络上非常流行这些天;))。 - Himmators
98
如果某事物对某人来说“不合理”,这并不是他们阻碍别人的借口。 - Rolf
1
我正在尝试在<span>标签中显示代码,并且它被解析的方式会在代码块开头添加额外的换行符。使用负填充,我可以消除这个额外的空间。 - Steven Lu
显示剩余5条评论
7个回答

98

我最近回答了一个不同的问题,在那里我讨论了为什么盒模型是这样的。

盒模型的每个部分都有具体的原因。填充旨在将背景扩展到其内容之外。如果您需要缩小容器的背景,则应使父容器具有正确的尺寸,并给子元素一些负边距。在这种情况下,内容不是填充,而是溢出。


2
谢谢伙计。这给了我一个满意的理由。干杯。 :) - ikartik90
11
如果你想要将边框缩小到更接近文本的位置,比如在使用边框图片时,该怎么办? - Himmators
5
有时候,编辑容器内所有子元素的CSS并不切实际。你可能有一些适用于整个文档中这些元素的通用CSS,而且你不想为了一个特定的容器内容而更改它们。 - Rolf
18
嗯,这确实是一个理由,但我不认为这是一个令人满意的理由。 在这种情况下,规范超出了告诉我如何定义我的页面,并开始告诉我如何“应该”定义我的页面。如果我想让我的内容重叠在背景边缘、边框和/或边距上,那应该是我的自由,而规范制定者为什么认为我可能想这样做并不重要。很抱歉,我有点烦恼,因为我不得不添加语法上的细节,或者更糟的是,添加单像素宽度的单色图像才能获得一个垂直居中、高度小于文本高度的特定大小分隔符。 - Jason
2
@zzzzBov,我觉得这很相关,因为我在最后举了一个例子,解释了为什么我想要做这样的事情,这也是评论区经常问到的问题。不过,承认一下,在那之前我的说辞有点夸张。 - Jason
显示剩余5条评论

8

填充(Padding)的定义是正整数(包括0)。

负填充会导致边框塌陷到内容中(请参见w3上的box-model页面),这将使内容区域比内容本身更小,这是没有意义的。


46
边框与内容合并正是所需效果。你知道还有其他方法可以实现这种效果吗? - Rolf
4
同意Rolf的观点。Oded,显然你对于复杂的实验设计不感兴趣。使用负边距和边框,而又不能使用明确的像素值,几乎是不可能获得相似的结果。据我所知,为了实现相同的效果,您需要多个嵌套元素,但在某些情况下,事情会变得更加复杂。 - Yeti

6
我愿意提供一个非常好的例子,以证明为什么“负填充(negative padding)”会非常有用和强大。
众所周知,对于动态大小的div元素进行垂直居中是一件麻烦的事情,对于大多数CSS开发人员来说,这被认为只能使用CSS是不可能实现的。然而,使用“负填充(negative padding)”可以改变这种情况。
请查看以下HTML代码:
<div style="height:600px; width:100%;">
    <div class="vertical-align" style="width:100%;height:auto;" >
        This DIV's height will change based the width of the screen.
    </div>
</div>

使用以下CSS,我们可以将内部
的内容垂直居中在外部
中:
.vertical-align {
    position: absolute;
    top:50%;
    padding-top:-50%;
    overflow: visible;
}

请允许我解释一下...

将内部div的顶部绝对定位于50%,会将内部div的顶边放置在外部div的中心。很简单,这是因为基于百分比的定位是相对于父元素的内部尺寸

另一方面,基于百分比填充基于目标元素的内部尺寸。因此,通过应用padding-top: -50%;属性,我们已经将内部div的内容向上移动了一个距离,该距离是内部div内容高度的50%,因此将内部div的内容居中在外部div中,并且仍然允许内部div的高度维度是动态的!

如果你问我的话,这将是最好的用例,我认为应该实施这种技巧。哈哈,或者,他们应该修复vertical-align的功能,并给我们一个适用于所有元素的版本。


1
是的,但为此我宁愿为html元素添加新属性,而不是劫持其他属性的行为。你的例子需要一个新的inner-top属性;就像相对定位元素的top属性一样,但是相对于自身而不是父级。另一个好的使用负填充的方法是使元素按比例填充100%填充,但如果更多内容溢出,则允许元素在垂直方向上增长,如果内容在额外的abs-pos兄弟姐妹中,则这是不可能的。负填充将把填充折叠的元素恢复到其大小。 - sergio
在2018年,居中对齐只需使用display:flex和justify-content以及align-items即可轻松实现...只需要3行代码就可以拥有完美的居中div。 - kaiser

3
你问的是“为什么”,而不是如何欺骗它:
通常是因为最初实现的程序员懒惰,因为他们已经在其他功能上投入了更多的精力,提供了更多奇怪的副作用,比如浮动,因为当时设计师更需要它们,但他们没有花时间让我们使用四个属性来推/拉元素与其邻居(现在我们只有四个属性来推,只有两个属性来拉)。
当设计 HTML 时,杂志爱文字围绕着图片流动,现在则不喜欢,因为今天我们有触摸趋势,喜欢方形的东西,有很多空间和没什么阅读内容。这就是为什么他们对浮动施加了更大的压力而不是居中,或者他们可以设计像 margin-top: fill;margin: average 0; 这样的东西来简单地将内容对齐到底部,或者在其周围分配其额外的空间。
在这种情况下,我认为它还没有被实现,是因为与 CSS 缺乏一个 :parent 伪选择器相同的原因:为了防止循环评估。
不是工程师,我可以看到 CSS 现在是用来绘制元素一次,记住一些属性以便将来要绘制的元素,但永远不会回到已经绘制的元素。
这就是为什么(我猜)填充是根据宽度计算的,因为这是在开始绘制时可用的值。
如果填充的值为负值,则会影响外部限制,这已经在设置边距时定义好了。我知道,还没有绘制任何东西,但当你阅读绘画过程的方式时,由90年代技术创造的天才们,我感觉自己在问愚蠢的问题,只是说“谢谢”呵呵。
网页的要求之一是它们可以快速使用,而不像应用程序那样需要花费时间并占用计算机资源才能在显示之前正确地获取所有内容,网页需要使用少量资源(以适合每个可能的设备)并轻松滚动。
如果您看到具有复杂重新流动和定位的应用程序(如 InDesign),则无法快速滚动!从处理器和图形卡跳转到下一页需要大量的工作!
因此,向前绘制和计算并忘记一旦绘制的元素,现在似乎是必须的。

2
< p > 更新: 现在flexbox有gap属性来解决下面所述的特定问题,但这并不改变负填充可以解决许多样式问题的事实,这些问题只能通过诸如非语义包装元素和父元素之间的负边距等技巧来解决。


因为CSS的设计者没有预见到这将带来的灵活性。有很多原因可以扩展框的内容区域而不影响其与相邻元素的关系。如果您认为这在技术上不可能,请在框中放入一些长的nowrap文本,设置框的宽度,然后观察溢出的内容对布局没有任何影响。这似乎是基于物理约束的严格解释,而这些约束根本不适用于数字对象。没有理由使边距不能继续表示“外”边缘与相邻元素之间的距离,而填充则是元素内容相对于该外边缘的相对位置。

是的,在2019年的CSS3中仍然相关;例如:flexbox布局。Flexbox项的边距不会折叠,因此为了将它们均匀间隔并与容器的视觉边缘对齐,必须从它们的容器填充中减去项的边距。如果任何结果为<0,则必须在容器上使用负边距或将该负值与现有边距相加。即元素的内容会影响人们为其定义边距的方式,这是反向的。当flex元素的内容以不同单位定义边距或受不同字体大小等影响时,求和不会干净地工作。

下面的示例理想情况下应该具有对齐和均匀间隔的灰色框,但遗憾的是它们没有。

body {
  font-family: sans-serif;
  margin: 2rem;
}
body > * {
  margin: 2rem 0 0;
}
body > :first-child {
  margin-top: 0;
}
h1,
li,
p {
  padding: 10px;
  background: lightgray;
}
ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  padding: 0;/* just to reset */
  padding: -5px;/* would allow correct alignment */
}
li {
  flex: 1 1 auto;
  margin: 5px;
}
<h1>Cras facilisis orci ligula</h1>

<ul>
  <li>a lacinia purus porttitor eget</li>
  <li>donec ut nunc lorem</li>
  <li>duis in est dictum</li>
  <li>tempor metus non</li>
  <li>dapibus sapien</li>
  <li>phasellus bibendum tincidunt</li>
  <li>quam vitae accumsan</li>
  <li>ut interdum eget nisl in eleifend</li>
  <li>maecenas sodales interdum quam sed accumsan</li>
</ul>

<p>Fusce convallis, arcu vel elementum pulvinar, diam arcu tempus dolor, nec venenatis sapien diam non dui. Nulla mollis velit dapibus magna pellentesque, at tempor sapien blandit. Sed consectetur nec orci ac lobortis.</p>

<p>Integer nibh purus, convallis eget tincidunt id, eleifend id lectus. Vivamus tristique orci finibus, feugiat eros id, semper augue.</p>

这些年来,我遇到了很多小问题,如果有一点负边距,就能解决大问题,但是现在我不得不添加非语义标记,使用calc()或只有单位相同时才有效的CSS预处理器。

"Original Answer"翻译成中文是"最初的回答"。


2

0

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