はじめに
本記事は、Heydon Pickering(ヘイドン・ピカリング)によって提唱された開発手法であるテスト駆動マークアップの解説と運用のベストプラクティスを紹介します。今回のサンプルコードは GitHub で公開しています。
- 2019/12/29 追記
- 新しいモジュールシステムの
meta.load-css()
を利用したテスト駆動マークアップ用スタイルシートの読み込み方法を変更しました。
- 新しいモジュールシステムの
テスト駆動マークアップとは
プログラムのテストは、機能の実装後に書くのが一般的です。逆にプログラムを実装する前にテストを書く手法が テスト駆動開発(Test Driven Development; TDD) です。CSS にテスト駆動開発を適用すれば、HTML マークアップの構造の正しさをテストできます。
CSS のロジック
CSS のセレクタは、HTML の構造にマッチさせるための条件式です。たとえば、disabled 属性がない button 要素に対してスタイルを当てる場合、以下のように書きます。
button:not(:disabled) {
/* disabled 属性がない button 要素にあたるスタイル */
}
通常、CSS は HTML の要素をどのように修飾するかを指示するために宣言を書きます。しかし、誤ったパターンを対象にエラースタイルを適用して問題を可視化ができます。
img:not([alt]) {
outline: 5px solid red;
}
あとは、その要素がどのような問題があるのかをエラーメッセージで伝わるようにすればよいのです。
ERROR プロパティ
問題のある要素にエラーメッセージを通知するには ERROR プロパティを使います。ご存知の通り、CSS には **ERROR プロパティはありません。**無効な CSS プロパティは無視されます。
img:not([alt]) {
outline: 5px solid red;
ERROR: img 要素には、alt 属性が必須です。;
}
このエラーメッセージは、各ブラウザの開発ツールで確認できます。Chrome の開発ツールでエラーメッセージを確認した場合、以下のように警告マークをつけてくれます。
運用のベストプラクティス
テスト駆動マークアップは、gulp + Sass の運用で開発モードにテスト駆動マークアップの制御を行えます。Node.js の環境変数を Sass の変数に渡すには gulp-sass-variables を使います。gulp のバージョンは最新版の 4.0 になります。(2019/04/21 現在)
const gulp = require('gulp');
const sassVariables = require('gulp-sass-variables');
const sass = require('gulp-sass');
sass.compiler = require('sass');
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
function styles() {
return gulp.src('src/sass/**/*.scss')
.pipe(sassVariables({
$mode: process.env.NODE_ENV
}))
.pipe(sass())
.pipe(gulp.dest('dist/'));
}
exports.styles = styles;
また、package.json に環境変数を渡す npm-scripts を登録します。
"scripts": {
"dev": "NODE_ENV=development gulp styles",
"build": "NODE_ENV=production gulp styles"
}
Sass の組み込みモジュールの meta.load-css()
で動的にテスト駆動マークアップ用スタイルシートを読み込ませましょう。
@use "sass:meta";
:root {
@if $mode == "development" {
@include meta.load-css("test");
}
}
これで Node.js の環境変数が development の場合、テスト駆動マークアップ用スタイルシートの読み込みが行われます。
さいごに
テスト駆動マークアップは、HTML マークアップの構造の正しさだけでなく、アイデア次第でプロジェクトの規約に沿ったソースコードを担保できます。たとえば、YouTube 動画の埋め込みで関連動画を同じチャンネル内に制御するようなケースがあります。
iframe[src^="https://www.youtube.com/embed/"]:not([src*="rel=0"]) {
outline: 5px solid red;
ERROR: YouTube の関連動画を同じチャンネル内に制御されてまいせん。;
}
まずは、テスト駆動マークアップの活用事例として REVENGE.CSS をヒントに作成してみましょう!
参考文献
インクルーシブHTML+CSS & JavaScript 多様なユーザーニーズに応えるフロントエンドデザインパターン
https://amazon.jp/dp/4862463878/