前端面试基础知识总结(二):CSS

层叠样式表 (Cascading Style Sheets,缩写为 CSS),是一种样式表语言,用来描述 HTML 或 XML 文档的呈现。CSS 描述了在屏幕、纸质、音频等其它媒体上的元素应该如何被渲染的问题。

大纲

CSS知识点大纲

CSS 特性:值和单位

长度

px 表示的是 CSS 中的像素,是 CSS 中长度的绝对单位,是设备的相对单位。
设备像素比(DPR) = 设备像素(Device pixels)数 / CSS 像素数;

em、rem 都是 CSS 中的相对长度单位。rem 相对的是 HTML 的根元素 html 的 font-size。em 相对的是当前元素的 font-size。因为当前元素的 font-size 会继承父元素的,如果当前元素未指定 font-size,则相对的是父元素的 font-size。

vw 和 vh 分别是相对于屏幕视口宽度和高度而言的长度单位。1vw = 视口宽度均分成 100 份中 1 份的长度。

CSS 特性:CSS动画

animation

1
animation: name duration timing-function delay iteration-count direction;

animation-name | 规定需要绑定到选择器的 keyframe 名称。

transition

1
transition: property duration timing-function delay;

transition-property | 规定设置过渡效果的 CSS 属性的名称。

requestAnimationFrame

你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行

动画优化

  1. 使用requestAnimationFrame替换setTimeout/setInterval

    requestAnimationFrame是在屏幕刷新后执行,避免掉帧。

  2. CSS硬件加速

    动画卡顿是在移动web开发时经常遇到的问题,解决这个问题一般会用到css3硬件加速。简单来说:通过GPU进行渲染,解放CPU。

    transformopacityfilter可以触发

  3. 针对性优化:特定平台禁用动画

    this.userClient = /Android/i.test(navigator.userAgent);

  4. 使用will-change通知浏览器你打算更改元素的属性,浏览器会在你进行更改之前做最合适的优化。

  5. 尽可能地使用基于css的动画,不仅仅更快,也不会被大量的js计算所阻塞。

布局:文档流

文档流:会把内容按照从左到右、从上到下的顺序进行排列显示。

文档一旦脱流,计算其父节点高度时不会将其高度纳入,脱流节点不占据空间。如何脱离文档流?

  • 浮动元素
  • 绝对定位

布局:块级上下文

块格式化上下文(Block Formatting Context,BFC)是一个作用范围,独立的容器。

  • 容器里面的元素不会在布局上影响到外面的元素。
  • BFC 的区域不会与 float 盒子重叠。
  • 内部的盒子会在垂直方向,一个接一个地放置
  • 计算 BFC 的高度时,浮动元素也参与计算
  • 属于同一个 BFC 的两个相邻盒子的 margin 会发生重叠

如何创建 BFC?

常见的有:

  • 根元素:html
  • 浮动元素:float 属性不为 none
  • 绝对定位元素:position 为 absolute 或 fixed
  • overflow 不为 visible 的元素
  • display 值为 flow-root 的元素
  • 定义成块级的非块级元素:display: inline-block/table-cell/table-caption/flex/inline-flex/grid/inline-grid

应用

  1. 自适应两栏布局:BFC 的区域不会和浮动区域重叠,所以就可以把侧边栏固定宽度且左浮动,而对右侧内容触发 BFC,使得它的宽度自适应该行剩余宽度。
  2. 清除内部浮动:浮动造成的问题就是父元素高度坍塌,所以清除浮动需要解决的问题就是让父元素的高度恢复正常。而用 BFC 清除浮动的原理就是:计算 BFC 的高度时,浮动元素也参与计算。只要触发父元素的 BFC 即可。
  3. 防止垂直 margin 合并:BFC 渲染原理之一:同一个 BFC 下的垂直 margin 会发生合并。所以如果让 2 个元素不在同一个 BFC 中即可阻止垂直 margin 合并。

格式化上下文的分类

  • BFC (Block Formatting Context) 块级格式化上下文;
  • IFC (Inline Formatting Context) 行内格式化上下文;
  • FFC (Flex Formatting Context) 弹性格式化上下文;
  • GFC (Grid Formatting Context) 格栅格式化上下文;

布局:层叠上下文

参考:MDN-层叠上下文

我们假定用户正面向(浏览器)视窗或网页,而 HTML 元素沿着其相对于用户的一条虚构的 z 轴排开,层叠上下文就是对这些 HTML 元素的一个三维构想。众 HTML 元素基于其元素属性按照优先级顺序占据这个空间。

如何比较两个元素的层叠等级?

  1. 先比较两个元素分别所处的层叠上下文的等级
  2. 如果在同一个层叠上下文中,再比较层叠顺序(见下图)
  3. 如果两个元素都在同一个层叠上下文,且层叠顺序相同,则在 HTML 中定义越后面的层叠等级越高。

同一个层叠上下文中的层叠顺序

布局:position 属性

CSSposition属性用于指定一个元素在文档中的定位方式。top,right,bottom 和 left 属性则决定了该元素的最终位置。

  • static:默认值。元素在文档常规流中当前的布局位置。
  • relative:⽣成相对定位的元素,相对于其正常位置进⾏定位。
  • absolute:⽣成绝对定位的元素,相对于static 定位以外的第一个父元素进行定位。
  • fixed:⽣成绝对定位的元素,相对于浏览器窗⼝进⾏定位。
  • sticky:粘性定位,基于浏览器的滚动位置变化,是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。须指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。

常见需求:1px 边框问题

1px 问题指的是:在一些 Retina 屏幕的机型上,移动端页面的 1px 会变得很粗,呈现出不止 1px 的效果。是因为:设备的物理像素 = window.devicePixelRatio * CSS像素

解决方案(以devicePixelRatio = 2为例):

  • 伪元素 + transform 实现:利用伪元素 :after 重做 border ,并用 transform 的 scale 缩小一半
  • viewport 缩放:修改initial-scale等属性
    1
    2
    3
    4
    <meta
    name="viewport"
    content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no"
    />

常见需求:清除浮动

为什么要清除浮动?

因为浮动元素会脱离正常的文档流,并不会占据文档流的位置,易造成父元素高度坍塌的问题。

解决方案:

  1. 父级 div 定义 height
  2. BFC 清除浮动:因为计算 BFC 高度的时候浮动子元素的高度也将计算在内,所以创建 BFC 即可(如父级 div 定义overflow: hidden
  3. 父级 div 定义伪元素:after 和 zoom
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /*
    * For IE 6/7 only
    * Include this rule to trigger hasLayout and contain floats.
    */
    .clearfix {
    *zoom: 1;
    }
    .clearfix::after {
    content: "";
    display: block;
    clear: both;
    }

常见需求:布局方案

参考:1.5 万字 CSS 基础拾遗(核心知识、常见需求)

水平垂直居中

让元素在父元素中呈现出水平垂直居中的形态,无非就 3 种情况:

  1. 单行的文本、inline 或者 inline-block 元素;
    1
    2
    3
    4
    5
    .single-line {
    text-align: center;
    height: 100px;
    line-height: 100px;
    }
  2. 固定宽高的块级盒子
    • 绝对定位(absolute + calc)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      .parent {
      position: relative;
      }
      .child {
      position: absolute;
      width: 100px;
      height: 100px;
      top: calc(50% - 50px);
      left: calc(50% - 50px);
      }
  3. 不固定宽高的块级盒子
    • 绝对定位(absolute + transform)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      .parent {
      position: relative;
      }
      .child {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      }
    • flex 布局
      1
      2
      3
      4
      5
      .parent {
      display: flex;
      justify-content: center;
      align-items: center;
      }
    • table-cell 布局
      1
      2
      3
      4
      5
      6
      7
      8
      .parent {
      display: table-cell;
      vertical-align: middle;
      text-align: center;
      }
      .child {
      display: inline-block;
      }

实现垂直居中:

  • 视口的垂直居中可以使用 margin:50vh auto
  • 使用绝对定位 top:50% 加载负 margin
  • 绝对定位 top 加上 calc
  • 绝对定位 加上 transform
  • 使用 flex 布局

实现水平居中:

  • 父元素使用 text-align:center,子元素为 inline/inline-block
  • 使用 margin:0 auto(对于块级元素,要定义宽度)
  • 使用绝对定位

两栏布局:一边给定宽度,一边自适应

  1. 使用 float,左栏 float:right 右栏 overflow: hidden;(BFC)
  2. 使用定位布局,左栏 position:absolute,右栏 margin-left:200px
  3. 使用 flex 布局,容器 display:flex,左栏定宽,右栏 flex:1
  4. 使用 grid 布局,容器 display:grid,grid-template-columns: 200px auto;

三栏布局:两边顶宽,中间自适应

  1. 圣杯布局
    为了中间div内容不被遮挡,将父元素设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div。可参考:demo
    圣杯布局
  2. 双飞翼布局
    为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在中间div里用margin-left和margin-right为左右两栏div留出位置。可参考:demo
    双飞翼布局
  3. float布局(BFC)
  4. flex布局
  5. grid布局
    1
    2
    3
    4
    .layout{
    display: grid;
    grid-template-columns: 200px auto 200px;
    }

flex布局

对于父元素:

  • flex-direction 主轴方向
  • flex-wrap 排不下是否换行
  • flex-flow flex-direction 和 flex-wrap 的简写形式
  • justify-content 项目在主轴上的对齐方式
    1
    justify-content: flex-start | flex-end | center | space-between |space-around; 
  • align-items 项目在交叉轴上如何对齐
    1
    align-items: flex-start | flex-end | center | baseline | stretch;
  • align-content 多根轴线的对齐方式

对于子元素:

  • flex-grow 定义项目的放大比例,默认值为0,不放大
  • flex-shrink 定义了项目的缩小比例,默认为1,空间不足将缩小
  • flex-basis 分配多余空间之前,项目占据的主轴空间,默认为auto,即项目的本来大小
  • flex flex-grow,flex-shrink和flex-basis的简写,默认值为0 1 auto。后面两个属性可选
  • align-self 允许单个项目有与其他项目不一样的对齐方式
  • order 项目的排列顺序。数值越小,排列越靠前

响应式布局

Responsive design,意在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。

方案:

  1. 媒体查询 + rem (动态控制根元素font-size的大小)
  2. flex弹性布局
  3. 百分比布局,如vw/vh

常见面试题

margin: 0 auto;中auto的取值

想要水平居中某个元素时,可以设置margin: 0 auto;

auto 的取值 :

  • 当父元素的布局方式为 static/relative 且宽高已知时:父元素剩余空间的宽度
  • 当父元素的布局方式为 absolute/fixed 或者 float/inline 或者宽高未知时:0

CSS中的百分比是相对什么?

元素百分比的计算值是通过元素的包含块(containing block)计算得到的。

元素的尺寸及位置,常常会受它的包含块所影响。对于一些属性,例如 width, height, padding, margin,绝对定位元素的偏移值 (比如 position 被设置为 absolute 或 fixed),当我们对其赋予百分比值时,这些值的计算值,就是通过元素的包含块计算得来。
MDN: containing block

  • 要计算height, topbottom 中的百分值,是通过包含块的height的值。如果包含块的 height 值会根据它的内容变化,而且包含块的 position 属性的值被赋予 relative 或 static ,那么,这些值的计算值为auto
  • 要计算width, left, right, padding, margin 这些属性由包含块的width属性的值来计算它的百分值。

参考

  1. 1.5 万字 CSS 基础拾遗(核心知识、常见需求)
  2. MDN - 学习 CSS 第一步

TODO:

  • 圣杯和双飞翼布局写个demo
  • CSS动画的demo