前端知识体系(3) —— CSS 基础(2)

302 阅读43分钟

前言:本前端知识体系供个人复习与巩固用,不一定适合其他人。会逐步的完善该系列文章。

flexbox 基本概念

float最初做出来是做文字环绕效果的,对很多场景下的布局有心无力。

image.png

参见 FlexBox Playround

flexbox 属性汇总

image.png

image.png

flexbox 剩余空间分配规则

通过使用 flexbox 布局,可以更轻松实现以往很难实现的页面布局。这里主要讲解 flexbox 布局是如何去分配和计算布局剩余空间的。

基础概念

为了更好地理解内容,需要先了解下面一些基础概念。

flexbox 容器 (flexbox container)

flexbox 容器又称弹性容器,通过设置 display: flex 而产生,简单示例如下:

.container {
  display: flex; /* 或者 inline-flex */
}

flexbox 项目 (flexbox item)

当设置一个元素为 flexbox 容器时,其直接子元素将自动成为容器成员,也可以称之为:flexbox 项目。

注:因为 flexbox 布局是发生在父元素和子元素之间的,所以下面为了行文方便,统一将 flexbox 容器称为“父容器”,而 flexbox 项目统一称为“子元素”

剩余空间

剩余空间就是指父容器在主轴方向上剩余未分配的空间,它是 flexbox 布局中一个很重要的词。可以借助下面的例子来更好地理解:

flexbox-leftsize.png

<div class="container" width="600px" style="display:flex;">
  <span class="item1" width="200px">item1</span>
  <span class="item2" width="200px">item2</span>
</div>

上面代码,定义了一个宽度为600px的父容器 container,以及宽度为200px的子元素 item1 和 item2 ,那么得出其剩余空间为200px,计算公式为:

剩余空间 = 父容器的宽度 - item1的宽度 - item2的宽度

剩余空间分配相关属性

flexbox 布局中的子元素可以通过设置 flex 属性来改变其所分配到的空间大小。flex 属性包括了 flex-basis、 flex-growflex-shrink

flex-basis

flex-basis 用来定义子元素的默认宽或高。如果父容器 flex-direction 属性的方向为水平方向则为宽度,如为垂直方向则为高度。相当于给子元素设置宽或高。如果同时设置了该属性与宽或高,则该属性权重大于宽或高的值。

flex-grow

flex-grow 用来指定父容器多余空间的分配比率,默认值为0。看到这里,大家可能还是没有概念。为了更形象地理解,一起看看下面的例子。

例子: 只设置 item1 的 flex-grow 为1

flexbox-grow.png

其 HTML 代码如下:

<div class="container">
  <span class="item item-flex-grow">item1</span>
  <span class="item item2">item2</span>
</div>

其 CSS 代码如下:

/* css 部分 */
.container {
  display: flex;
  width: 600px;
  height: 140px;
  align-items: center;
  background-color: #ddd;
}
.item {
  width: 200px;
  height: 120px;
  line-height: 120px;
  text-align: center;
  background-color: orange;
}
.item2 {
  background-color: green;
}
.item-flex-grow{
  flex-grow:1;
  background-color: 
}

这里对 item1 设置flex-grow:1 后,可以看到 item1 的所占空间宽度变成400px,也就是说 item1 把之前所说的父容器剩余的200px空间都占用了。

在这里可以得出:其实 flex-grow 即定义如何去分配父容器的剩余空间 ,当值为0时,则子元素都不会索取父容器的剩余空间。当 item1 设置 flex-grow: 1 的时候,由于 item2 没有设置 flex-grow 的值,则剩余空间将会被分成一份,并且分别分给了 item1。

例子: 设置 item1 的 flex-grow 为1,且 item2 的 flex-grow 为3

如果此时设置 item2 的flex-grow:3 ,item2 也将会参与索取父容器的剩余空间,此时父容器的剩余空间将分为4份,然后1份分配到 item1,而分配3份到 item2,如下图:

flexbox-grow2.png

如果子元素的宽度的总和超过父容器,flex-grow 将不生效。

上面的例子,只考虑了子元素的宽度总和都是没有超过父容器的宽度的情况,则其可以使用 flex-grow 来分配父容器的剩余空间。那么当子元素的宽度总和超过父容器的宽度时,这时剩余空间还可以分配吗?此时 flex-grow 是否还有效呢?先看看下面的例子:

这里设置上面例子的 item1 和 item2 的宽度为350px,则子元素的宽度总和为700px且超过父容器container的600px宽度。

flexbox-grow3.png

可以看到 flex-grow 并没有起到作用,且两个 item 的宽度还被压缩到只有300px。

通过之前的如何计算剩余空间的方法,可以算出本例子的剩余空间为600px - 700px即 -100px,这里可以得出由于没有剩余空间,则定义了 flex-grow 的子元素能分配到的空间为0,故不生效。另外需要知道的是 flexbox 环境的父容器的宽度600px并不会因为子元素的总宽而改变,即子元素的宽度总和最多等于父容器的宽度,所以为了让子元素完整显示在父容器内,只有两个办法:

  • 通过设置 flex-wrap 来使子元素换行
  • 通过压缩子元素来使其能容纳在父容器内

flex-shrink

flex-shrink 用来指定父容器空间不够时子元素的缩小比例,默认为1。如果一个 flexbox 项目的 flex-shrink 属性为0,则该元素不会被压缩。

为什么需要 flex-shrink 来定义缩小比例呢?

上面可以知道,当子元素的宽度总和大于 flexbox 父容器的宽度时,其剩余空间将为负数,如果没有设置换行的情况下,其将会通过压缩子元素来使其能够容纳在父容器内。那么如何控制子元素的压缩比例呢?答案就是通过将通过设置 flex-shrink 这个属性。

例子:设置项目的flex-shrink

下面例子,设置两个 item 的宽度为350px,而容器 container 的宽度仍为600px。同时定义了 item1 和 item2 的 flex-shrink 的属性分别为1和4。如下所示:

flexbox-shrink.png

代码如下:

/* 这里只展示关键css */
.container {
  display: flex;
  width: 600px;
  height: 140px;
}
.item {
  width: 350px;
  height: 120px;
}
.item1 {
  flex-shrink: 1;
}
.item2{
  flex-shrink: 4;
}

看到由于缺少100px的空间,按照 item1 和 item2 定义的 flex-shrink 的值,缺少的100px将分成5份。item1 将压缩其中的 1/5 即20px,item2 的将压缩其中的 4/5 即80px。

例子:设置项目的 flex-shrink 为0

在上面的知识中,了解到 flex-shrink 默认值为1,即默认子元素在父容器空间不足时会被压缩。现在把项目的 flex-shrink 设为0来看下不压缩的情况。如下所示:

flexbox-shrink0.png

代码如下:

/* 这里只展示关键css */
.container {
  display: flex;
  width: 600px;
  height: 140px;
}
.item {
  width: 350px;
  height: 120px;
  flex-shrink: 0;
}

更多阅读

grids 布局系统

之前有提到过网格系统,比如960sbootstrap 的网格系统,但是这些网格系统都是模拟出来的(使用 float 或 flexbox),而并非天生的,虽然可以解决一些常见布局问题,但面临 Win10 UI 还是有点力所不及,如下图:

grid-win10.jpeg

但是随着 CSS 的不断发展及完善,一种新的网格布局方式被纳入规范,它将会解决所有的网格问题,这就是 CSS Grid Layout。

网格系统基础概念

在说 CSS Grid Layout 之前,先来看看 excel 的表格。

grids-excel-1.png

以 Sheet1 的 A1 单元格为例,先是有上下左右四条线围着,然后定位是由竖直的 A 栏与横向的1行二维坐标表示 A1。如果有需要甚至还还可以和邻近的单元格合并。

现在提炼下上面的几个概念:线条,栏(竖直),行(横向),单元格,合并。接下来把这些概念对应到网格系统:

grids-excel-2.png

  • Grid Container:首先要设置父元素的布局为 grid,通过使用 display 属性给元素显式设置属性值grid或inline-grid,此时这个元素将自动变成网格容器,对应上图的Sheet1
  • Grid Item:Item 是 container 的直接子元素,如果不考虑单元格的合并跟下面的 cell 是一样的,如果有单元格合并,在该 item 可能包括几个cell,对应上图的一个个格子,如蓝色的 A1
  • Grid Lines:网格线分为水平线和垂直线,对应上图的橙色线条
  • Grid Track:就是由lines构成的水平和垂直空间,对应到上图的水平和垂直灰色区域,而对于table来说就是row和column
  • Grid Cell:简单来说就是单元格了,对应到上图就是蓝色的A1,而对于table来说就是单元格
  • Grid Area:网格区域是由任意四条网格线组成的空间,可能由一个或多个单元格组成。对应到上图就是红色区域,相当于表格中的合并单元格之后的区域

网格系统基本属性

网格系统布局其实跟 flexbox 布局差不多,都是由父子元素构成的布局。所以属性分为父元素属性和子元素属性。

因篇幅有限,这里只简单介绍每个属性的用途,具体的属性取值请参考:

父元素(Grid Container)属性

这里将父元素属性大概分为三大类,其中第一类与第二类属性可以简写为 grid 属性(不包括 display 属性):

第一类:如何去定义一个网格系统,行列及间距等。

  • display:grid/inline-grid,定义使用网格系统
  • grid-template-columns:定义垂直栏
  • grid-template-rows:定义水平行
  • grid-template-areas:定义区域
  • grid-column-gap:定义垂直栏与垂直栏之间的间距,如上图的A与B之间的间距
  • grid-row-gap:定义水平行与水平行之间的间距,如上图的1与2之间的间距
  • grid-gap:上面两个栏与行间距的缩写

第二类:自动分配形式,当定义的行或列数量不够时,多出 item 的自动排列方式:

  • grid-auto-columns:定义多出的 item 的自动column的宽度大小
  • grid-auto-rows:定义多出的 item 自动 row 的高度大小
  • grid-auto-flow:定义自动 item 是按照先水平方向排列还是垂直方向排列

第三类:分布对齐的方式(属性跟 flexbox 的有点像)。

  • justify-items:item 在水平行中的对齐方式
  • align-items:item 在垂直栏中的对齐方式
  • justify-content:整个水平行在 grid 范围的对齐方式,这里有个好用的 space-evenly 值,补足了以前flex的 space-around 和 space-between 的不足
  • align-content:整个垂直栏在 grid 范围的对齐方式

子元素(Grid Item)属性

接下来是 item 属性,同样这里也将它分为两类:

第一类:单元格所占格子多少

  • grid-column-start:item 的起始栏
  • grid-column-end:item 的结束栏
  • grid-column:起始栏和结束栏的简写
  • grid-row-start:item 的起始行
  • grid-row-end:item 的结束行
  • grid-row:起始行与结束行的简写
  • grid-area:item所在区域

第二类:单元格的自定义对齐方式,这个跟 flexbox 的 item 有点相似。

  • justify-self:自定义 item 的水平方向对齐方式
  • align-self:自定义 item 的垂直方向对齐方式

实例演示

接下来使用网格系统来实战下 Win10 UI,如下图:

grids-demo-1.png

html结构为:

<div class="grid">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
    <div class="item">10</div>
    <div class="item">11</div>
</div

写好结构后,就开始使用刚才说得 grid 来实现效果了。先拆分成最小的单元格为 6栏 * 3行,最小单元格的大小为140px,整体内容一屏水平垂直居中。

html,body {
 height: 100%;
}
.grid {
  height: 100%;
  display: grid; /* 网格布局 */

  /* 整体水平垂直居中 */
  justify-content: center;
  align-content: center;

  /* 定义6栏3行 */
  grid-template-columns: 140px 140px 140px 140px 140px 140px;
  grid-template-rows: 140px 140px 140px;

  /* 定义item之间的间距为20px */
  grid-gap: 20px;

  background: #efefef;
}
.item{
  background: #ccc;
}

现在可以看到效果如下:

grids-demo-2.png

接下来要合并单元格实现最终效果。合并单元格有两种实现方式一种是 line 的开始与结束(包括 colunm 与 row),另一种就是在 grid 上面定义的 area,这里使用第一种方法。

这里重提下上面的 Grid Lines 概念,如要实现 n栏 * m行的网格,则需要n+1条垂直line,m+1条水平线。

第一个 item 元素单元格占了两列,第一列和第二列,那么就垂直栏开始于第一条 line,结束于第三条 line,同样第5个 item 元素也是如此

.item:nth-child(1),
.item:nth-child(5) {
  grid-column: 1 / 3; /* 起始于1,结束于3 */
}

而第二个 item 元素栏和行都跨了两个,CSS 代码如下:

.item:nth-child(2) {
  grid-column: 3 / 5; /* column起始于3,结束于5 */
  grid-row: 1 / 3;  /* row起始于1,结束于3 */
}

同样第七个 item 元素行跨了两个,第9个 item 元素栏跨了两个,CSS 代码如下:

.item:nth-child(7) {
  grid-column: 6;
  grid-row: 2 / 4; /* row起始于2,结束于4 */
}
.item:nth-child(9) {
  grid-column: 2 / 4; /* column起始于2,结束于4 */
}

这个布局就这么简单的完成了,效果可见 demo

浏览器支持

现代浏览器最新版本基本上都支持了 CSS Grid Layout, caniuse 上的支持情况.

有些浏览器旧版本的已经实现但是没有默认开启(chrome < 57,firefox < 52)则需要通过下面的方式手动设置开启:

  • chrome 在地址栏输入“chrome://flags”,找到"experimental web platform features"开启
  • firefox在地址栏输入"about:config",找到"layout.css.grid.enabled"开启

总结

上面只是 grid 布局的简单使用,实际上 grid 布局十分强大,使用起来也十分方便,未来将会是布局的主力军,但是目前由于兼容问题暂时不建议在生产环境中使用,不过相信很快就可以见识到 grid 布局的强大威力了。

参考资料

浏览器如何渲染 HTML & CSS

现在已经知道,使用 HTML & CSS 可以搭建出一个漂亮的 Web 页面。

那么浏览器到底是如何使用 HTML & CSS 渲染成在屏幕上所看到的页面呢?

虽然具体渲染过程很复杂,但是还是可以将其分为几个关键路径,如下:

  • 处理 HTML 标记并构建 DOM 树
  • 处理 CSS 标记并构建 CSSOM 树
  • 将 DOM 与 CSSOM 合并成一个渲染树
  • 根据渲染树来布局,以计算每个节点的几何信息,再将各个节点绘制到屏幕上

构建 DOM 树

首先浏览器渲染页面前会根据 HTML 结构构建成对应的 DOM 树。

以下面的 HTML 代码为例:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
  </body>
</html>

其 DOM 树生成的流程如下图:

render-1.png

  • 转换: 浏览器从磁盘或网络读取 HTML 的原始字节,并根据文件的指定编码(例如 UTF-8)将它们转换成各个字符。
  • 令牌化: 浏览器将字符串转换成 W3C HTML5 标准规定的各种令牌,例如,“”、“”,以及其他尖括号内的字符串。每个令牌都具有特殊含义和一组规则。
  • 词法分析: 发出的令牌转换成定义其属性和规则的“对象”。
  • DOM 构建: 最后,由于 HTML 标记定义不同标记之间的关系(一些标记包含在其他标记内),创建的对象链接在一个树数据结构内,此结构也会捕获原始标记中定义的父项-子项关系:HTML 对象是 body 对象的父项,body 是 paragraph 对象的父项,依此类推。

整个流程的最终输出就是这个简单页面的文档对象模型 (DOM),如下图:

render-2.png

CSSOM

在浏览器构建上面的 DOM 时,在文档的 head 部分遇到了一个 link 标记,该标记引用一个外部 CSS 样式表:style.css。由于预见到需要利用该资源来渲染页面,它会立即发出对该资源的请求,并返回以下内容:

/* style.css */

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

与处理 HTML 时一样,需要将收到的 CSS 规则转换成某种浏览器能够理解和处理的东西。因此,会重复 HTML 过程,不过是为 CSS 而不是 HTML:

render-3.png

CSS 字节转换成字符,接着转换成令牌和节点,最后挂靠到一个称为“CSS 对象模型”(CSSOM) 的树结构内:

render-4.png

CSSOM 为何具有树结构?这是因为浏览器为页面上的任何对象计算最后一组样式时,都会先从适用于该节点的最通用规则开始(例如,如果该节点是 body 元素的子项,则应用所有 body 样式),然后通过应用更具体的规则(即规则“向下级联”)以递归方式优化计算的样式。

以上面的 CSSOM 树为例进行更具体的阐述。span 标记内包含的任何置于 body 元素内的文本都将具有 16 像素字号,并且颜色为红色 — font-size 指令从 body 向下级联至 span。不过,如果某个 span 标记是某个段落 (p) 标记的子项,则其内容将不会显示。

合并渲染树

接下来就是将 DOM 树与 CSSOM 树合并形成渲染树。

渲染树会网罗网页上所有可见的 DOM 内容,以及每个节点的所有 CSSOM 样式信息。

render-5.png

注:渲染树只包含渲染网页所需的节点,如display: none;的元素是不会出现在渲染树种的。

布局及绘制

有了渲染树,就可以进入“布局”阶段。

到目前为止,计算了哪些节点应该是可见的以及它们的计算样式,但尚未计算它们在设备视口内的确切位置和大小---这就是“布局”阶段,也称为“自动重排”。

为弄清每个对象在网页上的确切大小和位置,浏览器从渲染树的根节点开始进行遍历。考虑下面这样一个简单的实例:

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

以上网页的正文包含两个嵌套 div:第一个(父)div 将节点的显示尺寸设置为视口宽度的 50%;而里面内嵌的第二个 div 将其宽度设置为其父项的 50%,即视口宽度的 25%。如下图:

render-6.png

布局流程的输出是一个“盒模型”,它会精确地捕获每个元素在视口内的确切位置和尺寸:所有相对测量值都转换为屏幕上的绝对像素。

最后,既然知道了哪些节点可见、它们的计算样式以及几何信息,终于可以将这些信息传递给最后一个阶段:将渲染树中的每个节点转换成屏幕上的实际像素形成可见的页面。这一步通常称为“绘制”或“栅格化”。

注:执行渲染树构建、布局和绘制所需的时间将取决于文档大小、应用的样式,以及运行文档的设备:文档越大,浏览器需要完成的工作就越多;样式越复杂,绘制需要的时间就越长(例如,单色的绘制开销“较小”,而阴影的计算和渲染开销则要“大得多”)。

参考资料

重排与重绘

一个页面渲染完毕后,随着用户的操作,或者数据变化,网页还会进行重新渲染。根据不同的触发条件,重新渲染分为两种情况:重排(reflow)和重绘(repaint)。

所有对元素视觉表现属性的修改,都会导致重绘(repaint)。比如修改了背景颜色、文字颜色等。

所有会触发元素布局发生变化的修改,都会导致重排(reflow)。比如窗口尺寸发生变化,删除、添加 DOM 元素,修改了影响元素盒子大小的 CSS 属性如 width、 height、 padding 等。

通常情况下,重排的影响更大,重排会导致文档局部或全部的重新运算:重新计算元素位置,大小。(改变一个元素的布局,可能会影响很多个元素的布局)

不管是重绘还是重排导致的重新渲染,都会阻塞浏览器。重新渲染的的过程中,JavaScript 会被阻塞,用户的交互行为也会被卡住。复杂的 CSS 动画甚至会拖慢 JavaScript 的运行速度。

导致重排和重绘的场景

CSS 属性改变

网站 CSS trigglers 列出了所有 CSS 属性对 layout (布局)、paint (绘制)的影响。通过这个表,可以查到不同内核下,对 CSS 属性的修改会导致重绘、重排还是两者都会发生。

0.png

注:Composite (渲染层合并) 是 chrome 引入 GPU 加速带来的新概念。(相关信息可参看下面的参看资料)

对 CSS 属性进行修改,包括但不限于以下场景:

  • 通过 display: none 隐藏 DOM 节点(导致重绘和重排)
  • 通过 visibility: hidden 隐藏 DOM 节点 (导致重绘,因为它没有影响其它元素位置布局)
  • CSS 动画
  • 通过 JavaScript 添加样式,修改样式

用户交互

  • 对浏览器窗口进行缩放操作会导致重排
  • 对 DOM 节点进行操作,添加、删除、更新 DOM 节点都会导致重排
  • 光标 :hover 、进入文本输入框、修改浏览器的字体都会导致重排

最佳实践

所有的最佳实践都是围绕尽最大可能的降低重绘和重排的频率,来达到减少重新渲染的目的。

CSS 属性的读、写操作分开

浏览对 CSS 属性的连续修改做了优化,比如下面的连续修改两次 style,不会导致两次重新渲染:

div.style.color = 'blue';
div.style.marginTop = '30px';

上面代码只会进行一次重新渲染。但是如果写的不好,则会触发两次重新渲染,如下:

div.style.color = 'blue';
var margin = parseInt(div.style.marginTop);
div.style.marginTop = (margin + 10) + 'px';

上面代码对 div 元素设置背景色以后,第二行要求浏览器给出该元素的位置,所以浏览器不得不重新渲染然后得到该元素的位置。

除此之外,样式的写操作之后,如果有下面这些属性的读操作,都会引发浏览器立即重新渲染:

  • offsetTop/offsetLeft/offsetWidth/offsetHeight
  • scrollTop/scrollLeft/scrollWidth/scrollHeight
  • clientTop/clientLeft/clientWidth/clientHeight
  • getComputedStyle()

通过 class 或者 csstext 来批量更新样式

上面对通过对 style 对 CSS 属性一个一个修改,其实更好的方式应该是通过 class 来批量化。

// bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top  = top  + "px";

// good 
el.className += " theclassname";

// good
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

其他方法

  • DOM 样式离线更新:尽量使用离线 DOM,而不是真实的网页 DOM 来改变元素样式。比如,操作 Document Fragment对象,完成后再把这个对象加入 DOM。再比如,使用 cloneNode() 方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。
  • 使用 display: none 进行样式批量更新:先将元素设为 display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,就用两次重新渲染,取代了可能高达100次的重新渲染。
  • 善用 position:position 属性为 absolute 或 fixed 的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。
  • 将元素设置为不可见:只在必要的时候,才将元素的 display 属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden 的元素只对重绘有影响,不影响重排。
  • 减少样式的更新频率:使用虚拟 DOM 脚本库,比如 React 等。
  • 调节 js 运行帧率:使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染的频率。
  • 慎用 table 布局:table 的单元格具有非常好的自适应特性,但是同时代价也很高,能不用就不用。如果非要使用 table ,给 table 添加 table-layout: fixed 属性,这个属性的目的是让后面单元格的宽度由表头的宽度来决定——减少布局的计算量。

参看资料

CSS 动画

分为两种,补间动画和帧动画。

补间动画就是自动补齐中间状态的一种动画,

帧动画可以通过关键帧,来定义中间态。可以做出非常复杂的动画。

补间动画使用transition属性,帧动画使用animation属性。

transition 动画

image.png

image.png

动画必备属性 transform

概述

transform 本意是变形,变换之意,在 CSS 中使用该属性可对元素进行移动(translate)、旋转(rotate)、缩放(scale)、倾斜(skew)等效果。因其有着各种特效及优良的性能,所以成为动画的标配。

简单欣赏下几个案例:

二维(2D)变换

translate

其语法为:transform: translate(tx[, ty])。其中 tx 表示 x 方向偏移,ty 表示 y 方向偏移,如果 ty 没有指定值则为0。

还可以分拆为:transform: translateX(tx) 或 transform: translateY(ty)

简单示例如下(虚线框表示原先位置):

.box {
    transform: translate(50px, 30px);
}

translate.png

注:tx,ty 如果为百分比值的话,其参考计算的是元素本身的宽和高,而不是父元素的宽和高。所以经常使用该方法设置定位居中,代码如下:

.demo {
  position: absolute;
  top: 50%; /* 父元素高度的一半位置 */
  left: 50%; /* 父元素宽度的一半位置 */
  transform: translate(-50%, -50%); /* 元素本身的一半宽、高 */
}

scale

其语法为:transform: scale(sx[, sy])。其中 sx 表示 x 方向的缩放比例,sy 表示 y 方向的缩放比例,如果 sy 没有指定值则与 sx 相等。

同样也可以分拆为:transform: scaleX(sx) 和 transform: scaleY(sy)

简单示例如下:

.box {
    transform: scale(1.2);
}

scale.png

rotate

其语法为:transform: rotate(angle)。angle 表示顺时针角度。

简单示例如下:

.box {
    transform: rotate(15deg);
}

rotate.png

skew

其语法为:transform: skew(ax[, ay])。其中 ax 表示 x 方向的顺时针角度,ay 表示 y 方向的顺时针角度,如果 ay 没有指定值则 y 方向没有倾斜。

简单示例如下:

.box {
    transform: skew(30deg);
}

skew.png

复合变换

上面几个变换,都可以自由组合形成更复杂的复合变换。

简单示例如下:

.box {
    transform: translate(30px) rotate(10deg) skew(0, 5deg);
}

mix.png

以上所有示例在线查看地址: transform 简单 demo

变换中心点

默认上面所有的变换都是以元素的中心位置为参考原点的,不过可以通过属性 transform-origin 来改变参考原点。

其语法为:transform-origin: ox oy。其中 ox 表示 x 方向的位置,可使用 leftrightcenter<length><percentage>,oy 表示 y 方向的位置,可使用topbottomcenter<length><percentage>。如果只传入一个值,则另一个值默认为 50%

简单示例如下(在线 demo):

.box {
    transform: rotate(15deg);
}
.box-origin-top-left {
    transform-origin: left top;
}
.box-origin-right {
    transform-origin: right; /* 设置一个值,则另一个为50% */
}
.box-origin-px {
    transform-origin: 200px 80%;
}

origin-top-left.png

origin-right.png

origin-px.png

trasform 2D 的本质 —— 矩阵变换

上面已经简单了解了 transform 2D 的基本语法,接下来简单探讨下 transform 2D 的本质。

transform 2D 除了以上的四种基本语法(translate、rotate、scale、skew)外,还有一个矩阵语法,如下:

transform: matrix(a, b, c, d, e, f);

上面 matrix(a, b, c, d, e, f) 的形式用矩阵符号表示,是这样的:

matrix-0.png

需要注意的是,第三行是固定的,都是 0,0,1 ,所以 CSS 语法中省去了这一行。因为涉及到 xy 及旋转,所以二维变换需要三个变量来表示。

下面以实例了解下矩阵是如何用来表示变换的,以上面的 translate 为例:

.box {
    transform: translate(50px, 30px);
}

上面 css 代码的意思是说,把所有点都相对于 原点 (通过 transform-origin 指定,默认为中心点),往 x 正方向平移 50px,往 y 正方向平移 30px。用数学表达式表示就是:

matrix-1.png

这里 tx = 50px ,ty = 30px。稍微变换一下,x' 和 x,y 都相关,写成如下的形式:

matrix-2.png

把两行的x、y系数取出来,再补充一行(为什么多了一行?为了运算方便,看下图也许就清楚了),得下面的语法形式—— 矩阵运算

matrix-3.png

那么,变换的本质是什么?就是把一组 (x, y) 通过算术运算,变为新的坐标 (x',y') ,刚好 矩阵 这种数学工具就可以用来描述这种数学变换。通用的二维矩阵变换就是:

matrix-4.png

常见的二维变换

上面公式的最左边的矩阵,通常是如下几种基本形式组合而成:

matrix-5.png

如果每个变换,都用 matrix 语法来表示,要写很多参数,显然这样是不合理的。所以有了四个基本的简化写法:

matrix-6.png

三维(3D)变换

3D 变换大概有如下几种使用方法:

transform: translate3d(12px, 50%, 3em);
transform: translateZ(2px);
transform: scale3d(2.5, 1.2, 0.3);
transform: scaleZ(0.3);
transform: rotate3d(1, 2.0, 3.0, 10deg);
transform: rotateX(10deg);
transform: rotateY(10deg);
transform: rotateZ(10deg);
transform: perspective(17px);
transform: matrix3d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0);

3D 变换的复杂性及可以创造的特效远超 2D 变换。

推荐两篇高质量入门文章如下:

参考资料

缓动函数

Dingtalk_20220524225054.jpg

image.png

推荐函数网站:cubic-bezier

推荐函数曲线:eastOutQuint

image.png

animation 动画

image.png

关键帧语法解析

image.png

image.png

transiton 动画和 animation 动画的异同

image.png

常见 CSS 动画库

自从 CSS3 有了动画功能,从此 Web 页面就迈进“忽如一夜春风来,千页万页动画开”的盛况。 所以 CSS 动画除了是炫技之选更是一项基本技能,当然也就有无数前辈为之呕心沥血总结经验了。这里推荐一些常见且十分好用的 CSS 动画库,既可以用来学习也可用来提高工作效率。

Animate.css

Animate.css 是最早的也是目前最流行和最易于使用的CSS动画库之一,其包含了60多款不同类型的 CSS 动画如晃动、闪动、淡出淡出效果等,如果你想快速的使用各种 CSS 动画特效的话,你可以选择它。

  • 创作者:Daniel Eden
  • 发行:2013年
  • 当前版本:3.5.2
  • 人气:GitHub上有40000+的star
  • 未压缩大小:72kB
  • GitHub:github.com/daneden/ani…

Magic CSS3 Animation

Magic CSS3 Animations 是一个特殊效果的 CSS 动画库,可以免费用于你的 Web 项目,简单的引用 CSS 样式:magic.css 或 magic.min.css (压缩版)即可。该项目提供了一个特别酷的演示应用程序。与 animate.css 相比,Magic CSS3 Animation 的大小适中,它的特色动画,如魔法效果,愚蠢的效果和炸弹效果十分出众和特别。

  • 创作者:Christian
  • 发行:2014年
  • 当前版本:1.1.0
  • 人气:GitHub上有4700+的star
  • 未压缩大小:20.5kb
  • GitHub:github.com/miniMAC/mag…

Hover CSS

Hover.css 是一个 CSS 动画库,专为您的网站中的按钮和其他 UI 元素而设计。它具有非常好的2D转换,以及许多其他精心制作的动画。

  • 创作者: Ian Lunn
  • 发行:2013年
  • 当前版本:2.1.1
  • 人气:GitHub上有16000+的star
  • 未压缩大小:100+kb
  • GitHub:github.com/IanLunn/Hov…

Effeckt

Effeckt.css 是一个集合了众多新鲜而又实用的的 CSS/jQuery 动画效果,这些都适用于网站或是移动 APP 的网页,比如一些 AJAX 弹出框动画、菜单动画、图片标题展示等等,这些特效动画都能给你的网站提升一定用户体验,而且简单实用。

  • 创作者:paulirish
  • 发行:2013年
  • 当前版本:0.5.0
  • 人气:GitHub上有10900+的star
  • GitHub:github.com/h5bp/Effeck…

Single Element CSS Spinners

在页面中,时常需要使用 gif 图片来实现比较炫酷的 loading 动画。Single Element CSS Spinners是一个CSS螺旋加载动画的集合。使用Single Element CSS Spinners 来替代 gif 来实现螺旋加载动画,不仅减少了请求图片的次数,同时还能够通过代码来灵活地修改动画的参数。

  • 创作者:Lukehaas
  • 发行:2014年
  • 当前版本:1.0.0
  • 人气:GitHub上有4700+的star
  • 未压缩大小:10kB
  • GitHub:github.com/lukehaas/cs…

注:一般不建议全部拿来使用,而是使用哪个动画效果就拷贝对应的样式。

动画性能优化

CSS3 动画给 Web 的用户体验带来了巨大提升,本文将尝试从浏览器渲染的角度,来解析动画优化的原理及其技巧。提供一些动画性能优化的参考。

60fps 与设备刷新率

目前大多数设备的屏幕刷新率为60fps(Frame per Second),即每秒60帧。因此,如果在页面中有一个动画或渐变效果,或者用户正在滚动页面,那么浏览器渲染动画或页面的每一帧的速率也需要跟设备屏幕的刷新率保持一致,即每一帧要在16毫秒(1S/60 = 16.66ms)之内完成。如果无法完成,由于帧率的下降会导致内容在屏幕上抖动。 此现象通常称为卡顿,会对用户体验产生负面影响

浏览器渲染

在讲性能之前,需要先对浏览器渲染页面有一个基础的理解。

CSS 图层

浏览器在渲染一个页面时,会将页面分为很多个图层,图层有大有小,每个图层上有一个或多个节点。需要注意的是,如果图层中某个元素需要重绘,那么整个图层都需要重绘(关于重绘下面会讲到)。

渲染过程

简单来说,浏览器的渲染过程其实就是将页面转换成像素显示到屏幕上,大致有如下几个步骤:

frame-full.jpg

  • Javascript操作: 一般来说,会使用 JavaScript 来实现一些交互操作。比如用往页面里添加一些元素,切换显示隐藏等
  • style 样式计算: 该过程根据 CSS 选择器,获取每个元素匹配的 CSS 样式并计算其最终应用样式
  • Layout 布局:该过程计算元素要占据的空间大小及其在屏幕的位置。网页的布局模式意味着一个元素可能影响其他元素,例如 <body> 元素的宽度一般会影响其子元素的宽度以及树中各处的节点,因此对于浏览器来说,布局是经常发生的
  • Paint 绘制:本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等。也就是绘制元素所有的可视效果
  • Composite 渲染层合并:在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上

如果需要提高动画的性能,需要做的就是减少浏览器在动画运行时所需要做的工作。当 CSS 在进行动画时,其不同属性值引起的改变,重新渲染可能会有三种执行路径:

  • A:layout -> paint -> composite
  • B:paint -> composite
  • C:composite

很明显,最短路径的 C 动画性能是最高的,所以在使用动画的时候就得考虑使用什么属性,以尽量减少执行路径。

动画属性

CSS 的属性大致分为三类:布局类(layout),绘制类(paint),合成类(composite)。

重排(reflow)

由元素的布局类属性改变所触发的行为过程,称为 reflow,也叫做 relayout(重新布局)。当某个节点 reflow 时会重新计算节点的尺寸和位置,还可能会引起其它节点的 reflow。

该系列属性的改变,会执行路径 A 进行重新渲染,所以性能是最差的。(这充分说明,重排会引起重绘)

触发重排的属性

盒子模型相关属性会触发重布局:

  • width
  • height
  • padding
  • margin
  • display
  • border-width
  • border
  • min-height

定位属性及浮动也会触发重布局:

  • top
  • bottom
  • left
  • right
  • position
  • float
  • clear

改变节点内部文字结构也会触发重布局:

  • text-align
  • overflow-y
  • font-weight
  • overflow
  • font-family
  • line-height
  • vertival-align
  • white-space
  • font-size

重绘(repaint)

由绘制类属性改变触发节点重新绘制其可视效果的过程,称为 repaint。

该系列属性的改变,会执行路径 B,所以性能一般。

触发重绘的属性

修改时只触发重绘的属性有:

  • color
  • border-style
  • border-radius
  • visibility
  • text-decoration
  • background
  • background-image
  • background-position
  • background-repeat
  • background-size
  • outline-color
  • outline
  • outline-style
  • outline-width
  • box-shadow

上面的属性由于不会修改节点的大小和位置,因此不会触发重排,其只是改变了节点内部的渲染效果,所以只会进行重绘以下的步骤。

composite

目前只有两个属性属于 composite 类:

  • transform
  • opactiy

该系列属性的改变,会执行路径 C,所以性能最佳。

如果想了解更多 CSS 中会影响 Layout、Paint 和 Composite 的属性,可参考:CSS Triggers

优化技巧

减少动画元素

减少动画元素,是动画性能优化中首先需要完成的。通过审查页面动画 DOM 元素结构,去除不必要的动画元素,减少元素的数量,相应地会减少布页面局和绘制的时间。

尽量使用 fixed、absolute 定位

对于动画元素,尽量使用用 fixed、absolute 定位方式,避免影响到其他节点重排。

尽量只改变transform和opacity

能用 transform、opacity 优先使用,其属性的改变不会发生重排和重绘。如位移操作的,可以使用translate 来实现,渐隐渐现效果可以使用 opacity 属性来实现。

恰当开启硬件加速效果

对动画元素应用transform: translate3d(0, 0, 0)will-change: transform 等来开启硬件加速。通常开启硬件加速可以让动画变得更加流畅。但这里需注意,在不需要的时候需去掉避免过多的内存消耗。

transform: translate3d(0, 0, 0);
transform: translateZ(0);
will-change: transform;

更多阅读

响应式设计

image.png

viewport

浏览器的可视区域

image.png

image.png

宽度 width 为 device-width 设备宽度,initial-scale 为 1.0 即不缩放。

retina 显示屏

关键词

iphone 7 其显示屏介绍如下:

retina-keywords.png

以 7 plus 为例抽取如下几个关键词:

  • Retina HD 显示屏
  • 5.5 英寸
  • 1920 x 1080 像素分辨率
  • 401 ppi

下面再来一一详细谈论这些关键词。先从第二个说起,因为第一个的解释需要用到下面的一些关键词。

5.5 英寸

这个比较简单,就是显示屏对角线的长度(可以通过勾股定理计算得到,甚至可以自己用尺子去量)。如下几种不同的 iPhone 的几种尺寸规格:

retina-chicun.png

注:1英寸(inch)=2.54厘米(cm)

1920 x 1080 像素分辨率

1920 x 1080 像素分辨率表示该显示屏的分辨率为:1920px x 1080px。

前面已经说过,显示屏上的每个图形都是由一个一个像素点构成的,下面的图形可以很形象的帮助你明白:

retina-pixel.jpg

既然明白了像素点,现在就可以解释分辨率1920px x 1080px的意思了。它表示在这个iPhone 7 plus 5.5 英寸英寸屏幕上,在竖向的高度上有1920个像素点,在横向的宽度上有1080个像素点。

注:一般来说电脑可以直接右键查看屏幕分辨率(windows操作系统),而手机可以在“设置>关于本机”中找到分辨率,如果不知道也可以参考下面两个链接:

像素密度——PPI

Pixels Per Inch(PPI)也叫像素密度,所表示的是每英寸所拥有的像素数量,PPI值越高,画面的细节就会越丰富。

其计算公式如下图:

retina-ppi.jpg

简单来说就是利用上面所说的分辨率运用勾股定理求出对角线上的像素点,然后再把该像素点除以对角线的长度。也就得到了每英寸所拥有的像素数量。

更多关于 PPI 的资料可参看:

Retina HD 显示屏

所谓“Retina”是一种显示技术,可以将更多的像素点压缩至一块屏幕里,从而达到更高的分辨率并提高屏幕显示的细腻程度。这种分辨率在正常观看距离下足以使人肉眼无法分辨其中的单独像素,也被称为视网膜显示屏。

Retina 既不是指分辨率,也不是单独指PPI,而是指视觉效果。其计算公式为(可以不用了解):

retina-retina.jpg

a 代表人眼视角,h 代表像素间距,d 代表肉眼与屏幕的距离。符合以上条件的屏幕可以使肉眼看不见单个物理像素点。这样的显示屏就可被苹果称作“Retina显示屏”。

将通常使用距离代入上公式可知:

  • 手机显示器的像素密度达到或高于 300ppi 就不会再出现颗粒感(视线距离在35CM左右)
  • 而苹果电脑的 Retina 显示器像素密度只要超过 200ppi 就无法区分出单独的像素(视线距离在60CM左右)

已经知道了 Retina 显示屏,那么 Retina HD 显示屏又是什么呢?

然而苹果官方对它自己发明的这个词也没有一个具体的概念,可以简单的理解为一个升级版,有着更好的显示效果就可以了。

更多关于 Retina 的资料可参看:

devicePixelRatio(设备像素比)

上面四个概念我们已经明白了,但是离最终问题还差一点,接着引入第五个概念:devicePixelRatio。

在解释这个概念之前,先来看个 demo(CSS 尺寸大小)

通过 chrome 调试工具我们模拟iPhone 7(因为 iPhone 6、7的大小一样,所以实际使用iPhone 6 模拟即可),并且查看对应的 demo 元素的 CSS 宽高,会发现其宽高分别为: 375px * 667px。(该 demo 已经设置了 viewport 的宽度为 device-width,不然的话得到的宽度就是 980px 了。)。

这个宽高正好是前面所说 iPhone 7 分辨率(750px * 1334px) 的一半大小,这说明两者之间是存在一定关系的。而 devicePixelRatio 正好是用来描述这两者的比例关系的,下面将进行详细介绍。

  • 物理像素:把分辨率的像素称之为物理像素或设备像素(如 iPhone 7 的物理像素为 750px * 1334px),它是显示设备中一个最微小的物理部件。
  • 设备独立像素:CSS 的尺寸像素称之为设备独立像素(device-independent pixels 简称为“DIPs”)或 CSS 像素(如 iPhone 7 的设备独立像素为 375px * 667px),它是一个抽象的单位,主要使用在浏览器上,用来精确的度量(确定)Web页面上的内容。
  • devicePixelRatio(简写 DPR): 用来描述物理像素与设备独立像素的比例,其值等于 “物理像素 / 设备独立像素”。devicePixelRatio 值为 1 时就是标准屏,值为 2 时则是俗称的 2 倍屏(2x),同样 3 就是 3 倍屏(3x)。

注:其实在打开 chrome 开启移动端调试的时候,就可以看到设备独立像素和 DPR(如果看不到 DPR,则打开右边设置,找到 device pixel ratio 即可) ,如下图:

retina-mobile-debug.png

通过上面的说明,可以得到 iPhone 7 的 devicePixelRatio 为 2 (750px / 375px = 2),就是 2 倍屏。那么这个 2 倍屏跟普通的标准屏有什么区别呢?

对一个标准屏来说,渲染一个 2px 2px 的盒子将会使用 2px 2px 物理像素,如普通电脑屏;但是对于一个 2 倍屏来说,渲染一个 2px 2px 的盒子将会使用 (2px 2)  (2px 2) 物理像素,如 iPhone 4、5、6、7,如下图:

retina-dpr.png

注:在 3 倍屏出现以前,retina 显示屏一般就指代了 2 倍屏,所以如果是查看以往的资料,会有很多这种情况。

更多关于 devicePixelRatio 的资料可参看:

面临问题

熟悉了这些概念之后,就要开始解决需要面临的问题了。由于 devicePixelRatio 不再是1,物理像素与设备独立像素不再对等,所以在实际网页开发时面临了2个问题:图片虚化、1px边框变粗

图片虚化

位图(png, jpg, gif等)是由一个个像素点构成的,每个像素都具有特定的位置和颜色值,称之为位图像素,如下图:

retina-bitmap.png

当一个位图在标准屏显示时,一位图像素对应的就是一物理像素,这样就保证了一个完全保真的显示。但是当在 2 倍屏下时,它需要要放大四倍(宽高各两倍)来保持相同的物理像素的大小,这样就会丢失很多细节,造成失真的情形,也就是常说的图片虚化问题。如下图:

retina-bitmap-pixels.png

那么怎么解决该问题呢?说到底就是为了让一位图像素对应一物理像素,既然物理像素已经定了不能变,那么是否可以改变位图像素呢?答案是肯定的。

可以把要使用的图片扩大一倍,如要用的图片大小为 2px 2px,我以使用 4px 4px 的图片然后设置图片大小为 2px * 2px,这样对于2倍屏则正好,而标准屏则减少像素取样(一定程度上的浪费),如下图:

retina-bitmap-2x.png

这样就解决了图片在2倍屏的虚化问题,对于3倍屏也是一样的道理

1px 边框变粗

为了说明这个问题,先看一个1px demo,截图如下(iPhone 6截图):

1px-1.png

如果把上图与手机系统上的 1px 边框进行对比,如下图:

1px-2.png

会发现,上面两个上下线条,下线条的粗细才是正确的,上线条就显得有点粗了。但是上线条是用纯正的 1px border生成的,而下线条实际是采用transform压缩了1px高度的一半模拟实现的,也就相当于 0.5px 的高度了。为什么会这样呢?

这是因为在2倍屏时1 CSS 像素实际对应2个物理像素, 所以为了实现真正的 1px 粗细,得使用 0.5px 来模拟。目前除 ios8+ 可以直接使用 0.5px 单位外,其余皆得通过模拟的办法搞定。具体实现办法有很多,可以参考:7种方法解决移动端Retina屏幕1px边框问题

注:一般使用上面 1px demo 中的方法。

附:iPhone 6/6s/7 plus 的 3 倍屏

iPhone 6/6s/7 plus 的分辨率为1080px 1920px ,而其设备独立像素为 414px 736px,如果按照计算其devicePixelRatio(1080 / 414) 并不等于 3,但是通过window.devicePixelRatio或在模拟的时候都是 3。

这是因为它进行了缩放,如下图(具体可参看:iPhone 6 Screens Demystified 的图形说明):

retina-7plus-3x.png

参考资料

媒体查询(media queries)

image.png

  • 媒体类型:all、screen、print、TV...
  • 逻辑操作符:and、not、all
  • 媒体属性:min/max-height、orientation、device-width/height、-webkit-device-pixel-ratio...

另一种写法: image.png

响应式布局

各类响应式技术可应用于响应式布局。响应式布局案例:流体布局、固定 & 流体、表现形式改变(比如 PC 导航栏和移动端导航栏的样式不同)

响应式图片

image.png

这里的 640px 指的是当前面条件不满足时,取的默认值。

sizes

需要的图片大小(相当于响应式查询),

image.png

srcset

供选择的图片规格

w 为宽度描述符。

image.png

x 为倍屏描述符。

响应式资源参考

只要处理好以下两点:

  • 断点设置:可以先综合判断要实现各个平台断点,然后再针对一些特殊局部进行单独的断点
  • 内容布局呈现:这个可能就比较繁琐,有些时候还得有一定的想象力。

目前响应式社区很活跃,资源也非常多。

基本认识

整体布局

内容处理相关

框架相关

工具相关

其他

注:一般来说复杂的站点都会单独处理移动端,而不是全兼容从 PC 到 移动端的全兼容,毕竟移动端还是以轻快为主。

常见 CSS 框架

有时候为了提高开发效率,往往会使用一些前端的 CSS 框架。当框架的功能能够满足需求时,使用框架是一个不错的主意。下面介绍几款常见的 CSS 框架,以供学习或工作之选。

Bootstrap

Bootstrap 是世界上最流行的前端基础框架之一,可用于构建响应式或移动端项目以及帮助快速开发web应用。其在推出之后就广受追捧,并掀起了 UI 框架热。在许多有名的网站都能看到使用 Bootstrap 的身影,而在管理后台方面更是一骑绝尘成为首先框架。

framework-boostrap.png

Pure CSS

Pure.css 是一套小型响应式 CS S模块,可用于所有 Web 项目,为原生 HTML 元素以及最常见的 UI 组件提供布局和样式。Pure.css 其代码十分精简,压缩后体积才3.8kb,十分适合移动端和响应式场景的开发。

framework-pure.png

WE UI

WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。如果需要开发微信场景的 H5 页面,可以使用 WeUI 来使用微信风格的样式和提高样式开发效率。

framework-weui2.png

总结

市面上还有许多优秀的 CSS 框架,在选择使用 CSS 框架前,需要先认真考虑自身使用场景和了解可选框架的提供的功能。只有选择适合的框架,才能事半功倍。

CSS 预处理

网站复杂度日益加深,或 CSS 语法能力不够时,CSS 预处理器可以处理上述问题。

流行的三种预处理器:sass、less、stylus

这里以 sass 为例

嵌套

image.png

变量

image.png

mixin

image.png

循环

image.png

Sass 资源参考

Sass 学习参考资源也是非常的多,语法入门其实也比较简单,更深入的了解可以参考如下教程:

Sass 安装与编译

ruby sass

首先,Sass 是用 ruby 写的,所以可以使用 ruby 来编译。

可以选择使用淘宝RubyGems镜像安装。

注:因为 ruby 的编译速度实在不怎么的,所以在项目中一般选择下面的 libsass。

libsass

libsass 是一个用 C 语言实现的 Sass 解析器。特点是简单、速度快而且易于集成。但是 libsass 只是一个库,并不能直接使用,如果要实际使用还需要一个外壳来进行包装,如PHP,Node等

对于前端来说,优先选择的当然是用 Node 包裹的 node-sass

手动下载对应的node sass binaries放到对应的目录中。

注:对于大项目来说,配置自动化 node-sass 编译才是最优选择。

其他编译

  • 编辑器编译:一般来说,编辑器都会有相应的 Sass 编译插件,或默认就自带了 Sass 编译功能
  • 在线编译:Sass meister
  • 图形化编译工具:Koala
  • 构建自动化编译:node-sass

水平垂直居中技术

下面是一些总结文章,可以参考:

不定宽高图片处理

如何处理可参看:CSS 中如何做到容器按比例缩放

其他

CSS 标准、支持及未来

由于从 CSS3 开始,CSS 属性是按照功能模块来分开开发的,每个模块开发完毕就会进入下一个版本,这样持续更新迭代发展,而整个 CSS 的大版本还是一致保留在 3 这个阶段,所以不存在 CSS4,但是存在某个模块版本的4,5,6...

常逛站点

个人重构经验

参考资料