前沿优化解决方案

一、拯救移动端图标 —— SVG

常见的字体方案经历了三种:PNG、Iconfont、SVG。

(一)PNG

先说说PNG,是比较早的方案了。PNG 属于一种图片格式,颜色丰富、边缘平滑,而且还支持透明度,所以最早被设计师作为 Icon 输出的格式,从而沿用到前端代码中;但这种图片icon也存在很大的缺陷:

  1. 尺寸问题,必须关注图片的宽高、比例,以免导致失真、变形。
  2. 请求数量和体积问题,多个图片Icon需要通过雪碧图等技术来规避请求数量,而雪碧图的应用还需要关心icon的定位。
  3. 灵活性,比较难以使用CSS3中的一些属性,效果不佳。比如:hover、阴影、transform、filter。

(二)Iconfont

Iconfont 是将图标制作成为了字体,从而利用上了字体的诸多优点,基本上能够规避 PNG 大部分缺点:

  1. 请求数量,只需要考虑字体文件的加载即可。
  2. 矢量图形足够灵活,像字体能够使用的 CSS 属性皆可使用,从而不必关心宽高、比例等问题(只需设置字体大小即可)。

Iconfont 也存在一个致命问题:Icon 是单色的,或者仅能使用 CSS3 变色。

Iconfont 背后原理是怎样的呢?

  1. 将Icon制作成字体文件
  2. 通过 i 标签(比较常见),并设置 class 来添加伪元素,而伪元素的值为字体文件中的字形编码,浏览器通过字形编码找到字符并渲染出来的。

字符是如何被计算机渲染的?
绝大多数的字体都包含一个或多个Charmap,它的作用是就是把一个字符从它的字符编码印射到字形索引。
一般一个字符的渲染过程是这样的:

  1. 加载字体文件
  2. 确定要输出的字体大小
  3. 输入这个字符的编码值
  4. 根据字体文件中的 Charmap,把编码值转换成字形索引(就是这个字符对应字体文件中的第几个形状)
  5. 根据索引从字体中加载这个字形
  6. 将这个字形渲染成位图,有可能进行加粗、倾斜等变换。

(三)SVG

SVG 的优点:

  1. 作为普通的页面元素,更具语义化
  2. 矢量图形,足够灵活
  3. 保持图片能力,支持彩色图标
  4. 节省体积(Iconfont 往往需要一整套字体)

二、最新的布局方案——Grid & Flex

布局经历了几种方案:table布局、传统布局(float、position、display、盒模型)、flex布局、grid布局。

table布局已经彻底淘汰了,传统布局PC端还有一些使用,尤其是CSS响应式;相较于最新的Grid、Flex来说,兼容性最好,但是效率最低,开发起来比较麻烦。

当下用的最多的是flex布局和grid布局。

flex布局移动端用的特别多,学习成本低,开发效率高,兼容性也还不错,它依据某个轴布局,可以看做是一维布局

grid布局在水平垂直两个方向上同时控制,可以称之为二维布局。Grid布局非常强大,但概念也最多,学习成本高一些,兼容性不如flex。

(一)flex布局

(1)核心概念
flex 容器(Flex Container)

它是所有flex项的直接父元素
我们把一个元素的display属性值改为 flex 或者 inline-flex后,这个元素就会成为flex容器,而容器中的直接子元素就会变为 flex元素

flex容器会有一些属性,通过它可以控制flex元素的大小、顺序、对齐以及间隔。

  1. flex-direction
    flex容器最典型的特征就是拥有水平和垂直方向两个轴,它决定了flex容器的主轴是哪个方向(与主轴相对的是交叉轴),也就是flex项的排列方向。
  2. flex-wrap
    决定flex项是否换行,默认是不换行的,当容器小于flex项所需要的面积时,flex项会等比例缩小。
  3. flex-flow
    上面两个属性的简写方式。
  4. justify-content
    决定flex项目在主轴上的对齐方式。
  5. align-items
    决定flex项目在交叉轴上的对其方式。
  6. align-content
    控制“多条主轴”的 flex 项目在交叉轴的对齐。所谓“多条主轴”是指存在换行。
flex 项(Flex Item)

它是flex容器的直接子元素,也有一些属性可以控制flex项:

  1. order
    定义flex项在排列时的顺序,数值越小优先级越高。
  2. flex-grow
    决定了flex项宽度或者高度的增长系数,它指定了flex容器中剩余空间的多少应该分配给项目,所谓剩余的空间是指flex容器的大小减去所有flex项的大小加起来的大小。如果所有的兄弟项目都有相同的flex-grow系数,那么所有的项目将获得相同的剩余空间,否则将根据不同的flex-grow系数定义的比例进行分配。
  3. flex-shrink
    决定了flex容器空间不足时,flex项目的缩小系数,与flex-grow相对。
  4. flex-basis
    决定了主轴方向上的初始大小,也就是主轴空间。
    有以下几点需要注意:
    • 单独使用 flex-basis,其实是定义了最小宽度,当内容撑大时,flex项目也变大。
    • 单独使用width,正常使用。
    • 两者同时使用,会采用较大的宽度,并且内容会溢出。(不设置break-all)
  5. flex
    属性2、3、4的简写方式。
  6. align-self
    决定了flex项目在交叉轴上的排列方向,覆盖flex容器中设置的align-items。

flex 项目也可以通过 display:flex 设置为另一个弹性容器,形成嵌套关系。因此一个元素既可以是flex容器也可以是flex项目。

(二)grid布局

(1)grid 布局的核心概念
  1. 网格容器(Grid Container),它是所有网格项的直接父元素
// display 为 grid 的元素就是网格容器了
.container {
	display: grid;
}
  1. 网格项(Grid Item),它是网格容器的直接子元素
  2. 网格线(Grid Line),是组成网格结构的分隔线,分为水平方向和垂直方向
  3. 网格单元(Grid cell),由网格线将网格容器切分而成
  4. 网格轨迹(Grid track),可以简单理解为网个容器的行和列
  5. 网格区域(Grid area),由网格单元组成的块

Grid布局主要有两种元素,即网格容器和网格项,因此就有作用于这两种元素上的属性。

(2)网格容器属性
  1. display:grid | inline-grid
    grid 中的容器元素都是块级元素,而inline-grid中的容器元素是行内元素。

  2. grid-template-columns 和 grid-template-rows
    它们分别用来定义网格的行和列,它们的取值用来定义网格的大小,而直接的间隔表示网格线,网格线可以使用中括号进行命名。例如:grid-template-columns: [firstline] 40px [secondline] 40px [thirdline] 40px [endline]
    对于重复的取值可以用 repeat 函数简写,例如:grid-template-columns: 40px 40px 40px等价为repeat(3, 40px)
    再来看看有取值有哪些单位:

    • 传统单位,例如:px、百分比、auto等等
    • fr,这是网格特有的单位,表示行和列中可用空间的一等份。
  3. grid-template-areas,用来定义网格区域。

上述网格容器属性就是将网格分割成行列,而行列又可以组成区域。划分好区域以后,我们就可以利用网格项属性将区域分配给网格项。

  1. column-gaprow-gap用来定义行列之间的间隔。
  2. justify-items用来定义网格单元的水平对齐方式。
  3. align-items用来定义网格单元的垂直对齐方式。
  4. place-items 是上述两个属性的简写方式。
  5. justify-content用来定义容器内容的水平排布方式。
  6. align-content用来定义容器内容的垂直排布方式。
  7. place-content是上述两个属性的简写方式。
  8. grid-auto-columns为那些隐式列指明宽度。
  9. grid-auto-rows为那些隐式行指明高度。
  10. grid-auto-flow为那些没有分配区域的网格项指明流动方式,是按行流动还是按列流动。

备注:grid-template,可以同时定义行、列、区域。

扩展:关于CSS对齐属性的总结,详细说明了justify-items、align-items、justify-content、align-content、justify-self、align-self的区别。

(3)网格项属性
  1. grid-column-startgrid-column-endgrid-row-startgrid-row-end都是描述网格线的,通过这四个属性可以画出一个区域,而这个区域即分配给了网格项。
  2. grid-columngrid-row为上述四个属性的简写属性。
  3. grid-area为上述四个属性的进一步简写形式,同时其值也可以直接写为区域名称。
  4. justify-self指明网格项自身的水平对齐方式。
  5. align-self指明网格项自身的垂直对齐方式。
  6. place-self是上述两个属性的简写属性。

三、优化资源加载的顺序

  1. Preload
 <link rel="preload" href="test.jpg">
  1. Prefetch包括资源预加载、DNS预解析、http预连接和页面预渲染。
资源预加载:<link rel="prefetch" href="test.css">
DNS预解析:<link rel="dns-prefetch" href="//haitao.nos.netease.com">
http预连接:<link rel="prefetch" href="//www.kaola.com"> 将建立对该域名的TCP链接
页面预渲染:<link rel="prerender" href="//m.kaola.com"> 将会预先加载链接文档的所有资源

那么PrefetchPreload有什么区别呢?
具体来讲,Preload来告诉浏览器预先请求当前页需要的资源,从而提高这些资源的请求优先级。比如,对于那些本来请求优先级较低的关键请求,我们可以通过设置Preload来提升这些请求的优先级。
Prefetch来告诉浏览器用户将来可能在其他页面(非本页面)可能使用到的资源,那么浏览器会在空闲时,就去预先加载这些资源放在http缓存内,最常见的dns-prefetch。比如,当我们在浏览A页面,如果会通过A页面中的链接跳转到B页面,而B页面中我们有些资源希望尽早提前加载,那么我们就可以在A页面里添加这些资源Prefetch,那么当浏览器空闲时,就会去加载这些资源。
所以,对于那些可能在当前页面使用到的资源可以利用Preload,而对一些可能在将来的某些页面中被使用的资源可以利用Prefetch。如果从加载优先级上看,Preload会提升请求优先级;而Prefetch会把资源的优先级放在最低,当浏览器空闲时才去预加载。

资源加载优先级可以放在首屏资源优化中,通过首屏那一帧找出对应的关键请求链,然后调整这些资源的加载优先级可以提高首屏加载速度。

另外,首屏速度也可以基于关键请求链做文章,从Localstorage、缓存等角度着手。

参考:
1. 从Chrome源码看浏览器如何加载资源
2. 浏览器页面资源加载过程与优化

用户头像
登录后发表评论