SVG & CSS でアンサガのスキルパネルのようなメニューを作る

Category : CSS, SVG

「SVG にチャレンジ! 第1回」です。第2回があるかは分かりません。
インライン SVG を使って「アンリミテッド:サガ」というゲームのスキルパネル風のメニューを作ります。 実物は "アンリミテッドサガ スキルパネル" とかで画像検索してみてください。

このスクエアさんの「アンリミテッド:サガ」というゲームがすごく好きでですね……以前からこれをウェブページとして作ってみたいと思っていたんですよ。
クリッカブルマップとかも考えましたが、あれあまり好きじゃない。
というわけで SVG でやることにしました。拡大しても綺麗ですしね!

Unlimited Saga Style Panel Menu with SVG & CSS

デモファイルをダウンロード

表示確認で一番期待通りに表示できたのは、Firefox 7 と Chrome 16 dev です。
IE9 と Safari 5.1 は、transition しません。IE9 には最初からないですけど、Safari はよく分かりません。
Opera ですが、 Opera 11 はインライン SVG 未対応なので表示できません。Opera 12 alpha では一応表示はされます。

とりあえず、完成品は次のような感じになります。スクリーンショットは Firefox 7 です。

Unlimited Saga Style Panel Menu with SVG & CSS スクリーンショット

色が変わっている部分はマウスオーバー中です。

タイトル部分は本題じゃないですが、あれも SVG で作ってあります。
使っているフォントはドットコロンさんの Tenderness です。
それを Inkscape でカーニングしたりサイズ調整して、パスに変換しました。

今回はインライン SVG を使うので、最初に普通の HTML を書きます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Unlimited Saga Style Panel Menu with SVG &amp; CSS</title>
<link rel="stylesheet" type="text/css" media="screen" href="style.css" />
</head>
<body>

<h1><!-- ここにタイトル --></h1>

<div id="svg-container">
  <!-- ここにパネル -->
</div>

</body>
</html>

コメントした部分に SVG を書いていきます。CSS は最後です。
ではパネル部分を作っていきます。

<svg xmlns="http://www.w3.org/2000/svg"
	 xmlns:xlink="http://www.w3.org/1999/xlink"
	 version="1.1"
	 width="484" height="466"
	 viewBox="0 0 484 466" preserveAspectRatio="xMinYMin meet"
	 id="panels">
  <!-- ここに中身を書いていく -->
</svg>

widthheight は最初に大きめに作って、最後に実際に作ったものを見て変更しました。とりあえず今回はこのサイズです。
viewBoxpreserveAspectRatio は大きさが変更されたときにアスペクト比を保つために指定していますが……まだちゃんと分かっていないのでおかしいかもしれません。

次はメインとなる六角形を作ります。
これは流石に手書きできないので、Inkscape で作りました。大きさは後で楽しやすいように、横160px 縦184.75px に調整しています。

<polygon id="hexagon" points="..." />

Inkscape はパスで出力しますが、せっかくのなので polygon 要素に書き換えました。
これを使いまわすので defs 要素に入れておきます。

<svg><!-- 長いので属性などは省略します -->
  <defs>
	<polygon id="hexagon" points="..." />
  </defs>
</svg>

他にも、2回以上使うものを同様に作っていきます。
グラデーションとアイコンですね。

<!-- 放射状グラデーション -->
<radialGradient id="flash" gradientUnits="userSpaceOnUse"
				cx="80" cy="92.375" r="80">
  <stop offset="0%" stop-color="#fff" stop-opacity="0.45" />
  <stop offset="100%" stop-color="#fff" stop-opacity="0" />
</radialGradient>

<!-- アイコン -->
<path id="icon-wordpress" d="..." />
<path id="icon-twitter" d="..." />
...

グラデーションですが、RGBA が使えないので、stop-opacity を使って不透明度を変更します。
これはパネルの上に重ねて使うために作りました。
アイコンは Inkscape で出力したパスを使っています。
アイコンのサイズは、横または縦が最大で 60px になるように調整しました。

できあがったものを配置していきます。
次のコードは defs 要素の後に書きます。

<g id="inner-box">

  <g id="line1" transform="translate(81,0)">

	<g id="panel1" class="item blog">
	  <a xlink:href="...">
		<g>
		  <use xlink:href="#hexagon" x="0" y="0" class="bgcolor" />
		  <use xlink:href="#hexagon" x="0" y="0"
			   fill="url(#flash)" class="overlay" />
		</g>
		<g>
		  <use xlink:href="#icon-wordpress" x="49" y="61.375" class="pressed" />
		  <use xlink:href="#icon-wordpress" x="50" y="62.375" class="icon" />
		</g>
	  </a>
	</g><!-- // panel1 -->

	<g id="panel2" class="item twitter" transform="translate(162,0)">
	  ...
	</g><!-- // #panel2 -->

  </g><!-- // #line1 -->

  ...

</g><!-- // #inner-box -->

g#inner-box は特に必要はないです。自分が見やすくするために使っています。
六角形が上から順に 2 – 3 – 2 と並ぶので、g#line(n) のようにグループ化しました。
また、各パネルも上から順に g#panel(n) という感じでグループ化しています。

<a xlink:href="...">...</a> はリンクです。

a 要素の個要素、g が2つありますが、1つ目は六角形、2つ目はアイコンです。
use 要素で最初に作った六角形を使い、その直後に同様に六角形を置いて、そちらには fill="url(#flash)" で塗りつぶし色にグラデーションを指定しています。
fill を指定していない1つ目の六角形は、この時点では黒いままです。

アイコンのグループ。
アイコンのパスを2回使っているのは、レタープレス風の効果を出すためです。
最初はフィルタでやろうとしたんですが、SVG を直接開いたときの Opera でしか上手く表示できなかったので……。
pressed というクラス名が付いているものを、本来の位置(中心)より上と左に 1px ずらすことでそれっぽく見せています。
これは CSS の text-shadow でレタープレスやるときなんかと同じです。
アイコンの配置は、各アイコンごとに割り算と引き算で出しました。

また、line(n)panel(n) といったグループは transform="translate(x,y)" で位置を調整します。
計算方法が分からなかったので、実際に見ながらやりました。数学というか算数がよく分からないんですよ……。

次に CSS を書いていきます。
塗りつぶし色などは SVG に直接書いてもよかったんですが、CSS の方が慣れているので、できそうなものは CSS で指定しています。

html, body, div, h1 {
  margin : 0;
  padding: 0;
  border : 0;
}

body {
  background: #fff;
}

@media screen and (max-width: 500px) {
  body {
	margin: 0 10px;
  }
}

h1,
#svg-container {
  width    : 484px;
  max-width: 100%;
}

h1 {
  margin: 20px auto;
}

.logo {
  fill: #073642;
}

#svg-container {
  margin: 0 auto 20px;
}

#title {
  width: 100%;
}

#panels {
  display: block;
  width  : 100%;
}

.bgcolor {
  fill: #efefef;
}

.overlay,
.icon,
.pressed {
  pointer-events: none;
}

.icon {
  fill: #bfbfbf;
}

.pressed {
  fill        : #000;
  fill-opacity: 0.4;
}

.bgcolor,
.icon {
  transition: all 300ms linear;
}

.blog:hover .bgcolor {
  fill: #dc322f;
}

/* 残り6つのパネルの色 */

.item:hover .icon {
  fill: #fff;
}

パネルにマウス乗せたときにパネルの色が変わるのは、最初は SVG アニメーションでやろうとしてたんですが、まだよく分からなかったので CSS transition を使いました。
pointer-events:none; が指定されていますが、これは念のためです。
メディアクエリとか max-width:100%; とかは、SVG 部分を Fluid Image のようにしたかったからです。


毎度のように説明不足な感がありますが、これで終わりです。
というかまだ分からないことも多いので説明するのも難しいです。

本当はツールチップとかも作りたかったんですが、とりあえず今回はこれでいいかなーと。
初めてにしては頑張れたと思いますw

Leave a Reply