基础

2021/03/08

# 盒模型

CSS 盒模型描述了以文档树中的元素而生成的矩形框,并根据排版模式进行布局。每个盒子都有一个内容区域(例如文本,图像等)以及周围可选的 padding、border 和 margin 区域。

CSS 盒模型负责计算:

  • 块级元素占用多少空间
  • 边框是否重叠,边距是否合并
  • 盒子的尺寸

盒模型有以下规则:

  • 块级元素的大小由 width、height、padding、border 和 margin 决定

  • 如果没有指定 height,则块级元素的高度等于其包含子元素的内容高度加上 padding(除非有浮动元素,请参阅下文)

  • 如果没有指定 width,则非浮动块级元素的宽度等于其父元素的宽度减去父元素的 padding

  • 元素的 height 是由内容的 height 来计算的

  • 元素的 width 是由内容的 width 来计算的。

  • 默认情况下,padding 和 border 不是元素 width 和 height 的组成部分

* { box-sizing: border-box; } 会产生怎样的效果?

  • 元素默认应用了 box-sizing: content-box,元素的宽高只会决定内容(content)的大小

  • box-sizing: border-box 改变计算元素 widthheight 的方式,borderpadding 的大小也将计算在内

  • 元素的 height = 内容(content)的高度 + 垂直方向的 padding + 垂直方向 border 的宽度

  • 元素的 width = 内容(content)的宽度 + 水平方向的 padding + 水平方向 border 的宽度

inline, block, inline-block 有什么区别?

  • inline

    • 大小:取决于内容
    • 定位:与其他内容一起流动,并允许旁边有其他元素
    • 能否设置 widthheight:不能
    • 是否可以使用 vertical-align 对齐:可以
    • 边距(margin)和填充(padding):只有水平方向存在。垂直方向会被忽略。尽管 borderpaddingcontent 周围,但垂直方向上的空间取决于 line-height
    • 浮动(float):表现为一个 block 元素,可以设置垂直边距和填充
  • block

    • 大小:填充其父容器的宽度
    • 定位:从新的一行开始,并且不允许旁边有 HTML 元素(除非是 float
    • 能否设置 widthheight:能
    • 是否可以使用 vertical-align 对齐:不可以
    • 边距(margin)和填充(padding):各个方向都存在
    • 浮动(float):-
  • inline-block

    • 大小:取决于内容
    • 定位:与其他内容一起流动,并允许旁边有其他元素
    • 能否设置 widthheight:能
    • 是否可以使用 vertical-align 对齐:可以
    • 边距(margin)和填充(padding):各个方向都存在
    • 浮动(float):-

static, relative, absolute, fixed, sticky 定位有什么区别?

经过定位的元素,其 position 属性值必然是 relative / absolute / fixed / sticky

  • static: 默认定位属性值。该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, leftz-index 属性无效

  • relative: 该关键字下,元素先放置在未添加定位时的位置,在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)

  • absolute: 不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margin),且不会与其他边距合并

  • fixed: 不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先

  • sticky: 盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: stickytable 元素的效果与 position: relative 相同

# Flex 布局

flex 主要用于一维布局。

flex 容器中存在两条轴,横轴和纵轴,容器中的每个单元称为 flex item。

在容器上可以设置6个属性:flex-direction, flex-wrap, flex-flow, justify-content, align-items, align-content

**注意:**当设置 flex 布局之后,子元素的 float, clear, vertical-align 的属性将会失效。

有六种属性可运用在 item 项目上: order, flex-basis, flex-grow, flex-shrink, flex, align-self

参考资料:

# Grid 布局

Grid 主要用于二维布局。

CSS 网格布局用于将页面分割成数个主要区域,或者用来定义组件内部元素间大小、位置和图层之间的关系。

像表格一样,网格布局让我们能够按行或列来对齐元素。但是,使用 CSS 网格可能还是比 CSS 表格更容易布局。例如,网格容器的子元素可以自己定位,以便它们像 CSS 定位的元素一样,真正的有重叠和层次。

Grid 布局与 Flex 布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。

Flex 布局是轴线布局,只能指定「项目」针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成「行」和「列」,产生单元格,然后指定「项目所在」的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。

容器属性:display: grid;, grid-template-columns, grid-template-rows, grid-column-gap, grid-row-gap, grid-gap, grid-template-areas, grid-auto-flow, justify-items, align-items, justify-content, align-content, grid-auto-columns, grid-auto-rows

项目属性:grid-column-start, grid-column-end, grid-row-start, grid-row-end, grid-area, justify-self, align-self

**注意:**设为网格布局以后,容器子元素(项目)的 floatdisplay: inline-blockdisplay: table-cellvertical-aligncolumn-* 等设置都将失效。

参考资料:

  • (CSS Grid 网格布局教程)[http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html]

# CSS 单位

px, em, rem, vw, vh, vmin, vmax, %

扩展至 rem & vw 移动端适配问题

# CSS 选择器

css 选择符(css 选择器)有哪些?

  1. 标签选择器(如:body, div, p, ul, li)
  2. 类选择器(如:class="head", class="head_logo")
  3. ID选择器(如:id="name", id="name_txt")
  4. 全局选择器(如:* 号)
  5. 组合选择器(如:.head .head_logo, 注意两选择器用空格键分开)
  6. 后代选择器 (如:#head .nav ul li 从父集到子孙集的选择器)
  7. 群组选择器(如:div, span, img { color: red } 即具有相同样式的标签分组显示)
  8. 继承选择器(如:div p,注意两选择器用空格键分开)
  9. 伪类选择器(如:就是链接样式,a 元素的伪类,4种不同的状态:link, visited, active, hover)
  10. 字符串匹配的属性选择符(^, $, * 三种,分别对应开始、结尾、包含)
  11. 子选择器 (如:div > p,带大于号 >)
  12. CSS 相邻兄弟选择器 (如:h1 + p,带加号 +)

CSS 选择器的优先级是如何计算的?

浏览器通过优先级规则,判断元素展示哪些样式。CSS 优先级是由四个级别和各级别的出现次数决定的。四个级别分别为:行内选择符、ID选择符、类别选择符、元素选择符。我们假定以a、b、c、d命名,分别代表以下含义:

  • a. 表示是否使用内联样式(inline style),如果使用,a 为 1,否则为 0
  • b. 表示 ID 选择器的数量
  • c. 表示类选择器、属性选择器和伪类选择器数量之和
  • d. 表示标签(类型)选择器和伪元素选择器之和。

优先级的结果并非通过以上四个值生成一个得分,而是每个值分开比较。a、b、c、d 权重从左到右,依次减小。判断优先级时,从左到右,一一比较,直到比较出最大值,即可停止。所以,如果 b 的值不同,那么 c 和 d 不管多大,都不会对结果产生影响。比如 0, 1, 0, 0 的优先级高于 0, 0, 10, 10

当出现优先级相等的情况时,最晚出现的样式规则会被采纳。如果你在样式表里写了相同的规则(无论是在该文件内部还是其它样式文件中),那么最后出现的(在文件底部的)样式优先级更高,因此会被采纳。

在写样式时,我会使用较低的优先级,这样这些样式可以轻易地覆盖掉。尤其对写 UI 组件的时候更为重要,这样使用者就不需要通过非常复杂的优先级规则或使用 !important 的方式,去覆盖组件的样式了。

总结排序!important > 行内样式 > ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性

参考资料:

  • (CSS 优先级 - MDN)[https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificity]

# BFC 清除浮动

什么是 BFC?

BFC 是 W3C CSS2.1 规范中的一个概念,它决定了元素如何对其子元素进行定位,以及与其它元素的关系和相互作用。

当涉及到可视化布局的时候,BFC 提供了一个环境,HTML 元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。比如浮动元素会形成 BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。这里有点类似一个 BFC 就是一个独立的行政单位的意思。

怎样才能形成 BFC

  • float 的值不为 none
  • overflow 的值不为 visible
  • display 的值为 inline-block, flex, inline-flex, table-cell, table-caption 中的任何一个
  • position 的值不为 relativestatic

BFC 的特点:

  • 不和浮动元素重叠
  • 清除元素内部浮动
  • 嵌套元素 margin 边距折叠问题的解决 按照 BFC 的定义,只有同属于一个 BFC 时,两个元素才有可能发生垂直 margin 的重叠,这个包括相邻元素,嵌套元素,只要他们之间没有阻挡(例如边框,非空内容,padding 等)就会发生 margin 重叠。因此要解决 margin 重叠问题,只要让它们不在同一个 BFC 就行了。

扩展:

  • IFC(Inline formatting contexts) 内联格式上下文 IFC 的 line box(线框)高度由其包含行内元素中最高的实际高度计算而来(不受到竖直方向的 padding/margin 影响)。IFC 中的 line box 一般左右都贴紧整个 IFC,但是会因为 float 元素而扰乱。float 元素会位于 IFC 与 line box 之间,使得 line box 宽度缩短。 同个 IFC 下的多个 line box 高度会不同。IFC 中是不可能有块级元素的,当插入块级元素时(如 span 中插入 div)会产生两个匿名块与 div 分隔开,即产生两个 IFC,每个 IFC 对外表现为块级元素,与 div 垂直排列。那么 IFC 一般有什么用呢? + 水平居中:当一个块要在环境中水平居中时, 设置其为 inline-block 则会在外层产生 IFC,通过 text-align 则可以使其水平居中 + 垂直居中:创建一个 IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align: middle,其他行内元素则可以在此父元素下垂直居中
  • GFC(GrideLayout formatting contexts) 网格布局格式化上下文当为一个元素设置 display 值为 grid 的时候,此元素将会获得一个独立的渲染区域,我们可以通过在网格容器(grid container)上定义「网格定义行」(grid definition rows)和「网格定义列」(grid definition columns)属性,和在网格项目(grid item)上定义网格行(grid row)和网格列(grid columns) 为每一个网格项目(grid item)定义位置和空间。那么 GFC 有什么用呢,和 table 又有什么区别呢? 首先同样是一个二维的表格,但 GridLayout 会有更加丰富的 属性来控制行列,控制对齐以及更为精细的渲染语义和控制。
  • FFC(Flex formatting contexts) 自适应格式上下文 display 值为 flex 或者 inline-flex 的元素将会生成自适应容器(flex container)。Flex Box 由伸缩容器和伸缩项目组成。通过设置元素的 display 属性为 flexinline-flex 可以得到一个伸缩容器。设置为 flex 的容器被渲染为一个块级元素, 而设置为 inline-flex 的容器则渲染为一个行内元素。伸缩容器中的每一个子元 素都是一个伸缩项目。伸缩项目可以是任意数量的。伸缩容器外和伸缩项目内的一切元素都不受影响。简单地说,Flexbox 定义了伸缩容器内伸缩项目该如何布局。

# zindex

CSS 中的 z-index 属性控制重叠元素的垂直叠加顺序。z-index 只能影响 position 值不是 static 的元素。

没有定义 z-index 的值时,元素按照它们出现在 DOM 中的顺序堆叠(层级越低,出现位置越靠上)。非静态定位的元素(及其子元素)将始终覆盖静态定位(static)的元素,而不管 HTML 层次结构如何。

层叠上下文是包含一组图层的元素。在一组层叠上下文中,其子元素的 z-index 值是相对于该父元素而不是 document root 设置的。每个层叠上下文完全独立于它的兄弟元素。如果元素 B 位于元素 A 之上,则即使元素 A 的子元素 C 具有比元素 B 更高的 z-index 值,元素 C 也永远不会在元素 B 之上。

每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父层叠上下文中按顺序进行层叠。少数 CSS 属性会触发一个新的层叠上下文,例如 opacity 小于 1,filter 不是 nonetransform 不是 none

# 常见页面布局

# 响应式设计与自适应设计

响应式设计和自适应设计都以提高不同设备间的用户体验为目标,根据视窗大小、分辨率、使用环境和控制方式等参数进行优化调整。

响应式设计的适应性原则:网站应该凭借一份代码,在各种设备上都有良好的显示和使用效果。响应式网站通过使用媒体查询,自适应栅格和响应式图片,基于多种因素进行变化,创造出优良的用户体验。就像一个球通过膨胀和收缩,来适应不同大小的篮圈。

自适应设计更像是渐进式增强的现代解释。与响应式设计单一地去适配不同,自适应设计通过检测设备和其他特征,从早已定义好的一系列视窗大小和其他特性中,选出最恰当的功能和布局。与使用一个球去穿过各种的篮筐不同,自适应设计允许使用多个球,然后根据不同的篮筐大小,去选择最合适的一个。

# CSS 预处理,后处理

使用 CSS 预处理的优缺点分别是什么?

优点:

  • 提高 CSS 可维护性
  • 易于编写嵌套选择器
  • 引入变量,增添主题功能,可以在不同的项目中共享主题文件
  • 通过混合(Mixins)生成重复的 CSS
  • 可将代码分割成多个文件,方便维护(未使用预处理的 CSS,虽然也可以分割成多个文件,但需要建立多个 HTTP 请求加载这些文件)

缺点:

  • 需要预处理工具
  • 重新编译的时间可能会很慢

对于你使用过的 CSS 预处理,说说喜欢和不喜欢的地方?

喜欢:

  • 绝大部分优点上题以及提过
  • Less 用 JavaScript 实现,与 NodeJS 高度结合

Dislikes:

  • 通过 node-sass 使用 Sass,它用 C ++ 编写的 LibSass 绑定。在 Node 版本切换时,我必须经常重新编译。
  • Less 中,变量名称以 @ 作为前缀,容易与 CSS 关键字混淆,如 @media@import@font-face

# CSS3 新特性

animation 和 transiton 的相关属性 animate 和 translate

# display 取值

none, block, inline, inline-block, table, table-row, table-cell, list-item 等。

# 相邻的两个 inline-block 节点为什么会出现间隔,该如何解决

这个特性的原因可以上述到 SGML(标准通用标记语言) 和 TeX(排版工具),它实际上是一个行内(inline)的问题,它由空格/换行/回车所产生空白符所致。

去除 inline box 元素之间间隙的方法:

  • 干掉元素之间的空格/换行/回车
  • 使用 margin 负值 margin 负值的大小与上下文的字体和文字大小相关。由于外部环境的不确定性及最后一个元素多出的父 margin 值等问题,这个方法不适合大规模使用。
  • 使用 font-size: 0(基本上可以解决大部分浏览器下 inline box 类元素之间间距导致的问题)
  • letter-spacing / word-spacing(在不同浏览器下表现不同,同样不适合大规模使用)

实际应用上,以上四种方法其实都不实用,第一种不方便书写,后几种会导致内容和格式的依赖性较强,违背内容与样式分离的要求。在实际布局中也很少单纯用 inline-block 排版,经常和 float,position, flex 等配合使用

# meta viewport 移动端适配

viewport 是用户网页的可视区域。

手机浏览器是把页面放在一个虚拟的「窗口」(viewport)中,通常这个虚拟的「窗口」(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局),用户可以通过平移和缩放来看网页的不同部分。

一个常用的针对移动网页优化过的页面的 viewport meta 标签大致如下:

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

viewport 属性值:

  • width:控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)
  • height:和 width 相对应,指定高度
  • initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
  • maximum-scale:允许用户缩放到的最大比例
  • minimum-scale:允许用户缩放到的最小比例
  • user-scalable:用户是否可以手动缩放(yes/no

# CSS 实现宽度自适应 100%,宽高 16:9 的比例的矩形

<div class="box">
    <div class="scale">
        <p class="item">这是一个16:9的矩形</p>
    </div>
</div>
.box {
    width: 80%;
}

.scale {
    position: relative;
    width: 100%;
    height: 0;
    padding-bottom: 56.25%;
}

.item {
    width: 100%;
    height: 100%;
    background-color: aquamarine;
    position: absolute;
}

# rem 布局的优缺点

优点:

  • 兼容性强
  • 能够较完美实现弹性布局

缺点:

  • 非标准移动端适配方案,依赖 JS
  • 由于设置了根元素字体的大小,会影响所有没有设置字体大小的元素(可以在 body 上做字体修正解决)
  • 字体大小不能使用 rem,字体的大小和字体宽度,并不成线性关系

参考资料:

# 画三角形

.info-tab {
    position: relative;
}

.info-tab::after {
    content: '';
    border: 4px solid transparent;
    border-top-color: #2c8ac2;
    position: absolute;
    top: 0;
}

# 1像素边框问题

逻辑像素:CSS 像素 物理像素:设备像素

为什么移动端 CSS 里面写了 1px,实际上看起来比 1px 粗?

CSS 1px 实际占用了 2px 物理像素,在多倍屏下就显得粗了。

  1. Flexible 方案
  2. @media (-webkit-min-device-pixel-ratio: 2) {}+0.5px 方案(iOS7 及以下浏览器 0.5px 表现为 0px
  3. border-image 方案
  4. background-image 方案
  5. postcss-write-svg 插件(border-image/background+svg)方案
  6. box-shadow 方案(-webkit-box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);
  7. ::before/::after+transform 方案(transform: scale(0.5)

# 编写高效的 CSS 应该注意什么

首先,浏览器从最右边的选择器,即关键选择器(key selector),向左依次匹配。根据关键选择器,浏览器从 DOM 中筛选出元素,然后向上遍历被选元素的父元素,判断是否匹配。选择器匹配语句链越短,浏览器的匹配速度越快。避免使用标签和通用选择器作为关键选择器,因为它们会匹配大量的元素,浏览器必须要进行大量的工作,去判断这些元素的父元素们是否匹配。

BEM 原则上建议为独立的 CSS 类命名,并且在需要层级关系时,将关系也体现在命名中,这自然会使选择器高效且易于覆盖。

搞清楚哪些 CSS 属性会触发重新布局(reflow)、重绘(repaint)和合成(compositing)。在写样式时,避免触发重新布局的可能。

# 什么情况下,用 translate() 而不用绝对定位?什么时候,情况相反。

translate()transform 的一个值。改变 transformopacity 不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。而改变绝对定位会触发重新布局,进而触发重绘和复合。transform 使浏览器为元素创建一个 GPU 图层,但改变绝对定位会使用到 CPU。因此 translate() 更高效,可以缩短平滑动画的绘制时间。

当使用 translate() 时,元素仍然占据其原始空间(有点像 position:relative),这与改变绝对定位不同。

# 文本超出部分显示省略号

单行:

.ellips {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

多行:

.ellips-multi {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3; /* 最多显示几行 */
    overflow: hidden;
}
  1. 从属关系区别 @import 是 CSS 提供的语法规则,只有导入样式表的作用;link 是 HTML 提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等
  2. 加载顺序区别 加载页面时,link 标签引入的 CSS 被同时加载;@import 引入的 CSS 将在页面加载完毕后被加载
  3. 兼容性区别 @import 是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link 标签作为 HTML 元素,不存在兼容性问题
  4. DOM可控性区别 可以通过 JS 操作 DOM ,插入 link 标签来改变样式;由于 DOM 方法是基于文档的,无法使用 @import 的方式插入样式
  5. 权重区别 link 引入的样式权重大于 @import 引入的样式
上次更新: 2021/5/6 下午4:08:15