# CSS

# 1. CSS的优先级

# 1.1 一般的优先级

  • 内联样式 > 内部样式表 > 外部样式表
  • 内联 > ID选择器 > 类选择器 > 标签选择器

# 1.2 优先级的计算

计算:

  • 内联样式,A=1
  • ID选择器,B+=1
  • 类选择器、属性选择器、伪类,C+=1
  • 标签选择器、伪元素,D+=1

比较规则:

  • 依次求出A、B、C、D的值
  • 从A、B、C、D依次比较,大者胜出。相等则下一位。
  • 全等,则后面的覆盖前面的
  • 特殊情况,!important会覆盖任何其他的声明。甚至可以覆盖内联样式

# 2. 水平居中

image

# 2.1 行内元素

#parent {
  text-align: center;
}

# 2.2 块级元素

#element {
  margin: 0, auto;
}

# 2.3 子元素包含 float-left 属性

#parent {
  width: -moz-fit-content;
  width: -webkit-fit-content;
  width:fit-content;
  margin:0 auto;
}

# 2.4 flex布局

#child {
  display: flex;
  justify-content: center;
}

# 2.5 absolute + transform

#child {
  position:absolute;
  left: 50%;
  transform: translate(-50%, 0);
}

# 2.6 absolute + -margin-left

#child {
  position:absolute;
  width: 固定;
  left: 50%;
  margin-left: -0.5宽度;
}

# 2.7 absolute + left + margin

#child {
  position:absolute;
  width: 固定;
  left: 0;
  right: 0;
  margin: o auto;
}

# 3.垂直居中

# 3.1 单行文本

#child {
  line-height: 父元素高度;
}

# 3.2 行内块级元素

#parent::after, #child {
  display: inline-block;
  vertical-align: middle;
}

#parent::after {
  content: '';
  height: 100%;
}

// vertical-align:middle
// 使元素的中部与父元素的基线加上父元素x-height的一半对齐
// 因此伪元素中部 就要与父元素的基线 + x-height/2 对齐
// 但是伪元素 height:100%,它的中点不能变化
// 只能移动父元素的基线与它对齐
// 因此:父元素的基线 + x-height/2 对齐于 子元素的中线

// 其实要是想达到父元素基线跟中部对齐,也可以用line-height = height
// 但是这样一来,子元素的文字也要对齐的话,也还需要line-height = height

image

# 3.3 元素高度不定

#parent {
  display: table;
}

#child {
  display: table-cell;
  vertical-align:middle;
}

// vertical-align属性只有在父元素为td或者th的时候才会生效,对于其他块级元素不支持

# 3.4 flex

#parent {
  display: flex;
  align-items: center;
}

# 3.5 absolute + transform

#child {
  position: absolute;
  top:50%;
  transform: translateY(-50%); // translate 是向右/下移动多少距离,其百分比是根据自己的宽度和高度
}

# 3.6 absolute + margin-top

#child {
  position: absolute;
  top: 50%;
  height: 固定;
  margin-top: -0.5高度;
}

# 3.7 absolute + top + margin

#child {
  position: absolute;
  height: 固定;
  top: 0;
  bottom: 0;
  margin: auto 0;
}

# 4. 两列自适应布局

# 4.1 左列定宽,右列自适应

# 4.1.1 float + margin

<body>
<div id="left">左列定宽</div>
<div id="right">右列自适应</div>
</body>
#left {
    background-color: #f00;
    float: left;
    width: 100px;
    height: 500px;
}

#right {
    background-color: #0f0;
    height: 500px;
    margin-left: 100px; /*设置间隔,大于等于#left的宽度*/
}

# 4.1.2 float + margin (fix)

<body>
<div id="left">左列定宽</div>
<div id="right-fix">
    <div id="right">右列自适应</div>
</div>
</body>
#left {
    background-color: #f00;
    float: left;
    width: 100px;
    height: 500px;
}

#right-fix {
    float: right;
    width: 100%;
    margin-left: -100px; /*正值大于或等于#left的宽度,才能上移一行*/
}

#right {
    margin-left: 100px; /*大于或等于#left的宽度,才不会遮挡#left*/
    background-color: #0f0;
    height: 500px;
}

# 4.1.3 float + overflow

<body>
<div id="left">左列定宽</div>
<div id="right">右列自适应</div>
</body>
#left {
    background-color: #f00;
    float: left;
    width: 100px;
    height: 500px;
}

#right {
    background-color: #0f0;
    height: 500px;
    overflow: hidden; /* 触发bfc达到自适应 */
    /* overflow 定义当一个元素的内容太大而无法适应 块级格式化上下文 时候该做什么。 */
}

/* 左列浮动,脱离文档流,所以右列无法感知左列,便以为自己占据了一整行 */
/* 通过 overflow: hidden 属性,触发 bfc,同时 bfc 不与浮动元素重叠,所以裁剪到了刚好合适的尺寸 */

# 4.1.4 table

<div id="parent">
    <div id="left">左列定宽</div>
    <div id="right">右列自适应</div>
</div>
#parent {
    width: 100%;
    display: table;
    height: 500px;
}
#left {
    width: 100px;
    background-color: #f00;
}
#right {
  background-color: #0f0;
}
/*利用单元格自动分配宽度*/
#left, #right {
  display: table-cell;
}

# 4.1.5 position:absolute

<body>
<div id="parent">
    <div id="left">左列定宽</div>
    <div id="right">右列自适应</div>
</div>
</body>
#parent {
  position: relative;
}  /*父相*/

#left {
    position: absolute;  /*子绝*/
    top: 0;
    left: 0;
    background-color: #f00;
    width: 100px;
    height: 500px;
}

#right {
    position: absolute;  /*子绝*/
    top: 0;
    left: 100px;  /*值大于等于#left的宽度*/
    right: 0;
    background-color: #0f0;
    height: 500px;
}

# 4.1.6 flex

<body>
<div id="parent">
    <div id="left">左列定宽</div>
    <div id="right">右列自适应</div>
</div>
</body>
#parent {
    width: 100%;
    height: 500px;
    display: flex;
}
#left {
    width: 100px;
    background-color: #f00;
}
#right {
    flex: 1;
    background-color: #0f0;
}

# 4.2 左列自适应,右列定宽

# 4.2.1 padding-left + float + margin

<body>
<div id="parent">
    <div id="left">左列自适应</div>
    <div id="right">右列定宽</div>
</div>
</body>
#parent{
    height: 500px;
    padding-left: 100px;  /*抵消#left的margin-left以达到#parent水平居中*/
}
#left {
    width: 100%;
    height: 500px;
    float: left;
    margin-left: -100px; /*正值等于#right的宽度*/
    background-color: #f00;
}
#right {
    height: 500px;
    width: 100px;
    float: right;
    background-color: #0f0;
}

# 4.2.2 float + overflow(不要求掌握)

<body>
<div id="parent">
    <div id="right">右列定宽</div>
    <div id="left">左列自适应</div>   <!--顺序要换一下-->
</div>
</body>
#left {
    overflow: hidden;  /*触发bfc*/
    height: 500px;
    background-color: #f00;
}
#right {
    margin-left: 10px;  /*margin需要定义在#right中*/
    float: right;
    width: 100px;
    height: 500px;
    background-color: #0f0;
}

# 4.2.3 table

<body>
<div id="parent">
    <div id="left">左列自适应</div>
    <div id="right">右列定宽</div>
</div>
</body>
#parent{
    width: 100%;
    height: 500px;
    display: table;
}
#left {
    background-color: #f00;
    display: table-cell;
}
#right {
    width: 100px;
    background-color: #0f0;
    display: table-cell;
}

# 4.2.4 position:absolute

<body>
<div id="parent">
    <div id="left">左列自适应</div>
    <div id="right">右列定宽</div>
</div>
</body>
#parent{
    position: relative;  /*子绝父相*/
}
#left {
    position: absolute;
    top: 0;
    left: 0;
    right: 100px;  /*大于等于#rigth的宽度*/
    background-color: #f00;
    height: 500px;
}
#right {
    position: absolute;
    top: 0;
    right: 0;
    background-color: #0f0;
    width: 100px;
    height: 500px;
}

# 4.2.5 flex

<body>
<div id="parent">
    <div id="left">左列自适应</div>
    <div id="right">右列定宽</div>
</div>
</body>
#parent{
    height: 500px;
    display: flex;
}
#left {
    flex: 1;
    background-color: #f00;
}
#right {
    width: 100px;
    background-color: #0f0;
}

# 5. 三列布局

# 5.1 两列定宽,一列自适应

# 5.1.1 float + margin

<body>
  <header></header>
  <div id="container">
    <div id="left"></div>
    <div id="center"></div>
    <div id="right"></div>
  </div>
  <footer></footer>
</body>
header {
  height: 60px;
  background-color: #ccc;
}

#container {
  min-width: 800px;
}

#left {
  float: left;
  width: 600px;
  height: 500px;
  background-color: #f80;
}

#center {
  float: left;
  width: 200px;
  height: 500px;
  background-color: #00f;
}

#right {
  height: 500px;
  margin-left: 800px;
  background-color: #f0f;
}

footer {
  height: 60px;
  background-color: #cccccc;
}

# 5.1.2 float + overflow

<body>
  <header></header>
  <div id="container">
    <div id="left"></div>
    <div id="center"></div>
    <div id="right"></div>
  </div>
  <footer></footer>
</body>
header {
  height: 60px;
  background-color: #ccc;
}

#container {
  min-width: 300px;
}

#left {
  float: left;
  width: 100px;
  height: 500px;
  background-color: #ff8000;
}

#center {
  float: left;
  width: 200px;
  height: 500px;
  background-color: #00f;
}

#right {
  height: 500px;
  background-color: #0f0;
  overflow: hidden;
}

footer {
  height: 60px;
  background-color: #cccccc;
}

# 5.1.3 table

<body>
<div id="parent">
    <div id="left">左列定宽</div>
    <div id="center">中间定宽</div>
    <div id="right">右列自适应</div>
</div>
</body>
#parent {
    width: 100%; 
    height: 520px; /*抵消上下间距10*2的高度影响*/
    margin: -10px 0;  /*抵消上下边间距10的位置影响*/
    display: table;
    /*左右两边间距大了一点,子元素改用padding设置盒子间距就没有这个问题*/
    border-spacing: 10px;  /*关键!!!设置间距*/
}
#left {
    display: table-cell;
    width: 100px;
    background-color: #f00;
}
#center {
    display: table-cell;
    width: 200px;
    background-color: #eeff2b;
}
#right {
    display: table-cell;
    background-color: #0f0;
}

# 5.1.4 flex

<body>
<div id="container">
    <div id="left">左列定宽</div>
    <div id="center">中间定宽</div>
    <div id="right">右列自适应</div>
</div>
</body>
#container {
    height: 500px;
    display: flex;
}
#left {
    width: 100px;
    background-color: #f00;
}
#center {
    width: 200px;
    background-color: #eeff2b;
}
#right {
    flex: 1;
    background-color: #0f0;
}

# 5.2 两侧定宽,中间自适应

# 5.2.1 圣杯布局

  • 圣杯布局的缺陷:当main部分的宽小于left部分时就会发生布局混乱。(main<left即会变形)
  • 原因:由于设置了相对定位,所以当left原来的位置和right的位置产生重叠时,由于浮动的原因一行放不下就会换行。
  • 解决方案:可以给body设置min-width = left-width * 2 + right-width
  • 或者:使用双飞翼布局
<body>
  <header></header>
  <div id="container">
    <div id="main">With hands held high in the sky so blue the ocean opens up to swallow you. With hands held high in
      the sky so blue the ocean opens up to swallow you. With hands held high in the sky so blue the ocean opens up to
      swallow you.
    </div>
    <div id="left"></div>
    <div id="right"></div>
  </div>
  <footer></footer>
</body>
body {
  min-width: 700px;
}

header {
  height: 60px;
  background-color: #ccc;
}

#container {
  padding-left: 200px;
  padding-right: 300px;
}

#main {
  width: 100%;
  height: 400px;
  float: left;
  background-color: #ff0;
}

#left {
  float: left;
  width: 200px;
  height: 400px;
  background-color: #ff8000;
  margin-left: -100%;
  position: relative;
  right: 200px;
}

#right {
  float: left;
  width: 300px;
  height: 400px;
  background-color: #00f;
  margin-left: -300px;
  position: relative;
  left: 300px;
}

footer {
  height: 60px;
  background-color: #ccc;
  clear: left;
}

# 5.2.2 双飞翼布局

  • 注意点:不能直接给main添加margin属性,因为我们已经设置了width:100%,再设置margin的话就会超过窗口的宽度
<body>
  <header></header>
  <div id="container">
    <div id="main">
      <div id="main-content">
        With hands held high in the sky so blue the ocean opens up to swallow you. With hands held high in
        the sky so blue the ocean opens up to swallow you. With hands held high in the sky so blue the ocean opens up to
        swallow you.
      </div>
    </div>
    <div id="left"></div>
    <div id="right"></div>
  </div>
  <footer></footer>
</body>
header {
  height: 60px;
  background-color: #ccc;
}

#main {
  float: left;
  width: 100%;
  height: 400px;
  background-color: #ff0;
}

#main-content {
  margin-left: 200px;
  margin-right: 300px;
}

#left {
  float: left;
  width: 200px;
  height: 400px;
  background-color: #ff8000;
  margin-left: -100%;
}

#right {
  float: left;
  width: 300px;
  height: 400px;
  background-color: #00f;
  margin-left: -300px;
}

footer {
  height: 60px;
  background-color: #ccc;
  clear: left;
}

# 6. flex布局

# 6.1 轴

image

  • 主轴默认情况:指向右,当主轴为水平方向时,交叉轴默认为向下
  • 主轴变为垂直方向时,交叉轴变化为向右,无论主轴是向下还是向上

# 6.2 父容器

# 6.2.1 主轴

属性决定主轴的方向:即项目的排列方向
flex-direction: row;  向右
flex-direction: column;	向下
flex-direction: row-reverse;	向左
flex-direction: column-reverse; 向上

# 6.2.2 justify-content

定义如何沿着主轴方向排列子容器。
justify-content: flex-start;	起始端对齐
justify-content: flex-end;		末尾端对齐
justify-content: center;			居中对齐,一堆挤在中间,无空隙

justify-content: space-around;	子容器沿主轴均匀分布,位于首尾两端的子容器到父容器的距离是子容器间距的一半。
justify-content: space-between;	子容器沿主轴均匀分布,位于首尾两端的子容器与父容器相切。

image

# 6.2.3 align-items

设置子容器如何沿交叉轴排列。
align-items: flex-start
align-items: flex-end
align-items: center
align-items: baseline			基线对齐,这里的 baseline 默认是指首行文字
align-items: stretch			子容器沿交叉轴方向的尺寸拉伸至与父容器一致。

image

# 6.2.4 flex-wrap

决定子容器是否换行排列,不但可以顺序换行而且支持逆序换行。
flex-wrap: nowrap;			 不换行
flex-wrap: wrap;					换行
flex-wrap: wrap-reverse		逆序换行,即沿着交叉轴的反方向换行。

# 6.2.5 align-content

定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
align-content: flex-start | flex-end | center | stretch | space-between | space-around

space-between: 与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around: 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch:(默认值),轴线占满整个交叉轴。

image

# 6.3 子容器

# 6.3.1 flex

确定子容器在主轴上如何伸缩。
子容器是有弹性的(flex 即弹性),它们会自动填充剩余空间,子容器的伸缩比例由 flex 属性确定。
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
flex-grow: 0

属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。
flex-shrink: 1

属性定义了在分配多余空间之前,项目占据的主轴空间(main size)
flex-basis: 10px/20em

# 6.3.2 align-self

允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性
align-self: auto | flex-start | flex-end | center | baseline | stretch

# 6.3.3 order

定义项目的排列顺序。数值越小,排列越靠前,默认为0。
order: <integer>;

# 7.响应式布局

# 7.1 什么是响应式布局

响应式布局设计,是指将桌面设备上的网页内容在移动设备上进行优化排版,使用户能够在移动设备上更方便地阅读并操作

自适应网页设计/自响应网页设计(Responsive Web Design)是指网页能自动识别屏幕宽度、并做出相应调整的网页设计。

# 7.2 概念

  1. 像素:

    • 物理像素:只与设备的硬件密度有关,任何设备的物理像素都是固定的。
    • CSS像素:为web开发者提供,在css中使用的一个抽象单位。
  2. 视口(viewport):

    • 布局视口(layout viewport):

      image

    • 视觉视口(visual viewport):

      image

    • 理想视口(ideal viewport):

      “它是对设备来说最理想的布局视口尺寸。显示在理想视口中的网页拥有最理想的浏览和阅读的宽度,用户刚进入页面时不再需要缩放。”

      理想视口是给定设备物理像素的情况下,最佳的“布局视口”。

  3. px与自适应:

    • 每英寸点数 DPI(Dots Per Inch):像素数量/宽度

    • 设备像素比 DPR(Device Pixel Ratio):设备像素和理想视口

      比如,iphone早起设备像素是320,理想视口宽度也是320,所以DPR就是1。后来的视网膜屏,iphone设备像素变成了640,理想窗口不变320,所以DPR也就变成了2。

    • 1 CSS 像素 = 物理像素 / 分辨率

      比如,在pc端的布局视口通常情况下为980px,移动端以iphone6为例,分辨率为375 * 667,也就是说布局视口在理想的情况下为375px。比如现在我们有一个750px * 1134px的视觉稿,那么:

      • PC端:1 CSS像素 = 物理像素/分辨率 = 750 / 980 = 0.76 px
      • iPhone6:1 CSS像素 = 物理像素/分辨率 = 750 / 375 = 2 px

      也就是说在PC端,一个CSS像素可以用0.76个物理像素来表示,而iphone6中 一个CSS像素表示了2个物理像素。此外不同的移动设备分辨率不同,也就是1个CSS像素可以表示的物理像素是不同的,因此如果在css中仅仅通过px作为长度和宽度的单位,造成的结果就是无法通过一套样式,实现各端的自适应。

# 7.3 解决方案

# 7.3.1 媒体查询

给不同的设备配置不同的效果。使用@media媒体查询可以针对不同的媒体类型定义不同的样式,特别是响应式页面,可以针对不同屏幕的大小,编写多套样式,从而达到自适应的效果。

但是媒体查询的缺点也很明显,如果在浏览器大小改变时,需要改变的样式太多,那么多套样式代码会很繁琐。

# 7.3.2 百分比

比如当浏览器的宽度或者高度发生变化时,通过百分比单位,通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果。

百分比的具体分析:

  1. 子元素height和width:相对于子元素的直接父元素的对应元素。
  2. top和bottom、left和right:相对于直接非static定位(默认定位)的父元素的高度和宽度。
  3. padding和margin:上下左右所有padding都是相对于父元素的width。
  4. border-radius:相对于自身的宽度

百分比的缺点:

  1. 计算困难,如果我们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。
  2. 百分比所对应的父元素的属性不同,有的是height有的是width,还有的是自身的width,布局很复杂。

# 7.3.3 自适应场景下的rem

rem:1rem = 浏览器的根元素(HTML元素)的font-size。

默认情况下,html元素的font-size为16px,即1rem = 16px。

区别 em:em是相对于父元素的font-size,即 rem = root em

npm install px2rem-loader
// 进行px到rem的单位转换

缺点:**在响应式布局中,必须通过js来动态控制根元素font-size的大小。**也就是说css样式和js代码有一定的耦合性。且必须将改变font-size的代码放在css样式之前。

# 7.3.4 vw/vh实现自适应

css3中引入的新单位:

  • vw:相对于视窗的宽度,视窗的宽度为100vw。
  • vh:相对于视窗的高度,视窗的高度为100vh。
  • vmin:min(vw,vh)
  • vmax:max(vw,vh)

vw单位与百分比类似,单确有区别,前面我们介绍了百分比单位的换算困难,这里的vw更像"理想的百分比单位"。任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一。

缺点:兼容性问题,绝大多数的浏览器支持vw单位,但是ie9-11不支持vmin和vmax,opera浏览器整体不支持vw单位。

# 8. 浮动清除

# 8.1 clear

<div class="clear"></div>
.clear {
  clear: both;
}

或者给浮动元素后面的元素添加clear属性

# 8.2 overflow

给浮动元素的容器添加

overflow: hidden
或者
overflow: auto
或者
float: left/right

# 8.3 after伪元素

.clearfix:after{
  content: ""; 
  display: block; 
  height: 0; 
  clear: both; 
  visibility: hidden;  
}

.clearfix {
  zoom: 1; 
}

# 9. BFC

# 9.1 前置概念

  • 盒的类型由display属性决定

    • 块盒(block box):

      • 当元素的CSS属性displayblocklist-itemtable时,它是块级元素 block-level;
      • 视觉上呈现为块,竖直排列;
      • 块级盒参与(块格式化上下文);
      • 每个块级元素至少生成一个块级盒,称为主要块级盒(principal block-level box)。一些元素,比如<li>,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。
    • 行内盒(inline box):

      • 当元素的CSS属性display的计算值为inlineinline-blockinline-table时,称它为行内级元素;
      • 视觉上它将内容与其它行内级元素排列为多行;典型的如段落内容,有文本(可以有多种格式譬如着重),或图片,都是行内级元素;
      • 行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文(inline formatting context)。同时参与生成行内格式化上下文的行内级盒称为行内盒(inline boxes)。所有display:inline的非替换元素生成的盒是行内盒;
      • 不参与生成行内格式化上下文的行内级盒称为原子行内级盒(atomic inline-level boxes)。这些盒由可替换行内元素,或 display 值为 inline-blockinline-table 的元素生成,不能拆分成多个盒;
    • 匿名盒(anonymous box):

      • 因为匿名盒没有名字,不能利用选择器来选择它们,所以它们的所有属性都为inherit或初始默认值;

      • <div>
            Some inline text
            <p>followed by a paragraph</p>
            followed by more inline text.
        </div>
        
        <!-- 上面的例子创建了三个盒子,中间的是块盒,上下的两个都是匿名盒 -->
        

# 9.2 BFC

  • 概念:Block Formatting Context(块格式化上下文):用于决定块盒子的布局及浮动相互影响范围的一个区域,它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

  • BFC的创建方法:

    • 根元素或其它包含它的元素;

    • 浮动 (元素的float不为none);

    • 绝对定位元素 (元素的positionabsolutefixed);

    • 行内块inline-blocks(元素的 display: inline-block);

    • 表格单元格(元素的display: table-cell,HTML表格单元格默认属性);

    • overflow的值不为visible的元素;

    • 弹性盒 flex boxes (元素的display: flexinline-flex);

    • /* 常见的几种 */
      .className {
        overflow: hidden/auto;
        float: left/right;
        position: absolute/fixed;
        display: inline-block / flex;
      }
      
  • BFC的范围:

    • 一个BFC包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。
    • 即,一个元素不能同时存在于两个BFC中。
  • BFC特性:

    • BFC内部的盒会在垂直方向一个接一个排列(可以将BFC内部视作一个常规流)
    • 处在同一个BFC中的元素相互影响,可能会发生margin collapse
    • BFC中的每个元素的 margin box 的左边,与容器块 border box 的左边相接触(对于从左往右的格式化,否则相反),即使存在浮动也是如此。
    • BFC就是页面上的一个隔离的独立容器,容器内的元素不会影响到容器外的元素,容器外的元素也不会影响到容器内的元素。
    • 计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算。
    • 浮动盒区域不叠加到BFC上。
  • 使用场景:

    • 避免margin重叠/塌陷(两个相邻box垂直方向的margin重叠,取较大值)
    • 清除内部的浮动:BFC计算高度时要包含浮动元素,避免了高度坍塌
    • 自适应两栏布局:左右栏各自BFC,互不干扰

# 10. 重排和重绘

# 10.1 重排(回流)reflow

  • 概念:当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
  • 会导致回流的操作:
    • 页面首次渲染
    • 浏览器窗口大小发生改变
    • 元素尺寸或位置发生改变
    • 元素内容变化(文字数量或图片大小等等)
    • 元素字体大小变化
    • 添加或者删除可见DOM元素
    • 激活CSS伪类(例如::hover
    • 查询某些属性或调用某些方法

# 10.2 重绘 repainted

  • 概念:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:colorbackground-colorvisibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

# 10.3 浏览器优化机制

  • 浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。

  • 但是,当你访问以下属性或方法时,浏览器会立刻清空队列:

    • clientWidthclientHeightclientTopclientLeft
    • offsetWidthoffsetHeightoffsetTopoffsetLeft
    • scrollWidthscrollHeightscrollTopscrollLeft
    • widthheight
    • getComputedStyle()
    • getBoundingClientRect()

    因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。

# 10.4 如何避免

  • CSS:

    • 避免使用table布局。
    • 尽可能在DOM树的最末端改变class
    • 避免设置多层内联样式。
    • 将动画效果应用到position属性为absolutefixed的元素上。
    • 避免使用CSS表达式(例如:calc())。
  • JavaScript:

    • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。

    • 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。

    • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

# 11. 隐藏

1.visibility=hidden
// 不会改变页面布局,可以触发绑定的事件(eg.click)

2.opacity=0
// 不会改变页面布局,不会触发该元素已经绑定的事件

3.display:none
// 会改变布局,不会触发事件

# 12. 盒模型

# 12.1 W3C盒模型

widthheight指的是内容区域的宽度和高度。

image

# 12.2 IE盒模型

widthheight指的是内容区域 + border+ padding的宽度和高度。

image

# 13. 水平垂直居中

# 13.1 行内 / 行内块级 / 图片

#parent {
  height: 150px;
  line-height: 150px;
  text-align: center;
  font-size: 0;        /*消除幽灵空白节点的bug*/
}

#child {
  /* display: inline-block; */ /*块级元素需要变为行内块级元素*/
  vertical-align: middle;
}

# 13.2 table-cell

#parent {
  height: 100px;
  width: 50px;
  display: table-cell;
  vertical-align: middle;
  /* text-align: center */ /* 行内元素才需要修改 */
}

#child {
  width: 100px;
  height: 50px;
}

# 13.3 absolute + translate

#parent {
  position: relative;
}

#child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

# 13.3 absolute + margin

#parent {
  position: relative;
}

#child {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 固定高度
  margin-top: -0.5 * width;
  margin-left: -0.5 * width;
}

# 13.4 absolute + left + margin

#parent {
  position: relative;
}

#child {
  position: absolute;
  width: 100px;
  height: 50px;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
}

# 13.5 flex

#parent {
    display: flex;
}
#child {
    margin: auto;
}

/* 或者 */
#parent {
    display: flex;
    justify-content: center;
    align-items: center;
}

/* 或者 */
#parent {
    display: flex;
    justify-content: center;
}

#child {
    align-self: center;
}

# 14. 清除浮动

# 14.1 概念

  • 浮动:浮动元素会脱离文档流并向左/向右浮动,直到碰到父元素或者另一个浮动元素。
  • 特点:
    • 脱离标准流
    • 内联排列
    • 导致父元素高度坍塌
  • 重要的区别
    • float 是半脱离,在文档流中会占有一定位置, 使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在周围。意思就是,其他的盒子会与float元素的位置重叠,但是其中的文本不会
    • position:absolute 是完全脱离, 对于使用absolute position脱离文档流的元素,其他盒子与其他盒子内的文本都会无视它。也就是说,其他盒子的文本与盒子都会与absolute的块重叠

# 14.2 清除浮动的方法

# 14.2.1 利用clear样式

  • clear:
    • 在浮动的元素的相邻元素设置属性clear
      • 当应用于非浮动块时,它将非浮动块的边框边界移动到所有相关浮动元素外边界的下方。这个非浮动块的垂直外边距会折叠。(测试的时候,这个非浮动块的 margin-top 完全不生效了)
      • 当应用于浮动块时,两个浮动元素的垂直外边距将不会折叠。当应用于浮动元素时,它将元素的外边界移动到所有相关的浮动元素外边框边界的下方。
    • 或者在有浮动元素的父级元素的末尾插入一个没有内容的块级元素div,并且设置以上的 clear 属性(类似见14.2.3)
.idName {
  clear: left/both;
}

# 14.2.2 BFC 清除浮动

  • BFC的特性:
    • BFC会阻止内部与外部的外边距(margin-top、margin-bottom)重叠
    • BFC不会重叠浮动元素(解释:浮动元素有自己的BFC,BFC也有自己的BFC,所以两个BFC不重叠。)
    • BFC计算高度时候包含所有元素,包括浮动元素
  • 给包含浮动元素的父级元素创建BFC:
    • float: left / right
    • display: inline-block / flex / inline-flex
    • overflow: hidden
    • position: absolute / fixed

# 14.2.3 利用伪元素 clearfix

.clear-fix::after {
  content: "";
  display: block;
  clear: both;

  /* 兼容浏览器 */
  height: 0;
  visibility: hidden;
}

/* 兼容IE6~7浏览器 */
.clear-fix {
  *zoom: 1;
}

# 15. margin的负值

  • 非浮动
    • position: static
      • margin-top/margin-left: 元素本身向左/向上移动。
      • margin-bottom/margin-right: 元素本身不移动,元素后面的其他元素会向该元素的方向移动相应的距离,并且覆盖该元素。
    • position: relative
      • margin-top/margin-left: 元素本身向左/向上移动。
      • margin-bottom/margin-right: 元素本身不移动,元素后面的其他元素会向该元素的方向移动相应的距离,但是会被该元素覆盖。
    • position: absolute
      • margin-top/margin-left: 元素本身向左/向上移动。
      • margin-bottom/margin-right: 元素本身不移动,元素后面的其他元素会向该元素的方向移动相应的距离,对后面的元素不影响。(因为已经脱离了文档流)
  • 浮动
    • 如果设置的 margin 的方向与浮动的方向相同:元素会往对应的方向移动对应的距离。
    • 如果设置的 margin 的方向与浮动的方向相反:则元素本身不动,元素之前或者之后的元素会向该元素的方向移动相应的距离。

# 16. display: inline-block 的问题

  • 问题:两个 display: inline-block 元素放在一起时,它们之间会产生一段空白。
  • 原因:元素被当成行内元素排版的时候,元素之间的空白符(空格、回车换行等)都会被浏览器处理,根据CSS中white-space属性的处理方式(默认是normal,合并多余空白),原来HTML代码中的回车换行被转成一个空白符,在字体不为0的情况下,空白符占据一定宽度,所以inline-block的元素之间就出现了空隙。
  • 解决方法:
    • 将子元素标签的结束符和下一个标签的开始符写在同一行或把所有子标签写在同一行
    • 父元素中设置font-size: 0,在子元素上重置正确的font-size
    • 为子元素设置float: left

# 17. CSS百分比的参照

  • 相对于包含块(不一定是父元素)widthpaddingmarginwidthleft/right
  • 相对于包含块的heightheighttop/bottom
  • 相对于自身的width/heightborder-radiustransformtranslatezoom
  • 相对于行高:vertical-align
  • 相对于继承字号:font-size
  • 相对于自身字号:line-height

# 18. 文字超过增加省略号

/* 单行文本 */
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
/* 多行文本 */

.text {
  width: 100px;
  word-wrap:break-word;         /* 内容存在英语或数字时强制换行 */
  overflow: hidden;             /* 隐藏溢出部分 */
  text-overflow: ellipsis;      /* 显示省略符号来代表被隐藏的文本 */
  display: -webkit-box;         /* 将对象作为弹性伸缩盒子模型显示 */
  
  -webkit-box-orient: vertical; /* 设置盒子内排列顺序为纵向 */
  -webkit-line-clamp: 2;        /* 限制块元素显示的文本的行数 */
}

# 19. alt和title属性

  • title作为属性时,用来为元素提供额外说明信息。例如,给超链接标签a添加了title属性,把鼠标移动到该链接上面是,就会显示title的内容,以达到补充说明或者提示的效果。
  • alt属性则是用来指定替换文字,只能用在img、area和input元素中(包括applet元素),用于网页中图片无法正常显示时给用户提供文字说明使其了解图像信息。注意,alt是替代图像作用而不是提供额外说明文字的。

# 20. nth-child和nth-of-type的区别

  • nth-child(an+b):从当前元素的兄弟元素中,按顺序查找,n = 0, 1, 2, ...
  • nth-of-type(an+b):从当前元素的兄弟元素中的该类标签的元素中,按顺序查找,n = 0, 1, 2, ...
  • 区别:这两个都是对某一个标签的元素有效,但是nth-child是从该元素的所有兄弟元素开始计数,nth-of-type是从兄弟元素中的该类元素开始计数,更严格。

# 21. offsetWidth / clientWidth / scrollWidth

  • HTMLElement.offsetWidth = width + padding + border,如果存在竖直方向滚动条(scrollbar),也要计算在内。
  • Element.clientWidth = width + padding,内容可视区的宽度。
  • Element.scrollWidth = width + padding,实际内容的宽度。

# 22. CSS选择器

  • nothing交集选择器:选择器之间没有任何的连接符号。

  • ,并集选择器:求两个的并集。

  • +相邻兄弟选择器:只有符合规则且相邻的兄弟元素才会被选中。

  • ~全兄弟选择器:所有符合规则的兄弟元素都会被选中。

  • >子元素选择器:选择直接子元素,而非隔代元素。

  • 示例辨析:

    /* 选择class=a的元素中的,class=b的元素 */
    .a.b {
      color: green;
    }
    
    /* 选择class=a的元素的子元素中的,class=b的元素 */
    .a .b {
      color: green
    }