width/height 作用的具体细节
一 ,深藏不露的 width:auto
width:auto
在不同场景下的宽度表现
-
(1)充分利用可用空间。比方说,< div>、< p>这些元素的宽度默认是 100% 于父级容器的。这种充分利用可用空间的行为还有个专有名字,叫作 fill-available,大家了解即可。
-
(2)收缩与包裹。典型代表就是浮动、绝对定位、inline-block 元素或 table 元素, 英文称为 shrink-to-fit,直译为“收缩到合适”。CSS3 中的 fit-content 指的就是这种宽度表现。
-
(3)收缩到最小。这个最容易出现在 table-layout 为 auto 的表格中,
当每一列空间都不够的时候,文字能断就断,但中文是随便断的,英文单词不能断。于是,第一列被无情地每个字都断掉,形成一柱擎天。
这种行为在规范中被描述为“preferred minimumwidth”或者“minimum content width”。后来还有了一个更加好听的名字 min-content。
- (4)超出容器限制。除非有明确的 width 相关设置,否则上面 3 种情况尺寸都不会主动超过父级容器宽度的,但是存在一些特殊情况。
例如,内容很长的连续的英文和数字,或者内联元素被设置了 white-space:nowrap。
.father {
width: 150px;
background-color: #cd0000;
white-space: nowrap;
}
.child {
display: inline-block;
background-color: #f0f3f9;
}
子元素既保持了 inline-block 元素的收缩特性,又同时让内容宽度最大,直接无视父级容器的宽度限制。这种现象后来有了专门的属性值描述,这个属性值叫作 max-content,
这个属于 CSS3 内容,作者提了下,没有继续开展。
1.1 外部尺寸与流体特性
上面 4 种尺寸表现,哪个是“外部尺寸”?哪个是“内部尺寸”?
答:就第一个,也就是<div>
默认宽度 100%显示,是“外部尺寸”,其余全部是“内部尺寸”。
而这唯一的“外部尺寸”,是“流”的精髓所在。
1 正常流宽度
这里,作者指出了一些冗余的写法
a {
display: block;
width: 100%;
}
这里display: block;
本身就是全宽度展开的,没有必要再次写width: 100%;
;
并列举了一个文档流的导航
<style>
.left-area {
width: 800px;
}
.nav {
background-color: #cd0000;
}
.nav-a {
display: block;
margin: 0 10px;
padding: 9px 10px;
border-bottom: 1px solid #b70000;
border-top: 1px solid #de3636;
color: #fff;
}
.nav-a:first-child {
border-top: 0;
}
.nav-a+.nav-a+.nav-a {
border-bottom: 0;
}
</style>
<div class="left-area">
<div class="nav">
<a href="" class="nav-a">导航1</a>
<a href="" class="nav-a">导航2</a>
<a href="" class="nav-a">导航3</a>
</div>
</div>
这么写是文档流流无宽度布局,就算外面容器left-area
尺寸变化,我们的导航也可以自适应,这就是充分利用浏览器原生流特性的好处。
这种布局,注重:无宽度,无图片,无浮动
与之相反的一个布局是写死宽度的,这种写法是每次改都要重新计算width的;
.nav {
width: 240px;
}
.nav-a {
display: block;
/* 200px = 240px - 10px*2 - 10px*2 */
width: 200px;
margin: 0 10px;
padding: 9px 10px;
...
}
2 格式化宽度
这种情况是脱离文档流场景下的;也就是出现在 position属性值为 absolute 或 fixed 的元素中。
在默认情况下,绝对定位元素的宽度表现是“包裹性”,宽度由内部尺寸决定,但是,有一种情况其宽度是由外部尺寸决定的,
对于非替换元素(见本书第 4 章),当 left/top 或 top/bottom 对立方位的属性值同时存在的时候,元素的宽度表现为“格式化宽度”,
其宽度大小相对于最近的具有定位特性(position 属性值不是 static)的祖先元素计算。
div { position: absolute; left: 20px; right: 20px; }
假设该< div>元素最近的具有定位特性的祖先元素的宽度是 1000 像素,
因为 left 和 right 是对立的
则这个 < div>元素的宽度是 960(即 1000−20−20)像素。
此外,和上面的普通流一样,“格式化宽度”具有完全的流体性,也就是 margin、border、padding 和 content 内容区域同样会自动分配水平(和垂直)空间。
“格式化宽度”水很深,同时也非常实用,更多内容可参见本书第 6 章与 position:absolute 相关的内容。
1.2 内部尺寸与流体特性
上讲的是“外部尺寸”,本节就讲讲“内部尺寸”。
所谓“内部尺寸”,简单来讲就是元素的尺寸由内部的元素决定,而非由外部的容器决定。
如何快速判断一个元素使用的是否为“内部尺寸”呢?很简单,
假如这个元素里面没有内容,宽度就是 0,那就是应用的“内部尺寸”。
1. 包裹性/自适应性
作者造了一个词"包裹性",我感觉叫"自适应性"更好;
“自适应性”,指的是元素尺寸由内部元素决定,但永远小于“包含块”容器的尺寸;
对于一个元素,如果其 display 属性值是 inline-block,那么即使其里面内容再多,只要是正常文本,宽度也不会超过容器。
于是,图文混排的时候,我们只要关心内容,除非“首选最小宽度”比容器宽度还要大,否则我们完全不需要担心某个元素内容太多而破坏了布局;
按钮就是这样的;(注:<button>
标签按钮才会自动换行,<input>
标签按钮,默认 white-space:pre,是不会换行的,需要将 pre 值重置为默认的 normal。)
自适应性对实际开发有什么作用如下?
页面某个模块的文字内容是动态的,可能是几个字,也可能是一句话。然后,希望文字少的时候居中显示,文字超过一行的时候居左显示。
<div class="box">
<p id="conMore" class="content">文字内容-新增文字-新增文字-新增文字</p>
</div>
<style>
.box {
padding: 10px;
background-color: #cd0000;
text-align: center;
}
.content {
display: inline-block;
text-align: left;
}
</style>
2. 首选最小宽度
所谓“首选最小宽度”,指的是元素最适合的最小宽度。
外部容器的宽度假设宽度是0,请问里面的 inline-block 元素的宽度是多少?是 0 吗?不是。
在 CSS 世界中,图片和文字的权重要远大于布局,因此,CSS 的设计者显然是不会让图文在 width:auto 时宽度变成 0 的,此时所表现的宽度就是“首选最小宽度”。
- 东亚文字(如中文)最小宽度为每个汉字的宽度,
- 西方文字最小宽度由特定的连续的英文字符单元决定。并不是所有的英文字符都会组成连续单元,一般会终止于空格(普通空格)、短横线、问号以及其他非英文字符等。例如,“display:inline-block”这几个字符以连接符“-”作为分隔符,形成了“display:inline”和“block”两个连续单元,由于连接符“-”分隔位置在字符后面,因此,最后的宽度就是“display:inline-”的宽度,
- 如果想让英文字符和中文一样,每一个字符都用最小宽度单元,可以试试使用 CSS 中的 word-break:break-all。
- 类似图片这样的替换元素的最小宽度就是该元素内容本身的宽度。
3. 最大宽度
这个感觉没啥太大用处,了解即可;
上面讲的都是width:auto
二 ,width 值作用的细节
首先了解 盒子模型,见下图
作者强行用地球构造来比喻盒子模型,感觉增加了理解难度,简单问题复杂化了,这个比喻不建议看。作者引出的:“内在盒子”又被分成了 4 个盒子,分别是 content box、padding box、border box和 margin box;这个观点,建议新手不要尝试死磕,这节只需要理解下面一句话就可以了
盒子本身的尺寸不会因 margin值变化而变化,但border/padding/content尺寸的改变,均会影响盒子尺寸;
<div>
元素默认的 padding、border 和 margin 都是 0,如果我们在水平方向给定 padding 和 border 大小,则元素的宽度就会改变;
(1)流动性丢失
如果设置了宽度,则会影响文档流(并不会脱离文档流),比如再1920PX像素下,设置宽度为920;会被截断,导致右侧的1000像素没有任何元素显示在那里;(这也是设置宽度的特性)
(2)与现实世界表现不一致的困扰。
设置边框和内边距会在总宽度基础上增加;
日常使用软件,画一个宽度为140px的矩形,边框是2px,这时候默认画出来是包含边框的140px;而CSS写需要写宽度136px,边框2px;
(CSS3种有一种新的盒子模型,原理类似日常习惯,是下面第四部分讲的box-sizing: border-box;
)
三 ,CSS 流体布局下的宽度分离原则
宽度分离
作者提出的这个写法非常值得了解
需求:写一个包含1px边框的102px总宽度矩形;;你写完以后又告诉你,希望元素边框内有 20 像素的留白
普通写页面,
.box {
width: 100px;
border: 1px solid;
}
再改为
.box {
width: 60px; // 通过计算,减去 40 像素
padding: 20px;
border: 1px solid;
}
而用宽度分离的方法写页面就非常爽(CSS实用小技巧)
.father {
width: 102px;
}
.son {
border: 1px solid;
}
再改为
.father {
width: 102px;
}
.son {
border: 1px solid;
padding: 20px;//新增就好
}
这样的写法,浪费一个父级的HTML标签;当时感觉如果按照这个思路些;维护性更好;做自适应的页面,逻辑会更清晰;
四 ,改变 width/height 作用细节的 box-sizing
这个图可以直观说明,就是设置100px宽度,则表示内容+边框+padding+margin的总宽度是100px;
下面这种总宽度也是100px;
.box {
width: 100px;
box-sizing: border-box;
padding: 20px;
border: 1px solid;
}
注意:这个写法,margin是不支持的,如果你的两个盒子有margin;需要外面再套一层进行计算(好尴尬啊);
这个属性非常适合 原生普通文本框<input>
和文本域<textarea>
不错的用途;
拿文本域<textarea>
举例,<textarea>
为替换元素,替换元素的特性之一就是尺寸由内部元素决定,且无论其 display 属性值是 inline 还是 block。这个特性很有意思,对于非替换元素,如果其 display 属性值为 block,则会具有流动性,宽度由外部尺寸决定,但是替换元素的宽度却不受 display 水平影响,因此,我们通过 CSS 修改<textarea>
的display 水平是无法让尺寸 100%自适应父容器的:
textarea {
display: block; /* 还是原来的尺寸 */
}
所以,我们只能通过 width 设定让<textarea>
尺寸 100%自适应父容器。那么,问题就来了,<textarea>
是有 border 的,而且需要有一定的 padding 大小,否则输入的时候光标会顶
着边框,体验很不好。于是,width/border 和 padding 注定要共存,同时还要整体宽度 100%自适应容器。如果不借助其他标签,肯定是无解的。
下面这样写就非常不错(CSS实用小技巧)
textarea {
width: 100%;
-ms-box-sizing: border-box; /* for IE8 */
box-sizing: border-box;
}
五 ,相对简单而单纯的 height:auto
比较简单,正常就是自适应;没有宽度那么复杂;
六 ,关于 height:100%
插入一个< div>,然后满屏显示背景图(CSS实用小技巧)
下面是错误的写法
div {
width: 100%; /* 这是多余的 */
height: 100%; /* 这是无效的 */
background: url(bg.jpg);
}
正确的写法
//仅仅设置<body>也是不行的,因为此时的<body>也没有具体的高度值:
html, body {
height: 100%;
}
div {
background: url(bg.jpg);
height: 100%;
}
原理:对于 height 属性,如果父元素height 为 auto,只要子元素在文档流中,其百分比值完全就被忽略了。
为何 height:100%无效
规范中其实给出了答案。如果包含块的高度没有显式指定(即高度由内容决定),并且该元素不是绝对定位,则计算值为auto。一句话总结就是:因为解释成了 auto。要知道,auto 和百分比计算,肯定是算不了的
如何让元素支持 height:100%效果
(1)设定显式的高度值
html, body {
height: 100%;
}
(2)使用绝对定位。
div {
height: 100%;
position: absolute;
}