>웹 프론트엔드 >CSS 튜토리얼 >CSS 모듈 자세히 설명

CSS 모듈 자세히 설명

Guanhui
Guanhui앞으로
2020-06-20 18:02:133805검색

CSS 모듈 자세히 설명

Cascading Style Sheet

CSS의 전체 이름이 Cascading Style Sheet라는 것을 알고 있습니다.

한 가지 설명은 스타일 규칙을 먼저 작성하면(플레이어 1):


.title {
 color: silver;
}

하고 그 뒤에 비슷한 규칙을 작성하면(플레이어 2):


.title {
 color: gold;
}

이름이 동일하기 때문입니다. 플레이어 2는 플레이어 1과 싸울 것입니다(나인 척 해주세요!). 결과는 플레이어 2가 승리하고 클래스 이름이 있는 요소는 제목이며 최종 색상 값은 금색입니다.

CSS에서는 이렇습니다. 불일치가 있으면 언제든지 전쟁이 일어날 수 있으며, 패배한 쪽이 승리한 쪽을 덮어쓰게 됩니다. 계단식이라는 단어는 이 과정을 생생하게 묘사한다고 할 수 있습니다.

그럼 왜 이런 겹겹이(zhàn zhēng)가 있는 걸까요?

Css 범위 문제

자바스크립트에서는 다음과 같은 조합이 가능합니다.


var title = "silver";

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

console.log(title); // silver

자바스크립트의 함수 범위를 사용하면 이름이 같은 두 플레이어가 서로 잘 어울릴 수 있습니다.

하지만 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- 또는 레이아웃- 접두사를 사용하여 구별할 것을 권장합니다.

유사한 접근 방식이 많이 있지만 최종 분석에서는 모두 합리적인 명명 규칙을 제공하려고 노력하고 있습니다. 그리고 합리적인 명명 규칙은 실제로 CSS 코드를 구성하는 효과적인 전략입니다.

이제 새로운 전략을 사용할 수 있으며 CSS 모듈도 그 중 하나입니다.

기술 흐름의 모듈화

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 = &#39;<h2 class="&#39; + styles.title + &#39;">a title for CSS Modules</h2>&#39;;

이봐, CSS 파일이 필요했나요? 그렇죠, 그래서 webpack을 사용합니다. 컴파일 후 html과 css는 다음과 같습니다.

이렇게 보기 흉한 클래스 이름을 보면 아마도 이해하게 될 것입니다. CSS 모듈은 CSS의 전역 범위 특성을 변경할 수 없으며 동적으로 생성되는 클래스 이름에 의존합니다. 로컬 범위를 달성하기 위한 수단입니다. 분명히 이러한 클래스 이름은 고유할 수 있습니다. 원본 CSS 코드가 아무리 무심코 작성되었더라도 이러한 방식으로 변환하여 충돌하지 않는 CSS 코드를 얻을 수 있습니다.

시뮬레이션의 로컬 범위도 중요하지 않으며 신뢰할 수 있습니다.

이 CSS 모듈 예제는 끝났지만, 처음 봤을 때처럼 질문이 많을 거에요.

CSS 모듈 애플리케이션 세부정보

CSS 모듈 활성화 방법

"저도 CSS 컴파일을 위해 webpack을 사용했는데, 사용하면 왜 이렇게 되지 않나요?"

일반적으로 require CSS 파일 작성 방법은 다음과 같습니다.


require("./main.css");

하지만 이전 예제에서는 var styles = require("./main.css"); 작성 방법을 사용했습니다. 이는 마치 이 CSS 파일의 스타일을 로컬로 만들고 필요에 따라 사용할 수 있다고 말하는 것과 같습니다.

프로젝트에 CSS 모듈을 적용하는 방법에는 여러 가지가 있습니다. 현재 가장 일반적으로 사용되는 방법은 webpack의 CSS-loader를 사용하는 것입니다. webpack 구성 파일에 css-loader 모듈을 작성하여 CSS 모듈을 활성화할 수 있습니다. 예를 들어 이전 예제에서 사용된 모듈은 다음과 같습니다.


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

제가 사용하고 있는 CSS-loader에 이 기능이 있다는 것을 방금 발견했습니다. ? 실제로 CSS 모듈은 나중에 css-loader에 통합된 새로운 기능입니다.

사용자 정의된 생성 클래스 이름

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

为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


위 내용은 CSS 모듈 자세히 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jb51.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제