上位階層の .htaccess で書き換えられた Cache-Control ヘッダを修復する

あるディレクトリ以下 (/app とする) でアプリケーションを作成したが、アプリケーション側で出力している Cache-Control が効かない。原因を調べてみると上位階層の .htaccess で mod_headers を使って Cache-Control: no-cache と書き換えられていた。

サーバの環境は次の通り。

  • HTTP(S)サーバ: Apache/2.2.15
  • .htaccess が有効
  • mod_headers, mod_rewrite が有効
  • アプリケーションの実行: モジュール版PHP
  • ユーザのアップロードした画像は、実ファイルを配置せずアプリケーションを通して出力している(ここで Cache-Control ヘッダを設定)

mod_headers の基本的な使用方法

上位階層の .htaccess では次の記述がなされていた。

Header set Cache-Control "no-cache"
Header set Pragma "no-cache"

この設定がある場合、アプリケーションでキャッシュの方法や期限を設定していても、応答ヘッダが次のように書き換えられてしまう。

Cache-Control: no-cache
Pragma: no-cache

Header ディレクティブの動作は次の7通り(Apache 2.2系, 2.2.9以降)で、既存の設定を解除し、Apache のキャッシュ設定を使用する方法はないようだ。

set 応答ヘッダを設定する
add 応答ヘッダを追加する。同じ名前のヘッダがある場合は、複数の同じ名前のヘッダができる
append 既に存在する同じ名前のヘッダに値を追加する。既存の値の後ろにカンマ区切りで追加
merge append と同様だが、同じ値がある場合は追加しない
unset 指定した名前の応答ヘッダを削除する
echo リクエストヘッダと同じ名前の応答ヘッダを返す
edit 既存の応答ヘッダを正規表現によって置き換える

ファイルの種類によって応答ヘッダを設定

上位階層でなされた設定を解除する方法がないので、ファイルの種類によってひとつひとつ応答ヘッダを設定することにした。

RewriteEngine On
RewriteBase /app

## 静的ファイルだった場合に環境変数を設定
RewriteRule \.(css|js|png|jpg|gif|svg|svgz)$ - [E=StaticAssets:1]

## アップロードファイルに環境変数を設定
## (Query string を設定する方法以外はうまくいかなかった)
RewriteRule ^uploads/(.*) index.php?_uploads [QSA]

RewriteCond %{QUERY_STRING} ^_uploads
RewriteRule ^ - [E=AppUploads:1]

## アプリケーションのルーティング用設定
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]


## 静的ファイルのキャッシュ設定
Header set Cache-Control "public, max-age=86400" env=StaticAssets
Header set Pragma "cache" env=StaticAssets

## アップロードファイルのキャッシュ設定
Header set Cache-Control "public, max-age=31536000" env=AppUploads
Header set Pragma "cache" env=AppUploads

## 設定の確認用
Header set X-Env "%{StaticAssets}e / %{AppUploads}e"

Twitter の「ツイート」ボタン、Facebook の「いいね!」ボタンは一行でOK

TwitterFacebook のボタンを埋め込む際、通常は次のようなコードを埋め込むよう指示される。

<!-- Twitter -->
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<!-- Facebook -->
<div id="fb-root"></div>
<script>(function(d, s, id) {
 var js, fjs = d.getElementsByTagName(s)[0];
 if (d.getElementById(id)) return;
 js = d.createElement(s); js.id = id;
 js.src = "//connect.facebook.net/ja_JP/all.js#xfbml=1";
 fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

このコードは TwitterFacebook が提供するスクリプトが重複して読み込まれることがないよう考慮されている。

しかしながら、もし最終的に出力される HTML を一式管理できる場合は、次のコードを HTML の末尾に記述するのがよい。ページの読み込みが多少早くなるはずだ。

<!-- Twitter -->
<script src="//platform.twitter.com/widgets.js" async defer></script>
<!-- Facebook -->
<div id="fb-root"></div><script src="//connect.facebook.net/ja_JP/all.js#xfbml=1" async defer></script>

文字サイズ「小・中・大」と配色「A・B・C」変更ボタンはつけてはいけない

公共系のウェブサイトでこのようなボタンを目にする機会は多い。

しかしながらこのようなボタンは意図通りに機能することはなく、むしろ必要な人には気づかれず、不要な人には目障りなものだ。つけてはいけない。

文字の大きさや配色は OS で変更している

その理由は実際に目の悪い人がどのように PC を使用しているか想像してみればすぐに分かる。

Windows では20年も前の Windows 95 (1995年発売) の頃から、画面の文字を一括で大きくしたり、配色を変更する機能がついている。視力の低い人の間ではこのような機能を使用するのは常識と考えるのが普通ではないだろうか。

参考までに、ここに一個人の例ではあるが詳細に記述された貴重な記事がある。

文字を大きくしても、ハイコントラストモードでも見やすいか?

そのような利用者にとっては、文字サイズや配色の変更ボタンが不要なこと以上に、そのボタンの存在が必要な情報への到達を阻害する可能性すらある。

たとえば現在の Windows にはハイコントラストモードというものがあり、ウェブサイトの配色も一括で黒地に白文字にできる。その状態で石川県ホームページを表示した画面がこちら。

はたして文字サイズや配所の変更ボタンはどう見えるだろうか。

アクセシビリティのためにつけているとしたら、早くそんなものを取っ払うことを奨めたい。

制作者ができること

大きな文字サイズに対応する

文字サイズを大きくすると画面の仮想的な幅(情報が入る量)が小さくなる。つまり、情報の内容としては小さな画面で見ているのと同じことになる。

ここで現在のブラウザは、表示を拡大したとき、小さな画面を拡大したものとして表示する。CSS のメディアクエリもそれに従うので、レスポンシブデザインのページは表示を拡大していくとそれに応じてレイアウトも変化するはずだ。

すなわち正しく設計されたレスポンシブデザインのウェブページは、視力が低くて文字を拡大している利用者にもやさしい。

ハイコントラストモードに最適化する

Windows のハイコントラストモードを使用してウェブサイトを閲覧すると、背景が黒、文字と枠線 (border) は白、背景画像は無効となり、画像は色が反転される。

いくつかのサイトを見てみると、適切に枠線が使われたページは見やすいと感じる。見出しなどの意味の区切りとなるところでは border を使うのが望ましい。もし通常の表示で視覚的に不要なら、背景と同色にしたり、透明にすることもできる。

また、Internet Explorer 10-11 や Edge では CSS のメディアクエリ -ms-high-contrast を使うことで、ハイコントラストモードでの表示を制御することができる。標準化はされていないが、ブラウザのシェアの大きさを考えると有効だろう。

@media (-ms-high-contrast: active) {
    h1 {
        color: #f00;
    }
}

JavaScript のモジュール管理

JavaScript のモジュール管理について、個人的メモ。

モジュール管理ライブラリ

JavaScriptECMAScript 2015 (ECMAScript 6) になるまで、他のスクリプトを参照する機能は言語機能として提供されてこなかった。しかしながらサーバサイドで動作する node.js が生まれた頃からその必要性に駆られ、さまざまなモジュール管理ライブラリが登場した。
現在メジャーなモジュール管理ライブラリは次の二つ。

  • Asynchronous Module Design (AMD)
  • CommonJS (CJS)

ECMAScript 2015 の登場

ECMAScript 2015 では言語機能として import 文および export 文が追加された。

Babel

現在 import 文および export 文 をサポートするブラウザはないが、Babel というツール (トランスパイラ) を使うと現在のブラウザが実行できる形に変換できる。

Babel は npm からインストールすることができる。ローカルインストールが推奨されている。

% npm install --save-dev babel-cli babel-preset-es2015

実行する前に設定ファイル .babelrc を作成する。

{
    "presets": ["es2015"]
}

src.js を dest.js にコンパイル

% babel src.js --output dest.js

Webpack

Webpack は JavaScript だけでなく CSS や画像も含めて管理することができるツール。TypeScript や CoffeeScript で書かれたスクリプトや、Sass や Less で書かれたスタイルシートも、最終的に実行できる形に変換してくれる。

Windows で npm run が動かない場合

WindowsError: Cannot find module '…\webpack.config.js;' と言われ動かない場合、複数のコマンドを続けて実行するときのセミコロンが原因。Windows では ; の代わりに & を使わないといけない。

xyzzy で Less CSS を編集するための less-mode

xyzzy でも快適に Less を書きたかったので less-mode を作った。ベースは c-mode。

導入は簡単。GitHub からダウンロードして適宜 etc/Less, site-lisp/less-mode.l を配置する。
そして、 .xyzzy に次の 2 行を追加する。

(load-library "less-mode")
(pushnew '("\\.less$" . less-mode) *auto-mode-alist*)

インデントを設定する

初期設定でタブ幅 4、インデントにはタブ文字を使わない設定になっている。これ以外のタブ幅を使っている場合や、どうしてもタブ文字を使えない事情がある場合は次のように設定する。

(setq ed::*less-mode-hook*
      '(lambda ()
        ;; タブ幅を 5 に設定する
        (setq c-indent-level 5)
        (setq c-brace-offset -5)
        (setq c-argdecl-indent 5)
        ;; インデントにスペースを使う
        (setq indent-tabs-mode nil)
       ))

キーワードファイルの場所を指定する

xyzzy 本体を更新した場合に、etc ディレクトリの内容が置き換わってしまう場合がある。変更したキーワードファイルを誤って上書きされないようにするには、キーワードファイルの場所を違う場所に設定すればよい。

;; ホームディレクトリの xyzzy/etc をキーワードファイル置き場にする
(setq *keyword-load-path* '("~/xyzzy/etc"))