Heim  >  Artikel  >  Web-Frontend  >  CSS-Module im Detail erklärt

CSS-Module im Detail erklärt

Guanhui
Guanhuinach vorne
2020-06-20 18:02:133760Durchsuche

CSS-Module im Detail erklärt

Cascading Style Sheet

Wir wissen, dass der vollständige Name von CSS Cascading Style Sheet heißt. this „ Was genau bedeutet „Kaskadierung“?

Eine Erklärung ist, dass, wenn Sie zuerst eine Stilregel schreiben (Spieler 1):


.title {
 color: silver;
}

und dann eine ähnliche Regel schreiben (Spieler 2):


.title {
 color: gold;
}

Da die Namen gleich sind, kämpft Spieler 2 mit Spieler 1 (ich möchte, dass du so tust, als wärst du ich!). Das Ergebnis ist, dass Spieler 2 gewinnt, das Element mit dem Klassennamen Titel ist und der endgültige Farbwert Gold ist.

Im CSS kann es jederzeit zu einem Krieg kommen, der zur Folge hat, dass die Verliererseite von der Gewinnerseite überschrieben wird. Man kann sagen, dass das Wort „Kaskadierung“ diesen Prozess anschaulich beschreibt.

Warum gibt es also eine solche Schichtung (zhàn zhēng)?

CSS-Bereichsproblem

In Javascript können Sie diese Kombination erreichen:


var title = "silver";

(function(){
 var title = "gold";
 console.log(title); // gold
}());

console.log(title); // silver

Verwenden Aufgrund des Funktionsumfangs von JavaScript können zwei Spieler mit demselben Namen gut miteinander auskommen.

Aber wenn wir auf die Stilregeln in CSS zurückkommen, ist die Situation völlig anders.

CSS ist keine Programmiersprache, aber wenn wir ihr ein Scope-Konzept hinzufügen wollen, dann ist es: nur globaler Scope.

Egal wie viele CSS-Dateien aufgeteilt sind, egal wie sie eingeführt werden, alle Stilregeln liegen im gleichen Bereich. Solange die Selektoren ähnlich sind, besteht die Möglichkeit des Überschreibens.

Strategien zur Reduzierung der gegenseitigen Beeinflussung

Um die gegenseitige Beeinflussung zu reduzieren und unerwartete Stilüberschreibungen zu vermeiden, haben wir uns viele Möglichkeiten überlegt.

Wenn Sie beispielsweise ein altes Projekt übernehmen, das jemand anderes hinterlassen hat, und dann ein Titelelement hinzufügen, werden Sie bewusst keinen mehrdeutigen Klassennamen wie .title verwenden, da es zu einfach ist, den Namen zu duplizieren. . Am Ende könnte der von Ihnen verwendete Name lauten:


.module-sp-title {
 color: deepskyblue;
}

Auch wenn Sie sich für die Verwendung des Namens .title entscheiden, qualifizieren Sie ihn auch mit dem Include-Selektor:


.module-1 .title { 
 font-size: 18px;
}
/* ... */
.module-2 .title {
 font-size: 14px;
}

Die Namen von .module-1 und .module-2 sollten eindeutig sein. Diese Art von Code kommt im komponentenbasierten (modularen) Entwicklungsstil sehr häufig vor.

Darüber hinaus empfehlen einige bekannte CSS-Theorien, wie z. B. SMACSS, dass Sie für alle Layoutstile das Präfix „l“ oder „layout“ verwenden, um sie zu unterscheiden.

Es gibt viele ähnliche Ansätze, aber letztendlich versuchen sie alle, eine vernünftige Namenskonvention bereitzustellen. Und eine vernünftige Namenskonvention ist in der Tat eine wirksame Strategie zum Organisieren von CSS-Code.

Jetzt stehen uns neue Strategien zur Verfügung, CSS-Module sind eine davon.

Modularisierung des technischen Ablaufs

CSS Modules ist eine technische Ablaufstrategie zum Organisieren von CSS-Code, die einen lokalen Standardbereich für CSS bereitstellt.

Wie machen CSS-Module das? Schauen wir uns ein einfaches Beispiel für CSS-Module an.

Es gibt ein solches HTML-Element:


<h2 id="example_title" class="title">a title for CSS Modules</h2>

Gemäß der normalen CSS-Schreibmethode können wir ihm Stile wie folgt hinzufügen:


.title {
 background-color: snow;
}

Jetzt verwenden wir stattdessen CSS-Module. Erstens bleibt das CSS unverändert. Ändern Sie dann die Schreibmethode von HTML. Anstatt HTML direkt wie folgt zu schreiben, fügen Sie es stattdessen dynamisch in die Javascript-Datei ein (die CSS-Datei heißt main.css):


var styles = require("./main.css");

var el = document.getElementById("example_title");
el.outerHTML = &#39;<h2 class="&#39; + styles.title + &#39;">a title for CSS Modules</h2>&#39;;

Hey, es ist eine erforderliche CSS-Datei ? Richtig, also wird Webpack verwendet. Nach der Kompilierung sehen HTML und CSS wie folgt aus:

Wenn Sie einen so unansehnlichen Klassennamen sehen, werden Sie wahrscheinlich verstehen, dass CSS-Module den globalen Geltungsbereich von CSS nicht ändern können. Naturgemäß ist es auf die dynamische Generierung von Klassennamen angewiesen, um einen lokalen Geltungsbereich zu erreichen. Offensichtlich kann ein solcher Klassenname eindeutig sein, egal wie zufällig der ursprüngliche CSS-Code geschrieben ist, er kann auf diese Weise konvertiert werden, um einen nicht widersprüchlichen CSS-Code zu erhalten.

Der lokale Umfang der Simulation spielt auch keine Rolle, sie ist zuverlässig.

Dieses Beispiel für CSS-Module ist fertig, aber Sie haben sicher genauso viele Fragen wie ich, als ich es zum ersten Mal sah.

Anwendungsdetails von CSS-Modulen

So aktivieren Sie CSS-Module

"webpack kompiliert CSS Für mich habe ich es schon einmal verwendet. Warum sieht es nicht so aus, wenn ich es verwende?

require("./main.css");

Aber im vorherigen Beispiel wurde die Schreibmethode var style = require("./main.css"); Das ist, als würde man sagen: Ich möchte, dass die Stile in dieser CSS-Datei lokal sind und ich sie dann nach Bedarf verwenden kann.

Es gibt viele Möglichkeiten, CSS-Module in Projekten anzuwenden. Derzeit wird am häufigsten der CSS-Loader von Webpack verwendet. Sie können CSS-Module aktivieren, indem Sie css-loader?modules in die Webpack-Konfigurationsdatei schreiben. Zum Beispiel das im vorherigen Beispiel verwendete:

module: {
 loaders: [{
  test: /\.css$/,
  loader: &#39;style!css?modules&#39;
 }]
}

Dann habe ich entdeckt, dass Der von mir verwendete CSS-Loader war ursprünglich Hat er diese Funktion? Tatsächlich handelt es sich bei CSS-Modulen um eine neue Funktion, die später in den CSS-Loader integriert wurde.

Benutzerdefiniert generierter Klassenname

名字都这样了,还怎么调试?”

为css-loader增加localIdentName参数,是可以指定生成的名字。localIdentName的默认值是[hash:base64],一般开发环境建议用类似这样的配置:


{
 test: /\.css$/,
 loader: &#39;style!css?modules&localIdentName=[name]__[local]___[hash:base64:5]&#39;
}

同样应用到前面的例子里,这时候就会变成这样的结果:

这样是不是要有意义多了?

如果是线上环境,可以考虑用更短的名字进一步减小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 &#39;./ScopedSelectors.css&#39;;

import React, { Component } from &#39;react&#39;;

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: &#39;jade&#39;
}

编译运行,就可以得到想要的结果。除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: &#39;style!css?modules!resolve-url!sass?sourceMap&#39;
}

注意不要因为是sass就习惯性地用嵌套写法,CSS Modules并不适合使用包含选择符。

建议的命名方式

CSS Modules会把.title转换为styles.title,由于后者是用在javascript中,因此驼峰命名会更适合。

如果像我之前那样写.btn-sp,需要注意在javascript中写为styles["btn-sp"]。

此外,你还可以为css-loader增加camelCase参数来实现自动转换:


{
 test: /\.css$/,
 loader: &#39;style!css?modules&camelCase&#39;,
}

这样即便你写.btn-sp,你也可以直接在javascript里用styles.btnSp。

结语

无论是一直以来我们认真遵循的命名约定,还是这个新的CSS Modules,目的都是一样的:可维护的css代码。我觉得就CSS Modules基本还是在写css这一点来说,它还是很友好的。

虽然本文为了严谨,结果写了相当长的篇幅,但希望你读过之后,还能觉得CSS Modules是简单易懂的。因为这样,我就达成我的目的:扣题,了。

推荐教程:《PHP


Das obige ist der detaillierte Inhalt vonCSS-Module im Detail erklärt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:jb51.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen