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;
}

AXIHE / 精选资源

浏览全部教程

面试题

学习网站

前端培训
自己甄别

前端书籍

关于朱安邦

我叫 朱安邦,阿西河的站长,在杭州。

以前是一名平面设计师,后来开始接接触前端开发,主要研究前端技术中的JS方向。

业余时间我喜欢分享和交流自己的技术,欢迎大家关注我的 Bilibili

关注我: Github / 知乎

于2021年离开前端领域,目前重心放在研究区块链上面了

我叫朱安邦,阿西河的站长

目前在杭州从事区块链周边的开发工作,机械专业,以前从事平面设计工作。

2014年底脱产在老家自学6个月的前端技术,自学期间几乎从未出过家门,最终找到了满意的前端工作。更多>

于2021年离开前端领域,目前从事区块链方面工作了