Maison >interface Web >tutoriel CSS >Modules CSS expliqués en détail
Feuille de style en cascade
Nous savons que le nom complet du CSS est appelé feuille de style en cascade, ceci " Que signifie « en cascade » ?
Une explication est que si vous écrivez d'abord une règle de style (joueur 1) :
.title { color: silver; }
puis écrivez une règle similaire après (joueur 2) :
.title { color: gold; }
Parce que les noms sont les mêmes, le joueur 2 se battra avec le joueur 1 (je veux que vous fassiez semblant d'être moi !). Le résultat est que le joueur 2 gagne, l'élément avec le nom de classe est le titre et la valeur de couleur finale est l'or.
C'est comme ça en CSS. Une guerre peut éclater à tout moment en cas de désaccord. En conséquence, le camp perdant sera écrasé par le camp gagnant. Le mot « cascade » peut être considéré comme décrivant ce processus de manière vivante.
Alors, pourquoi y a-t-il une telle superposition (zhàn zhēng) ?
Problème de portée CSS
En javascript, vous pouvez réaliser cette combinaison :
var title = "silver"; (function(){ var title = "gold"; console.log(title); // gold }()); console.log(title); // silver
En utilisant Dans le cadre des fonctions de JavaScript, deux joueurs portant le même nom peuvent bien s'entendre.
Mais pour en revenir aux règles de style en CSS, la situation est complètement différente.
CSS n'est pas un langage de programmation, mais si l'on veut y ajouter une notion de portée, c'est bien : uniquement une portée globale.
Peu importe le nombre de fichiers CSS divisés, quelle que soit la manière dont ils sont introduits, toutes les règles de style ont la même portée. Tant que les sélecteurs sont similaires, il existe une possibilité d'écrasement.
Stratégies pour réduire l'influence mutuelle
Afin de réduire l'influence mutuelle et d'éviter les remplacements de style inattendus, nous avons réfléchi à plusieurs façons.
Par exemple, si vous reprenez un ancien projet laissé par quelqu'un d'autre, puis ajoutez un élément title, vous n'utiliserez consciemment pas un nom de classe ambigu comme .title car il est trop facile de dupliquer le nom. . Au final, le nom que vous utiliserez pourra être :
.module-sp-title { color: deepskyblue; }
Même si vous décidez d'utiliser le nom .title, vous le qualifierez également avec le sélecteur d'inclusion :
.module-1 .title { font-size: 18px; } /* ... */ .module-2 .title { font-size: 14px; }
Les noms de .module-1 et .module-2 doivent être uniques. Ce type de code est très courant dans le style de développement à composants (modulaire).
De plus, certaines théories CSS bien connues, comme SMACSS, vous recommanderont d'utiliser le préfixe l- ou layout- pour tous les styles de mise en page afin de les distinguer.
Il existe de nombreuses approches similaires, mais en dernière analyse, elles tentent toutes de fournir une convention de dénomination raisonnable. Et une convention de dénomination raisonnable constitue en effet une stratégie efficace pour organiser le code CSS.
Maintenant, nous avons de nouvelles stratégies disponibles, les modules CSS en font partie.
Modularisation du flux technique
Les modules CSS sont une stratégie de flux technique pour organiser le code CSS, qui fournira une portée locale par défaut pour CSS.
Comment les modules CSS font-ils ? Regardons un exemple simple de modules CSS.
Il existe un tel élément html :
<h2 id="example_title" class="title">a title for CSS Modules</h2>
Selon la méthode d'écriture CSS ordinaire, nous pouvons y ajouter des styles comme ceci :
.title { background-color: snow; }
Maintenant, nous utilisons des modules CSS à la place. Premièrement, le CSS reste inchangé. Ensuite, modifiez la méthode d’écriture du HTML. Au lieu d'écrire du HTML directement comme ceci, ajoutez-le dynamiquement dans le fichier javascript (le fichier css s'appelle 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>';
Hé, c'est obligatoire Un fichier css ? C'est vrai, donc webpack est utilisé. Après compilation, le HTML et le CSS deviendront comme ceci :
Quand vous verrez un nom de classe aussi disgracieux, vous comprendrez probablement que les modules CSS ne peuvent pas changer la portée globale du CSS. Par nature, il repose sur la génération dynamique de noms de classe pour atteindre une portée locale. Évidemment, un tel nom de classe peut être unique, même si le code CSS d'origine est écrit avec désinvolture, il peut être converti de cette manière pour obtenir un code CSS non conflictuel.
La portée locale de la simulation n'a pas d'importance non plus, elle est fiable.
Cet exemple de modules CSS est terminé, mais vous devez avoir autant de questions que moi lorsque je l'ai vu pour la première fois.
Détails de l'application des modules CSS
Comment activer les modules CSS
"webpack compile le CSS pour moi, je l'ai déjà utilisé, pourquoi ne ressemble-t-il pas à ceci lorsque je l'utilise ? "
De manière générale, la façon d'exiger un fichier CSS est :
require("./main.css");
Mais dans l'exemple précédent, la méthode d'écriture var styles = require("./main.css"); C'est comme dire que je veux que les styles de ce fichier CSS soient locaux, puis je peux les utiliser selon mes besoins.
Il existe de nombreuses façons d'appliquer des modules CSS dans des projets. Actuellement, la plus couramment utilisée consiste à utiliser le chargeur CSS de Webpack. Vous pouvez activer les modules CSS en écrivant css-loader?modules dans le fichier de configuration du webpack. Par exemple, celui utilisé dans l'exemple précédent :
module: { loaders: [{ test: /\.css$/, loader: 'style!css?modules' }] }
Ensuite, j'ai découvert que le css-loader que j'utilisais à l'origine a-t-il cette fonction ? En fait, les modules CSS sont en effet une nouvelle fonctionnalité qui a ensuite été intégrée à CSS-loader.
Nom de classe généré personnalisé
«
名字都这样了,还怎么调试?”
为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》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!