中国第二届CSS开发者大会

展新:企业CSS应用
支付宝前端发展过程:

很早之前的支付宝的时候只有pa.css, 解决基础样式、重用等功能
=> 后来超过了6000行/100k,全局样式太多,重置困难,烂代码积压
=> 2011年的时候出现了前端解决方案: CSS样式规范,浏览器解决方案: 例如: 解决1px圆角,解决ie6下的浮动 形成了 Alice V3 写样式有道可寻,可维护性强..文件进行拆分,最基础只有20k 但是随着 交互组件缺乏,工程化不足,产品差异化越来越多
=> 出现了AliceUI 模块化命名 和组织方式,强大的工具支持-spm等 CSS3新技术使用 但是视觉规范多变,企业平台业务据增,新技术发展。 所以很多前端技术可能刚开始的使用是放在后台去使用。

(1)在图标设计规范:
在设计iconfont字体的时候,比如在16*16px的设计图中,内部的icon的大小应该是在14*14 或则 15*15,而不是16*16
1. 尽可能地接近普通文字的font-size
2. 视觉上不同的形状做适当的调整,以保证[看起来]都差不多大
3. 图标的线条的粗细保证是像素格的整数倍

(2)iconfont的命名上也是非常讲究的:
一般命名的规范: name - type - direction
比如: caret-circle-left
caret-circle-o-right
caret-o-down
caret-up

(3)色彩中的学问
固定必须要知道的色谱,
基础的色谱: active / link / hover / outline
固定的色谱: 标题颜色, 正文的颜色,辅助的颜色
提示性色谱: 出错的颜色, 成功的颜色, 警告的颜色

郑海波: CSS预处理器
为什么要写css预处理器.?

  CSS的"罪":
        变量
        函数
        逻辑/循环
        前缀
        运算/表达式
  CSS缺乏是抽象能力。
        抽离细节
        减少关注点

CSS中的抽象:CASCADING

'm-layer m-layer-bg m-layer-primary z-show'> Cascading 是CSS的灵魂, 也是限制预处理能力的 “关键点”
.m-layer{...} .m-layer-bg{...} .m-layer-primary{...} .z-show{...}

预处理器:处理特定格式源文件到目标CSS的处理程序。

// 编译前
$color-primary = #de12ec;
.m-layer{
    background-color: $color-primary;
    &:hover{
        background-color: l-adjust($color-primary, -10%);
    }
}

// 编译后
.m-layer{
    background-color:#de12ec;
}
.m-layer:hover{
    background-color:#b10ebd;
}

预处理器青铜时代: LESS-SCSS-Stylus

nav {
    ul {
        margin: 0;
        padding: 0;
        list-style: none;
    }

    li { display: inline-block; }

    a {
        display: block;
        padding: 6px 12px;
        text-decoration: none;
    }
}

优点:
对前端更友好
不基于缩进,不简洁但更安全
与自定义DSL同样强大的语言能力
可以直接使用css书写

预处理器钢铁时代(纯CSS语法)
严格遵守CSS语法的提供额外能力的CSS预处理器
postcss: https://github.com/postcss
rework: https://github.com/reworkcss
postcss简介:

            npm install postcss --save-dev

            postcss其实只是个平台,它提供解析,AST便利操作。
            SourceMap和翻译器,具体功能由插件实现。            

官方案例:

var postcss = require('postcss');

postcss([ 
        // 允许你使用"阉割版"的未来的CSS特性
        require('cssnext')(), 
        // 一个高级的css压缩器
        require('cssnano')() 
        ])
.process(css, { from: 'src/app.css', to: 'app.css' })
.then(function (result) {
        // 写入变换后的css文件
    fs.writeFileSync('app.css', result.css);
    // sourmap文件
    if ( result.map ) fs.writeFileSync('app.css.map', result.map);
});

POSTCSS正在渐渐成为预处理器中的jQuery;

// 编译前before compile
.m-nav{
    .list{
        padding: 10px;
    }
    .link{
        color: red;
        &:hover{
            color: green;
        }
    }
}

// 编译后 after compile
.m-nav .list{
    padding:10px;
}
.m-nav .link{
    color:#f00;
}
.m-nav .link:hover{
    color:#008000;
}

Nesting建议嵌套尽量不要超过3层
1. 使用选择器提升

.m-layer{   // 一般这个表示的是一个组件对应的样式,但是嵌套多层不好
    .cnt{
        .nav{
            .bar{
                padding: 10px;
            }
        }
    }
}

=>

.m-layer{      // 这样的选择依然是唯一的,但是不用嵌套多层
    .layer_bar{
        padding: 10px;
    }
}

2 避免深层选择器序列

// 不好的实践
div, p, span, ul{
    div, p, span, ul{
        div, p, span, ul{
            left: 10px;
        }
    }
}

变量的最佳实践:

  1. 变量名要达意
    // BAD
   $fs1 = 14px;
   $fs2 = 16px;
   $fs3 = 18px;
   $fc0 = #253443; // 主色1 
   $fc1 = #153c3d; // 主色2 
   $fc2 = #777 ;   // 灰色 

   // GOOD
   $fsize-base  = 14px;
   $fsize-small = 12px;
   $fsize-big      = 16px;
   $color-primary = #253443;
   $color-inverse = #153c3d;
   $color-gray      = #777;

2 全局变量集中管理
Rule更易于迁移
变量更易于查找管理
3 私有变量声明在模块内

.m-module{
    $gap = 32px;
    .side{
        margin-right: $gap;
    }
}

4 必须统一管理z-index

// z-index config:
$modal-index = 1000;
$dropdown-index = 100;
$mask-index = $modal-index - 10;

施峰峰:移动下的布局
vw: viewport 宽度的1%
vh: viewport 高度的1%
vmin: viewport Math.min(高度, 宽度)的1%
vmax: viewport Math.max(高度, 宽度)的1%
案例如下:

<div>按钮内容div>

div{
    height: 10vw;
    width: 50vw;
    line-height: 10vw;
    font-size: 5vw;
    text-align: center;
    color: #fff;
    background: red;
    margin: auto;
}

css: 神奇的padding/margin-top;子元素的padding-top百分比基准是父元素的宽度。

.papa { width:100px; height: 300px; background-color: #ddd; overflow: hidden; }

.child { width: 50px; height: 50px; background-color: red; margin-top: 100%; // 这里的值是父元素的宽度 }

结合使用rem和@media

html { font-size:62.5%; }
body { font-size: 1.6rem; }
h1 { text-align: center; font-size: 3rem; }
p { text-align: center; font-size: 1.8rem; }

@media all and (max-width: 700px) {
    html { font-size: 60%; }
}
@media all and (max-width: 608px) {
    html { font-size: 52%; }
}
@media all and (max-width: 533px) {
    html { font-size: 45%; }
}

黄薇(瓜瓜):高性能CSS动画

讲讲web浏览器渲染过程:

1 通过一个get请求,获取一个html页面
2 分析html结构生成DOM树
3 Recalculate Style:分析CSS,浏览器让DOM+CSS生成了叫渲染树(render tree)
4 layout 将渲染树中每个节点,根据宽度高度模型相关的属性来计算它的位置和大小
5 Paint 开始涂鸦,把每个区域涂鸦完毕生成一个位图
6 Composite Layers 浏览器将位图从CPU 传送到 GPU 然后渲染到屏幕上,完成一次渲染工作

从图中可以看出,在width,height,margin等是处于Layout阶段。以及box-shadow处于paint阶段,transform处在Composite Layers阶段。
所以在改变CSS样式属性的时候会触发浏览器中的哪个阶段呢,当触发了某个阶段的执行,同时也会触发该阶段后面的执行。举例触发了Layout阶段,那么Paint和Composite Layers阶段也一样要触发。所以 绘制的阶段,触发的时间越早,消耗的代价越大。

渲染小结

  • 渲染主要三阶段: Layout计算范围,Paint计算展现,Composite合成Bitmap
  • 修改不同CSS属性会触发不同阶段
  • 触发的阶段越前,渲染的代价越高

硬件加速
硬件加速也称为GPU加速。

  • 术语: texture。 可看做一个放在GPU上的位图
  • GPU擅长队texture进行偏移,放大缩小,旋转,更改透明度(意思是处理的特别快,时间短)

浏览器是如何使用GPU的呢?

浏览器中有个Layer模型

  • 浏览器会根据CSS属性为元素生成Layers
  • 将Layers作为texture上传到GPU
  • 当改变Layer的transform,opacity属性时,渲染会跳过Layout,paint;直接通知GPU对Layer做变换。

为什么使用硬件加速实现动画快?

(1)首先,当使用jquery实现div向下移动的动画时。浏览器是做了那些事情?
这里写图片描述

这里每一次top新增1px之后都会触发浏览器重排和重绘制。

(2)使用硬件加速,就可以使用CSS3中的Animate transform
这里写图片描述
然而这里是直接触发了Composite Layers阶段,减少了重排和重绘的过程。
节省了CPU进行Layout,Paint的时间,CPU向GPU传输位图的时间。

fps
对人类的眼睛来说,30FPS+是感觉流畅的,60FPS(1s显示60张图片)会更加舒服。
所以为了使得舒服顺滑的动画,就必须在1/60FPS,约等于16.7ms内,把这一帧准备好。

渲染时机的选择:
(1)setTimeout(callback, 1/60)来实现动画
缺点:

  • 依靠浏览器内置时钟更新频率,然后ie等浏览器更新的间隔时间不一样
  • main thread队列,如果上个帧的动画展示出错那么会影响下一帧的动画。

(2)HTML5的出现:requestAnimationFrame(更好的选择)

  • 定义绘制每一帧前的工作。 requestAnimationFrame(callback)
  • 自动调节频率。callback工作太多无法在一帧内完成,会自动降低为30FPS, 虽然频率降低但比丢帧好。

渲染一帧的时间:
目标:16ms

触发Layout:

  • 改变width, height, margin等和大小、位置相关的属性
  • 读取size, position相关得属性(因为一个页面中有多个脚本,有时候很多脚本就是改变了width和height,为了页面的正确性,所以当读取这些属性的时候会触发Layout阶段)
    相关属性有:
clientHeight, clientLeft, clientTop, clientWidth, focus(), getBoundingClientRect(), getClientRects(), innerText, offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth, outerText, scrollByLines(), scrollByPages(), scrollHeight, scrollIntoView(), scrollIntoViewIfNeeded(), scrollLeft, scrollTop, scrollWidth .....

尽量不要去触发Layout: 使用transform代替top, left的动画

// 频繁Layout
var h1 = element1.clientHeight;
element1.style.height = (h1 * 2) + 'px';

var h2 = element2.clientHeight; 
element2.style.height = (h2 * 2) + 'px';

var h3 = element3.clientHeight;
element3.style.height = (h3 * 2) + 'px';

读取clientHeight属性的时候,就会出发Layout,比如上图,读取h2的时候无法确认h1的位置有没有变化,所以会发生Layout。

// 分离读取操作
// Read
var h1 = element1.clientHeight;
var h2 = element2.clientHeight;
var h3 = element3.clientHeight;

// Write
element1.style.height = (h1 * 2) + 'px';
element2.style.height = (h2 * 2) + 'px';
element3.style.height = (h3 * 2) + 'px';

这样浏览器会先将数据取出来,然后再下面才会进行改变,触发一次Layout。

事实上,两段代码的实际写法如下:

document.body.addEventListener('click', function() {
    var h1 = element1.clientHeight;
    element1.style.height = (h1 * 2) + 'px';
});

document.body.addEventListener('click', function() {
    var h2 = element2.clientHeight;
    element2.style.height = (h2 * 2) + 'px';
});   // 在这里无法将两次的操作读写放在一起

所以使用requestAnimationRequest推迟执行

document.body.addEventListener('click', function() {
    // Read
    var h1 = element1.clientHeight;
    // Write
    requestAnimationFrame(function() {
      element1.style.height = (h1 * 2) + 'px';
    });
});
document.body.addEventListener('click', function() {
  // Read
  var h2 = element2.clientHeight;
  // Write
  requestAnimationFrame(function() {
    element2.style.height = (h2 * 2) + 'px';
    });
});
// 使用了requestAnimationFrame使得在第一帧的时候只会去读取h1和h2这两个数据的值,
// 而在下一帧的时候才回去去触发Layout

触发Paint
当修改border-radius,box-shadow,color等展示相关属性时,会触发paint

减少不必的绘制: gif图即使被其他Layer盖住不可见,也可能导致paint,不需要时应将gif图的display属性设为none。
减少绘制区域:为引起大范围Paint的元素生成独立的Layer以减小Paint的范围

附上中国第二届CSS开发者大会地址
https://www.w3ctech.com/topic/1463

你可能感兴趣的:(css)