搜索
首页web前端html教程全局CSS的终结_html/css_WEB-ITnose

2016-01-05

»更好的阅读体验

原文链接

所有的CSS选择器共享同一个全局作用域。

每个接触CSS足够长时间的人一定都对CSS全局特性感到困扰 - 这种在文档型网页时代设计出来的模式,面对当今的Web应用,想要提供良好的开发环境却未免显得乏力。

每个选择器都有可能带来意想不到的影响,比如指向不需要的元素或者与其他选择器产生冲突。更始料不及的是,选择器的权重甚至可能在全局作用域中败下阵来,导致样式在页面中发挥不了任何作用。

任何时候我们修改CSS文件,我们都需要小心翼翼地考虑这些样式在全局环境下的影响。没有任何一个前端技术是需要如此之多的规范,仅仅是为了保证代码最小程度的可维护性。

但这本不该如此。

是时候将全局样式抛之脑后。

是时候拥抱本地CSS。

其他语言中,全局环境下少量的永久性修改是可以被接受的。

感谢JavaScript社区提供的这些工具, Browserify, Webpack和 JSPM,让我们的代码可以由一小块一小块的模块组合而成,这些模块中只需要明确指定它们的依赖,并且导出少量的API接口。

然而,不知为何,CSS似乎依旧无人问津。

我们中的许多人 - 包括我自己,直到现在 - 使用CSS太久了以至于我们觉得CSS缺失本地作用域是一个我们无法解决,只能等所有人都用上支持 Shadow DOM的浏览器才能解决的问题。

我们使用过一系列的命名规范来解决全局作用域的问题,比如 OOCSS, SMACSS, BEM和 SUIT,这些规范为我们提供了避免命名冲突的方法并提供了一套可用的作用域规则。

毫无疑问,这是迈向良性CSS的关键一步,但即便如此,这些规范都没有解决样式表的真正问题。无论我们选择使用哪种规范,我们还是会被全局选择器所困扰。

但2015年4月22日这天,一切都迎来改变。

正如我们不久前的博文 - “BEM 你的下一代JavaScript组件”- 中提到的,我们可以使用 Webpack在JavaScript模块中导入CSS。如果这对于你来说不太熟悉,你最好先阅读 这篇文章,不然你可能会忽略接下来介绍的关键点。

使用Webpack的 css-loader加载器,像这样导入组件的CSS:

require('./MyComponent.css');

乍一看 - 即使没注意到我们导入的是CSS而不是JavaScript - 这行代码也显得相当奇怪。

通常,require调用会给当前的作用域提供一些东西。如果没有,这很可能是引入了影响全局的模块 - 通常这都是糟糕的设计。

但这是CSS - 全局的影响是必须的。

至少我们是这么认为的。

在 2015年4月22日, Tobias Koppers- 永不知疲惫的Webpack作者 - 为css-loader加载器一个新功能的提交了第一个迭代版本,当时该功能名叫placeholders,就是现在众所周知的 local scope。

这个功能让我们能够从CSS文件中把类名导入到JavaScript代码中。

简单来说,不这么写:

require('./MyComponent.css');

而是这么写:

import styles form './MyComponent.css';

那么,这个例子中,styles变量到底等于什么?

为了了解CSS文件到底输出了什么,让我们来看看样式表的写法:

:local(.foo) {  color: red;}:local(.bar) {  color: blue;}

上述代码中,我们使用css-loader加载器的特定语法 :local(.identifier)输出了两个标识 - foo和bar。

我们可以在JavaScript文件中使用这些标识对应的类名。例如,我们使用 React:

import styles from './MyComponent.css';import React, { Component } from 'react';export default class MyComponent extends Component {  render() {    return (      <div>        <div className={styles.foo}>Foo</div>        <div className={styles.bar}>Bar</div>      </div>    );  }}

重要的是,这些标识在全局环境下生成出来类名都是唯一的。

我们不再需要给所有的选择器添加长长的前缀来实现作用域了。组件可以定义专属的foo和bar标识 - 不像传统的全局选择器模式 - 而不造成任何的命名冲突。

更重要的是,我们要知道这里面发生了什么重大的改变。

现在当我们修改CSS文件,我们有信心不会对网页的其他元素造成影响。我们给CSS文件引入了一个良好的作用域模式。

全局CSS的优点 - 实用的类可以复用到各个组件中… - 在这个模式下依旧得到保留。关键的不同点在于,就像我们使用别的技术那样,我们可以明确的导入我们想要的类。在代码中,我们不可以对全局环境进行任何的假设。

如今我们都应该编写可维护的CSS,不是通过小心翼翼地遵守命名规范,而是在开发过程中对样式进行封装。

由于这种作用域化的方式,类名交由Webpack进行控制生成。幸好,这是可以进行配置的。

默认情况下,css-loader加载器将标识转换为哈希值。

例如:

:local(.foo) { … }

会被编译成:

._1rJwx92-gmbvaLiDdzgXiJ { … }

在开发时,这对debug来说没有任何帮助。为了让类名更可读,我们可以在Webpack的配置文件中给css-load加载器传个参数来配置类名的格式:

loaders: [  ...  {    test: /\.css$/,    loader: 'css?localIdentName=[name]__[local]___[hash:base64:5]'  }]

这样,foo类名将会编译为:

.MyComponent__foo___1rJwx { … }

现在我们可以清晰的看到标识的名称,同样也能辨别出它所在的组件。

使用 node_env环境变量,我们可以为开发环境和打包环境配置不同的类名生产方式。

loader: 'css?localIdentName=' + (  process.env.NODE_ENV === 'development' ?    '[name]__[local]___[hash:base64:5]' :    '[hash:base64:5]')

现在通过Webpack控制类名的生成,在生产环境中压缩类名变得非常简单。

当我们知道了这个功能,我们迫不及待的给项目的样式都进行本地化。如果我们已经通过BEM命名规范来本地化CSS样式,那么我们只需要简单的修改。

有趣的是,这模式的引入是如此的简单。我们大部分的CSS文件只需要加入local标识:

:local(.backdrop) { … }:local(.root_isCollapsed .backdrop) { … }:local(.field) { … }:local(.field):focus { … }

等等…

在开发中,需要用到全局选择器的地方并不多。所以这让我们自然而然地想到了一个非常重要的问题。

假如选择器默认是本地作用域 - 并不需要特殊的语法 - 而全局的选择器则是可选择性的加入,这样会不会比较好呢?

译注:作者的意思是,当我们引入了CSS作用域的技术后,我们会发现大部分模块的CSS都会进行本地化,只有少量的全局CSS存在,那么,我们应该对这少部分的全局CSS进行特殊处理,而不是对大部分的具有作用域的CSS进行标识。

假设我们可以这么写:

.backdrop { … }.root_isCollapsed .backdrop { … }.field { … }.field:focus { … }

即使一般情况下看来,这些选择器的表达模糊不清,但通过css-loader加载器的本地化可以解决这个问题,而且也能够把它们作用域限定在当前模块中。

在少数的情况下,我们不可避免的要使用到全局样式,我们可以将它们用指定的 :global语法来标记出来。

比如我们用 ReactCSSTransitionGroup来生成全局的类名:

.panel :global .transition-active-enter { … }

在这例子中,我们不只将panel标识限定在模块中, 而且我们还定义了一个全局的类名 transition-active-enter。

当我们着手研究该如何实现这种“默认自带作用域”的类名语法时,我们发现其实这并不是非常困难。

为了实现这功能,我们要用到 PostCss- 这是一个出色的工具,他能让你将自定义的CSS转换器编写成组件。如今最流行的CSS构建工具之一 - Autoprefixer- 就是用PostCss开发出来的独立插件工具。

为了实现本地CSS,我已开源了一个实验性的PostCss插件,叫做 postcss-local-scope。该工具依旧在开发中,你可以在个人的项目中使用。

如果你正在使用Webpack,那么你可以在CSS构建流程中结合使用 postcss-loader加载器和 postcss-local-scope工具。这里不贴出例子,我已经创建了一个示例代码库,里面给出了示例 - postcss-local-scope-example。

让人激动的是,引入本地作用域只是个开始。

通过构建工具生成类名,我们能实现更多的事情。长远来看,我们可以不再需要人工参与编译而是让计算机来优化编辑结果。

不久将来,我们将可以让构建工具自动地生成组件共用的类,在编辑的过程中对可复用样式进行优化。

当你已经试着开始使用本地CSS时,你真的再也不会使用以前的那套老做法了。在样式表中体验一下真正的本地CSS吧 - 使用这种兼容所有浏览器的方法 - 这真的让你会终生难忘的。

引入本地CSS对我们看待CSS造成一连串的显著影响,无论是命名习惯,复用原则,还是样式提取分离,但这仅仅是CSS本地化这新领域的起点。

一旦你将它赋予实践,你会知道,全局CSS完结这一天终将会到来。CSS的未来属于本地化。

注意:组件之间可复用样式的自动优化将是一个惊人的飞跃,但这需要比我更聪明的人来实现。希望这会是你。☺

##附录

2015年5月24日:post-local-scope工具最开始的设想已经被Tobias koppers引入到了Webpack中,这意味着这个项目已经不再推荐使用了。现在css-loader加载器中可使用模块标识来实现CSS的模块化了。我用css-loader加载器写了个 CSS模块的例子来演示它们的用法,其中也包括了类继承来实现组件之间样式智能复用。

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
公众号网页更新缓存难题:如何避免版本更新后旧缓存影响用户体验?公众号网页更新缓存难题:如何避免版本更新后旧缓存影响用户体验?Mar 04, 2025 pm 12:32 PM

公众号网页更新缓存,这玩意儿,说简单也简单,说复杂也够你喝一壶的。你辛辛苦苦更新了公众号文章,结果用户打开还是老版本,这滋味,谁受得了?这篇文章,咱就来扒一扒这背后的弯弯绕绕,以及如何优雅地解决这个问题。读完之后,你就能轻松应对各种缓存难题,让你的用户始终体验到最新鲜的内容。先说点基础的。网页缓存,说白了就是浏览器或者服务器为了提高访问速度,把一些静态资源(比如图片、CSS、JS)或者页面内容存储起来。下次访问时,直接从缓存里取,不用再重新下载,速度自然快。但这玩意儿,也是个双刃剑。新版本上线,

如何使用HTML5表单验证属性来验证用户输入?如何使用HTML5表单验证属性来验证用户输入?Mar 17, 2025 pm 12:27 PM

本文讨论了使用HTML5表单验证属性,例如必需的,图案,最小,最大和长度限制,以直接在浏览器中验证用户输入。

HTML5中跨浏览器兼容性的最佳实践是什么?HTML5中跨浏览器兼容性的最佳实践是什么?Mar 17, 2025 pm 12:20 PM

文章讨论了确保HTML5跨浏览器兼容性的最佳实践,重点是特征检测,进行性增强和测试方法。

如何高效地在网页中为PNG图片添加描边效果?如何高效地在网页中为PNG图片添加描边效果?Mar 04, 2025 pm 02:39 PM

本文展示了使用CSS为网页中添加有效的PNG边框。 它认为,与JavaScript或库相比,CSS提供了出色的性能,详细介绍了如何调整边界宽度,样式和颜色以获得微妙或突出的效果

&lt; datalist&gt;的目的是什么。 元素?&lt; datalist&gt;的目的是什么。 元素?Mar 21, 2025 pm 12:33 PM

本文讨论了html&lt; datalist&gt;元素,通过提供自动完整建议,改善用户体验并减少错误来增强表格。Character计数:159

&lt; meter&gt;的目的是什么。 元素?&lt; meter&gt;的目的是什么。 元素?Mar 21, 2025 pm 12:35 PM

本文讨论了HTML&lt; meter&gt;元素,用于在一个范围内显示标量或分数值及其在Web开发中的常见应用。它区分了&lt; meter&gt;从&lt; progress&gt;和前

我如何使用html5&lt; time&gt; 元素以语义表示日期和时间?我如何使用html5&lt; time&gt; 元素以语义表示日期和时间?Mar 12, 2025 pm 04:05 PM

本文解释了HTML5&lt; time&gt;语义日期/时间表示的元素。 它强调了DateTime属性对机器可读性(ISO 8601格式)的重要性,并在人类可读文本旁边,增强Accessibilit

&gt; gt;的目的是什么 元素?&gt; gt;的目的是什么 元素?Mar 21, 2025 pm 12:34 PM

本文讨论了HTML&lt; Progress&gt;元素,其目的,样式和与&lt; meter&gt;元素。主要重点是使用&lt; progress&gt;为了完成任务和LT;仪表&gt;对于stati

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境