子元素设置max-height: 100%时会超出父元素

257

我试图理解对我来说似乎是意外行为的内容:

我有一个元素,其最大高度为100%,位于一个也使用最大高度的容器内,但意外的是,子元素溢出了父元素:

.container {
  background: blue;
  padding: 10px;
  max-height: 200px;
  max-width: 200px;
}

img {
  display: block;
  max-height: 100%;
  max-width: 100%;
}
<div class="container">
  <img src="http://placekitten.com/400/500" />
</div>

不过,如果给父元素设置了明确的高度,则该问题就可以得到解决:

.container {
  background: blue;
  padding: 10px;
  max-height: 200px;
  max-width: 200px;
  height: 200px;
}

img {
  display: block;
  max-height: 100%;
  max-width: 100%;
}
<div class="container">
  <img src="http://placekitten.com/400/500" />
</div>

有人知道为什么在第一个例子中,子元素不遵守其父元素的最大高度吗?为什么需要明确设置高度?


1
浏览器的默认行为改变了吗?因为在我当前版本的Google Chrome上,上面两个代码示例实际上都没有显示子元素溢出。是新的浏览器默认使用box-sizing: border-box或其他什么东西吗? - David Mays
11个回答

374

当您在子元素上指定max-height的百分比时,它是基于父元素的实际高度而不是父元素的max-height,这有点奇怪,与规范所述的一样。同样适用于max-width

因此,当您没有在父元素上指定明确的高度时,子元素的max-height无法计算出基础高度,因此max-height会计算为none,允许子元素尽可能地高。现在作用于子元素的唯一限制是其父元素的max-width,由于图像本身的高度大于宽度,在保持其纵横比的同时仍然尽可能大地显示,它会向下溢出容器的高度。

当您为父元素指定明确的高度时,子元素知道它必须最多达到该明确高度的100%。这使它可以被限制在父元素的高度内(同时仍然保持其纵横比)。


6
这是一个有用的解释,特别是结合我的朋友的输入:“max-height: 100%(子元素)of max-height: 100%(父元素)= 0 - 这就是为什么你的子元素没有遵守其父元素值”的原因。 - iamkeir
32
我不确定应该接受哪个答案 - 这个回答解释了“为什么”的问题。 - iamkeir
2
我只回答了“为什么”,因为我不确定你的目标是什么,因为它没有明确提到。也许如果你详细说明一下,我可以回答它。 - BoltClock
2
接受此答案,因为它回答了我的实际问题,谢谢。请注意,@Daniel下面的答案提供了一个修复方法。 - iamkeir
5
在我的情况下,使用display: flex; flex-direction: column解决了问题,并添加了我所想要的滚动条。 - xdevs23
显示剩余3条评论

114

.container {
  background: blue;
  padding: 10px;
  max-height: 200px;
  max-width: 200px;
  float: left;
  margin-right: 20px;
}

.img1 {
  display: block;
  max-height: 100%;
  max-width: 100%;
}

.img2 {
  display: block;
  max-height: inherit;
  max-width: inherit;
}
<!-- example 1  -->
<div class="container">
  <img class='img1' src="http://via.placeholder.com/350x450" />
</div>

<!-- example 2  -->

<div class="container">
  <img class='img2' src="http://via.placeholder.com/350x450" />
</div>

我做了一些实验。在Firefox上一个更大的图片上,使用继承属性值得到了很好的结果。这会对你有帮助吗?

.container {
    background: blue;
    padding: 10px;
    max-height: 100px;
    max-width: 100px;
    text-align:center;
}

img {
    max-height: inherit;
    max-width: inherit;
}

4
我不确定要接受哪个答案——这个回答解决了“修复”问题。 - iamkeir
已接受 @BoltClock 的答案解释原因,但感谢您提供修复方案。 - iamkeir
1
除了@BoltClock之外,我的回答确切地做了他所说的。CSS只是告诉计算机如何处理元素,但在计算后,它将限制所有值,仅保留用于渲染的基本必需值,例如高度、宽度、颜色、坐标等。 继承属性告诉img获取父元素的“计算”值。因此,在max-height和max-width CSS属性中,您可以获得高度和宽度的计算值。 - Daniel
4
max-height: 100% 而不是固定高度时,这个方法无法奏效:http://jsfiddle.net/umbreak/n6czk9xt/1/ - Didac Montero
2
我不能将宽度和高度声明为固定值,因为我的布局是响应式的 display: flex;。我开了一个新线程:http://stackoverflow.com/questions/29732391/make-img-responsive-and-fill-into-a-div但是,在最糟糕的情况下,我可以使用 jQuery 获取图像的实际宽度和高度,并将它们设置在父图像的 div 中。 - Didac Montero
显示剩余4条评论

32

不要使用max-height: 100%/100%的方法填满所有空间,而是采用将position:absolute和top/bottom/left/right都设置为0的替代方案。

换句话说,HTML应该如下所示:

<div class="flex-content">
  <div class="scrollable-content-wrapper">
    <div class="scrollable-content">
      1, 2, 3
    </div>
   </div>
</div>


.flex-content {
  flex-grow: 1;
  position: relative;
  width: 100%;
  height: 100%;
}

.scrollable-content-wrapper {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  overflow: auto;
}

.scrollable-content {
    /* Add styling here */
}

在下面尝试一下:

.flex-content {
  flex-grow: 1;
  position: relative;
  width: 100%;
  height: 100%;
}
.scrollable-content-wrapper {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  overflow: auto;
}
html {
  height: 50%;
  width: 50%;
}
body {
  height: 100%;
  width: 100%;
}
.parent {
  height: 100%;
  outline: 1px solid red;
}
<html>
<body>
  <div class="parent">
    <div class="flex-content">
      <div class="scrollable-content-wrapper">
        <div class="scrollable-content" id="scrollable">
          1, 2, 3
        </div>
      </div>
    </div>
  </div>
  
  <button onClick="scrollable.innerText += '\nSome more text'" style="margin-top: 1rem;">Add Line</button>
  <p>
    The red outline represents the parent. Click above to add a line until overflow occurs to see that the size of the parent is not increased.
  </p>
</body>
</html>


2
这是唯一的解决方案,如果您需要容器在溢出时能够滚动,并且是其父级大小而不增加父级高度。太棒了。 - Nate Levin

8
我在这里找到了一个解决方案:http://www.sitepoint.com/maintain-image-aspect-ratios-responsive-web-design/ 这个技巧的可行性是因为元素的宽度和底部填充之间存在关系。因此:
父元素:
container {
  height: 0;
  padding-bottom: 66%; /* for a 4:3 container size */
  }

子元素(移除所有与宽度相关的CSS,即width:100%):

img {
  max-height: 100%;
  max-width: 100%;
  position: absolute;     
  display:block;
  margin:0 auto; /* center */
  left:0;        /* center */
  right:0;       /* center */
  }

5
您可以使用属性 object-fit
.cover {
    object-fit: cover;
    width: 150px;
    height: 100px;
}

此处所建议的。

Chris Mills在Dev.Opera中对此属性进行了全面解释

CSS-Tricks中更好的解释

支持该属性的浏览器有:

  • Chrome 31+
  • Safari 7.1+
  • Firefox 36+
  • Opera 26+
  • Android 4.4.4+
  • iOS 8+

我刚刚检查了vivaldi和chromium,它们也支持它(这不出奇)

目前IE不支持,但是...谁在乎呢? 另外,iOS支持object-fit,但不支持object-position,但很快就会支持。


不错的选择!如果在IE中可以接受优雅降级,我想flex-box也可能有所帮助。 - iamkeir
1
这与实际问题无关,提供的示例与所描述的问题无关。 - vsync

3
以下是关于最近被标记为重复问题的解决方案。在该问题中,<img> 标签超过父级 <div> 的最大高度。

有问题的代码: Fiddle

已修复的代码: Fiddle

在这种情况下,将两个父级 <div> 添加 display:flex 属性就是解决方法。


2
一个好的解决方案是不在父元素上使用高度,而只在子元素上使用视口

示例代码:https://jsfiddle.net/voan3v13/1/

body, html {
  width: 100%;
  height: 100%;
}
.parent {
  width: 400px;
  background: green;
}

.child {
  max-height: 40vh;
  background: blue;
  overflow-y: scroll;
}

2

也许其他人可以解释您问题的原因,但您可以通过指定容器的高度,然后将图像的高度设置为100%来解决它。重要的是,width出现在height之前。

<html>
    <head>
        <style>
            .container {  
                background: blue; 
                padding: 10px;
                height: 100%;
                max-height: 200px; 
                max-width: 300px; 
            }

            .container img {
                width: 100%;
                height: 100%
            }
        </style>
    </head>
    <body>
        <div class="container">
            <img src="http://placekitten.com/400/500" />
        </div>
    </body>
</html>

如果他们希望当图片小于200x200时容器变小,那么是的,必须使用min-height/max-height来实现。 - cimmanon

2
我能找到的最接近这个问题的例子是这个: http://jsfiddle.net/YRFJQ/1/
.container {  
  background: blue; 
  border: 10px solid blue; 
  max-height: 200px; 
  max-width: 200px; 
  overflow:hidden;
  box-sizing:border-box;
}

img { 
  display: block;
  max-height: 100%; 
  max-width: 100%; 
}

主要问题在于高度采用容器高度的百分比,因此它在寻找父容器中显式设置的高度,而不是最大高度。
我唯一能想到的方法是使用上面的小例子来隐藏溢出,但是内边距仍然作为可见空间使图像流入,因此可以用实线边框替换它(然后添加border-box将其设置为200px,如果您需要的是这个宽度)。
不确定这是否符合您的需求,但这是我能找到的最好的解决办法。

不幸的是,裁剪图像并不是理想的解决方案。感谢您的建议。 - iamkeir

1

容器通常会很好地包裹其内容。但反过来就不太行了:子元素不能很好地填充其祖先元素。因此,应该在最内层元素上设置宽度/高度值,而不是在最外层元素上设置,然后让外部元素包裹其内容。

.container {
    background: blue;
    padding: 10px;
}

img {
    display: block;
    max-height: 200px;
    max-width: 200px;
}

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