Skip to main content

积累的知识点

2009 年一直工作到现在开发和日常学习中得到的经验,已经被淘汰不值得一提的例如 IE hack 就不会再提起了

浏览器怎样解析 CSS 选择器

  • CSS 选择器的解析是从右向左解析的。若从左向右的匹配,发现不符合规则,需要进行回溯,会损失很多性能。
  • 若从右向左匹配,先找到所有的最右节点,对于每一个节点,向上寻找其父节点直到找到根元素或满足条件的匹配规则,则结束这个分支的遍历。
  1. 两种匹配规则的性能差别很大,是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点),而从左向右的匹配规则的性能都浪费在了失败的查找上面。
  2. 而在 CSS 解析完毕后,需要将解析的结果与 DOM Tree 的内容一起进行分析建立一棵 Render Tree,最终用来进行绘图。
  3. 在建立 Render Tree 时(WebKit 中的「Attachment」过程),浏览器就要为每个 DOM Tree 中的元素根据 CSS 的解析结果(Style Rules)来确定生成怎样的 Render Tree

CSS 的盒子模型

  • 相关知识点:

    1. 有两种盒子模型:IE盒模型(border-box)W3C标准盒模型(content-box)
    2. 盒模型:分为内容(content)填充(padding)边界(margin)边框(border)四个部分
  • IE 盒模型和 W3C 标准盒模型的区别:

    1. W3C 标准盒模型:属性 widthheight 只包含内容 content ,不包含 borderpadding
    2. IE 盒模型:属性 widthheight 包含 contentborderpadding ,指的是 content + padding + border
必知必会的盒模型
  1. 在 ie8+浏览器中使用哪个盒模型可以由 box-sizingCSS 新增的属性)控制,默认值为 content-box ,即 W3C标准盒模型
  2. 如果将 box-sizing 设为 border-box 则用的是 IE盒模型
  3. 如果在 ie6,7,8DOCTYPE 缺失会将盒子模型解释为 IE盒子模型
  4. 若在页面中声明了 DOCTYPE类型 ,所有的浏览器都会把盒模型解释为 W3C盒模型
  • 盒模型都是由四个部分组成的
  • margin 外边距
  • border 边框
  • padding 内边距
  • content 内容
tip
  1. 标准盒模型IE盒模型 的区别在于设置 widthheight 时,所对应的范围不同。
  2. 标准盒模型widthheight 属性的范围只包含了 content
  3. IE盒模型widthheight 属性的范围包含了 borderpaddingcontent
  4. 我们可以通过修改元素的 box-sizing 属性来改变元素的盒模型。

CSS 选择器

  1. id 选择器
#block {
color: red;
}
  1. 类选择器
#block__element--info {
color: gray;
}
  1. 标签选择器
div,
h1,
p {
padding: 0;
}
  1. 后代选择器
div span {
color: #fff;
}
  1. 相邻后代选择器(子)选择器
ul > li {
color: red;
}
  1. 兄弟选择器
li ~ a {
color: red;
}
  1. 相邻兄弟选择器
li + a {
color: red;
}
  1. 属性选择器
a[rel="external"] {
color: red;
}
  1. 伪类选择器
a:hover,
li:nth-child {
color: red;
}
  1. 伪元素选择器
a::after {
content: "";
display: block;
clear: both;
}
  1. 通配符选择器
* {
margin: 0;
padding: 0;
list-style: none;
}
  • CSS 选择器优先级 降序排列

    选择器说明
    !important加在样式属性值后,权重值为 10000
    内联样式style=””,权重值为 1000
    ID 选择器#content,权重值为 100
    类,伪类和属性选择器class="content"、:hover 权重值为 10
    标签选择器和伪元素选择器div、p、:before 权重值为 1
    通用选择器(*)、子选择器(>)、相邻选择器(+)、同胞选择器(~)权重值为 0
    继承(Inherited)权重值最低级 只要有人任意其他的选择器都会覆盖(细节)

::before:after 中 双冒号 和 单冒号 有什么区别?

  • 按照标准的写法:
    • 单冒号(:)用于 CSS3 伪类。
    • 双冒号(::)用于 CSS3 伪元素。

双冒号是在当前规范中引入的,用于区分伪类和伪元素。不过浏览器需要同时支持旧的已经存在的伪元素写法,比如:first-line、:first-letter、:before、:after 等。

想让插入的内容出现在其它内容前,使用 ::before ,否则使用 ::after

在代码顺序上: ::after 生成的内容也比 ::before 生成的内容靠后。

如果按堆栈视角,::after 生成的内容会在 ::before 生成的内容之上。

伪类与伪元素的区别

CSS 引入 伪类伪元素 概念是为了格式化文档树以外的信息。也就是说,伪类伪元素 是用来修饰不在文档树中的部分,比如,一句话中的第一个字母,或者是列表中的第一个元素。

  • 伪类 用于当已有的元素处于某个状态时,为其添加对应的样式,这个状态是根据用户行为而动态变化的。 比如说,当用户悬停在指定的元素时,我们可以通过 :hover 来描述这个元素的状态。

  • 伪元素 伪元素用于创建一些不在文档树中的元素,并为其添加样式。它们允许我们为元素的某些部分设置样式。比如说,我们可以通过 ::before 来在一个元素前增加一些文本,并为这些文本添加样式。 虽然用户可以看到这些文本,但是这些文本实际上不在文档树中,说白了伪元素内的内容不出现在 DOM 里面, 它属于 CSS 的内容。

ACE 对 伪元素符号的理解以及查的 MDN文献

有时你会发现伪元素使用了两个冒号(::)而不是一个冒号(:)。

这是 CSS3 的一部分,并尝试区分伪类和伪元素。大多数浏览器都支持这两个值。按照规则应该使用(::)而不是(:),从而区分伪类和伪元素。

但是,由于在旧版本的 W3C 规范并未对此进行特别区分,因此目前绝大多数的浏览器都支持使用这两种方式表示伪元素。

  • 伪元素文献

    选择器含义CSS 版本
    ::first-letter选择指定元素的第一个单词1
    ::first-line选择指定元素的第一行1
    ::after在指定元素的内容前面插入内容2
    ::before在指定元素的内容后面插入内容2
    ::selection选择指定元素中被用户选中的内容3
  • 伪类文献

    选择器含义CSS 版本
    :active选择正在被激活的元素1
    :hover选择被鼠标悬浮着元素1
    :link选择未被访问的元素1
    :visited选择已被访问的元素1
    :first-child选择满足是其父元素的第一个子元素的元素2
    :lang选择带有指定 lang 属性的元素2
    :focus选择拥有键盘输入焦点的元素2
    :enable选择每个已启动的元素3
    :disable选择每个已禁止的元素3
    :checked选择每个被选中的元素3
    :target选择当前的锚点元素3
    :first-of-type选择满足是其父元素的第一个某类型子元素的元素3
    :last-of-type选择满足是其父元素的最后一个某类型子元素的元素3
    :only-of-type选择满足是其父元素的唯一一个某类型子元素的元素3
    :nth-of-type(n)选择满足是其父元素的第 n 个某类型子元素的元素3
    :nth-last-of-type(n)选择满足是其父元素的倒数第 n 个某类型的元素3
    :only-child选择满足是其父元素的唯一一个子元素的元素3
    :last-child选择满足是其父元素的最后一个元素的元素3
    :nth-child(n)选择满足是其父元素的第 n 个子元素的元素3
    :nth-last-child(n)选择满足是其父元素的倒数第 n 个子元素的元素3
    :empty选择满足没有子元素的元素3
    :in-range选择满足值在指定范围内的元素3
    :out-of-range选择值不在指定范围内的元素3
    :invalid选择满足值为无效值的元素3
    :valid选择满足值为有效值的元素3
    :not(selector)选择不满足 selector 的元素3
    :optional选择为可选项的表单元素,即没有“required”属性3
    :read-only选择有"readonly"的表单元素3
    :read-write选择没有"readonly"的表单元素3
    :root选择根元素3

关于伪类 LVHA 的解释

<a></a> 有四种状态:链接访问前、链接访问后、鼠标滑过、激活,分别对应四种伪类 :link:visited:hover:active

css3 的滤镜(filter)

  • 滤镜文献

    Filter描述
    none没有效果
    blur(px)给图像设置高斯模糊。
    brightness(%)给图片应用一种线性乘法,使其看起来更亮或更暗。如果值是 0%,图像会全黑。值是 100%,则图像无变化。其他的值对应线性乘数效果。值超过 100%也是可以的,图像会比原来更亮。如果没有设定值,默认是 1。
    contrast(%)调整图像的对比度。值是 0%的话,图像会全黑。值是 100%,图像不变。值可以超过 100%,意味着会运用更低的对比。若没有设置值,默认是 1。
    drop-shadow(h-shadow v-shadow blur spread color)给图像设置一个阴影效果。阴影是合成在图像下面,可以有模糊度的,可以以特定颜色画出的遮罩图的偏移版本。
    grayscale(%)将图像转换为灰度图像。值定义转换的比例。值为 100%则完全转为灰度图像,值为 0%图像无变化。值在 0%到 100%之间,则是效果的线性乘子。若未设置,值默认是 0;
    opacity(%)转化图像的透明程度。
清明节专属 你懂的 ☞
.html,
body {
filter: url(data:image/svg+xml;utf8,#grayscale); /*兼容IE10、IE11*/
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); /*兼容IE6~9*/
}

flex 布局的常用 api

  1. 父元素属性 | 属性名 | 属性值 | 备注 | display | flex | 定义了一个 flex 容器,它的直接子元素会接受这个 flex 环境 |

    属性名属性值备注
    flex-directionrow, row-reverse, column, column-reverse决定主轴的方向
    flex-wrapnowrap, wrap, wrap-reverse如果一条轴线排不下,如何换行
    flex-flow[flex-direction] , [flex-wrap]是 flex-direction 属性和 flex-wrap 属性的简写形式, 默认值为 row nowrap
    justify-contentflex-start, flex-end, center, space-between, space-around设置或检索弹性盒子元素在主轴(横轴)方向上的对齐方式
    align-itemsflex-start, flex-end, center, baseline, stretch设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式
  2. 子元素属性

    属性名属性值备注
    order[int]默认情况下 flex order 会按照书写顺训呈现, 可以通过 order 属性改变, 数值小的在前面,还可以是负数。
    flex-grow[number]设置或检索弹性盒的扩展比率, 根据弹性盒子元素所设置的扩展因子作为比率来分配剩余空间
    flex-shrink[number]设置或检索弹性盒的收缩比率, 根据弹性盒子元素所设置的收缩因子作为比率来收缩空间
    flex-basis[length], auto设置或检索弹性盒伸缩基准值
    align-selfauto,flex-start,flex-end,center,baseline,stretch设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式, 可以覆盖父容器 align-items 的设置

    flex 属性是 flex-grow,flex-shrink 和 flex-basis 的简写,默认值为 0 1 auto。

Grid

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

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

display:grid 这个属性不兼容 Android 5.0,可以自己写一个 GridLayout 实现网格布局的效果。代码:
import React from "react";
import styled, { css } from "styled-components";
import PropTypes from "prop-types";

const Container = styled.div`
width: 100%;
display: flex;
flex-direction: column;
`;

const LineContainer = styled.div`
width: 100%;
display: flex;
flex-direction: row;
${(props) =>
props.gridRowGap &&
css`
margin-bottom: ${props.gridRowGap}px;
`}
`;

const ItemContainer = styled.div`
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: none;
${(props) =>
props.gridColumnGap &&
css`
margin-right: ${props.gridColumnGap}px;
`}
`;

/**
* 网格布局
* @param {} param0
*/
const GridLayout = ({
gridRowGap,
gridColumnGap,
columns,
datalist,
renderItem,
}) => {
if (!datalist || datalist.length === 0 || columns === 0) {
return <Container></Container>;
}
datalist = datalist.slice(0, datalist.length - 2);
const _length = datalist.length;
var domListOfEachLine = [];
var gridLines = [];

for (var i = 0; i < _length; i++) {
const isLastRow = _length - i > _length % columns ? false : true;
const isLastColumn = i % columns < columns - 1 ? false : true;

if (i % columns === columns - 1) {
//要换行了
gridLines.push(
<ItemContainer gridColumnGap={isLastColumn ? 0 : gridColumnGap}>
{renderItem(datalist[i], i)}
</ItemContainer>
);
domListOfEachLine.push(
<LineContainer key={i} gridRowGap={isLastRow ? 0 : gridRowGap}>
{gridLines}
</LineContainer>
);
gridLines = [];
} else {
gridLines.push(
<ItemContainer gridColumnGap={isLastColumn ? 0 : gridColumnGap}>
{renderItem(datalist[i], i)}
</ItemContainer>
);
}
}
if (gridLines.length !== 0) {
//说明最后一行没填满, 自动填满空的div
const blank_count = columns - gridLines.length;
for (var i = 0; i < blank_count; i++) {
gridLines.push(
<ItemContainer
gridColumnGap={i === blank_count - 1 ? 0 : gridColumnGap}
></ItemContainer>
);
}
domListOfEachLine.push(
<LineContainer key={"last"}>{gridLines}</LineContainer>
);
}
return <Container>{domListOfEachLine}</Container>;
};

GridLayout.propType = {
columns: PropTypes.number,
datalist: PropTypes.array,
renderItem: PropTypes.func,
gridColumnGap: PropTypes.number,
gridRowGap: PropTypes.number,
};

export default GridLayout;

Grid 文献,我也没太深入研究

CSS 中哪些常用属性可以继承?

类型属性
字体系列属性font、font-family、font-weight、font-size、font-style、font-variant、font-stretch、font-size-adjust
文本系列属性text-indent、text-align、text-shadow、line-height、word-spacing、letter-spacing、text-transform、direction、color
表格布局属性caption-side border-collapse empty-cells
列表属性list-style-type、list-style-image、list-style-position、list-style
光标属性cursor
元素可见性visibility
强制继承

当一个属性不是继承属性时,可以使用 inherit 关键字指定一个属性应从父元素继承它的值,inherit 关键字用于显式地指定继承性,可用于任何继承性/非继承性属性。

ACE 的理解

每一个属性在定义中都给出了这个属性是否具有继承性,一个具有继承性的属性会在没有指定值的时候,会使用父元素的同属性的值来作为自己的值。

当一个属性不是继承属性的时候,我们也可以通过将它的值设置为 inherit 来使它从父元素那获取同名的属性值来强制继承。

绝对定位元素与非绝对定位元素

绝对定位元素的宽高百分比是相对于临近的 position 不为 static 的祖先元素的 padding box 来计算的。

非绝对定位元素的宽高百分比则是相对于父元素的 content box 来计算的。

  1. relative 生成相对定位的元素,相对于其元素本身所在正常位置进行定位。

  2. absolute 脱离文档流,生成绝对定位的元素,相对于值不为 static 的第一个父元素的 padding box 进行定位,也可以理解为离自己这一级元素最近的 一级 position 设置为 absolute 或者 relative 的父元素的 padding box 的左上角为原点的。

  3. fixed(老 IE 不支持) 生成绝对定位的元素,相对于浏览器窗口进行定位。

  4. static 默认值。没有定位,元素出现在正常的流中(忽略 topbottomleftrightz-index 声明)。

  5. inherit 规定从父元素继承 position 属性的值。

  6. sticky 元素根据正常文档流进行定位,其余的跟 absolute 一样。

tip

relative 定位的元素,是相对于元素本身的正常位置来进行定位的。

absolute 定位的元素,是相对于它的第一个 position 值不为 static 的祖先元素的 padding box 来进行定位的。 这句话我们可以这样来理解,我们首先需要找到绝对定位元素的一个 position 的值不为 static 的祖先元素,然后相对于这个祖先元 素的 padding box 来定位,也就是说在计算定位距离的时候,padding 的值也要算进去。

关于 absolute 和 sticky 的 🌰
<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}

.element_item--position {
position: relative;
height: 100px;
background-color: green;
overflow: scroll;
}

.sticky {
background-color: rebeccapurple;
position: sticky;
top: 0;
}

.absolute {
background-color: rebeccapurple;
position: absolute;
top: 0;
}
</style>
</head>

<body>
<div class="element_item--position">
<h1>标题</h1>
<p class="sticky">内容</p>

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Enim placeat
quas culpa facilis consequuntur laboriosam quidem, perspiciatis, similique
id sint, modi eaque at. Corrupti quibusdam, a autem laudantium dignissimos
excepturi! Lorem ipsum, dolor sit amet consectetur adipisicing elit. Vero
facere obcaecati assumenda iure excepturi eius, expedita distinctio
sapiente. Quibusdam, illum! Unde fugiat animi vitae pariatur. Dolor
assumenda rerum possimus tenetur. Lorem ipsum, dolor sit amet consectetur
adipisicing elit. Delectus sapiente ratione impedit asperiores. Nesciunt
pariatur esse reiciendis nisi dolor perferendis cupiditate officiis iusto
reprehenderit, optio aliquid totam sunt laboriosam numquam! Lorem ipsum
dolor sit amet consectetur adipisicing elit. Corporis temporibus
voluptates illo reprehenderit veritatis neque ut quisquam facere
asperiores numquam aliquam placeat, aut optio saepe, quis perferendis amet
expedita enim.
</div>

<br />

<div class="element_item--position">
<h1>标题</h1>
<p class="absolute">内容</p>

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Enim placeat
quas culpa facilis consequuntur laboriosam quidem, perspiciatis, similique
id sint, modi eaque at. Corrupti quibusdam, a autem laudantium dignissimos
excepturi! Lorem ipsum, dolor sit amet consectetur adipisicing elit. Vero
facere obcaecati assumenda iure excepturi eius, expedita distinctio
sapiente. Quibusdam, illum! Unde fugiat animi vitae pariatur. Dolor
assumenda rerum possimus tenetur. Lorem ipsum, dolor sit amet consectetur
adipisicing elit. Delectus sapiente ratione impedit asperiores. Nesciunt
pariatur esse reiciendis nisi dolor perferendis cupiditate officiis iusto
reprehenderit, optio aliquid totam sunt laboriosam numquam! Lorem ipsum
dolor sit amet consectetur adipisicing elit. Corporis temporibus
voluptates illo reprehenderit veritatis neque ut quisquam facere
asperiores numquam aliquam placeat, aut optio saepe, quis perferendis amet
expedita enim.
</div>
</body>
</html>

💡 参考 MDN 的文献

BFC 规范(块级格式化上下文:block formatting context)的理解?

块格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视化 CSS 渲染的一部分,是布局过程中生成块级盒子的区域,也是浮动元素与其他元素的交互限定区域。

  • 通俗来讲

    • BFC 是一个独立的布局环境,可以理解为一个容器,在这个容器中按照一定规则进行物品摆放,并且不会影响其它环境中的物品。
    • 如果一个元素符合触发 BFC 的条件,则 BFC 中的元素布局不受外部影响。
  • 创建 BFC

    1. 根元素或包含根元素的元素
    2. 浮动元素 floatleft | rightinherit≠none
    3. 绝对定位元素 positionabsolutefixed
    4. displayinline-block | flex | inline-flex | table-celltable-caption
    5. overflowhidden | autoscroll≠visible
  • 回答: BFC 指的是块级格式化上下文,一个元素形成了 BFC 之后,那么它内部元素产生的布局不会影响到外部元素,外部元素的布局也 不会影响到 BFC 中的内部元素。一个 BFC 就像是一个隔离区域,和其他区域互不影响。

一般来说根元素是一个 BFC 区域,浮动和绝对定位的元素也会形成 BFCdisplay 属性的值为 inline-blockflex 这些 属性时也会创建 BFC 。还有就是元素的 overflow 的值不为 visible 时都会创建 BFC

解决的问题
  1. 去除边距重叠现象
  2. 清除浮动(让父元素的高度包含子浮动元素)
  3. 避免某元素被浮动元素覆盖
  4. 避免元素被自动换行
  • ACE 的理解: Box: CSS 布局的基本单位,Box 是 CSS 布局的对象和基本单位, 直观点来说,就是⼀个⻚⾯是由很多个 Box 组 成的,实际就是说的 CSS 的盒子模型
BFC 布局规则
  • 内部的 Box 会在垂直方向,一个接一个地放置
  • Box 垂直方向的距离由 margin 决定。属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠
  • BFC 的区域不会与 float box 重叠
  • 计算 BFC 的高度时,浮动元素也参与计算高度
  • 元素的类型和 display 属性,决定了这个 Box 的类型。不同类型的 Box 会参与不同的 Formatting Context。

IFC 规范(块级格式化上下文:Inline formatting context)的理解?

IFC 指的是行级格式化上下文,它有这样的一些布局规则:

  1. 行级上下文内部的盒子会在水平方向,一个接一个地放置。
  2. 当一行不够的时候会自动切换到下一行。
  3. 行级上下文的高度由内部最高的内联盒子的高度决定。

CSS 中不同属性设置为百分比%时对应的计算基准

  • 公式:当前元素某 CSS 属性值 = 基准 * 对应的百分比

    CSS属性描述
    positionrelative,absolutetop 和 bottom、left 和 right 基准分别为包含块的 height、width
    positionfixedtop 和 bottom、left 和 right 基准分别为初始包含块(也就是视口)的 height、width,移动设备较为复杂,基准为 Layout viewport 的 height、width
    height,width百分比基准分别为包含块的 height 和 width
    margin,padding百分比元素的 margin 和 padding 设置为百分比时,基准为包含块的 width(易错)
    border-width百分比不支持百分比
    text-indent百分比基准为包含块的 width
    border-radius百分比基准为分别为自身的 height、width
    background-size百分比基准为分别为自身的 height、width
    translateX、translateY百分比基准为分别为自身的 height、width
    line-height百分比基准为自身的 font-size
    font-size百分比基准为父元素字体

display、float、position

  • 如果 display 取值为 none ,那么 positionfloat 都不起作⽤,这种情况下元素不产⽣框。
  • 如果 position 取值为 absolute 或者 fixed ,框就是绝对定位的, float 的计算值为 nonedisplay 根据下⾯的表格进⾏调整。
  • 如果 float 不是 none ,框是浮动的, display 根据下表进⾏调整。
  • 如果 元素是根元素, display 根据下表进⾏调整。
  • 其他情况下 display 的值为指定值。
  • 总结起来:绝对定位、浮动、根元素都需要调整 display

iframe

iframe 是用来在网页中插入第三方页面,早期的页面使用 iframe 主要是用于 导航栏 这种很多页面都相同的部分,大多用在后台管理系统的项目中,这样在切换页面的时候避免重复下载。

  • ACE 认为的优点:
  1. 便于修改,模拟分离,像一些信息管理系统会用到,或者是 微前端
  2. 可以用来加载速度较慢的第三方资源,如广告。
  • 缺点:
  1. iframe 的创建比一般的 DOM 元素慢,慢是肯定的,iframe 就等于是 HTML 的子应用,一个网站引用自己的子应用,也需要等待子应用的加载完毕所以一定会慢,至于有多慢,那得看你应用的大小。
  2. iframe 标签会阻塞页面的的加载,如果页面的 onload 事件不能及时触发,会让用户觉得网页加载很慢,用户体验不好,在 SafariChrome 中可以通过 JS 动态设置 iframesrc 属性来避免阻塞。
  3. iframe 对于 SEO 不友好。
  4. iframe 和主⻚⾯共享连接池,⽽浏览器对相同域的连接有限制,所以会影响⻚⾯的并⾏加载。
ACE 简述微前端

微前端实现的是一个应用集成了多个子应用,这时候就需要考虑到 JSCSS 的互相影响问题,所以微前端框架很重要的一步就是实现 css 隔离、js 隔离, 恰巧 iframe 具有先天优势,它最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决,这是 iframe 可以作为微前端方案的原因。

  • 缺点: 就因为应用间上下文无法被共享,锁的太死了,导致了无论是开发体验还是产品体验都不好。
  1. link 属于 HTML 标签,@importCSS ⽅式。
  2. link 最⼤限度⽀持并⾏下载, @import 过多嵌套导致串⾏下载,出现 FOUC (⽂档样式短暂失效)。
  3. link 可以通过 rel="alternate stylesheet" 指定候选样式。
  4. 页面被加载的时,link 会同时被加载,而 @import 引用的 CSS 会等到页面被加载完再加载。
  5. link 方式的样式的权重 高于 @import 的权重。

什么是 FOUC?如何避免

Flash Of Unstyled Content :⽤户定义样式表加载之前浏览器使⽤默认样式显示⽂档,⽤户样式加载渲染之后再从新显示⽂档,造成⻚⾯闪烁。

  • 解决⽅法:
    • 把样式表放到⽂档的 <head>

响应式设计与自适应

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

  • 响应式设计的适应性原则:
    • 网站应该凭借一份代码,在各种设备上都有良好的显示和使用效果。
    • 响应式网站通过使用媒体查询,自适应栅格和响应式图片,基于多种因素进行变化,创造出优良的用户体验。
响应式的两种方案
@media screen and (max-width: 1920) {
}
<link
rel="stylesheet"
type="text/css"
href="style.css"
media="screen and (min-width:1600px)"
/>
  • 自适应设计的原则:
    • 渐进式增强。
    • 与响应式设计单一地去适配不同,自适应设计通过检测设备和其他特征,从早已定义好的一系列视窗大小和其他特性中,选出最恰当的功能和布局。
tip

bootstrap 台湾css 的栅格布局等布局方案

  1. 网站向服务器请求的时候,会自动带上 cookie 这样增加表头信息量使请求变慢。
  2. 静态文件都放在主域名下,静态文件请求的时候都带有的 cookie 的数据提交给 WebServer ,造成流量资源浪费,所以不如隔离,静态资源存放 CDN
  3. 因为 cookie 有域的限制,因此不能跨域提交请求,所以请求 CDN 域名的时候,请求头中就不会带有 cookie 数据,这样可以降低请求头的大小,降低请求时间,从而达到降低整体请求延时的目的。
  4. 同时这种方式不会将 cookie 传入 WebServer ,也减少了 WebServercookie 的处理分析环节,提高了 WebServerhttp 请求的解析速度。

设备像素、css 像素、设备独立像素、dpr、ppi

  • 设备像素

    • 指的是物理像素,一般手机的分辨率指的就是设备像素,一个设备的设备像素是不可变的。
  • css 像素和设备独立像素是等价的,不管在何种分辨率的设备上,css 像素的大小应该是一致的,css 像素是一个相对单位,它是相 对于设备像素的,一个 css 像素的大小取决于页面缩放程度和 dpr 的大小。

  • dpr(device pixel ratio) 指的是设备像素和设备独立像素的比值,一般的 pc 屏幕,dpr=1。在 iphone4 时,苹果推出了 retina 屏幕,它的 dpr 为 2。屏幕的缩放会改变 dpr 的值。

  • ppi(pixels per inch) 指的是每英寸的物理像素的密度,ppi 越大,屏幕的分辨率越大。

layout viewport、visual viewport 和 ideal viewport

第一个视口是布局视口,在移动端显示网页时,由于移动端的屏幕尺寸比较小,如果网页使用移动端的屏幕尺寸进行布局的话,那么整 个页面的布局都会显示错乱。所以移动端浏览器提供了一个 layout viewport 布局视口的概念,使用这个视口来对页面进行布局展 示,一般 layout viewport 的大小为 980px,因此页面布局不会有太大的变化,我们可以通过拖动和缩放来查看到这个页面。

第二个视口指的是视觉视口,visual viewport 指的是移动设备上我们可见的区域的视口大小,一般为屏幕的分辨率的大小。visu al viewport 和 layout viewport 的关系,就像是我们通过窗户看外面的风景,视觉视口就是窗户,而外面的风景就是布局视口 中的网页内容。

第三个视口是理想视口,由于 layout viewport 一般比 visual viewport 要大,所以想要看到整个页面必须通过拖动和缩放才 能实现。所以又提出了 ideal viewport 的概念,ideal viewport 下用户不用缩放和滚动条就能够查看到整个页面,并且页面在 不同分辨率下显示的内容大小相同。ideal viewport 其实就是通过修改 layout viewport 的大小,让它等于设备的宽度,这个 宽度可以理解为是设备独立像素,因此根据 ideal viewport 设计的页面,在不同分辨率的屏幕下,显示应该相同。

渐进增强和优雅降级

  • 渐进增强:
    • 针对低版本浏览器进⾏构建⻚⾯,保证最基本的功能,然后再针对⾼级浏览器进⾏效果、交互等改进和追加功能达到更好的⽤户体验。
  • 优雅降级:
    • ⼀开始就构建完整的功能,然后再针对低版本浏览器进⾏兼容。
区别

区别:优雅降级是从复杂的现状开始,并试图减少⽤户体验的供给,⽽渐进增强则是从⼀个⾮常基础的,能够起作⽤的版本开始,并不断扩充,以适应未来 环境的需要。降级(功能衰减)意味着往回看;⽽渐进增强则意味着朝前看,同时保证其根基处于安全地带。

CSS sprite

  • 概念:

    • 将多个⼩图⽚拼接到⼀个图⽚中。通过 background-position 和元素尺⼨调节需要显示的背景图案。
  • 优点:

    • 减少 HTTP 请求数,极⼤地提⾼⻚⾯加载速度。
    • 增加图⽚信息重复度,提⾼压缩⽐,减少图⽚⼤⼩。
    • 更换⻛格⽅便,只需在⼀张或⼏张图⽚上修改颜⾊或样式即可实现。
  • 缺点:

    • 图⽚合并麻烦
    • 维护麻烦,修改⼀个图⽚可能需要从新布局整个图⽚,样式。

display: none; 与 visibility: hidden;

它们都能让元素 “隐身”

  • 区别:

    • display:none; 会让元素完全从渲染树中消失,渲染的时候不占据任何空间;
    • visibility: hidden; 不会让元素从渲染树消失,渲染师元素继续占据空间,只是内容不可⻅;
    • display: none; 是⾮继承属性,⼦孙节点消失由于元素从渲染树消失造成,通过修改⼦孙节点属性⽆法显示 ;
    • visibility: hidden; 是继承属性,⼦孙节点消失由于继承了 hidden ,通过设置 visibility: visible; 可以让⼦孙节点显式;
    • 修改常规流中元素的 display 通常会造成⽂档重排。修改 visibility 属性只会造成 本元素的重绘;
    • 读屏器不会读取 display: none; 元素内容;会读取 visibility: hidden; 元素内容;

CSS 实现硬件加速

  • ⼀般触发硬件加速的 CSS 属性有 transformopacityfilter ,为了避免 2D 动画在 开始和结束的时候的 repaint 操作,⼀般使⽤ tranform:translateZ(0)
tip

硬件加速是指通过创建独⽴的复合图层,让 GPU 来渲染这个图层,从⽽提⾼性能。

重绘和重排

  • 重排:

    • 当我们改变了一个元素的尺寸位置属性时,会重新进行样式计算 (computed style) 布局 (layout) 绘制 (paint) 以及后面的所有流程,这种行为成为重排。
  • 重绘:

    • 当改变了某个元素的颜色属性时不会重新触发布局,但还是会触发样式计算和绘制这就是重绘。

我们可以发现重排和重绘都会占用主线程,还有 JS 也会运行在主线程,所以就会出现抢占执行时间的问题,如果你写了一个不断导致重排重绘的动画,浏览器则需要在每一帧都运行样式计算布局和绘制的操作。

  • 原因:

    • 添加或者删除可⻅的 DOM 元素。
    • 元素和字体位置、尺⼨、内容改变。
    • 浏览器⻚⾯初始化。
    • 浏览器窗⼝尺⼨改变,重排⼀定重绘,重绘不⼀定重排。
    • 查询某些属性或调用某些计算方法:offsetWidth、offsetHeight 等,除此之外,当我们调用 getComputedStyle 方法, 或者 IE 里的 currentStyle 时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。
  • 如何优化

    • 我们知道当前页面以每秒 60 帧的刷新率时才不会让用户感觉到页面卡顿,如果在运行动画是还有大量的 JS 任务需要执行,因为布局、绘制和 JS 执行都是在主线程运行的, 当在一帧的时间内布局和绘制结束后,还有剩余时间 JS 就会拿到主线程的使用权,如果 JS 执行时间过长,就会导致在下一帧开始时 JS没有及时归还主线程,导致下一帧动画没有按时渲染, 就会出现页面的卡顿。

    • 第一种优化方式: requestAnimationFrame ,它会在每一帧被调用,通过回调 API 的回调,可以把 JS 运行任务分成一些更小的任务块,在每一帧事件用完前暂停 JS 执行归还主线程, 这样的话在下一帧开始时,主线程就可以按时执行布局和绘制。

    • 第二种优化方式: 栅格化的整个流程不占用主线程,只在合成器线程和栅格线程中运行,这就意味着它无需和 JS 抢占主线程。如果反复进行重绘和重排可能会导致掉帧,这是因为有可能 JS 执行阻塞了主线程, 而 CSS 中有个动画属性 transform, 通过该属性实现的动画不会经过布局和绘制,而是直接运行在合成器线程和栅格线程,不需要经过布局绘制样式计算等操作,所以节省了很多运算事件 (方便实现负责的动画)

  • 减少重绘和重排的⽅法:

    • 使用 transform 替代 top 等位移;
    • 使用 visibility 替换 display: none
    • 不使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。
    • 避免设置多层内联样式,尽量层级扁平。
    • 避免频繁操作样式,避免频繁操作 DOM
    • 防抖节流控制频率;
    • 避免使用 CSS 表达式
    • 避免频繁读取会引发回流/重绘的属性,比如上面的 C、O、S 属性
    • 对于多次重排的元素,如动画,使⽤绝对定位脱离⽂档流,让他的改变不影响到其他元素。
    • 集中改变样式,不要一条一条地修改 DOM的样式。
    • 设置 style 属性改变结点样式的话,每一次设置都会触发一次 reflow
  • <link> 标签不会阻塞 DOM 解析但会阻塞 DOM 渲染

    • 浏览器并行解析生成 DOM treeCSSOM tree,当两者都解析完毕,才会生成 rending,页面才会渲染。
  • <script> 标签会阻塞 DOM 的解析和渲染;

      1. 标签会阻塞 DOM 解析和渲染,但在阻塞同时,其他线程会解析文档的其余部分(预解析),找出并加载需要通过网络加载的其他资源。
      1. 资源可以在并行连接上加载,从而提高总体速度。
      1. 预解析不会修改解析出来的 DOM 树,只会解析外部资源(例如外部脚本、样式表和图片)的引用。
  • 优化:

    • 合理放置脚本位置
    • 预加载 link rel="preload"
    • DNS Prefetch 预解析 rel="dns-prefetch"
    • 优化引入样式文件的大小,提高首屏展示速度。
    • script 延迟脚本加载 defer/async
      • defer
        • 脚本会被延迟到整个页面都解析完毕后再运行。因此设置 defer 属性,相当于告诉浏览器立即下载,但延迟执行。 HTML5 规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于 DOMContentLoaded 事件执行。
      • async
        • 标记为 async 的脚本并不保证按照它们的先后顺序执行。async 比 defer 先执行,没有 defer 的情况下是在 DOMContentLoaded 之后执行, 如果出现标签里带 defer 的情况就是在 DOMContentLoaded 之前执行。
      • 区别
        • 相同点:
          • 加载文件时不阻塞页面渲染
          • 对于 inline 的 script 无效,当 script 标签中间有代码时,两个属性都不会起作用。
          • 使用这两个属性的脚本中不能调用 document.write 方法。
          • 有脚本的 onload 的事件回调。
        • 不同点
          • HTML4.0 中定义了 deferHTML5.0 中定义了 async
          • 每一个 async 属性的脚本都在它下载结束之后立刻执行,同时会在 windowonload 事件之前执行。
          • 每一个 defer 属性的脚本都是在页面解析完毕之后,按照原本的顺序执行,同时会在 DOMContentLoaded 之前执行。
  • 总结: HTML 代码中往往会引入一些额外的资源,比如图片、CSSJS 脚本等,图片和 CSS 这些资源需要通过网络下载或从缓存中直接加载,这些资源不会阻塞 HTML 的解析, 因为他们不会影响 DOM 树的生成,但当 HTML 解析过程中遇到 <SCRIPT> 标签,就会停止 HTML 解析流程,转而去加载解析并且执行 JS。这是因为浏览器并不知道 JS 执行是否会改变当前页面的 HTML 结构,如果 JS 代码里用了 window.write 方法来修改 HTML,之前的 HTML 解析就没有任何意义了,这也就是为什么我们一直说要把 SCRIPT 标签要放在合适的位置,或者使用 async/defer 属性来异步加载执行 JS