ホームページ > 記事 > ウェブフロントエンド > CSSモジュールの詳細説明
カスケード スタイル シート
css の正式名はカスケード スタイル シートと呼ばれることがわかっています。この「「カスケード」とは一体何を意味するのでしょうか?
1 つの説明は、最初にスタイル ルール (プレーヤー 1):
.title { color: silver; }
を記述し、その後に同様のルールを記述した場合 (プレーヤー 2):
.title { color: gold; }
名前が同じなので、プレイヤー 2 はプレイヤー 1 と戦います (私のふりをしてください!)。結果は、プレイヤー 2 が勝ち、クラス名の要素はタイトル、最終的な色の値は金になります。
CSSではこんな感じです 意見が分かればいつ戦争が始まってもおかしくなく、負けた側は勝った側に上書きされます。 「カスケード」という言葉はこの過程を如実に表していると言えます。
それでは、なぜそのような階層化 (zhàn zhēng) があるのでしょうか?
css スコープの問題
JavaScript では、次のような組み合わせを実現できます:
var title = "silver"; (function(){ var title = "gold"; console.log(title); // gold }()); console.log(title); // silver
JavaScriptの関数スコープを利用して、同じ名前のプレイヤー同士で仲良く遊ぶことができます。
しかし、CSS のスタイル ルールに戻ると、状況はまったく異なります。
CSS はプログラミング言語ではありませんが、それにスコープの概念を追加したい場合、それはグローバル スコープのみです。
CSS ファイルをいくつに分割しても、どのように導入しても、すべてのスタイル ルールは同じスコープ内にあり、セレクターが類似している限り、上書きされる可能性があります。
相互影響を減らすための戦略
相互影響を減らし、予期しないスタイルの上書きを避けるために、私たちは常に多くの方法を考えてきました。
たとえば、他の人が残した古いプロジェクトを引き継ぎ、新しいタイトル要素を追加したい場合、複製が簡単すぎるため、.title のような曖昧なクラス名を意識的に使用しません。名前。 。最終的に使用する名前は次のようになります:
.module-sp-title { color: deepskyblue; }
.title という名前を使用することに決めた場合でも、インクルード セレクターで修飾することになります:
.module-1 .title { font-size: 18px; } /* ... */ .module-2 .title { font-size: 14px; }
.module-1 と .module-2 の名前は一意である必要があります。このようなコードは、コンポーネント化 (モジュール) 開発スタイルでは非常に一般的です。
さらに、SMACSS などのいくつかのよく知られた CSS 理論では、すべてのレイアウト スタイルを区別するために l- またはlayout- 接頭辞を使用することを推奨しています。
同様のアプローチは数多くありますが、最終的には、どれも合理的な命名規則を提供しようとしています。そして、合理的な命名規則は、確かに CSS コードを整理するための効果的な戦略です。
現在、利用可能な新しい戦略があり、CSS モジュールもその 1 つです。
テクノロジー フローのモジュール化
CSS モジュールは、css コードを編成するためのテクノロジー フロー戦略であり、 css のデフォルトのローカル スコープを提供します。
CSS モジュールはどのように行うのでしょうか? CSS モジュールの簡単な例を見てみましょう。
このような HTML 要素があります:
<h2 id="example_title" class="title">a title for CSS Modules</h2>
通常の CSS の記述方法に従って、次のようにスタイルを追加できます:
.title { background-color: snow; }
次に、CSS モジュールに切り替えます。まず、CSSは変更されません。次に、htmlの記述方法を修正します。このように HTML を直接記述する代わりに、JavaScript ファイルに動的に追加します (CSS ファイルは main.css と呼ばれます):
var styles = require("./main.css"); var el = document.getElementById("example_title"); el.outerHTML = '<h2 class="' + styles.title + '">a title for CSS Modules</h2>';
ねえ、これは必須です CSS ファイル?そうです、Webpack が使用されます。コンパイル後の html と css は次のようになります:
#このような見苦しいクラス名を見ればわかると思いますが、CSS モジュールは css のグローバル スコープを変更できません。本質的に、ローカル スコープを実現するためにクラス名を動的に生成することに依存しています。もちろん、クラス名は一意であり、元の CSS コードがどんなに無造作に書かれていても、この方法で変換すると競合しない CSS コードが得られます。
シミュレートされたローカル スコープも問題ではなく、信頼性があります。
CSS モジュールの例はこれで終わりですが、私が最初に見たときと同じくらい多くの疑問があるはずです。
CSS モジュールのアプリケーションの詳細
CSS モジュールを有効にする方法
「webpack は CSS をコンパイルします」以前に使用したことがあるのに、使用するとこのように見えないのはなぜですか?」
一般的に、CSS ファイルを要求する方法は次のとおりです:
require("./main.css");
ただし、前の例では、varstyles = require("./main.css"); という記述方法が使用されていました。これは、この CSS ファイル内のスタイルをローカルにして、必要に応じて使用できるようにしたいと言っているようなものです。
CSS モジュールをプロジェクトに適用する方法はたくさんありますが、現在、より一般的に使用されている方法は、webpack の css-loader を使用することです。 CSS モジュールを有効にするには、webpack 設定ファイルに css-loader?modules を記述します。たとえば、前の例で使用したもの:
module: { loaders: [{ test: /\.css$/, loader: 'style!css?modules' }] }
I Discover that css私が元々使っていた -loader にはこの機能があるのでしょうか?実際、CSS モジュールは実際に、後で css-loader に組み込まれた新しい機能です。
カスタム生成クラス名
”
名字都这样了,还怎么调试?”
为css-loader增加localIdentName参数,是可以指定生成的名字。localIdentName的默认值是[hash:base64],一般开发环境建议用类似这样的配置:
{ test: /\.css$/, loader: 'style!css?modules&localIdentName=[name]__[local]___[hash:base64:5]' }
同样应用到前面的例子里,这时候就会变成这样的结果:
这样是不是要有意义多了?
如果是线上环境,可以考虑用更短的名字进一步减小css文件大小。
CSS Modules下的html
(看了前面例子里的el.outerHTML = ...后)
“什么,outerHTML?class名还要拼接?你家html才这么写呢!”
很遗憾,CSS Modules官方的例子,也是这个意思:要使用CSS Modules,必须想办法把变量风格的class名注入到html中。也就是说,html模板系统是必需的,也正是如此,相比普通css的情况,CSS Modules的html写起来要更为费劲。
如果你搜一下CSS Modules的demo,可以发现大部分都是基于React的。显然,虚拟DOM风格的React,搭配CSS Modules会很容易(ES6):
import styles from './ScopedSelectors.css'; import React, { Component } from 'react'; export default class ScopedSelectors extends Component { render() { return ( <p className={ styles.root }> <p className={ styles.text }>Scoped Selectors</p> </p> ); } };
如果不使用React,还是那句话,只要有办法把变量风格的class名注入到html中,就可以用CSS Modules。原始的字符串拼接的写法显然很糟糕,但我们可以借助各种模板引擎和编译工具做一些改进。下面请看一个用Jade的参考示例。
想象一下你有一个用普通css的页面,但你想在一小块区域使用CSS Modules。这一块区域在一个容器元素里:
<p id="module_sp_container"></p>
后用jade来写html(关联的css文件为module_sp.css):
- styles = require("./module_sp.css"); h2(class=styles.title) a title for CSS Modules
接下来,仍然是在javascript里添加这段jade生成的html:
var el = document.getElementById("module_sp_container"); var template = require("./main.jade"); el.innerHTML = template();
最后,记得在css-loader启用CSS Modules的同时,增加jade-loader:
{ test: /\.jade$/, loader: 'jade' }
编译运行,就可以得到想要的结果。除Jade以外,还有些其他CSS Modules的html应用方案,推荐参考github上的这篇issue。
目前CSS Modules还在发展中,而且也在考虑改进CSS Modules下的html写作体验。CSS Modules团队成员有提到一个叫CSS Modules Injector的未来规划项目,目的是让开发者不用javascript也可以使用CSS Modules(这就很接近原生html + css的组合了)。
CSS Modules下的样式复用
“样式都是唯一的了,怎么复用?”
我们已经说了挺多普通css单个全局作用域的坏处。但对应的,这也有一个很大的好处,就是便于实现样式的复用。css理论OOCSS也是在追求这一点。
CSS Modules提供一个composes方法用于样式复用。例如,你有一个btn.css里有一条:
.btn{ display: inline-block; }
然后,你在另一个CSS Module的module_sp.css里可以这样引入它:
.btn-sp{ composes: btn from "./btn.css"; font-size: 16px; }
那么,这个p.btn-sp的DOM元素将会是:
可以看到,composes的用法比较类似sass的@extend,但不同于@extend的是,composes并不增加css里的选择符总量,而是采用组合多个class名的形式。在这个例子里,原本仅有1个class的p.btn-sp,变成了2个class。
因此,CSS Modules建议只使用1个class就定义好对应元素所需的全部样式。它们会再由CSS Modules转换为适当的class组合。
CSS Modules团队成员认为composes是CSS Modules里最强大的功能:
For me, the most powerful idea in CSS Modules is composition, where you can deconstruct your visual inventory into atomic classes, and assemble them at a module level, without duplicating markup or hindering performance.
更详细的composes的用法及其理解,推荐阅读CSS Modules: Welcome to the Future。
其他可能有用的补充
和已有的普通css共存
很多项目会引入Bootstrap、Materialize等框架,它们是普通的、全局的css。此外,你也可能自己会写一些普通css。如何共存呢?CSS Modules团队成员对此提到过:
a CSS Module should only import information relative to it
意思是,建议把CSS Modules看做一种新的css,和原来的普通css区分开来。比如,composes的时候,不要从那些普通的css里去取。
在css-loader里通过指定test、include、exclude来区分它们。保持CSS Modules的纯净,只有想要应用CSS Modules的css文件,才启用CSS Modules。
只转换class和id
经过我自己的测试,CSS Modules只转换class和id,此外的标签选择符、伪类等都不会被转换。
建议只使用class。
一个CSS Module的输出
简单用console.log()就可以查看CSS Module的输出:
var styles = require("./main.css"); console.log("styles = ", styles);
结果类似这样:
{ "btn-sp": "_2SCQ7Kuv31NIIiVU-Q2ubA _2r6eZFEKnJgc7GLy11yRmV", title: "_1m-KkPQynpIso3ofWhMVuK" }
这可以帮助理解CSS Modules是怎样工作的。
预编译器
sass等预编译器也可以用CSS Modules,对应的loader可能是这样:
{ test: /\.scss$/, loader: 'style!css?modules!resolve-url!sass?sourceMap' }
注意不要因为是sass就习惯性地用嵌套写法,CSS Modules并不适合使用包含选择符。
建议的命名方式
CSS Modules会把.title转换为styles.title,由于后者是用在javascript中,因此驼峰命名会更适合。
如果像我之前那样写.btn-sp,需要注意在javascript中写为styles["btn-sp"]。
此外,你还可以为css-loader增加camelCase参数来实现自动转换:
{ test: /\.css$/, loader: 'style!css?modules&camelCase', }
这样即便你写.btn-sp,你也可以直接在javascript里用styles.btnSp。
结语
无论是一直以来我们认真遵循的命名约定,还是这个新的CSS Modules,目的都是一样的:可维护的css代码。我觉得就CSS Modules基本还是在写css这一点来说,它还是很友好的。
虽然本文为了严谨,结果写了相当长的篇幅,但希望你读过之后,还能觉得CSS Modules是简单易懂的。因为这样,我就达成我的目的:扣题,了。
推荐教程:《PHP》
以上がCSSモジュールの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。