ホームページ >ウェブフロントエンド >htmlチュートリアル >PostCSS_html/css_WEB-ITnose による CSS 処理
Web アプリケーション開発において、CSS コードの記述は重要な部分です。初期の CSS1 から現在の CSS3、そして次のバージョンの CSS 仕様に至るまで、仕様自体は常に進化してきました。これにより、開発者の効率が向上します。しかし、Web 分野の他の仕様と同様に、CSS 仕様にはブラウザの互換性に関して常にさまざまな問題がありました。 CSS 仕様の実装におけるブラウザごとの進捗状況にも大きな違いがあります。さらに、CSS 仕様自体の開発速度とコミュニティの期待の間には、依然として一定のギャップがあります。これは、SASS や LESS などの CSS 前処理言語が普及できる重要な理由でもあります。 SASS と LESS は、より実用的な機能を多数提供し、CSS 言語に対する開発者のニーズを反映しています。この記事で紹介する PostCSS は、CSS を加工するための人気のあるツールです。 PostCSS は、強力なプラグイン システムに依存して、CSS 処理に無限の可能性を追加します。
PostCSS自体は比較的単機能なツールです。 JavaScript コードを使用して CSS を操作する方法を提供します。 CSS コードを解析して抽象構文ツリー (AST) 構造にし、それを処理のためにプラグインに渡します。プラグインは、変数やミックスインのサポート、ブラウザ関連の宣言プレフィックスの追加、将来の CSS 仕様を使用したスタイル ルールの現在の CSS 仕様でサポートされる形式へのトランスパイルなど、CSS コードの AST に基づいてさまざまな操作を実行できます。この観点から見ると、PostCSS の威力は進化し続けるプラグイン システムにあります。現在、PostCSS にはさまざまな機能を備えた 200 以上のプラグインがあります。開発者は、プロジェクトのニーズに基づいて独自の PostCSS プラグインを開発することもできます。
PostCSS は、その開始以来、その分類についてコミュニティで論争を引き起こしてきました。これは主に、PostCSS が CSS の後処理 (ポストプロセッサ) に使用され、SASS や LESS などの既存の CSS 前処理 (プリプロセッサ) 言語と統合されることを人々に簡単に思い出させる、名前にポストが含まれているためです。 . たとえを待ちます。実際、PostCSS には主な機能が 2 つしかありません。1 つ目は、前述したように CSS を JavaScript で操作できる AST に解析することで、2 つ目は、プラグインを呼び出して AST を処理し、結果を取得することです。したがって、PostCSS を CSS の前処理ツールまたは後処理ツールとして単純に分類することはできません。 PostCSS は、従来の意味での前処理と後処理の両方をカバーする幅広いタスクを実行できます。 PostCSS は、フロントエンド開発者に CSS の異なる作業方法を提供するまったく新しいツールです。
PostCSS は通常、単独で使用されるのではなく、既存のビルド ツールと統合されます。 PostCSS は、Webpack、Grunt、Gulp などの主流のビルド ツールと統合できます。統合が完了したら、機能要件を満たす PostCSS プラグインを選択して構成します。 Webpack、Grunt、Gulp での PostCSS Autoprefixer プラグインの使い方を詳しく紹介します。
Postcss-loaderはWebpack内でプラグイン処理を行うために使用されます。では、postcss-loader は .css ファイルの処理に使用され、style-loader と css-loader の後に追加されます。追加の postcss メソッドを通じて、必要な PostCSS プラグインを返します。 require('autoprefixer') の機能は、Autoprefixer プラグインをロードすることです。
var path = require('path');module.exports = { context: path.join(__dirname, 'app'), entry: './app', output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' }, module: { loaders: [ { test: /\.css$/, loader: "style-loader!css-loader!postcss-loader" } ] }, postcss: function () { return [require('autoprefixer')]; }}Gulp
Gulp で gulp-postcss を使用して PostCSS を統合します。 CSS ファイルが gulp-postcss によって処理された後、結果は dist ディレクトリに書き込まれます。
var gulp = require('gulp');gulp.task('css', function() { var postcss = require('gulp-postcss'); return gulp.src('app/**/*.css') .pipe(postcss([require('autoprefixer')])) .pipe(gulp.dest('dist/'));});Grunt
Grunt で grunt-postcss を使用して PostCSS を統合します。図に示すように、Grunt ではプラグインをロードするために grunt.loadNpmTasks メソッドが必要です。
module.exports = function(grunt) { grunt.initConfig({ postcss: { options: { processors: [ require('autoprefixer')() ] }, dist: { src: 'app/**/*.css', expand: true, dest: 'dist' } } }); grunt.loadNpmTasks('grunt-postcss');}
以下に、一般的に使用される PostCSS プラグインを紹介します。
Autoprefixer は、ブラウザー固有のプレフィックスを CSS のプロパティに追加する人気のある PostCSS プラグインです。 CSS 仕様の策定と改善には一般に長い時間がかかるため、ブラウザ メーカーは、正式仕様バージョンの前に新しい CSS 機能を実験的な実装として実装する場合、特定のブラウザ プレフィックスを使用します。たとえば、Webkit ベースのブラウザは -webkit- を使用し、Microsoft の IE は -ms- を使用します。さまざまなブラウザのさまざまなバージョンと互換性を持たせるには、通常、CSS スタイル ルール宣言を記述するときに接頭辞付きのプロパティを追加する必要があります。これは退屈で退屈な仕事です。 Autoprefixer はこれを自動的に行うことができます。 Autoprefixer は、サポートされているブラウザーの種類とバージョンを指定するために、必要に応じて必須の接頭辞付き属性宣言を自動的に追加できます。開発者は、CSS を作成するときに CSS 仕様の標準プロパティ名を使用するだけで済みます。 CSS フレックスボックス モデルを使用した表示プロパティの宣言は
に示されています。
#content { display: flex;}
Autoprefixer によって処理された後に得られる CSS は次のとおりです。
#content { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex;}
Autoprefixer 使用 Can I Use 网站提供的数据来确定所要添加的不同浏览器的前缀。随着浏览器版本的升级,浏览器在新版本中可能已经提供了对标准属性的支持,从而不再需要添加额外的前缀。Autoprefixer 可以配置需要支持的浏览器。如“last 2 versions”表示主流浏览器的最近两个版本,“ie 6-8”表示 IE 6 到 8,“> 1%”表示全球使用率大于 1%的浏览器版本。中给出了配置 Autoprefixer 插件的示例。
require('autoprefixer')({ browsers: ['last 2 versions']})
Autoprefixer 除了添加所需要的属性名称前缀之外,还可以移除 CSS 代码中冗余的属性名称前缀。遗留 CSS 代码中可能包含由开发人员手动添加的旧版本的浏览器所支持的带前缀的属性名称。Autoprefixer 默认情况下会移除这些冗余的前缀。可以通过配置对象中的 remove 属性来配置该行为。
cssnext 插件允许开发人员在当前的项目中使用 CSS 将来版本中可能会加入的新特性。cssnext 负责把这些新特性转译成当前浏览器中可以使用的语法。从实现角度来说,cssnext 是一系列与 CSS 将来版本相关的 PostCSS 插件的组合。比如,cssnext 中已经包含了对 Autoprefixer 的使用,因此使用了 cssnext 就不再需要使用 Autoprefixer。
CSS 的层叠变量的自定义属性规范(CSS Custom Properties for Cascading Variables)允许在 CSS 中定义属性并在样式规则中作为变量来使用它们。自定义属性的名称以“--”开头。当声明了自定义属性之后,可以在样式规则中使用“var()”函数来引用,如所示。
:root { --text-color: black;}body { color: var(--text-color);}
在经过 cssnext 转换之后的 CSS 代码如所示。
body { color: black;}自定义选择器
CSS 扩展规范(CSS Extensions)中允许创建自定义选择器,比如可以对所有的标题元素(h1 到 h6)创建一个自定义选择器并应用样式。通过“@custom-selector”来定义自定义选择器。在中,“--heading”是自定义选择器的名称,其等同于选择器声明“h1, h2, h3, h4, h5, h6”。
@custom-selector :--heading h1, h2, h3, h4, h5, h6;:--heading { font-weight: bold;}
经过 cssnext 处理之后的 CSS 如所示。
h1,h2,h3,h4,h5,h6 { font-weight: bold;}样式规则嵌套
样式规则嵌套是一个非常实用的功能,可以减少重复的选择器声明。这也是 SASS 和 LESS 等 CSS 预处理器流行的一个重要原因。CSS 嵌套模块规范(CSS Nesting Module)中定义了标准的样式规则嵌套方式。可以通过 cssnext 把标准的样式嵌套格式转换成当前的格式。CSS 嵌套规范中定义了两种嵌套方式:第一种方式要求嵌套的样式声明使用“&”作为前缀,“&”只能作为声明的起始位置;第二种方式的样式声明使用“@nest”作为前缀,并且“&”可以出现在任意位置。中给出了两种不同声明方式的示例。
.message { font-weight: normal; & .header { font-weight: bold; } @nest .body & { color: black; }}
经过 cssnext 转换之后的 CSS 代码如所示。
.message { font-weight: normal}.message .header { font-weight: bold;}.body .message { color: black;}CSS 模块化
在编写 CSS 代码时会遇到的一个很重要的问题是 CSS 代码的组织方式。当项目中包含的 CSS 样式非常多时,该问题尤其突出。这主要是由于不同 CSS 文件中的样式声明可能产生名称冲突。现在的 Web 开发大多采用组件化的组织方式,即把应用划分成多个不同的组件。每个组件都可以有自己的 CSS 样式声明。比如,两个组件的 CSS 中可能都定义了对于 CSS 类 title 的样式规则。当这两个组件被放在同一个页面上时,冲突的 CSS 类名称可能造成样式的错乱。对于此类 CSS 类名冲突问题,一般的做法是避免全局名称空间中的样式声明,而是每个组件有自己的名称空间。BEM 通过特殊的命名 CSS 类名的方式来解决名称冲突的问题。两个不同组件中的标题的 CSS 类名可能为 component1__title 和 component2__title。
CSS 模块(CSS modules)并不要求使用 BEM 那样复杂的命名规范。每个组件可以自由选择最合适的简单 CSS 类名。组件的 CSS 类名在使用时会被转换成带唯一标识符的形式。这样就避免了名称冲突。在组件开发中可以继续使用简单的 CSS 类名,而不用担心名称冲突问题。中给出了使用 CSS 模块规范的 CSS 代码。样式规则之前的“:global”表示这是一个全局样式声明。其他的样式声明是局部的。
:global .title { font-size: 20px;}.content { font-weight: bold;}
经过转换之后的 CSS 样式声明如所示。全局的 CSS 类名 title 保存不变,局部的 CSS 类名 content 被转换成_content_6xmce_5。这样就确保了不会与其他组件中名称为 content 的类名冲突。
.title { font-size: 20px;}._content_6xmce_5 { font-weight: bold;}
由于在组件的 HTML 代码中引用的 CSS 类名和最终生成的类名并不相同,因此需要一个中间的过程来进行类名的转换。对于 React 来说,可以使用 react-css-modules 插件;在其他情况下,可以使用 PostHTML 对 HTML 进行处理。postcss-modules 插件把 CSS 模块中的 CSS 类名的对应关系保存在一个 JavaScript 对象中,可以被 PostHTML 中的 posthtml-css-modules 插件来使用。
在中,在使用 postcss-modules 插件时提供了一个方法 getJSON。当 CSS 模块的转换完成时,该方法会被调用。该方法的参数 json 参数表示的是转换结果的 JavaScript 对象。该对象被以 JavaScript 文件的形式保存到 cssModules 目录下,并添加了模块导出的逻辑。
require('postcss-modules')({ getJSON: function(cssFileName, json) { var cssName = path.basename(cssFileName, '.css'); var jsonFileName = path.resolve(dist, 'cssModules', cssName + '.js'); mkdirp.sync(path.dirname(jsonFileName)); fs.writeFileSync(jsonFileName, "module.exports = " + JSON.stringify(json) + ";"); } })
中给出了使用 Gulp 的 gulp-posthtml 来处理 HTML 文件的任务。posthtml-css-modules 可以处理一个目录下的多个 CSS 模块输出文件。
gulp.task('posthtml', function() { var posthtml = require('gulp-posthtml'); return gulp.src('app/**/*.html') .pipe(posthtml([ require('posthtml-css-modules')(path.join(dist, 'cssModules')) ])) .pipe(gulp.dest('dist/'));});
在 HTML 文件中使用“css-module”属性来指定对应的 CSS 类名。在中,名称“header.content”的 header 表示的是 CSS 文件名,而 content 是该文件中定义的 CSS 类名。
<div css-module="header.content">Hello world</div>
在经过处理之后,得到的 HTML 内容如所示。
<div class="_content_6xmce_5">Hello world</div>资源文件处理
在 CSS 中经常会需要引用外部资源,如图片和字体等。在 CSS 代码中处理这些资源时会遇到一些常见的问题,比如图片的路径问题,内联图片内容,生成图片 Sprites 等。对于这些问题,都有专门的 PostCSS 插件来提供所需的功能。
postcss-assets 插件用来处理图片和 SVG。在 CSS 声明中引用图片时,可以使用 resolve 加上图片路径的形式,如“resolve(‘logo.png’)”。在插件处理时,会按照一定的顺序在指定的目录中查找该文件,如果找到,会用图片的真实路径来替换。可以通过选项 loadPaths 来指定查找的路径,basePath 来指定项目的根目录。在 CSS 声明中,可以使用 width、height 和 size 方法来获取到图片的宽度、高度和尺寸。当需要内联一个图片时,可以使用 inline 方法。inline 会把图片转换成 Base64 编码的 data url 的格式,这样可以减少对图片的 HTTP 请求。给出了使用示例。
require('postcss-assets')({ loadPaths: ['assets/images']})
中给出了使用 resolve 的 CSS 样式声明。
.logo { background-image: resolve('logo.png');}
中给出了 cssnext 处理之后的 CSS 代码。
.logo { background-image: url('/assets/images/logo.png');}其他插件
还有其他实用的 PostCSS 插件可以在开发中使用。如 postcss-stylelint 用来检查 CSS 中可能存在的格式问题。cssnano 用来压缩 CSS 代码。postcss-font-magician 用来生成 CSS 中的 @font-face 声明。precss 允许在 CSS 中使用类似 SASS 的语法。
虽然 PostCSS 已经有 200 多个插件,但在开发中仍然可能存在已有插件不能满足需求的情况。这个时候可以开发自己的 PostCSS 插件。开发插件是一件很容易的事情。每个插件本质只是一个 JavaScript 方法,用来对由 PostCSS 解析的 CSS AST 进行处理。
每个 PostCSS 插件都是一个 NodeJS 的模块。使用 postcss 的 plugin 方法来定义一个新的插件。插件需要一个名称,一般以“postcss-”作为前缀。插件还需要一个进行初始化的方法。该方法的参数是插件所支持的配置选项,而返回值则是另外一个方法,用来进行实际的处理。该处理方法会接受两个参数,css 代表的是表示 CSS AST 的对象,而 result 代表的是处理结果。中给出了一个简单的 PostCSS 插件。该插件使用 css 对象的 walkDecls 方法来遍历所有的“color”属性声明,并对“color”属性值进行检查。如果属性值为 black,就使用 result 对象的 warn 方法添加一个警告消息。
var postcss = require('postcss');module.exports = postcss.plugin('postcss-checkcolor', function(options) { return function(css, result) { css.walkDecls('color', function(decl) { if (decl.value == 'black') { result.warn('No black color.', {decl: decl}); } }); };})
中的插件的功能比较简单。PostCSS 插件一般通过不同的方法来对当前的 CSS 样式规则进行修改。如通过 insertBefore 和 insertAfter 方法来插入新的规则。
CSS の処理は、Web 開発において常に複雑な問題であり、その一部は CSS 仕様に起因し、一部は異なるブラウザ実装によって引き起こされる互換性の問題に起因します。 PostCSS は、CSS を操作する新しい方法を提供します。 PostCSS の強力なプラグイン システムを通じて、CSS をさまざまな方法で変換および処理できるため、退屈で複雑な作業を可能な限りプログラムに任せ、開発者を解放します。この記事では、開発者の開発効率の向上に役立つことを期待して、PostCSS とその一般的に使用されるプラグインについて詳しく紹介します。
説明 | 名前 | サイズ |
---|---|---|
サンプルコード | sourcecode.zip | 11k |