html和css之前端系列,知其然,知其所以然

731 阅读38分钟

html和css的思维导图如下

image.png

1 HTML5文档类型声明

HTML5文档类型声明位于HTML文档的第一行:

<!DOCTYPE html>它是用来告知 Web 浏览器页面使用了哪种 HTML 版本。

DOCTYPE 是 HTML5 中一种标准通用标记语言的文档类型声明,它的目的是告诉浏览器(解析器)应该以什么样(html 或 xhtml)的文档类型定义来解析文档,不同的渲染模式会影响浏览器对 CSS 代码甚⾄ JavaScript 脚本的解析。它必须声明在 HTML ⽂档的第⼀⾏。

浏览器渲染页面的两种模式(可通过 document.compatMode 获取,比如,语雀官网的文档类型是CSS1Compat):

  • CSS1Compat:标准模式(Strick mode) ,默认模式,浏览器使用 W3C 的标准解析渲染页面。在标准模式中,浏览器以其支持的最高标准呈现页面。
  • BackCompat:怪异模式(混杂模式)(Quick mode) ,浏览器使用自己的怪异模式解析渲染页面。在怪异模式中,页面以一种比较宽松的向后兼容的方式显示。

2 HTML5 中的的新特性

新元素,新属性

  • 用于绘画的 canvas 元素
  • 用于媒体元素媒介回放的 video 和 audio 元素
  • 对本地存储的更好的支持 localStorage sessionStorage
  • 新的特殊内容语义元素,比如 article、header、footer、nav、section、aside
  • 新的表单控件,比如 calendar、date、time、email、url、search
  • WebSocket
  • 应用程序缓存
  • Web /workers

对HTML语义化理解

语义化是指 根据内容的结构化(内容语义化),选择合适的标签(代码语义化)。通俗来讲就是用正确的标签做正确的事情。

语义化的优点如下:

  • 对机器友好,带有语义的文字表现力丰富,更适合搜索引擎的爬虫爬取有效信息,有利于 SEO。除此之外,语义类还支持读屏软件,根据文章可以自动生成目录;
  • 对开发者友好,使用语义类标签增强了可读性,结构更加清晰,开发者能清晰的看出网页的结构,便于团队的开发与维护。

常见的语义化标签:

<header></header>  头部

<nav></nav>  导航栏

<section></section>  区块(有语义化的div)

<main></main>  主要区域

<article></article>  主要内容

<aside></aside>  侧边栏

<footer></footer>  底部

3 meta标签

meta元数据(Metadata)是数据的数据信息。

<meta> 标签提供了 HTML 文档的元数据。元数据不会显示在客户端,但是会被浏览器解析。

META元素通常用于指定网页的描述,关键词,文件的最后修改时间,作者及其他元数据。 元数据可以被使用浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 Web 服务调用。

meta 标签由 name 和 content 属性定义,用来描述网页文档的属性,比如网页的作者,网页描述,关键词等,除了 HTTP 标准固定了一些name作为大家使用的共识,开发者还可以自定义 name。

常用的 meta 标签:

(1)charset,用来描述 HTML 文档的编码类型:

<meta charset="UTF-8" >

(2) keywords,页面关键词:

<meta name="keywords" content="关键词" />

(3)description,页面描述:

<meta name="description" content="页面描述内容" />

(4)refresh,页面重定向和刷新:

<meta http-equiv="refresh" content="0;url=" />

X-UA-Compatible

<meta http-equiv="X-UA-Compatible" content="edge" />

Edge 模式通知 Windows Internet Explorer 以最高级别的可用模式显示内容,这实际上破坏了“锁定”模式。即如果你有IE9的话说明你有IE789,那么就调用高版本的那个也就是IE9。

(5)viewport,适配移动端,可以控制视口的大小和比例:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

其中,content 参数有以下几种:

  • width viewport :宽度(数值/device-width)
  • height viewport :高度(数值/device-height)
  • initial-scale :初始缩放比例
  • maximum-scale :最大缩放比例
  • minimum-scale :最小缩放比例
  • user-scalable :是否允许用户缩放(yes/no)

(6)搜索引擎索引方式:

<meta name="robots" content="index,follow" />

其中,content 参数有以下几种:

  • all:文件将被检索,且页面上的链接可以被查询;
  • none:文件将不被检索,且页面上的链接不可以被查询;
  • index:文件将被检索;
  • follow:页面上的链接可以被查询;
  • noindex:文件将不被检索;
  • nofollow:页面上的链接不可以被查询。

4 src和href的区别

1. 基本定义

  • src (Source) :表示"源",用于嵌入资源到当前文档
  • href (Hypertext Reference) :表示"超文本引用",用于链接到外部资源

2. 主要区别

特性srchref
用途加载并嵌入资源到当前文档建立与外部资源的关联/链接
常见标签<script><img><iframe><a><link><area>
加载行为立即加载并执行/显示只是建立关联,不立即加载内容
阻塞性可能阻塞文档解析(如<script>)不会阻塞文档解析

3. 详细说明

src 的特点

  • 用于需要替换嵌入到当前文档中的资源

  • 浏览器会立即获取并处理这些资源

  • 示例:

    <img src="image.jpg">  <!-- 嵌入图片 -->
    <script src="app.js"></script>  <!-- 嵌入并执行JS -->
    <iframe src="page.html"></iframe>  <!-- 嵌入其他HTML -->
    

href 的特点

  • 用于建立关联,而不是直接嵌入内容

  • 浏览器不会立即加载这些资源,除非用户触发(如点击链接)

  • 示例:

    <a href="page.html">跳转</a>  <!-- 链接到其他页面 -->
    <link href="styles.css" rel="stylesheet">  <!-- 关联CSS样式表 -->
    

4. 特殊注意事项

  1. <link> 标签

    • 虽然使用href,但rel="stylesheet"的CSS会立即加载
    • 这是href的一个特例
  2. 阻塞行为

    • 带有src<script>会阻塞HTML解析(除非添加asyncdefer)
    • 带有href的资源通常不会阻塞
  3. SEO影响

    • 搜索引擎会跟踪href链接来发现新页面
    • src资源通常不会被当作独立的可索引内容

理解这两者的区别有助于正确使用HTML标签和优化网页性能。

5 script标签defer和async的区别

主要弄清楚在html解析时,js的加载方式,执行时机和顺序

先解释三种加载js的方式,当浏览器碰到 script 脚本的时候:

<script src="script.js"></script>
  1. 没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。同步加载执行,阻塞html解析
<script async src="script.js"></script>
  1. 有 async,加载和渲染后续文档元素的过程将和 script.js 的加载并行进行(异步),执行还是阻塞页面解析的。乱序执行,加载完立即执行,
<script defer src="myscript.js"></script>
  1. 有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。按加载顺序执行

然后从实用角度来说呢,首先把所有脚本都丢到</body>之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。

接着,我们来看一张图咯:

image.png

蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。 此图告诉我们以下几个要点:

  1. defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
  2. 它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的
  3. 关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
  4. async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行,在js脚本执行的时候都会阻塞HTML解析
  5. 仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的. 大多数浏览器在实现的时候会作出优化。

脚本调用策略小结:

  • 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用 async。
  • 如果脚本需要等待页面解析,且依赖于其它脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 中。

扩展 从输入url到页面显示发生了什么?

来看看chrome是怎么做的

《WebKit技术内幕》:

  1. 当用户输入网页URL的时候,WebKit调用其资源加载器加载该URL对应的网页。
  2. 加载器依赖网络模块建立连接,发送请求并接受答复。
  3. WebKit接收到各种网页或者资源的数据,其中某些资源可能是同步或异步获取的。
  4. 网页被交给HTML解释器转变成一系列的词语(Token)。
  5. 解释器根据词语构建节点(Node),形成DOM树。
  6. 如果节点是JavaScript代码的话,调用JavaScript引擎解释并执行。
  7. JavaScript代码可能会修改DOM树的结构。
  8. 如果节点需要依赖其他资源,例如图片、CSS、视频等,调用资源加载器来加载他们,但是他们是异步的,不会阻碍当前DOM树的继续创建;如果是JavaScript资源URL(没有标记异步方式),则需要停止当前DOM树的创建,直到JavaScript的资源加载并被JavaScript引擎执行后才继续DOM树的创建

所以,通俗来讲,chrome浏览器首先会请求HTML文档,然后对其中的各种资源调用相应的资源加载器进行异步网络请求,同时进行DOM渲染,直到遇到<script>标签的时候,主进程才会停止渲染等待此资源加载完毕然后调用V8引擎对js解析,继而继续进行DOM解析。我的理解如果加了async属性就相当于单独开了一个进程去独立加载和执行,而defer是和将<script>放到<body>底部一样的效果。

6 HTML5 使用 CSS3

  • 新选择器
  • 新属性
  • 过渡 transition property duration timing-function delay
  • 动画@keyframs 创建动画规则
  • 2D/3D 转换 transform translate rotate scale skew matrix
  • 圆角 border-radius
  • 背景 background
  • 渐变 gradients line
  • 阴影效果
  • 可下载的字体
  • 弹性盒子
  • 多媒体查询
  • 多列布局
  • 盒模型

7 CSS 动画有哪些?

animation、transition、transform、translate 这几个属性要搞清楚:

  • animation:用于设置动画属性,他是一个简写的属性,包含6个属性
  • transition:用于设置元素的样式过度,和animation有着类似的效果,但细节上有很大的不同
  • transform:用于元素进行旋转、缩放、移动或倾斜,和设置样式的动画并没有什么关系
  • translate:translate只是transform的一个属性值,即移动,除此之外还有 scale 等

8 CSS 的权重和优先级

  1. 权重

从0开始,一个行内样式+1000,一个id选择器+100,一个属性选择器、class或者伪类+10,一个元素选择器,或者伪元素+1,通配符+0

  1. 优先级

权重相同,写在后面的覆盖前面的 使用 !important 达到最大优先级,都使用 !important 时,权重大的优先级高

9 盒模型

盒模型(Box Model)是用来设计和布局时使用,它描述了元素在页面中占据空间的方式。每个HTML元素都可以看作是一个矩形的盒子,这个盒子由内到外由四个部分组成,它包括:内容区(content),内边距(margin)、边框(border)、外边距(padding)四个属性。

重点:当您指定一个 CSS 元素的宽度和高度属性时,你只是设置内容区域的宽度和高度。要知道,完整大小的元素,你还必须添加内边距,边框和外边距。

两种盒模型类型

1. 标准盒模型(content-box) - 默认

box-sizing: content-box;
  • widthheight只设置内容区大小
  • 总宽度 = width + padding + border + margin
  • 总高度 = height + padding + border + margin

2. 边框盒模型(border-box)

box-sizing: border-box;
  • widthheight设置内容区+内边距+边框的总大小
  • 总宽度 = width + margin
  • 总高度 = height + margin
  • 更直观,更易于布局控制

元素类型

1.block-level boxes 块元素

block-Level 元素:

  1. 块级元素在视觉上的格式为 block 即块。
  2. 元素占有 100% ⽗元素的宽度, 和其内容⽆关。
  3. 元素默认从上到下垂直堆叠。
  4. 盒⼦模型适⽤。

绝⼤多数 html 元素默认都是 block-level 块级元素,例如: body, main, header, footer, section, nav, aside, div, h1~h6, p, ul, ol, li等等,

设置 CSS 属性 display: block ; 可以将其他类型盒⼦转换为 block 级盒⼦

2.inline-level boxes 内联元素

  1. 元素的宽度仅占⽤其内容所需的空间
  2. 在元素之后或之前都不产⽣换⾏。
  3. 盒⼦模型以不同的⽅式被应⽤:height和 width 不起作⽤
  4. padding和margin仅在⽔平⽅向(即左右⽅向)起作⽤。

⽣成inline 盒⼦的相应的 inline 元素有: a, img, strong, em,等等

设置 CSS 属性 display: inline; 可以将盒⼦转换为 inline-level boxes

3.inline-block boxes 内联块元素

inline-block介于inline和block 两者之间。

  1. 从外部看起来像 inline,在内部表现得像 block。
  2. 元素的宽度只占⽤内容需要的空间
  3. 不产⽣换⾏。

width, height, margin, padding四种属性全都适⽤。

dsipaly: inline-block;

元素有button ⼤多数时候,我们实际上会不理会 display 设置,⽽只是使⽤预定义的盒⼦类型,因为默认情况下,它们确实很有意义。少数情况下使⽤ display属性很⽅便。

  1. 特殊的元素img

img 内联元素,因为⽤浏览器 dev-tool 查看属性显⽰的就是 inline。 但在⾏为上它⼜表现得像inline-block 元素,例如,可以设width和height

10 BFC和IFC的区别

1. BFC

什么是BFC

BFC(Block Formatting Context)块级格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,指一个独立的渲染区域,内部的元素布局不会影响外部元素,同时也不会被外部元素所影响。可以理解为页面上的一个隔离的独立容器。

Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。Block formatting context直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干通俗地讲,BFC是一个容器,用于管理块级元素。

形成 BFC 的条件

  1. 根元素(<html>
  2. 浮动元素(float值不为none
  3. 定位元素(positionabsolutefixed
  4. display值为inline-blocktable-celltable-captionflexinline-flexgridinline-grid
  5. overflow值不为visible(如hiddenautoscroll
  6. contain值为layoutcontentstrict

BFC 的特性:

  1. 独立布局环境:BFC内部元素的布局不会影响外部元素
  2. 内部盒子垂直排列:BFC内的块级盒子会垂直排列
  3. 外边距重叠:同一个BFC内的相邻块级元素垂直外边距会发生折叠
  4. 包含浮动元素:BFC会包含其内部的所有浮动元素
  5. 阻止元素被浮动元素覆盖:BFC区域不会与浮动元素重叠

BFC 的用途:

解决外边距重叠 相邻元素和父子元素外边距合并

相邻元素外边距重叠

<style>
p{
        color: #fff;
        background: #888;
        width: 200px;
        line-height: 100px;
        text-align:center;
        margin: 100px;
  }
</style>
<body>
    <p>ABC</p>
    <p>abc</p>
</body>

//只需要在p外面包裹一层容器,并触发该容器生成一个BFC。
那么两个P便不属于同一个BFC,就不会发生margin重叠了

<style>
p{
        color: #fff;
        background: #888;
        width: 200px;
        line-height: 100px;
        text-align:center;
        margin: 100px;
    }
.wrap{
  overflow:hidden;
}
</style>
<body>
   <p>ABC</p>
  <div class="wrap">
    <p>abc</p>
  </div>
</body>

父子元素margin重叠问题

<style>
.box{
width:100px;
height:100px;
background:#ccc;
}
.wrap {
  background:yellow;
}
.wrap h1{
  background:pink;
  margin:40px;
}
</style>
<body>
<div class="box">box</div>
<div class="wrap">
  <h1>h1</h1>
</div>
</body>

image.png

上图wrap元素与h1元素之间理论上本该有个40px的上下margin值,然而实际上父子元素并没有存在margin值,与此同时,两个div元素的间距为40px。遇到这种情形,我们如何处理?
处理方法其实有很多,在wrap元素中添加:overflow:hidden;或者overflow:auto;使其父元素形成一个BFC;也可以在wrap元素中添加border:1px solid;或是padding:1px; 这些都可以有效解决父子元素margin重叠问题。

image.png

清除浮动-BFC可以包含浮动(解决浮动元素,造成父元素高度坍塌问题)

我们都知道浮动会脱离文档流,接下来我们看看下面的例子:

<style>
.box1{
  width:100px;
  height:100px;
  float:left;
  border: 1px solid #000;
}
.box2{
  width:100px;
  height:100px;
  float:left;
  border: 1px solid #000;
}
.box{
  background:yellow
}
</style>
<body>
<div class="box">
  <div class="box1"></div>
  <div class="box2"></div>
</div> 
</body>

image.png

由于容器内两个div元素浮动,脱离了文档流,父容器内容宽度为零(即发生高度塌陷),未能将子元素包裹住。解决这个问题,只需要把把父元素变成一个BFC就行了。常用的办法是给父元素设置overflow:hidden。

image.png

防止文字环绕(避免与浮动元素重叠)

BFC不会重叠浮动元素

利用这个特性,我们可以创造自适应两栏布局

<style>
.box1{
  height: 100px;
  width: 100px;
  float: left;
  background: lightblue;
}
.box2{width: 200px;
  height: 200px;
  background: #eee;
}
</style>
<body>
<div class="box1">我是一个左浮动的元素</div>
<div class="box2">喂喂喂!大家不要生气嘛,生气会犯嗔戒的。悟空你也太调皮了,
我跟你说过叫你不要乱扔东西,你怎么又……你看,我还没说完你就把棍子给扔掉了!
月光宝盒是宝物,你把它扔掉会污染环境,要是砸到小朋友怎么办,就算砸不到小朋友,
砸到花花草草也是不对的。</div>
</body>

image.png

上图中,文字围绕着浮动元素排列,不过在这里,这显然不是我们想要的。此时我们可以为.box2元素的样式加上overflow:hidden;使其建立一个BFC,让其内容消除对外界浮动元素的影响

image.png

自适应两栏布局

这个方法可以用来实现两列自适应布局,效果不错,此时左边的宽度固定,右边的内容自适应宽度。如果我们改变文字的大小或者左边浮动元素的大小,两栏布局的结构依然没有改变!

BFC会与float元素相互覆盖吗?为什么?举例说明

不会,因为 BFC 是页面中一个独立的隔离容器,其内部的元素不会与外部的元素相互影响,比如两个 div,上面的 div 设置了 float,那么如果下面的元素不是 BFC,也没有设置 float,会形成对上面的元素进行包裹内容的情况,如果设置了下面元素为 overflow:hidden;属性那么就能够实现经典的两列布局,左边内容固定宽度,右边因为是 BFC 所以会进行自适应。(参考上一小节)

两个div上下排列,都设margin,有什么现象?

都正取大,一正一负相加

为什么会有这种现象?你能解释一下吗

是由块级格式上下文决定的,BFC,元素在 BFC 中会进行上下排列,然后垂直距离由 margin 决定,并且会发生重叠,具体表现为同正取最大的,同负取绝对值最大的,一正一负,相加

BFC 是页面中一个独立的隔离容器,内部的子元素不会影响到外部的元素。

外边距合并

所谓外边距合并,指的是margin 合并,MDN是这样定义的 块的顶部外边距和底部外边距有时被组合(折叠)为单个外边距,其大小是组合到其中的最大外边距,这种行为称为外边距合并。

2. IFC

什么是IFC

既然块级元素会触发BFC,那么内联元素会触发的则是IFC IFC 只有在一个块元素中仅包含内联级别元素时才会生成

IFC特性

  • 内部的box 会在水平方向排布
  • 这些box 之间的水平方向的margin,boder,padding 都有效
  • Box垂直对齐方式:以它们的底部、顶部对齐,或以它们里面的文本的基线(baseline)对齐(默认,文本与图片对其),例:line-heigth与vertical-align。

image.png

3. BFC 与 IFC 区别

  • BFC 是块级格式上下文 box在常规流中竖着排列

  • IFC 是行内格式上下文 box在常规流中横着排列,水平的间距由 margin,padding,border 决定

11 Flex

介绍 Flex 布局

在网页开发中,"Flex" 通常指的是 CSS 弹性盒子布局 (CSS Flexible Box Layout) ,我们通常简称它为 Flexbox这是一种一维的布局系统,旨在更轻松高效地在容器中分配项目空间并对其进行对齐,特别适用于构建响应式和复杂的网页布局。

在 Flexbox 出现之前,实现某些布局效果(比如让一个元素在父容器中垂直和水平居中,或者创建能动态调整大小的响应式网格)往往需要复杂的浮动、定位或基于表格的布局。Flexbox 极大地简化了这些挑战。

基本概念

Flex容器与Flex项目

  • Flex容器:设置display: flex的元素
  • Flex项目:Flex容器内的直接子元素

主轴与交叉轴

  • 主轴(main axis) :Flex项目的默认排列方向
  • 交叉轴(cross axis) :垂直于主轴的方向

容器属性

1. display

.container {
  display: flex; /* 块级flex容器 */
  display: inline-flex; /* 行内flex容器 */
}

2. flex-direction

定义主轴方向:

.container {
  flex-direction: row; /* 默认值,水平从左到右 */
  flex-direction: row-reverse; /* 水平从右到左 */
  flex-direction: column; /* 垂直从上到下 */
  flex-direction: column-reverse; /* 垂直从下到上 */
}

3. flex-wrap

控制是否换行:

.container {
  flex-wrap: nowrap; /* 默认不换行 */
  flex-wrap: wrap; /* 换行 */
  flex-wrap: wrap-reverse; /* 反向换行 */
}

4. justify-content

主轴对齐方式:

.container {
  justify-content: flex-start; /* 默认值,起始对齐 */
  justify-content: flex-end; /* 末尾对齐 */
  justify-content: center; /* 居中对齐 */
  justify-content: space-between; /* 两端对齐 */
  justify-content: space-around; /* 均匀分布 */
  justify-content: space-evenly; /* 完全均匀分布 */
}

5. align-items

交叉轴对齐方式:

.container {
  align-items: stretch; /* 默认值,拉伸填满 */
  align-items: flex-start; /* 起始对齐 */
  align-items: flex-end; /* 末尾对齐 */
  align-items: center; /* 居中对齐 */
  align-items: baseline; /* 基线对齐 */
}

6. align-content

多行内容在交叉轴的对齐方式:

.container {
  align-content: stretch; /* 默认值 */
  align-content: flex-start;
  align-content: flex-end;
  align-content: center;
  align-content: space-between;
  align-content: space-around;
}

项目属性

1. order

控制项目排列顺序:

.item {
  order: 0; /* 默认值,数值越小越靠前 */
}

2. flex-grow

定义项目的放大比例:

.item {
  flex-grow: 0; /* 默认不放大 */
}

3. flex-shrink

定义项目的缩小比例:

.item {
  flex-shrink: 1; /* 默认可缩小 */
}

4. flex-basis

定义项目在分配多余空间前的初始大小:

.item {
  flex-basis: auto; /* 默认值 */
  flex-basis: 200px;
}

5. flex

flex-growflex-shrinkflex-basis的简写:

.item {
  flex: none; /* 0 0 auto */
  flex: auto; /* 1 1 auto */
  flex: 1; /* 1 1 0% */
}

6. align-self

单个项目的交叉轴对齐方式:

.item {
  align-self: auto; /* 继承align-items */
  align-self: flex-start;
  align-self: flex-end;
  align-self: center;
  align-self: baseline;
  align-self: stretch;
}

实用示例

水平垂直居中

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

等宽三栏布局

.container {
  display: flex;
}
.item {
  flex: 1;
}

响应式导航栏

.nav {
  display: flex;
  flex-wrap: wrap;
}
.nav-item {
  flex: 1 0 200px;
}

flex是什么属性的缩写

弹性盒布局,CSS3 的新属性,用于方便布局

CSS3 弹性盒( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式。

引入弹性盒布局模型的目的是提供一种更加有效的方式来对一个容器中的子元素进行排列、对齐和分配空白空间。 flex属性是 flex-grow、flex-shrink、flex-basis三个属性的缩写。

flex 主轴空间分配原则 先根据项目flex-basis分配项目主轴空间,然后根据 flex-grow flex-shrink 放大缩小 按比例分配剩余空间。

推荐使用此简写属性,而不是单独写这三个属性。

flex-grow:定义项目的的放大比例;

  • 默认为0,即 即使存在剩余空间,也不会放大;
  • 所有项目的flex-grow为1:等分剩余空间(自动放大占位);
  • flex-grow为n的项目,占据的空间(放大的比例)是flex-grow为1的n倍。

flex-shrink:定义项目的缩小比例;

  • 默认为1,即 如果空间不足,该项目将缩小;
  • 所有项目的flex-shrink为1:当空间不足时,缩小的比例相同;
  • flex-shrink为0:空间不足时,该项目不会缩小;
  • flex-shrink为n的项目,空间不足时缩小的比例是flex-shrink为1的n倍。

flex-basis: 定义在分配多余空间之前,项目占据的主轴空间(main size),浏览器根据此属性计算主轴是否有多余空间,

  • 默认值为auto,即 项目原本大小;
  • 设置后项目将占据固定空间。

flex属性值简写的含义

所以flex属性的默认值为:0 1 auto (不放大会缩小) flex为none:0 0 auto (不放大也不缩小) flex为auto:1 1 auto (放大且缩小)

flex为一个非负数字n:该数字为flex-grow的值,

   flex:n;= flex-grow:n;
             flex-shrink:1;
             flex-basis:0%;

flex为两个非负数字n1,n2: 分别为flex-grow和flex-shrink的值,

   flex:n1 n2; = flex-grow:n1;
                 flex-shrink:n2;
                 flex-basis:0%;

flex为一个长度或百分比L:视为flex-basis的值,

   flex: L; =  flex-grow:1;
               flex-shrink:1;
               flex-basis:L;

flex为一个非负数字n和一个长度或百分比L:分别为flex-grow和flex-basis的值,

   flex:n L;= flex-grow:n;
               flex-shrink:1;
               flex-basis:L;

可以发现,flex-grow和flex-shrink在flex属性中不规定值则为1,flex-basis为0%

到这里我已经解决我的问题啦,flex:1即为flex-grow:1,经常用作自适应布局,将父容器的display:flex,侧边栏大小固定后,将内容区flex:1,内容区则会自动放大占满剩余空间。

项目flex和width同时使用

在Flexbox布局中,当flex项目同时设置flexwidth属性时,它们会按照特定的优先级规则共同决定元素的最终尺寸。以下是详细的行为分析:

核心原则

  1. flex优先级高于width:当flex容器有剩余空间或空间不足时,flex属性会覆盖width的设置
  2. width作为基础参考width会作为flex计算的初始参考值,但最终尺寸可能被flex属性调整

具体行为分析

情况1:flex: none + width
.item {
  flex: none; /* 等价于 flex: 0 0 auto */
  width: 200px;
}
  • 行为:元素固定为200px宽度,不伸缩
  • 解释flex: none表示元素既不能放大也不能缩小,此时width值会被严格遵守
情况2:flex: auto + width
.item {
  flex: auto; /* 等价于 flex: 1 1 auto */
  width: 200px;
}
  • 行为

    • 当容器有剩余空间时:元素会从200px基础宽度开始分配剩余空间
    • 当空间不足时:元素可以从200px缩小
  • 解释:width作为初始尺寸,但会根据flex规则调整

情况3:flex: 1 + width
.item {
  flex: 1; /* 等价于 flex: 1 1 0% */
  width: 200px;
}
  • 行为

    • 元素会忽略width设置,完全参与flex分配
    • 最终宽度 = (容器宽度 - 其他固定尺寸项目) × flex-grow比例
  • 解释flex-basis: 0%会使width失效

情况4:自定义flex + width
.item {
  flex: 1 0 200px;
  width: 300px;
}
  • 行为

    • flex-basis: 200px会覆盖width: 300px
    • 元素最小宽度200px,可以放大但不会缩小

实际应用建议

  1. 需要固定宽度时

    .sidebar {
      flex: 0 0 250px; /* 不伸缩,固定250px */
    }
    
  2. 需要弹性但保留最小宽度时

    .content {
      flex: 1;
      min-width: 300px; /* 比width更安全的选择 */
    }
    
  3. 优先使用flex-basis代替width

    /* 优于 width + flex 的组合 */
    .item {
      flex: 1 0 200px;
    }
    

为什么width可能失效?

flex-basis不是auto时,它会替代width成为元素的初始尺寸参考。这是Flexbox规范的设计:

  1. 计算顺序:

    • 先应用flex-basis确定初始尺寸
    • 再根据剩余空间应用flex-grow/flex-shrink
    • 最后应用min-width/max-width约束
  2. flex-basis的auto值会回退到width,但其他值会覆盖width

最佳实践总结

  1. 避免混用:尽量不要同时使用width和flex,优先使用flex-basis

  2. 需要约束时:使用min-width/max-width而非width

  3. 明确意图

    • 固定尺寸 → flex: 0 0 <尺寸>
    • 弹性尺寸 → flex: 1 或 flex: <比例>
    • 弹性但有基础尺寸 → flex: 1 1 <基础尺寸>

12 Float

文档流:

  指盒子按照html标签编写的顺序依次从上到下,从左到右排列,块元素占一行,行内元素在一行之内从左到右排列,先写的先排,后写的后排,每个盒子都占据自己的位置.  
  

基本概念

Float 属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它。

常用值:

  • left - 元素向左浮动
  • right - 元素向右浮动
  • none - 默认值,不浮动
  • inherit - 继承父元素的浮动属性

特性

  1. 脱离文档流:浮动元素会脱离普通文档流,但仍会影响布局(比如高度坍塌)
  2. 环绕特性:内联内容会环绕浮动元素
  3. 块级格式化上下文:浮动元素会创建一个新的 BFC
  4. 宽度收缩:浮动元素如果没有设置宽度,会收缩到内容的宽度

清除浮动的方法

  • clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式:{clear:both;height:0;overflow:hidden;}
  • 给浮动元素父级设置高度
  • 父级添加overflow:hidden 清除浮动方法
  • 父级同时浮动(需要给父级同级元素添加浮动)
  • 父级设置成inline-block,其margin: 0 auto居中方式失效
  • 万能清除法 after伪类 清浮动(现在主流方法,推荐使用)
.float_div:after{
  content:".";
  display:block;
  height:0;
  visibility:hidden;
  clear:both;
  overflow:hidden;
}
.float_div{
  zoom:1
}

Float 的常见问题及解决方案

1. 高度塌陷(父元素无法包含浮动子元素)

解决方案

  • 清除浮动(clearfix)
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}
  • 使用 BFC
.parent {
  overflow: auto; /* 或 hidden */
}

2. 相邻元素布局混乱

解决方案

  • 使用 clear 属性:
.footer {
  clear: both;
}

3. 浮动元素超出容器

解决方案

  • 限制容器宽度
  • 使用 overflow: hidden 或 auto

13 Position

什么定位,是否脱离文档流,占不占空间,层叠

  • static:HTML 元素的默认值,即没有定位,无特殊定位,对象遵循正常文档流。top,right,bottom,left等属性不会被应用。
  • relative:生成相对定位的元素,相对于其正常位置进行定位。对象遵循正常文档流,但将依据top,right,bottom,left等属性在正常文档流中偏移位置。而其层叠通过z-index属性定义。相对定位元素的定位是相对其正常位置。相对定位元素经常被用来作为绝对定位元素的容器块。移动相对定位元素,但它原本所占的空间不会改变。
  • absolute:生成绝对定位的元素,相对于 static 定位以外的第一个定位父元素进行定位。对象脱离正常文档流,使用top,right,bottom,left等属性进行绝对定位。而其层叠通过z-index属性定义。绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于<html>,absolute 定位使元素的位置与文档流无关,因此不占据空间。
  • fixed:生成固定定位的元素,相对于浏览器窗口进行定位。对象脱离正常文档流,使用top,right,bottom,left等属性以窗口为参考点进行定位,当出现滚动条时,对象不会随着滚动。而其层叠通过z-index属性定义。
  • sticky:具体是类似 relative 和 fixed,在 viewport 视口滚动到阈值之前应用 relative,滚动到阈值之后应用 fixed 布局,由 top 决定。

14 布局

1. 两列布局

左position,右margin-left

<style>
  div {
    height: 500px;
  }

  .aside {
    width: 300px;
    position: absolute;    
    background: yellow;
  }

  .main {
    background: aqua;
    margin-left: 300px;
  }
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>

左float,右margin-left(右边自适应)

<style>
  div {
    height: 500px;
  }

  .aside {
    width: 300px;
    float: left;
    background: yellow;
  }

  .main {
    background: aqua;
    margin-left: 300px;
  }
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>

左float+BFC

<style>
  div {
    height: 500px;
  }

  .aside {
    width: 300px;
    float: left;
    background: yellow;
  }

  .main {
    overflow: hidden;
    background: aqua;
  }
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>

Flex

<style>
      /* div {
        height: 500px;
      } */
 
      /* .box {
        overflow: hidden;
      } */
 
      /* .container {
        padding: 0 300px 0 200px;
        border: 1px solid black;
      } */
 
      html,
      body {
        height: 100%;
      }
 
      div {
        height: 100%;
      }
 
      .container {
        display: flex;
      }
 
      .content {
        flex: 1 1;
        order: 2;
        background: #f00;
      }
 
      .left {
        flex: 0 0 200px;
        background: #0f0;
      }
 
      .right {
        flex: 1 1;
        background: #00f;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="left">你好</div>
      <div class="right">我好</div>
    </div>
  </body>

2. 三列布局

position + margin-left + margin-right

 <style>
      div {
        height: 500px;
      }

      .box {
        position: relative;
      }

      .left {
        position: absolute;
        left: 0;
        top: 0;
        width: 200px;
        background: green;
      }

      .right {
        position: absolute;
        right: 0;
        top: 0;
        width: 200px;
        background: red;
      }

      .middle {
        margin-left: 200px;
        margin-right: 200px;
        background: black;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div class="left"></div>
      <div class="middle"></div>
      <div class="right"></div>
    </div>
  </body>

通过 float + margin

<style>
      div {
        height: 500px;
      }

      .left {
        float: left;
        width: 200px;
        height: 200px;
        background: green;
      }

      .right {
        float: right;
        width: 200px;
        height: 200px;
        background: red;
      }

      .middle {
        margin-left: 210px;
        margin-right: 210px;
        background: black;
        height: 200px;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div class="left"></div>
      <div class="right"></div>
      <div class="middle"></div>
    </div>
  </body>

圣杯布局

当margin/padding取百分比的值时,无论是 left/right 还是top/bottom,都是基于父元素的宽度

圣杯布局的关键点就是:父元素左右padding先腾出空间,左右子元素再相对自身定位,去填补这个空白

<style>
        body {
            margin: 0;
            padding: 0;
        }
        .container {
            padding: 0 150px 0 100px;
        }
        .left,
        .middle,
        .right {
            float: left;
        }
        .middle {
            width: 100%;
            height: 100%;
            background: red;
        }
        .left {
            width: 100px;
            height: 100%;
            background: green;
            margin-left: -100%;
            position: relative;
            left: -100px;
        }
        .right {
            width: 150px;
            height: 100%;
            background: blue;
            margin-left: -150px;
            position: relative;
            right: -150px;
        }
    </style>
<body>
    <div class="container">
        <div class="middle">middle</div>
        <div class="left">left</div>
        <div class="right">right</div>
    </div>
</body>

双飞翼布局

双飞翼布局的关键点:多加了个inner层包裹,然后设置左右margin把内容(content)挤到中间显示

<style>
        body {
            margin: 0;
            padding: 0;
        }
        .left,
        .middle,
        .right {
            float: left;
        }
        .inner {
            margin: 0 150px 0 100px;
        }
        .middle {
            width: 100%;
            height: 100%;
            background: red;
        }
        .left {
            width: 100px;
            height: 100%;
            background: green;
            margin-left: -100%;
        }
        .right {
            width: 150px;
            height: 100%;
            background: blue;
            margin-left: -150px;
        }
   </style>
<body>
    <div class="container">
        <div class="middle">
            <div class="inner">middle</div>
        </div>
        <div class="left">left</div>
        <div class="right">right</div>
    </div>
</body>

flex

 <style>
      html,
      body {
        height: 100%;
      }

      div {
        height: 100%;
      }

      .container {
        display: flex;
      }

      .content {
        flex: 1 1;
        order: 2;
        background: #f00;
      }

      .left {
        flex: 0 0 200px;
        order: 1;
        background: #0f0;
      }

      .right {
        flex: 0 0 300px;
        order: 3;
        background: #00f;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="content">hello world</div>
      <div class="left">你好</div>
      <div class="right">王鹏浩</div>
    </div>
  </body>

3. CSS实现自适应正方形、等宽高比矩形

width 设置百分比

<style>
      .outer {
        padding-top: 50%;
        height: 0;
        background: #ccc;
        width: 50%;
        position: relative;
      }
 
      .inner {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        background: blue;
      }
    </style>
  </head>
  <body>
    <div class="outer">
      <div class="inner">hello</div>
    </div>
  </body>

padding 撑高

<style>
      .outer {
        width: 400px;
        height: 600px;
        background: blue;
      }
 
      .inner {
        width: 100%;
        height: 0;
        padding-bottom: 100%;
        background: red;
      }
    </style>
  </head>
  <body>
    <div class="outer">
      <div class="inner"></div>
    </div>
  </body>

如果只是要相对于 body 而言的话,还可以使用 vw 和 vh

    <style>
      .inner {
        width: 1vw;
        height: 1vw;
        background: blue;
      }
    </style>
  </head>
  <body>
    <div class="outer">
      <div class="inner"></div>
    </div>
  </body>

伪元素设置 margin-top: 100%撑高

<style>
      .inner {
        width: 100px;
        overflow: hidden;
        background: blue;
      }
 
      .inner::after {
        content: "";
        margin-top: 100%;
        display: block;
      }
    </style>
  </head>
  <body>
    <div class="outer">
      <div class="inner"></div>
    </div>
  </body>

4. css div 垂直水平居中,并完成 div 高度永远是宽度的一半(宽度可以不指定)

 <style>
    .container {
      position: relative;
      width: 100%;  /* 可以是任意宽度 */
      height: 300px; /* 父容器需要有一定高度 */
      background: #f0f0f0;
    }

    .box {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);

      width: 50%; /* 可以是任意百分比或固定值 */
      padding-bottom: 25%; /* 高度为宽度的一半 (50% / 2) */
      background: #3498db;
    }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="box"></div>
    </div>
  </body>

5. 水平垂直居中

grid

.container {
  display: grid;
  justify-content: center; /* 水平居中 */
  align-content: center;   /* 垂直居中 */
  height: 100vh;
}

或则
.container {
  display: grid;
  place-items: center; /* 同时实现水平和垂直居中 */
  height: 100vh; /* 容器需要有高度 */
}

.item {
  /* 项目会自动居中 */
}

absolute + 负margin

.father {
    position: relative;
}
 
.son {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: -50px;
}

absolute + transform

.father {
    position: relative;
}
 
.son {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

absolute + margin: auto

.father {
    position: relative;
}
 
.son {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    margin: auto;
}

flex

.father {
    display: flex;
    justify-content: center;
    align-items: center;
}

margin+transfrom

.father {
    overflow: hidden;
}
 
.son {
    margin: 50% auto;
    transform: translateY(-50%);
}

table-cell

.father {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
 
.son {
    display: inline-block;
}

inline-block + vertical-align

.father {
    text-align: center;
    line-height: 300px;
}
 
.son {
    display: inline-block;
    vertical-align: middle;
}

15. visibility ,display ,opacity的区别

在CSS中,visibilitydisplay 和 opacity 都可以控制元素的可见性,但它们的行为和影响有显著区别

1. visibility(可见性)

  • 作用:控制元素是否显示,但仍占据布局空间

  • 常用值

    • visible(默认):元素可见。
    • hidden:元素不可见,但保留原有空间(布局不变)。
    • collapse:仅用于表格元素(如<tr><colgroup>),表现类似hidden
  • 特点

    • 隐藏后仍可触发鼠标事件(如:hover)。
    • 无法点击(隐藏元素不响应点击事件)。
    • 不影响子元素:子元素可通过visibility: visible单独显示。

2. display(显示方式)

  • 作用:控制元素的渲染方式布局行为,隐藏时会完全移除布局空间

  • 常用值

    • blockinlineflex等:正常显示。
    • none:元素不渲染,且不占空间,DOM中仍存在。
  • 特点

    • display: none完全移除元素,包括其子元素。
    • 隐藏后不触发任何事件(包括鼠标事件)。
    • 切换display会导致重排(Reflow) ,性能开销较大。

3. opacity(透明度)

  • 作用:控制元素的透明度保留布局空间

  • 取值范围0(完全透明)到1(完全不透明)。

  • 特点

    • 元素仍占据空间,且可触发所有事件(如点击、悬停)。
    • 值为0时元素不可见,但仍存在于布局中
    • 支持动画过渡(适合做淡入淡出效果)。
    • 影响子元素:子元素无法单独设置opacity: 1来覆盖父级的透明度。

三者的核心区别总结

属性是否占空间是否触发事件是否影响子元素是否支持动画性能影响
visibility✅ 保留❌ 不触发❌ 可单独控制❌ 不支持低(无重排)
display❌ 移除❌ 不触发✅ 全部隐藏❌ 不支持高(触发重排)
opacity✅ 保留✅ 可触发✅ 全部透明✅ 支持中(触发重绘)

使用场景建议

  1. 需要保留布局空间

    • 用 visibility: hidden(不触发事件)或 opacity: 0(可触发事件)。
  2. 彻底隐藏元素

    • 用 display: none(优化渲染性能)。
  3. 实现淡入淡出动画

    • 用 opacity + transition
  4. 表格行/列隐藏

    • 用 visibility: collapse(仅表格元素)。

16. css会造成阻塞吗

js执行会阻塞DOM树的解析和渲染,那么css加载会阻塞DOM树的解析和渲染吗?所以,接下来我就来对css加载对DOM树的解析和渲染做一个测试。

利用chrome控制下载的速度 点击(No throttling)=》add 添加网速控制low20

截屏2022-03-11 下午3.11.23.png 截屏2022-03-11 下午3.08.44.png

分析

css加载会阻塞DOM树的解析渲染吗?

用代码说话:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>css阻塞</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
      h1 {
        color: red !important
      }
    </style>
    <script>
      function h () {
        console.log(document.querySelectorAll('h1'))
      }
      setTimeout(h, 0)
    </script>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
  </head>
  <body>
    <h1>这是红色的</h1>
  </body>
</html>

假设: css加载会阻塞DOM树解析和渲染

假设结果: 在bootstrap.css还没加载完之前,下面的内容不会被解析渲染,那么我们一开始看到的应该是白屏,h1不会显示出来。并且此时console.log的结果应该是一个空数组。

实际结果:如下图

css会阻塞DOM树解析?

由上图我们可以看到,当css还没加载完成的时候,h1并没有显示,但是此时控制台输出如下

可以得知,此时DOM树至少已经解析完成到了h1那里,而此时css还没加载完成,也就说明,css并不会阻塞DOM树的解析。

css加载会阻塞DOM树渲染?

由上图,我们也可以看到,当css还没加载出来的时候,页面显示白屏,直到css加载完成之后,红色字体才显示出来,也就是说,下面的内容虽然解析了,但是并没有被渲染出来。所以,css加载会阻塞DOM树渲染。

个人对这种机制的评价

其实我觉得,这可能也是浏览器的一种优化机制。因为你加载css的时候,可能会修改下面DOM节点的样式,如果css加载不阻塞DOM树渲染的话,那么当css加载完之后,DOM树可能又得重新重绘或者回流了,这就造成了一些没有必要的损耗。所以我干脆就先把DOM树的结构先解析完,把可以做的工作做完,然后等你css加载完之后,在根据最终的样式来

css加载会阻塞js运行吗?

​ 由上面的推论,我们可以得出,css加载不会阻塞DOM树解析,但是会阻塞DOM树渲染。那么,css加载会不会阻塞js执行呢?

同样,通过代码来验证.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>css阻塞</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script>
      console.log('before css')
      var startDate = new Date()
    </script>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
  </head>
  <body>
    <h1>这是红色的</h1>
    <script>
      var endDate = new Date()
      console.log('after css')
      console.log('经过了' + (endDate -startDate) + 'ms')
    </script>
  </body>
</html>

假设: css加载会阻塞后面的js运行

预期结果: 在link后面的js代码,应该要在css加载完成后才会运行

实际结果:

由上图我们可以看出,位于css加载语句前的那个js代码先执行了,但是位于css加载语句后面的代码迟迟没有执行,直到css加载完成后,它才执行。这也就说明了,css加载会阻塞后面的js语句的执行。详细结果看下图(css加载用了5600+ms):

结论

  1. css加载不会阻塞DOM树的解析
  2. css加载会阻塞DOM树的渲染
  3. css加载会阻塞后面js语句的执行

因此,为了避免让用户看到长时间的白屏时间我们应该尽可能的提高css加载速度,比如可以使用以下几种方法:

  1. 使用CDN(因为CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间)
  2. 对css进行压缩(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩)
  3. 合理的使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号)
  4. 减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)

17. 单行、多行文本溢出隐藏

  • 单行文本溢出
overflow: hidden;            // 溢出隐藏
text-overflow: ellipsis;      // 溢出用省略号显示
white-space: nowrap;         // 规定段落中的文本不进行换行
  • 多行文本溢出
overflow: hidden;            // 溢出隐藏
text-overflow: ellipsis;     // 溢出用省略号显示
display:-webkit-box;         // 作为弹性伸缩盒子模型显示。
-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列方式:从上到下垂直排列
-webkit-line-clamp:3;        // 显示的行数

注意:由于上面的三个属性都是 CSS3 的属性,不是所有浏览器都可以兼容,所以要在前面加一个-webkit- 来兼容一部分浏览器。

参考资料

字节跳动最爱考的前端面试题:CSS 基础
深入理解BFC
css加载会造成阻塞吗
CSS伪类和为元素