这样的元素宽度会是多少?
一个未指定宽度的绝对定位元素,内部有两张宽度为百分比的图片,这个绝对定位的元素和两张图片的宽度分别会是多少呢?
<div style={{ position: "absolute" }}>
{/* 原图为:500*300 */}
<img
style={{ width: "50%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.itc.cn%2Fq_70%2Fimages03%2F20200602%2Fe31e0b1434704616b70e105f0cbd3542.jpeg&refer=http%3A%2F%2Fp1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447015&t=6979602a7ce96b4714e129cbf090a43c"
/>
{/* 原图为:300*200 */}
<img
style={{ width: "25%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
结果是:
div
的宽度是 800px,第一张图片的宽度是 400px,第二张图片的宽度是 200px。
是怎么计算出这个结果的呢?这就需要说到 shrink-to-fit
宽度。
shrink-to-fit 自适应宽度
shrink-to-fit
是 CSS2.1 的一个规范——没有指定宽度的部分元素,会使用 shrink-to-fit
来计算宽度值。
会使用这种计算方式的元素有:
- 浮动元素
- 绝对定位元素
- inline-block
计算公式是:
shrink-to-fit width = min(max(preferred minimum width, available width), preferred width)
其中,preferred minimum width
、available width
、preferred width
分别是什么呢?这些名词在 CSS3 中都有对应的名称,可以结合起来理解一下。
在 CSS3 中,这些名词对应的叫法和样式是:
CSS2 | CSS3 | CSS3 对应的样式 |
---|---|---|
preferred minimum width | min-content size | width: min-content |
preferred width | max-content size | width: max-content |
available width | stretch-fit size | width: fill-available |
shrink-to-fit width | fit-content size | width: fit-content |
并且,fit-content size
和 shrink-to-fit width
的计算方式也是一样的:
fit-content size = min(max-content size, max(min-content size, stretch-fit size))
下面,具体来看一下它们是指什么。
width: min-content (preferred minimum width)
width: min-content
是指,采用内部元素「最小宽度值」最大的那个元素的宽度,作为最终容器的宽度。有点绕……
「最小宽度值」的意思是:
- 替换元素:比如图片元素,就是它呈现的宽度,特殊地,如果宽度为百分比,那么最小宽度值视作 0
- 中文:就是一个中文的宽度
- 英文:因为默认英文单词不换行,所以就是里面最长英文单词的宽度
🌰 替换元素:
<div style={{ width: "min-content" }}>
{/* 原图为:300*200 */}
<img
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
<div style={{ width: "min-content" }}>
{/* 原图为:300*200 */}
<img
width="50%"
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
🌰 中文:
<div style={{ width: "min-content" }}>
<p>中文中文中文</p>
</div>
🌰 英文:
<div style={{ width: "min-content" }}>
<p>English words English words</p>
</div>
width: max-content (preferred width)
width: max-content
是指,让元素内容强制不换行后的最大宽度。也就是,假设容器有足够的宽度,此时元素占据的宽度就是 max-content
的值。
它的表现会像设置了 white-space: nowrap
一样:
<div style={{ width: 100, backgroundColor: "#ccc" }}>
<p>很长的文字,会超出容器宽度</p>
</div>
<div style={{ width: 100, backgroundColor: "#ccc" }}>
<p style={{ width: "max-content" }}>很长的文字,会超出容器宽度</p>
</div>
当内部元素是宽度为百分比的图片时,最大宽度以图片的原始尺寸来计算:
<div style={{ width: "max-content", fontSize: 0 }}>
{/* 原图为:300*200 */}
<img
style={{ width: "50%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
width: fill-available (available width)
width: fill-available
是指,占满可用空间。
和 width: 100%
的区别是,width: fill-available
会在 100% 的基础上,去掉元素 margin
、border
、padding
的宽度。
🌰 一个 inline-block
的元素:
<div style={{ width: 200, height: 100, backgroundColor: "lightblue" }}>
<div
style={{
display: "inline-block",
width: "100%",
padding: 10,
margin: "0 10px",
border: "10px solid orange",
backgroundColor: "yellow",
}}
>
内容内容
</div>
</div>
width: 100%
<div style={{ width: 200, height: 100, backgroundColor: "lightblue" }}>
<div
style={{
display: "inline-block",
width: "100%",
padding: 10,
margin: "0 10px",
border: "10px solid orange",
backgroundColor: "yellow",
}}
>
内容内容
</div>
</div>
width: fill-available
<div style={{ width: 200, height: 100, backgroundColor: "lightblue" }}>
<div
style={{
display: "inline-block",
width: "-webkit-fill-available",
padding: 10,
margin: "0 10px",
border: "10px solid orange",
backgroundColor: "yellow",
}}
>
内容内容
</div>
</div>
开头栗子的计算过程
再回来看开头的栗子:
<div style={{ position: "absolute" }}>
{/* 原图为:500*300 */}
<img
style={{ width: "50%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.itc.cn%2Fq_70%2Fimages03%2F20200602%2Fe31e0b1434704616b70e105f0cbd3542.jpeg&refer=http%3A%2F%2Fp1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447015&t=6979602a7ce96b4714e129cbf090a43c"
/>
{/* 原图为:300*200 */}
<img
style={{ width: "25%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
结果是:
div
的宽度是 800px,第一张图片的宽度是 400px,第二张图片的宽度是 200px。
看下这个结果是怎么算出来的,带入 shrink-to-fit width
的计算公式:
shrink-to-fit width = min(max(preferred minimum width, available width), preferred width)
preferred minimum width
是 0
<div style={{ position: "absolute", width: "min-content" }}>
{/* 原图为:500*300 */}
<img
style={{ width: "50%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.itc.cn%2Fq_70%2Fimages03%2F20200602%2Fe31e0b1434704616b70e105f0cbd3542.jpeg&refer=http%3A%2F%2Fp1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447015&t=6979602a7ce96b4714e129cbf090a43c"
/>
{/* 原图为:300*200 */}
<img
style={{ width: "25%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
available width
是浏览器可视区域的宽度 1440px
<div style={{ position: "absolute", width: "-webkit-fill-available" }}>
{/* 原图为:500*300 */}
<img
style={{ width: "50%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.itc.cn%2Fq_70%2Fimages03%2F20200602%2Fe31e0b1434704616b70e105f0cbd3542.jpeg&refer=http%3A%2F%2Fp1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447015&t=6979602a7ce96b4714e129cbf090a43c"
/>
{/* 原图为:300*200 */}
<img
style={{ width: "25%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
preferred width
是 500 + 300 = 800px
<div style={{ position: "absolute", width: "max-content" }}>
{/* 原图为:500*300 */}
<img
style={{ width: "50%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp1.itc.cn%2Fq_70%2Fimages03%2F20200602%2Fe31e0b1434704616b70e105f0cbd3542.jpeg&refer=http%3A%2F%2Fp1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447015&t=6979602a7ce96b4714e129cbf090a43c"
/>
{/* 原图为:300*200 */}
<img
style={{ width: "25%" }}
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_lfill%2Cw_300%2Ch_200%2Cg_faces%2Fimages%2F20200430%2Fff0c28c89582426ab9e2d3098c129a31.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659447655&t=7b78fdc9779639cbf1e51ae0863ccb64"
/>
</div>
即,div
的 shrink-to-fit width
值为 min(max(0, 1440px), 800px) = 800px,再根据 div
的宽度按百分比计算出两张图片的宽度,分别为 400px 和 200px。