0

0

CSS 模块_html/css_WEB-ITnose

php中文网

php中文网

发布时间:2016-06-21 09:07:59

|

1173人浏览过

|

来源于php中文网

原创

如果你想知道 css 最近发展的转折点,你应该选择去观看 christopher chedeau 于 2010 年提出来的一个概念),那么 christopher 则是让许许多多的可能变得更加接近(译者注:上面三个工具中的两个灵感都是来自他的分享)。

上图列出的这些都是在许多大型 CSS 代码库中存在的问题。Christopher 指出,只要将你的样式通过用 JS 去管理,这些问题都能很好的解决。不得不说这的确是有道理的,但是这种方法有它的复杂性并会带来其他的相关问题。其实只要看看浏览器是如何处理 :hover 伪类状态的,我们就会发现有些东西在 CSS 中其实***很早***就解决了。

CSS 模块小组 觉得我们可以更加合理的解决问题:我们可以继续保持 CSS 现在的样子,并在 styles-in-JS 社区的基础上建立更合理的改进。虽然我们已经找到了解决办法同时又捍卫了 CSS 原始的美,但我们仍然欠那些把我们推向这个结果的那些人一声感谢。谢谢你们,朋友们!

下面让我来向大家解说一下什么是 CSS 模块并且为什么它才是未来吧。

立即学习前端免费学习笔记(深入)”;

第一步:像局部一样无需考虑全局冲突

在 CSS 模块中,每一个文件被编译成独立的文件。这样我们就只需要使用通用简单的类选择器名字就好了。我们不需要担心它会污染全局的变量。下面我就我们编写一个拥有四个状态的按钮来说明这个功能。

https://jsfiddle.net/pqnot81c/embedded/result/

CSS 模块之前我们是怎么做的

我们也许会使用 Suit 命名规范去进行样式命名,这样我们的 HTML 和 CSS 代码看起来就像如下所示:

/* components/submit-button.css */.Button { /* all styles for Normal */ }.Button--disabled { /* overrides for Disabled */ }.Button--error { /* overrides for Error */ }.Button--in-progress { /* overrides for In Progress */
<button class="Button Button--in-progress">Processing...</button>

这样写看起来还挺棒的。使用 BEM 命令方式使我们有了 4 个样式变量这样我们不必使用嵌套选择器。使用Button这种首字母大写的方法可以很好的避免与之前的代码或者是其他的依赖代码进行冲突。另外我们使用了--语法这样能很清楚的显示出我们的依赖 Class。

总的来说,这样做可以让我们的代码更易于维护,但是它需要我们在命名规范的学习上付出很多努力。不过这已经是目前 CSS 能给出的最好的解决办法了。

CSS 模块出来之后我们是怎么做的

CSS 模块意味着你从此再也不必为你的名字太大众而担心,只要使用你觉得有最有意义的名字就好了:

/* components/submit-button.css */.normal { /* all styles for Normal */ }.disabled { /* all styles for Disabled */ }.error { /* all styles for Error */ }.inProgress { /* all styles for In Progress */

请注意我们这里并没有在任何地方使用 button 这个词。不过反过来想,为什么我们一定要使用它呢?这个文件已经被命名成了 submit-button.css 了呀!既然在其它的语言中你不需要为你的局部变量增加前缀,没道理 CSS 需要加上这个蹩脚的功能。

通过使用 require 或者 import 从 JS 中导入文件使得 CSS 模块被编译成为可能。

/* components/submit-button.js */import styles from './submit-button.css';buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

你不必担心大众名字会倒置命名冲突,编译后实际上类名是会自动生成并保证是唯一的。CSS 模块为你做好一切,最终编译成一个 CSS 与 JS 交互的 ICSS 后缀文件(阅读这里了解更多)。因此,你的程序最终看起来可能会是这个样子的:

<button class="components_submit_button__normal__abc5436">  Processing...</button>

如果你的类名变的和上面的例子差不多的话,那么恭喜你你成功了!

命名约定

现在回过头来仔细看看我们的示例代码:

/* components/submit-button.css */.normal { /* all styles for Normal */ }.disabled { /* all styles for Disabled */ }.error { /* all styles for Error */ }.inProgress { /* all styles for In Progress */

请注意所有的类都是相互独立的,这里并不存在一个“**基类**”然后其它的类集成并“**覆盖**”它的属性这种情况。在 CSS 模块中**每一个类都必须包含这个元素需要的所有样式**(稍后会有详细说明)。这使得你在 JS 中使用样式的时候有很大的不同:

/* Don't do this */`class=${[styles.normal, styles['in-progress']].join(" ")}`/* Using a single name makes a big difference */`class=${styles['in-progress']}`/* camelCase makes it even better */`class=${styles.inProgress}`

当然,如果是的工资是按照字符串长度来计算的话,你爱怎么做就怎么做吧!

React 示例

CSS 模块并不是 React 特有的功能,但是不得不说在 React 中使用 CSS 模块会更爽。基于这个理由,我觉得我有必要展示下面这个如飘柔般丝滑的示例:

/* components/submit-button.jsx */import { Component } from 'react';import styles from './submit-button.css';export default class SubmitButton extends Component {  render() {    let className, text = "Submit"    if (this.props.store.submissionInProgress) {      className = styles.inProgress      text = "Processing..."    } else if (this.props.store.errorOccurred) {      className = styles.error    } else if (!this.props.form.valid) {      className = styles.disabled    } else {      className = styles.normal    }    return <button className={className}>{text}</button>  }}

你完全不需要担心你的类命名会和全局的样式表命名冲突,这样能让你的注意力更集中在**组件**上,而不是样式。我敢保证,使用过一次之后,你会再也不想回到原来的模式中去。

然而这仅仅是一切的开始。CSS 模块化是你的基本,但也是时候来思考一下如何把你的样式们都集中到一块了。

第二步:组件就是一切

上文中我提到了每一个类必须包含按钮不同状态下的**所有**的样式,与 BEM 命名方式上相比,代码上可能区别如下:

/* BEM Style */innerHTML = `<button class="Button Button--in-progress">`/* CSS Modules */innerHTML = `<button class="${styles.inProgress}">`

那么问题来了,你怎么在所有的状态样式中**共享**你的样式呢?这个答案就是 CSS 模块的强力武器 - **组件**:

.common {  /* all the common styles you want */}.normal {  composes: common;  /* anything that only applies to Normal */}.disabled {  composes: common;  /* anything that only applies to Disabled */}.error {  composes: common;  /* anything that only applies to Error */}.inProgress {  composes: common;  /* anything that only applies to In Progress */}

composes这个关键词将会使.normal类将.common内的所有样式包含进来,这个有点像 Sass 的 @extends 语法。但是 Sass 依赖重写你的 CSS 文件达到效果,而 **CSS 模块最后会通过 JS 编译导出,不需要修改文件**(译者注:下面会有例子详细说明)。

Sass

按照 BEM 的命名规范,我用 Sass 的 @extends 写的话可能会像如下的代码:

影谱
影谱

汉语电影AI辅助创作平台

下载
.Button--common { /* font-sizes, padding, border-radius */ }.Button--normal {  @extends .Button--common;  /* blue color, light blue background */}.Button--error {  @extends .Button--common;  /* red color, light red background */}

编译后的 CSS 文件如下:

.Button--common, .Button--normal, .Button--error {  /* font-sizes, padding, border-radius */}.Button--normal {  /* blue color, light blue background */}.Button--error {  /* red color, light red background */}

你可以只需要**一**个类来标记你的元素

CSS 模块

composes 语法看起来很像 @extends 但是他们的工作方式是不同的。为了岩石一下,让我们来看一个例子:

.common { /* font-sizes, padding, border-radius */ }.normal { composes: common; /* blue color, light blue background */ }.error { composes: common; /* red color, light red background */ }

编译后的文件可能是像如下一样:

.components_submit_button__common__abc5436 { /* font-sizes, padding, border-radius */ }.components_submit_button__normal__def6547 { /* blue color, light blue background */ }.components_submit_button__error__1638bcd { /* red color, light red background */ }

JS 代码中通过 import styles from "./submit-button.css" 最终会返回:

styles: {  common: "components_submit_button__common__abc5436",  normal: "components_submit_button__common__abc5436 components_submit_button__normal__def6547",  error: "components_submit_button__common__abc5436 components_submit_button__error__1638bcd"}

所以我们依然可以使用 style.normal 或者 style.error 在我们的代码中,**仍旧会有多个类样式渲染在我们的 DOM 上**。

<button class="components_submit_button__common__abc5436                components_submit_button__normal__def6547">  Submit</button>

这就是 composes 语法的厉害之处,你可以在不重写你的 CSS 的情况下对你的元素混合使用不同类的样式。

第三步:文件间共享

Sass 或者 LESS 中,你可以在每个文件中使用 @import 在全局工作区间内共享样式。这样你就可以在一个文件中定义变量或者函数(mixins)并在你的其它组件文件中共享使用。这样做是有好处的,但是很快你的变量命名就会与其它的变量名称相冲突(虽然它在另外一个全部空间下),你不可避免的会重构你的 variables.scss 或者 settings.scss,最后你就会发现你已经看不懂到底哪个组件依赖哪个变量了。最后的最后你会发现你的配置文件变量名称冗余到变得非常不实用。

针对上述问题仍然是有更好的解决办法的(试试上 Ben Smithett 的文章 Sass 和 Wepack 的混合使用 给了 CSS 模块话很大的启发,我推荐大家去读一读这篇文章),但是不管怎么做你还是局限在了 Sass 的全局环境下。

CSS 模块一次只运行一个文件,这样可以避免全局上下文的污染。而且像 JS 使用 import 或者 require 来加载依赖一样,CSS 模块使用 compose 来从另一个文件中加载:

/* colors.css */.primary {  color: #720;}.secondary {  color: #777;}/* other helper classes... */
/* submit-button.css */.common { /* font-sizes, padding, border-radius */ }.normal {  composes: common;  composes: primary from "../shared/colors.css";}

使用组件,我们能够深入到每一个像colors.css一样的基础样式表中,并随意重命名它。又因为组件只是改变了最后**导出**的类名称,而不是 CSS 文件本身,composes 语句在浏览器解析之前就会被删除。

/* colors.css */.shared_colors__primary__fca929 {  color: #720;}.shared_colors__secondary__acf292 {  color: #777;}
/* submit-button.css */.components_submit_button__common__abc5436 { /* font-sizes, padding, border-radius */ }.components_submit_button__normal__def6547 {}
<button class="shared_colors__primary__fca929               components_submit_button__common__abc5436                components_submit_button__normal__def6547">  Submit</button>

事实上,当它被浏览器解析之后,我们的局部是不存在一个"**normal**"样式的。这是一件好事!这意味着我们可以增加一个局部名字有意义的对象(可能就叫"**normal**")而不用在 CSS 文件中新增代码。我们使用的越多,对我们的网站会造成更少的视觉误差以及在用户浏览器上更少的不一致。

题外话:空的类样式可以使用 csso 这样的工具来检查去除掉。

第四步:功能单一模块

组件是非常强大的,因为它确实的让你描述了一个元素是什么,而不是它由那些样式组成。这是一种不同的方式去描述概念示例(**元素**)到样式实体(**样式规则**)之间的映射关系。让我们看一个简单的 CSS 例子:

.some_element {  font-size: 1.5rem;  color: rgba(0,0,0,0);  padding: 0.5rem;  box-shadow: 0 0 4px -2px;}

这些元素,样式都是特别简单的。然而也存在着问题:颜色,字体大小,盒子阴影,内边距-这里的一切都是量身定制的,这让**我们想要在其它地方复用这些样式**的时候变得有些困难。下面让我们用 Sass 重构这些这些代码:

$large-font-size: 1.5rem;$dark-text: rgba(0,0,0,0);$padding-normal: 0.5rem;@mixin subtle-shadow {  box-shadow: 0 0 4px -2px;}.some_element {  @include subtle-shadow;  font-size: $large-font-size;  color: $dark-text;  padding: $padding-normal;}

这是一个进化版,但是我们仅仅只达到了**一部分**目标。事实上 $large-font-size 和 $padding-normal 只是在名字上表示了它的用途,并不能在任何地方都执行。像 box-shadow 这种定义没办法赋值给变量,我们不得不实用 mixin 或者 @extends 语法来配合。

CSS 模块

通过使用组件,我们可以使用我们可复用的部分定义我们的组件:

.element {  composes: large from "./typography.css";  composes: dark-text from "./colors.css";  composes: padding-all-medium from "./layout.css";  composes: subtle-shadow from "./effect.css";}

这种写法势必会有很多单一功能文件产生,然而通过使用文件系统来管理不同用途的样式比起用命名空间来说要好的多。如果你想要从一个文件中导入多个类样式的话,有一种简单的写法:

/* this short hand: */.element {  composes: padding-large margin-small from "./layout.css";}/* is equivalent to: */.element {  composes: padding-large from "./layout.css";  composes: margin-small from "./layout.css";}

这开辟了一种可能,使用**极细粒**的类样式定义一些样式别名去给每一个网站使用:

.article {  composes: flex vertical centered from "./layout.css";}.masthead {  composes: serif bold 48pt centered from "./typography.css";  composes: paragraph-margin-below from "./layout.css";}.body {  composes: max720 paragraph-margin-below from "layout.css";  composes: sans light paragraph-line-height from "./typography.css";}

我对这种技术非常感兴趣,我觉得,它混合了像 Tachyons 那样变量分离可读的好处(译者注:就是说 CSS 模块的命名简单易懂,组件复用方便)。

但是 CSS 模块化之路仅仅是刚刚开始,未来我们希望大家能尝试更多为它写出谱写出新的篇章。

翻滚吧!CSS 模块!

我们希望 CSS 模块化能有助于你和你的团队在你们现有的 CSS 和产品的基础上维护代码,让它变得更舒适更高效。我们已经接近可能的把额外的语法减少到最少,并尽量确保语法和现有的变化不大。我们有 Webpack,Rails 的支持已经提上议程准备进行了。

但是为了让它变得更简单,我在 Plunker 上制作了一个预览示例,你不用安装任何东西就可以运行它:

这里还很小,我们还没有看到一些有用的例子,欢迎你们给我们投稿。

最后的最后,祝大家开心写样式,幸福每一天!

相关文章

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

616

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

194

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

91

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

54

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

15

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

598

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

56

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.4万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号