CSS模块化的演进

Posted 腾讯NEXT学位

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSS模块化的演进相关的知识,希望对你有一定的参考价值。


| 导语 CSS 做为 Web 技术的基石,从一开始就展示出了巨大的潜力。它的入门非常简单,你只需为元素定义好样式属性和值。然而 CSS 特性随着规范的升级越来越丰富,前端业务复杂性的增加也使得工程愈加庞大。在大型 Web 应用里面,CSS 的组织是一件复杂和凌乱的事情,你更改页面上任意一个元素的一行CSS样式都有可能影响到其他页面上的元素。

  

由于 CSS 本身并不编程特性,因此在演变过程中出现了很多优秀的编程思想,本文会带领大家探讨 CSS 模块化的演变历程。


CSS 预处理器


CSS 预处理器是什么?一般来说,它们基于 CSS 扩展了一套属于自己的 DSL,来解决我们书写 CSS 时难以解决的问题:


  • 语法不够强大,比如无法嵌套书写导致模块化开发中需要书写很多重复的选择器

  • 没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护。


Sass、LESS、Stylus 是目前最主流的 CSS 预处理器,它们本质上是一种编译器。此处以 Sass 为例,它支持 .scss,.sass 文件类型。其语法支持变量、选择器嵌套、继承(extend)、混合(mixin)和一些逻辑语句,同时还支持跨文件的导入功能,因而使得开发者能够很好的使用编程思想书写样式。


变量

$red: #f00;


.body {

  color: $red;

}


选择器嵌套

.hello {

  .world {

    color: red;

  }

}


生成的 CSS 为:

.hello .world {

  color: red;

}


mixin

对于预处理器来说,mixin(混合)应该是它的最精髓的功能之一了,它提供了 CSS 缺失的最关键的东西:样式层面的抽象。


Sass 用 @mixin@include 两个指令清楚地描述了语义:


@mixin large-text {

  font: {

    family: Arial;

    size: 20px;

    weight: bold;

  }

  color: #ff0000;

}


.page-title {

  @include large-text;

  padding: 4px;

  margin-top: 10px;

}


后处理器


后处理器其实也是一种编译器,如果说预处理器是事前编译,那么后处理器就是事后编译。比较典型的后处理器有:


  • clean-css: 用来压缩CSS

  • AutoPrefixer: 自动添加 CSS3 属性各浏览器的前缀

  • Rework: 取代 stylus 的插件化框架

  • PostCSS


举个例子:补足前缀。

.wrap {

  display: flex;

}


对于这段代码,AutoPrefixer会根据 Can I use 的浏览器支持数据为基础,自动补全前缀,编译后的代码如下:


.wrap {

  display: -webkit-box;

  display: -webkit-flex;

  display: -ms-flexbox;

  display: flex;

}


SMACSS可扩展CSS


SMACSS(Scalable and Modular Architecture for CSS) 即可扩展的模块化CSS架构。它的核心思想是将 CSS 的组织划分为5类:


基础样式

基础样式包括设置默认超链接的颜色,默认字体样式和body背景。通常用来定义全局的样式,比如 CSS Reset。


body, form {

  margin: 0;

  padding: 0;

}

a {

  color: #039;

}

a:hover {

  color: #03F;

}


布局

将页面分为各个区域的元素块,比如header, sidebar, footer等。


模块

可复用的单元。在模块中需要注意的是选择器一律选择 class selector,避免嵌套子选择器,减少权重,方便外部覆盖。


状态

状态 class 一般通过js动态挂载到元素上,可以根据状态覆盖元素上特定属性。


.tab { background-color: purple;... }

.is-tab-active { background-color: white; }


主题

可选的视觉外观。一般根据需求有颜色,字体,布局等等,实现是将这些样式单独抽出来,根据外部条件( data 属性,媒体查询等)动态设置。


BEM


BEM 即Block Element Modifier;类名命名规则: Block__Element—Modifier


  • Block 所属组件名称

  • Element 组件内元素名称

  • Modifier 元素或组件修饰符


其核心思想就是组件化。首先一个页面可以按层级依次划分未多个组件,其次就是单独标记这些元素。BEM通过简单的块、元素、修饰符的约束规则确保类名的唯一,同时将类选择器的语义化提升了一个新的高度。


CSS IN JS


我们都知道传统的前端开发的分层模型中,html, CSS和JS是相互分离的,也因此形成了一个网页开发的准则”关注点分离“。


CSS IN JS 这个理念是由 Facebook 工程师 vjeux 在一次分享中提出的,用来解决在 React 中使用 CSS 的问题。因为 React 的组件结构,强制要求把 HTML、CSS、javascript 写在一起。比如:


const style = {

  'color': 'red',

  'fontSize': '46px'

};


const clickHandler = () => alert('hello');


ReactDOM.render(

  <div style={ style } onclick={ clickHandler }>

    Hello, world!

  </div>,

document.getElementById('app')

);


这种写法将结构,样式和行为写在了一起,完全违背了”关注点分离”的原则。但是,这有利于组件的隔离。每个组件包含了所有需要用到的代码,不依赖外部,组件之间没有耦合,很方便复用。


CSS Module


CSS Module 并不是将 CSS 改造成编程语言,而是通过给 CSS 加入局部作用域和模块依赖的方式达到 CSS 的模块化。


比如,一个React组件App.js:


import style from './App.scss';


export default class App extends Component {


  render() {

    return (

      <div className={styles.app}>CSS Modules Demo</div>

    );

  }

}


上面代码中,我们将样式文件App.css输入到style对象,然后引用style.app代表一个class。


.app {

  text-size-adjust: none;

  font-family: helvetica, arial, sans-serif;

  line-height: 200%;

  padding: 6px 20px 30px;

}


构建工具会将类名style.app编译成一个哈希字符串。


<div>

  Hello World

</div>


对应的CSS如下:


.App__app___3lRY_ {

  -webkit-text-size-adjust: none;

  -ms-text-size-adjust: none;

  text-size-adjust: none;

  font-family: helvetica, arial, sans-serif;

  line-height: 200%;

  padding: 6px 20px 30px;

}


CSS Module为每个本地定义的类名动态创建一个全局唯一类名,然后注入到UI。从开发体验上来看,这种做法让开发者不必在类名的命名上小心翼翼,直接使用随机编译生成唯一标识即可。


CSS Module支持多种构建工具,本文使用的是 webpack 构建,在css-loader后面通过增加modules参数的方式开启 CSS Module,如下所示:


{

test: /\.css$/,

loader: 

"style-loader!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader"

},


备注:css-loader默认的哈希算法是[hash:base64],会将这会将 .app 编译成 ._3zyde4l1yATCOkgn-DBWEL 这样的字符串。此处通过localIdentName修改哈希名称为 Appapp_3lRY_ 的形式。


总结


CSS 的模块化演进历程还在继续,目前还未像 JavaScript 模块化出现 ES Modules 语言层面支持的终极方案。在 CSS 模块化演进的过程中,出现了很多优秀的设计思想和实践,这些值得我们借鉴和学习。


---------------------------------------------------------------

来源:腾讯内部KM论坛。


你也想成为腾讯工程师?

也想年终奖人手一部 Iphone X?

那就快加入前端NEXT学位吧!

前端NEXT学位课程第八期火热招生中!

上腾讯课堂官网搜索Next学位还有大量免费体验课等你哟~

  感兴趣的同学赶紧点击原文了解详情吧~


腾讯NEXT学位

求职干货 | 前辈blog  | 前端课程



以上是关于CSS模块化的演进的主要内容,如果未能解决你的问题,请参考以下文章

CSS3介绍

webpack

Node入门教程第五章:node 模块化(上)模块化演进

从混沌到规范:JavaScript模块化方案的演进史

从混沌到规范:JavaScript模块化方案的演进史

架构——android架构演进概述