インターナルCSSをワンライナーのPHPでミニファイする

　HTMLの`<head>`タグ内に`<style>`タグで記述されたCSSを「インターナルCSS（Internal CSS）」と云う。ちなみに、逆に`<link>`タグで外部から読み込むCSSを「エクスターナルCSS（External CSS）」と呼ばれ、直接BODY内の要素に`style=""`属性でスタイルを指定することは「インラインスタイル（Inline Style）」と呼ぶ。

　個人的には、インターナルCSSはHTMLの可読性を下げるのでなるべく使わないようにしているのだが、外部CSSのスタイルを上書きしたかったり、そのページだけで適用したいスタイルが少しだけあったりする時はお手軽に対応できる手法である。さらに、ページをAMP対応してスマートフォン向けに最適化する際などにはインターナルCSSが必要になってくるので、何気に使用するケースは多いのかもしれない。

　そこで、インターナルCSSもHTMLの出力時にはミニファイして、HTMLヘッダのオーバーヘッドを最適化しておきたいな……と思ったので、早速やってみた。

```php
<!DOCTYPE html>
<html lang="<?= $lang ?>">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta charset="utf-8">
    <title><?= $title ?></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/ka215/sloth@master/dist/sloth.min.css">
    <style><?php $internal_css = <<<EOS
/* Internal Styles */
div { margin-bottom: 0.5em; }
.h2 { margin-top: 1rem; font-size: 2.3rem !important; text-align: center; }
.wrap { margin: 0 auto; }
.w-sm { width: calc(100% - 2em); }
.w-md { width: calc(100% - 2em); padding-left: 0.5em; padding-right: 0.5em; }
.w-lg { width: calc(100% - 2em); max-width: 980px; padding-left: 1em; padding-right: 1em; }
.large-input { font-size: 2.5em !important; }
.large-input-sm { font-size: 2em !important; width: 100% !important; }
#confirm-message { padding: 2px 0 2px 4px; border-radius: 2px; background-color: #f0f5ff; }
.dropdown-readonly::after { visibility: hidden; }
.error { padding: 1px 0 1px 4px; border: solid 1px #ff3333; border-radius: 2px; color: #ff3333; font-size: 86%; }
.required { font-size: 86%; font-weight: 600; color: #ff3333; }
EOS;
// minify internal css
echo preg_replace( [ '@\s*([{}|:;,])\s+|\s*(\!)|/\*.+?\*\/|\R@is', '@;(})@' ], '$1$2', $internal_css ); ?></style>
</head>
(以下略…)
```

　こんな感じにPHP建てのテンプレートにHTMLを書く。インターナルCSSのマークアップ時の書き味的に、普段通りのスタイルシートを書いていけるので、スタイルの調整などはしやすい。これが、HTMLとして出力されると、

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta charset="utf-8">
    <title>ページのタイトル</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/ka215/sloth@master/dist/sloth.min.css">
    <style>div{margin-bottom:0.5em}.h2{margin-top:1rem;font-size:2.3rem!important;text-align:center}.wrap{margin:0 auto}.w-sm{width:calc(100% - 2em)}.w-md{width:calc(100% - 2em);padding-left:0.5em;padding-right:0.5em}.w-lg{width:calc(100% - 2em);max-width:980px;padding-left:1em;padding-right:1em}.large-input{font-size:2.5em!important}.large-input-sm{font-size:2em!important;width:100%!important}#confirm-message{padding:2px 0 2px 4px;border-radius:2px;background-color:#f0f5ff}.dropdown-readonly::after{visibility:hidden}.error{padding:1px 0 1px 4px;border:solid 1px #ff3333;border-radius:2px;color:#ff3333;font-size:86%}.required{font-size:86%;font-weight:600;color:#ff3333}</style>
</head>
(以下略…)
```

　インターナルCSS部分はきちんとミニファイされている。

　ミニファイ用のPHP処理はワンライナーで、

```php
echo preg_replace( [ '@\s*([{}|:;,])\s+|\s*(\!)|/\*.+?\*\/|\R@is', '@;(})@' ], '$1$2', $internal_css );
```

　これだけだ。まぁ、これで厳密なCSSのミニファイ化が出来ているのかまでは検証していないが、実用に耐えうるだけのミニファイ化は出来ているのではないかと。

　ちょいネタでした。