システムフォント San Francisco を Photoshop, Illustrator から使う

WWDC 2015 で発表された macOS, iOS, watchOS, tvOS 専用のシステムフォント San Francisco。

iOS 9 や OS X 10.11 El Capitan 以降、画面の様々な部分に使用されているが、一般のアプリケーションからは選択することができない。

しかしながら、 macOS, iOS, tvOS / watchOS 上で動作するソフトウェア製品のモックアップを作成する用途限定で Apple Developer のページからダウンロード、使用することができる。

San Francisco のダウンロード

次のページからダウンロードできる。iOS, macOS, tvOS 用の San Francisco Fonts と watchOS 用の San Francisco Compact Fonts は別のファイルとなっている。

ダウンロードした Zip ファイルを展開すると macOS 用のインストールパッケージになっているので、規約に同意の上インストールする。

すると「SF UI Display」「SF UI Text」の二つのファミリーが使えるようになる。

SF UI Display と Text の違い

和文フォントでは馴染みが薄いが、高品質な欧文フォントでは見出し用の Display と本文用の Text が含まれている場合がある。San Francisco でもこの例に漏れず、それぞれ見出し用と本文用を指している。

このように二種類用意されているのは、同じ形の文字であっても、大きさが違うと読みやすさや印象が異なってくるため。次の図はどちらも San Francisco Display で、大きさを変えたものを並べてあるのだが、どう見えるだろうか。

WWDC 2015 - Introducing the New System Fonts - 98 ページより

それに対し、小さい文字には San Francisco Text を使ったもの。

WWDC 2015 - Introducing the New System Fonts - 99 ページより

こちらのほうが、すっきりとした印象を受けるのではないだろうか。よく見ると文字の間隔や、a, e, g の横の隙間の空き具合が異なる。実際 Display と Text を重ねてみると、だいぶ輪郭が違うことが分かる。

WWDC 2015 - Introducing the New System Fonts - 113 ページより

また、Display のほうにはより細い Ultralight, Light, Thin の三種類のウェイトが追加されている。

SF UI Display と Text の使い分け

実は WWDC 2015 - Introducing the New System Fonts でも説明されている通り、この二つのファミリーは文字の大きさによって自動的に使い分けられている。

WWDC 2015 - Introducing the New System Fonts - 125 ページより

この図の通り、20 ポイント以上では Display を使い、それ未満では Text を使うのがよいだろう。

San Francisco と San Francisco Compact の違い

前述した通り、San Francisco は iPhone, iPod, Mac, Apple TV で使用される iOS, macOS, tvOS 用、San Francisco Compact は Apple Watch で使用される watchOS 用である。

San Francisco Compact では、より小さな画面でより多くの情報を表示するため、 e や o などの丸いアルファベットの側面が直線的に処理されいる。そして、次の図のように無印 San Francisco と混在して使用されることはない。

WWDC 2015 - Introducing the New System Fonts - 27 ページより


参考

しっとりとした本文用明朝体「ろうまん仮名」

新書や雑誌の本文が、モリサワリュウミン R-KL で組まれているものをよく見かける。買い切りでお得な基本書体パックに含まれているし、その業界ではだいたいの環境で使えることが多いので使いやすいのだろう。

しかしながら個人的にリュウミンは見出し向けの書体であると思っている。ハライは伸びやかだし、仮名はそれぞれの美しさを競っている。それが本文となると、必ずしも読みやすいとはいえない。

そんな中ひっそりと、フリーの本文用明朝体「ろうまん仮名」が公開された。

過去にフリーフォント界隈で話題になった「かちどき仮名」と同じ作者によるもので、それと同じように東京築地活版製造所の初号明朝体の面影が見られる。線のコントラストやハライの先端処理などを見る限り、リュウミンと組むことを想定しているようだ。

含まれるフォントは次の通り。

  • K-ろうまん仮名-L
  • K-ろうまん仮名-R
  • K-ふうが仮名-R

このうち、「K-ふうが仮名-R」は K-ろうまん仮名-R と骨格同じくして、やや細めのウェイトとなっている。

試しに リュウミン R と ろうまん仮名 R で組んでみたものがこちら。例文は北原白秋『雀の卵』より。すずめかわいい。

リュウミン R + ろうまん仮名 R

比較のため リュウミン R-KL だけのものがこちら。ろうまん仮名のほうがしっとりと落ち着いた印象を受ける。

いわゆる「オールドスタイル」の仮名を使いたい場合、最近のモリサワパスポートにはタイプバンク書体も含まれているので、「オールドスタイル」の源流である東京築地活版製造所の名を持つ「築地」を合わせる手もある。

リュウミン R + 築地 M

「ろうまん仮名」は DLmarket から無料でダウンロードすることができる(要会員登録)。

grunt-group-css-media-queries でメディアクエリを決まった順序にする

Less をはじめとした CSS プリプロセッサを使えば部品の単位ごとにメディアクエリによる分岐を行えるので便利だ。その一方、CSS ファイルのあちこちに @media (max-width: ...) { ... } という記述ができてしまうため、ややファイルサイズが大きくなる。

そこで group-css-media-queries で同じメディアクエリをまとめることになるのだが、現時点での最新バージョン1.1.0 より前のバージョンでは順序が定まっていない。Grunt 用のタスク grunt-group-css-media-queries ではバージョン 1.0.1 を使うようになっている。

Grunt 自体が見捨てられたのか、それとも別の CSS プリプロセッサではそこまで面倒を見てくれるのか分からないが、最新バージョンを使うようメンテナンスもされていない。

group-css-media-queries 1.1.0 を使う

すでにインストール済みの grunt-group-css-media-queries で group-css-media-queries 1.1.0 を使うよう変更するには、 node_modules/grunt-group-css-media-queries/package.json を編集する。

まず dependencies に書かれたバージョンを次のように変更する。

  "dependencies": {
    "group-css-media-queries": "~1.1.0"
  },

そして、node_modules/grunt-group-css-media-queries ディレクトリで次のコマンドを実行する。

npm install

応急処置的な方法だがこれで group-css-media-queries 1.1.0 が使用されるようになる。

上位階層の .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>