SVG & CSSでアンサガのスキルパネルのようなメニューを作る
公開:
「SVGにチャレンジ! 第1回」です。第2回があるかは分かりません。
インラインSVGを使って『アンリミテッド:サガ』というゲームのスキルパネル風のメニューを作ります。 実物は「アンリミテッドサガ スキルパネル」とかで画像検索してみてください。
このスクエアさんの『アンリミテッド:サガ』というゲームがすごく好きでですね……以前からこれをウェブページとして作ってみたいと思っていたんですよ。
クリッカブルマップとかも考えましたが、あれあまり好きじゃない。
というわけでSVGでやることにしました。拡大しても綺麗ですしね!
Unlimited Saga Style Panel Menu with SVG & CSS
表示確認で一番期待通りに表示できたのは、Firefox 7とChrome 16 devです。
IE 9とSafari 5.1は、transitionしません。IE 9には最初からないですけど、Safariはよく分かりません。
Operaですが、Opera 11はインラインSVG未対応なので表示できません。Opera 12 alphaでは一応表示はされます。
とりあえず、完成品は次のような感じになります。スクリーンショットはFirefox 7です。
色が変わっている部分はマウスオーバー中です。
タイトル部分は本題じゃないですが、あれもSVGで作ってあります。
使っているフォントは『ドットコロン』さんのTendernessです。
それをInkscapeでカーニングしたりサイズ調整して、パスに変換しました。
今回はインラインSVGを使うので、最初に普通の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>
width
やheight
は最初に大きめに作って、最後に実際に作ったものを見て変更しました。とりあえず今回はこのサイズです。viewBox
とpreserveAspectRatio
は大きさが変更されたときにアスペクト比を保つために指定していますが……まだちゃんと分かっていないのでおかしいかもしれません。
次はメインとなる六角形を作ります。
これは流石に手書きできないので、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 Transitionsを使いました。pointer-events: none
が指定されていますが、これは念のためです。
メディアクエリとかmax-width: 100%
とかは、SVG部分をFluid Imageのようにしたかったからです。
毎度のように説明不足な感がありますが、これで終わりです。
というかまだ分からないことも多いので説明するのも難しいです。
本当はツールチップとかも作りたかったんですが、とりあえず今回はこれでいいかなーと。
初めてにしては頑張れたと思いますw