SassがBOM付きCSSを吐いて先頭のCSS定義が効かなかった件(BOM付きPHPをincludeしつつBOMを削除する方法)

force_to_remove_bom_in_minified_css_2_sh

久しぶりにサイトのデザイン変更と内部のリファクタを進めていたところ、head タグ内に直書きした CSS の最初の1定義がどうにも効かなくて困ったのでメモ。

症状が出る CSS と出ない CSS との間に1文字も違いが無いので頭を捻っていたのですが、どうやら Sass で minify した CSS 由来の記述だと症状が出る。ということが分かってきたので、仕方なく Sass が吐き出した CSS ファイルのバイナリを見ることに。

すると、なんというかやっぱり UTF-8 の BOM(バイトオーダーマーク)「0xEF 0xBB 0xBF」がファイルの先頭に入っていることが原因だと分かりました。
force_to_remove_bom_in_minified_css_7_sh

ブラウザ側の動きとしては、HTML の Head タグ内などに直書きした CSS の先頭に BOM の「0xEF 0xBB 0xBF」コードが入ると、その直後の1定義のみ解釈されなくなるという症状が出ます。

Chrome のディベロッパーツールズでは、CSS が単純に効かない、CSS記述の先頭に赤い丸が付く。という2つの症状が確認できれば、この BOM を疑うのが良いと思います。
force_to_remove_bom_in_minified_css_4_sh

ということで、頑張って Sass に BOM 無しの CSS を吐かせる方法も調べてみたのですが、Sass で compressed オプションを使って minify する前提だと方法が見つからず断念。

プロジェクト内の Scss ファイルによってはコンパイル後の CSS に BOM が出ないケースも数多くあったので、方法はありそうには思うのですが、時間がないのでファイルを読んで BOM を削除する方針で対処しました。

うちの場合、Sass が吐き出す CSS ファイルに PHP のコードが入っていたのと、将来的に CSS ファイル以外の動的生成ファイルにBOMが含まれるケースを想定して、ファイルとして読み込んで BOM を削除するのではなく、include を使って PHP として解釈・実行させ、その実行結果から BOM を削除する方法を取りました。

ob_start();
include( $path_to_include_and_remove_bom );
$html = ob_get_contents();
ob_end_clean();
if ( $remove_bom === TRUE ) {
	$bom = pack('H*','EFBBBF');
	$fruit = preg_replace("/^$bom/", '', $html);		
}

使っているフレームワークによっては ob_start() との併用ができない場合もあると思うので、その場合は諦めることになりますが、こんな方法もあるよ。ということで。

静的なファイルならテキストエディタで BOM 無しの UTF-8N にエンコーディングを変換してやれば済む話ですが、Sass で :compressed を掛けると現在は BOM が標準で付く仕様になっている。ということでしたので、まあ、諦めです。

検索キーワード:Internal CSS, Embeded CSS, require, how to remove bom in css minified with Sass.

参考情報:

Hatena Pocket Line

コメントを記入