来自 前端知识 2019-11-21 21:27 的文章
当前位置: 金沙澳门官网网址 > 前端知识 > 正文

澳门金莎娱乐手机版用法教程

全局CSS的终结(狗带)

2015/10/24 · CSS · 全局

原文出处: Mark Dalgleish   译文出处:AlloyTeam   

CSS类名总是作用在同一的全局作用域里面。

任何一个跟CSS有长时间打交道的开发者,都不得不接受CSS那具有侵略性的全局特性,明显地这是一种文档流时代的设计模型。而对于今天现代web应用,更应该积极提出一种更健全的样式环境。

每一个CSS类名都有可能与其它元素产生的意想不到副作用,又或者产生冲突。更令人吃惊的是,我们的class的效果可能在全局作用域的互相影响下(原文这里比喻为全局唯一性战争),最终在页面上产生很少的效果或者根本没有效果。

任何时候我们改变一个CSS文件,我们都需要小心翼翼地考虑全局环境是否产生冲突。没有其他前端技术是需要如此之多的规范和约束,而这仅仅是为了保持最低级别的可维护性。

 

、、、

 

但我们不能一直这样下去。是时候摆脱这种全局样式的折磨。开启局部CSS的时代!

“在其他语言,全局环境的修改需要变动的代码很少”

在javascript的社区中,感谢Browserify,Webpack和JSPM,让我们的代码变得模块化,每个模块有明确的依赖及其输出的API。然而,不知怎么的,CSS视乎总时被忽略掉。

我们中许多人,包括我自己,一直使用CSS工作这么长时间,我们都没有发现缺少局部性作用域,是一种问题。因为没有浏览器厂商的重大帮助下我们也能够解决。即使这样,我们仍然需要等待着,大部分用户能使用上浏览器的ShadowDOM的支持。

在全局作用域问题上,我们已经使用一系列的命名规范来编码。想OOCSS, SMACSS,BEM和SUIT,每一个都提供着一种方式模拟健全的作用域规则,达到避免命名冲突效果。

虽然驯服CSS无疑是一个巨大的进步,但这些方法都没有解决我们样式表上真正的问题。无论我们选择哪个规范,我们依然被卡在全局类名上。

但,在2015年的四月22号将会发生改变。

、、、
正如我们此前的一篇文章涉及到——“Block,Element,修改你的JavaScript组件”——我们可以利用Webpack把我们的CSS
作为一种JavaScript模块来引用。如果这听起来很陌生,去读读这篇文章会是一个good idea,以免你错失接下来要讲的内容。

使用Webpack的css-loader,引用一个组件的CSS如下:

JavaScript

require('./MyComponent.css');

1
require('./MyComponent.css');

乍一看,这很奇怪,我们引用的是CSS而不是JavaScript

通常,一个require引入的应该提供一些局部作用域。如果不是,明显低会产生全局作用域的副作用,这是一种拙劣的设计。而CSS的全局作用域特性,却必定产生这样的副作用。

因此我们在思考

、、、

2015年4月22日,Tobias Koppers这位对Webpack孜孜不倦的代码提交者,提交了一个css-loader新特性的版本提交。当时叫placeholder,而现在叫local-scope。这个特性允许我们输出classname从我们的CSS到使用中的JavaScript代码。

简而言之,下面这种写法:

JavaScript

requrie('./MyComponent.css');

1
requrie('./MyComponent.css');

我们改为

JavaScript

import styles from './MyComponent.css';

1
import styles from './MyComponent.css';

看看我们导出的CSS是怎么样的,我们的代码大概如下:

:local(.foo){ color: red; } :local(.bar){ color:blue; }

1
2
3
4
5
6
:local(.foo){
    color: red;
}
:local(.bar){
    color:blue;
}

在上面的例子中我们使用css-loader的定制的语法  :local(.idntifier) ,输出了两个的标识符,foo和bar。
这些标识符对应着class strings,这将用在javascript文件中去。例如,当我们使用React:

import styles from './MyComponent.css'; import React, { Component } from 'react'; export default class MyComponent extends Component { render() { return ( <div> <div className={styles.foo}>Foo</div> <div className={styles.bar}>Bar</div> </div> ); } }

1
2
3
4
5
6
7
8
9
10
11
12
import styles from './MyComponent.css';
import React, { Component } from 'react';
export default class MyComponent extends Component {
  render() {
    return (
      <div>
        <div className={styles.foo}>Foo</div>
        <div className={styles.bar}>Bar</div>
      </div>
    );
  }
}

重要的是,这些标识符映射的class strings,在全局作用域上是保证唯一的。
我们不再需要给所有的类名添加冗长的前缀来模拟范围。多个组件可以自定义自己的foo和bar标识符。——不像传统的全局作用域的模式,也不会产生命名冲突。

、、、

非常关键的一点,不得不承认这已经发生了巨大转变。
我们现在更有信心地大胆修改我们的CSS,不用小心翼翼地怕影响其他页面的元素。我们引入了一个健全的作用域模式

全局CSS的好处是,组件间通过通用的class来达到复用的效果——这仍然可以在局部作用域模型上实现。关键的区别是,就像我们编码在其他语言上,我们需要显式地引入我们依赖的类。假想一下在全局命名环境,我们引入的局部CSS不需要很多。

“编写可维护的CSS现在是值得提倡的,但不是通过谨慎地准守一个命名约定,而是在开发过程中通过独立的封装”

由于这个作用域模型,我们把实际的classname的控制权移交给Webpack。幸运的是,这是我可以配置的。默认情况下,css-loader会把标识符转换成为hash。
例如:

JavaScript

:local(.foo){....}

1
:local(.foo){....}

 

编译为:

JavaScript

._1rJwx92-gmbvaLiDdzgXiJ { … }

1
._1rJwx92-gmbvaLiDdzgXiJ { … }

在开发环境调试来讲,会带带来一些阻碍。为了令到我们的classes变得更加有用,我们可在Webpack的config里面设置css-loader的参数,配置class的格式。

JavaScript

loaders: [ ... { test: /.css$/, loader: 'css?localIdentName=[name]__[local]___[hash:base64:5]' } ]

1
2
3
4
5
6
7
loaders: [
  ...
  {
    test: /.css$/,
    loader: 'css?localIdentName=[name]__[local]___[hash:base64:5]'
  }
]

在这一次,我们的foo这个class会比之前编译的更加好辨认:

JavaScript

.MyComponent__foo___1rJwx { … }

1
.MyComponent__foo___1rJwx { … }

我们能清晰地看得到标识符的名字,以及他来自哪个组件。使用node_env环境变量,我们能根据开发模式和生产环境配置不同的class命名模式。

JavaScript

loader: 'css?localIdentName=' + ( process.env.NODE_ENV === 'development' ? '[name]__[local]___[hash:base64:5]' : '[hash:base64:5]' )

1
2
3
4
5
loader: 'css?localIdentName=' + (
  process.env.NODE_ENV === 'development' ?
    '[name]__[local]___[hash:base64:5]' :
    '[hash:base64:5]'
)

 

一旦我们发现这个特性,我们不用犹豫地在我们最新的项目上本地化起来。如果按照惯例,我们已经为组件化而使用BEM命名CSS,这真是天作之合。

有趣的是,一种现象很快地出现了,我们大部分CSS文件里只有局部化class:

JavaScript

:local(.backdrop) { … } :local(.root_isCollapsed .backdrop) { … } :local(.field) { … } :local(.field):focus { … } etc…

1
2
3
4
5
:local(.backdrop) { … }
:local(.root_isCollapsed .backdrop) { … }
:local(.field) { … }
:local(.field):focus { … }
etc…

 

全局性的class仅仅在web应用里面的一小部分,本能地引开出一个重要问题:

“如果不需要特殊语法,我们的class默认是局部性的,而让全局性的class需要例外。怎么样?”

如果这样,我们上面的代码就变成如下:

JavaScript

.backdrop { … } .root_isCollapsed .backdrop { … } .field { … } .field:focus { … }

1
2
3
4
.backdrop { … }
.root_isCollapsed .backdrop { … }
.field { … }
.field:focus { … }

 

虽然这class通常会过于模糊,但当他们转换为css-lodaer的局部作用域的格式后将会消除这一问题。并且确保了明确的模块作用域来使用。

少数情况,我们无法避免全局样式,我们可以明确地表明一个特殊的全局语法。例如,当样式使用ReactCSSTransitionGroup来生成一个无作用域classes。

.panel :global .transition-active-enter{…}

在这个例子中,我们不只是使用本地化方式命名我的模块,我们也命名了一个不在我们的作用域上的全局class。

、、、

一旦我开始调查我如何实现这个默认局部化class语法,我们意识到它不会太困难。
为了达到这个目的,我们推荐PostCSS——一个神奇的工具允许你编写自定义的CSS转换插件。今天最受欢迎的CSS构建工具Autoprefixer实际上是PostCSS插件,同时为一个独立的工具而已。

为让局部CSS正式地使用,我已经开源了一个高度实验性质的插件postcss-local-scope。它仍然在发展,所以在生产环境中使用你需要控制风险。

如果你使用Webpack,这是非常简单的流程:挂上postcss-loader和postcss-local-scope在你的CSS构建流程。比起文档,我已经创建了一个示例库——postcss-local-scope-example。里面显示了怎么使用的例子。
令人激动的是,引入局部作用域仅仅是一个开始。
让构建工具处理classname有一些潜在的巨大影响。从长远来看,我们应该停止人为的编译器,而是让计算机来优化输出。

“在未来,我们可以在一个最优的编译时间内,自动化找出可重用的样式,生成可组件之间共享的class”

一旦你尝试了局部CSS,你就回不去了。真正体验过,样式的局部作用性在所有浏览器上运行正常,你会难以忘记的体验。

引入局部作用域对我们处理CSS有重大的的连锁反应。命名规范,重用模式,潜在的样式抽离,分包等等,都会直接受到这种转变的影响。我们仅仅在这里开始了局部CSS的时代。

理解这种转变的影响是我们依旧需要努力。伴随你有价值的投入和实验,我希望这是作为一个更大的社区的一次谈话

“加入我们,check出postcss-local-scope-example的代码,眼见为实”

一旦你行动了,我认为你会同意这并不夸张: 全局CSS的日子将会终结,局部CSS才是未来。

 

后记:
2015年5月24日: postcss-local-scope的最初想法已经被Webpack的TobiasKoppers所接受。这意味着改项目已经被弃用了。现在我们初步确认在css-loader上通过一个module的标志可以支持CSS Modules。我创建了一个库来演示CSSModules在css-loader上的用法,包括类的继承及职能组件间共享样式等。

1 赞 1 收藏 评论

澳门金莎娱乐手机版 1

二、全局作用域

CSS Modules 允许使用:global(.className)的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。

App.css加入一个全局class。

JavaScript

.title { color: red; } :global(.title) { color: green; }

1
2
3
4
5
6
7
.title {
  color: red;
}
 
:global(.title) {
  color: green;
}

App.js使用普通的class的写法,就会引用全局class。

JavaScript

import React from 'react'; import styles from './App.css'; export default () => { return ( <h1 className="title"> Hello World </h1> ); };

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import styles from './App.css';
 
export default () => {
  return (
    <h1 className="title">
      Hello World
    </h1>
  );
};

运行这个示例。

JavaScript

$ npm run demo02

1
$ npm run demo02

打开

CSS Modules 还提供一种显式的局部作用域语法:local(.className),等同于.className,所以上面的App.css也可以写成下面这样。

JavaScript

:local(.title) { color: red; } :global(.title) { color: green; }

1
2
3
4
5
6
7
:local(.title) {
  color: red;
}
 
:global(.title) {
  color: green;
}

CSS Modules 用法教程

2016/06/19 · CSS · Modules

原文出处: 阮一峰   

学过网页开发就会知道,CSS 不能算编程语言,只是网页样式的一种描述方法。

为了让 CSS 也能适用软件工程方法,程序员想了各种办法,让它变得像一门编程语言。从最早的Less、SASS,到后来的 PostCSS,再到最近的 CSS in JS,都是为了解决这个问题。

澳门金莎娱乐手机版 2

本文介绍的 CSS Modules 有所不同。它不是将 CSS 改造成编程语言,而是功能很单纯,只加入了局部作用域和模块依赖,这恰恰是网页组件最急需的功能。

因此,CSS Modules 很容易学,因为它的规则少,同时又非常有用,可以保证某个组件的样式,不会影响到其他组件。

澳门金莎娱乐手机版 3

六、输入变量

CSS Modules 支持使用变量,不过需要安装 PostCSS 和 postcss-modules-values。

JavaScript

$ npm install --save postcss-loader postcss-modules-values

1
$ npm install --save postcss-loader postcss-modules-values

把postcss-loader加入webpack.config.js。

JavaScript

var values = require('postcss-modules-values'); module.exports = { entry: __dirname + '/index.js', output: { publicPath: '/', filename: './bundle.js' }, module: { loaders: [ { test: /.jsx?$/, exclude: /node_modules/, loader: 'babel', query: { presets: ['es2015', 'stage-0', 'react'] } }, { test: /.css$/, loader: "style-loader!css-loader?modules!postcss-loader" }, ] }, postcss: [ values ] };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var values = require('postcss-modules-values');
 
module.exports = {
  entry: __dirname + '/index.js',
  output: {
    publicPath: '/',
    filename: './bundle.js'
  },
  module: {
    loaders: [
      {
        test: /.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: ['es2015', 'stage-0', 'react']
        }
      },
      {
        test: /.css$/,
        loader: "style-loader!css-loader?modules!postcss-loader"
      },
    ]
  },
  postcss: [
    values
  ]
};

澳门金莎娱乐手机版 ,接着,在colors.css里面定义变量。

JavaScript

@value blue: #0c77f8; @value red: #ff0000; @value green: #aaf200;

1
2
3
@value blue: #0c77f8;
@value red: #ff0000;
@value green: #aaf200;

App.css可以引用这些变量。

JavaScript

@value colors: "./colors.css"; @value blue, red, green from colors; .title { color: red; background-color: blue; }

1
2
3
4
5
6
7
@value colors: "./colors.css";
@value blue, red, green from colors;
 
.title {
  color: red;
  background-color: blue;
}

运行这个示例。

JavaScript

$ npm run demo06

1
$ npm run demo06

打开

1 赞 3 收藏 评论

澳门金莎娱乐手机版 4

四、 Class 的组合

在 CSS Modules 中,一个选择器可以继承另一个选择器的规则,这称为”组合”(“composition”)。

在App.css中,让.title继承.className 。

JavaScript

.className { background-color: blue; } .title { composes: className; color: red; }

1
2
3
4
5
6
7
8
.className {
  background-color: blue;
}
 
.title {
  composes: className;
  color: red;
}

App.js不用修改。

JavaScript

import React from 'react'; import style from './App.css'; export default () => { return ( <h1 className={style.title}> Hello World </h1> ); };

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import style from './App.css';
 
export default () => {
  return (
    <h1 className={style.title}>
      Hello World
    </h1>
  );
};

运行这个示例。

JavaScript

$ npm run demo04

1
$ npm run demo04

打开

App.css编译成下面的代码。

JavaScript

._2DHwuiHWMnKTOYG45T0x34 { color: red; } ._10B-buq6_BEOTOl9urIjf8 { background-color: blue; }

1
2
3
4
5
6
7
._2DHwuiHWMnKTOYG45T0x34 {
  color: red;
}
 
._10B-buq6_BEOTOl9urIjf8 {
  background-color: blue;
}

相应地, h1的class也会编译成<h1 class=”_2DHwuiHWMnKTOYG45T0x34 _10B-buq6_BEOTOl9urIjf8″>。

本文由金沙澳门官网网址发布于前端知识,转载请注明出处:澳门金莎娱乐手机版用法教程

关键词: