9 スライス
9-Slice Scaling別名:9 パッチ、ナインスライス、9 分割拡大
概要
UI の枠やボタンの画像を縦横 3 つずつ、計 9 つの領域に分けて拡大する方法。四隅は元の大きさのまま描き、辺は一方向にだけ、中央は縦横に伸ばす。角の丸みや枠線の太さを保ったまま、1 枚の画像を好きな大きさで使える。
デモ
使われる場面
ゲームやアプリの UI
ダイアログの枠、ボタン、体力ゲージの枠を、1 枚の小さな画像から任意の大きさで作る。表示する内容に合わせて枠を伸び縮みさせられる。
画面の大きさや言語の違いへの対応
画面の解像度や縦横比が変わっても、同じ画像で枠を描ける。翻訳で文字列の長さが変わるボタンにも対応しやすい。
吹き出しとメッセージウィンドウ
会話の吹き出しを、台詞の長さに合わせて広げる。吹き出しのしっぽは、別の画像として重ねることが多い。
Web の枠線
CSS の border-image は、画像を 9 つに分けて要素の枠に使う仕組みで、9 スライスと同じ考え方である。
判断基準
| こういうとき | こうする |
|---|---|
| 角が丸い、または角や枠に装飾がある UI 画像を、いろいろな大きさで使う | 9 スライスを使う。大きさごとに画像を用意する必要がなくなる。 |
| 境界の位置を決める | 角の丸みや装飾が四隅の領域に収まるように置く。辺の領域には、伸ばしても見た目が変わらない一様な部分だけを残す。 |
| 辺や中央に模様がある | 伸ばすと模様も引き伸ばされる。辺と中央を伸ばす代わりに繰り返して敷き詰める設定を使うか、模様を別の画像として重ねる。 |
| 四隅の大きさの合計より小さく表示することがある | 四隅どうしが重なって崩れる。最小の大きさを決めておくか、四隅ごと縮小する。 |
| 角も装飾もない、単純な四角形の枠 | 9 スライスは不要で、塗りと線の描画で足りる。 |
こう見えたら
指示の例
ボタンを横に伸ばしたら、角の丸みと左右の枠線がゆがんだ。枠の画像を 9 スライスで拡大して
9 スライスにしたのに、角の丸みの一部が伸びている。境界の位置を内側にずらして、角の丸み全体が四隅に収まるようにして
枠の辺の模様が引き伸ばされている。辺は伸ばさずに、繰り返して敷き詰める設定にして
小さく表示すると、角どうしが重なって崩れる。枠の最小の大きさを、四隅の合計より大きくして
詳細
伸ばしてよい部分と、伸ばしてはいけない部分
画像を単純に拡大すると、画像の中のすべてが同じ比率で伸びる。横長に伸ばせば、丸い角は横長の楕円になり、左右の枠線は上下の枠線より太くなる。UI の枠では、角の形と枠線の太さはそのまま保ち、内側の領域だけを広げたい。
9 スライスは、画像を縦と横それぞれ 2 本の境界線で 9 つの領域に分け、領域ごとに伸ばし方を変える。
- 四隅:伸ばさない。元の大きさのまま描く。
- 上下の辺:横方向にだけ伸ばす。
- 左右の辺:縦方向にだけ伸ばす。
- 中央:縦と横の両方に伸ばす。
伸ばす量の計算
元の画像の幅を 、左右の境界の位置を端からそれぞれ と 、表示したい幅を とする。四隅の幅 と は変えないので、伸ばすのは中央の区間だけで、その拡大率は次のようになる。
縦方向も同じように、上下の境界の位置から拡大率を求める。実装では、元の画像と表示先のそれぞれで横と縦の区切りの位置を 4 つずつ求め、9 つの領域を一つずつ描く。
// 元画像の区切りと、表示先(幅 W2、高さ H2)の区切り
const xs = [0, left, W - right, W], xd = [0, left, W2 - right, W2];
const ys = [0, top, H - bottom, H], yd = [0, top, H2 - bottom, H2];
for (let j = 0; j < 3; j++) {
for (let i = 0; i < 3; i++) {
ctx.drawImage(img,
xs[i], ys[j], xs[i + 1] - xs[i], ys[j + 1] - ys[j], // 元画像の領域
x + xd[i], y + yd[j], xd[i + 1] - xd[i], yd[j + 1] - yd[j]); // 表示先の領域
}
}
見分け方と落とし穴
9 スライスで描いた枠は、大きさが変わっても角の丸みと枠線の太さが変わらない。単純に拡大した枠は、横に伸ばすと左右の枠線が太くなり、角の飾りが楕円につぶれる。
境界の位置は、角の丸みや装飾が四隅の領域に収まるように決める必要がある。境界が丸みにかかっていると、丸みの一部が辺の領域に入って一方向に伸び、角が崩れる。デモで境界の位置を小さくすると、この崩れ方が見える。
辺と中央は伸ばされるので、そこにある模様は引き伸ばされる。また、画像を拡大するときの補間で、境界の隣の領域の色が混ざり、つなぎ目に細い線が出ることがある。複数の画像を 1 枚にまとめて使う場合は、各画像のまわりに余白を取っておくと防げる。