HTMLとCSSで魔法陣を描いてみる





#そもそも魔法陣って？

創作作品でよく見る、モンスターが召喚されたり~~iPhoneを充電したり~~するときに下にひいてあるアレ。
「魔法陣」というのはいわゆる創作作品で描かれる演出用の陣の名称で、実在の魔術で使われるガチな方のやつは「魔法**円**」と区別される。

魔術的な意味での魔法陣とは、「円の中と外を魔術的に遮断する」という目的の元に作成される結界。神社の御神木に巻いてある注連縄とかと近しい存在だそうだ。だから、その中に悪魔を召喚するのは間違いで、むしろ魔法使いが魔法陣の中に立つのが正しい利用法なのだという。というか、そうしないと召喚した悪魔に襲われてしまう。
（なお、お祈りや魔除けとしての魔法陣も存在する。）

ちゃんとした魔術的儀式をやって魔法陣を使うには「聖別」といって、水で清めたりお香を炊いたり、あと火であぶったりする下準備が必要らしいが、さすがにパソコンを火にくべるわけにはいかない。
ので、本記事ではあくまで演出としての「魔法陣」の作り方を記述していくことにする。


#構造解説

完成図がこちら。
![1582636266722.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/118ed03f-033d-3a6c-f672-5b53e55c7f82.jpeg)

<p class="codepen" data-height="265" data-theme-id="default" data-default-tab="css,result" data-user="yomogenium" data-slug-hash="gOpgVPx" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Magic Circle example by CSS">
  <span>See the Pen <a href="https://codepen.io/yomogenium/pen/gOpgVPx">
  Magic Circle example by CSS</a> by Yomogenium (<a href="https://codepen.io/yomogenium">@yomogenium</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>



CSSで魔法陣を作るにあたってカギとなるのは、CSSの一つ、「`position`」。
最大のポイントは以下の部分。

> position: absolute
絶対位置への配置となります。**親ボックスにpositionプロパティのstatic以外の値が指定されている場合には、親ボックスの左上が基準位置となります。**親ボックスにpositionプロパティのstatic以外の値が指定されていない場合には、ウィンドウ全体の左上が基準位置となります。
出典： http://www.htmq.com/style/position.shtml

つまり、複数の要素に連続して`position:absolute;`を使えば、要素同士の干渉を防ぎつつ図形を重ねられるのだ。
CSSで魔法陣を描くのは確かに困難だ。だが、魔法陣に使われる図形を個々で作成していけば、そこまで難易度の高い工作にはならないのではないだろうか？

そういう設計思想で作ってみた。うまくいった。
以下がhtmlソースだが、比較的見やすいものになっている。

<details>
<summary>コード。長いので折りたたみ</summary><div>

```html:html

<div class="base">
	<!-- 外側の輪 -->
	<div class="pattern01"></div>

	<!-- 輪状に並ぶ文字 -->
	<div class="pattern02 rune">
		<span>P</span>
		<span>r</span>
		<span>o</span>
		<span>t</span>
		<span>e</span>
		<span>g</span>
		<span>o</span>
		<span> </span>
		<span>H</span>
		<span>o</span>
		<span>r</span>
		<span>r</span>
		<span>i</span>
		<span>b</span>
		<span>i</span>
		<span>l</span>
		<span>i</span>
		<span>s</span>
	</div>

	<!-- 内側の輪 -->
	<div class="pattern03"></div>

	<!-- ヘキサグラム -->
	<div class="pattern04">
		<p></p>
		<p></p>
		<p></p>
		<p></p>
		<p></p>
		<p></p>
	</div>

	<!-- アクセント -->
	<div class="pattern05">
		<div>
			<p class="rune">v</p>
		</div>
	</div>
</div>
```

ここに準備のためのCSSを書き加え、以下のようにしてから、工作スタートだ。


```html:html

<style>
body{
	background-color: black;
}

.base{
    position: relative;
    width: 300px;
    height: 300px;
    background-color: black;
}

/* 具体的に言えば、「pattern01～pattern04は中心が親要素の中心と重なる位置に来る」という効果。 */
.pattern01, .pattern02, .pattern03, .pattern04{
    position: absolute;
    margin: auto;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}
</style>

<div class="base">
	<!-- 外側の輪 -->
	<div class="pattern01"></div>

	<!-- 輪状に並ぶ文字 -->
	<div class="pattern02 rune">
		<span>P</span>
		<span>r</span>
		<span>o</span>
		<span>t</span>
		<span>e</span>
		<span>g</span>
		<span>o</span>
		<span> </span>
		<span>H</span>
		<span>o</span>
		<span>r</span>
		<span>r</span>
		<span>i</span>
		<span>b</span>
		<span>i</span>
		<span>l</span>
		<span>i</span>
		<span>s</span>
	</div>

	<!-- 内側の輪 -->
	<div class="pattern03"></div>

	<!-- ヘキサグラム -->
	<div class="pattern04">
		<p></p>
		<p></p>
		<p></p>
		<p></p>
		<p></p>
		<p></p>
	</div>

	<!-- アクセント -->
	<div class="pattern05">
		<div>
			<p class="rune">v</p>
		</div>
	</div>
</div>
```
</div></details>



#外側の円
これはかんたん。

```html:html

<style>
.pattern01{
    border: 2px solid white;
    border-radius: 50%;
    width: 95%;
    height: 95%;	
}

</style>

<div class="pattern01"></div>

```


`width`と`height`の値は親である`.base`を参照しているので、そこから適度に縮めればよい。これは以降の図形でも同じ。
ちなみに、`border-radius`の値を50%にすると、どんなサイズの要素でも完全な円形になる。

#円形に並ぶ文字

この部分を制作するにあたって、こちらのサイトが大きな助けになった。
https://mail.conifer.jp/csstest/css-circle-text.html

このサイトで使っているのはこちらの応用。
やっていることは箇条書きにするとざっくり以下の通りだ。

- 文字を一文字ずつ区切る
- 一文字ごとに異なる傾斜をつける
   (その角度は、360° ÷ 文字の数。今回は18文字なので360 ÷ 18 = 20、つまり20°ずつ傾ければいい。)
- その文字が含まれる要素に高さをつける
- `transform-origin`で回転の中央軸を本来の位置からずらす
- 出来上がった円形文字は本来の位置からズレるので、`position:absolute`を使って正しい位置に戻す

この５つができていれば、おかしな形になることはないだろう。
（`transform-origin`については[こちら](https://developer.mozilla.org/ja/docs/Web/CSS/transform-origin)を参照のこと。）


呪文には、ハリーポッター・シリーズに登場する防衛呪文、「`Protego Horribilis`」(18文字)を使うことにした。

<details>
<summary>コード。長いので折りたたみ</summary><div>

```html:html

<style>
.pattern02{
    width: 95%;
    height: 95%;
}

/* top、bottom、left、right、heightは%で指定しよう。親要素のサイズに合わせて可変するので、幅や位置を微調整する必要がなくなるからだ。 */
.pattern02 span{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 49%;
    color: white;
    height: 50%;
    transform-origin: bottom center;
}

.pattern02 span:first-of-type{
	transform: rotate(0deg);
}
.pattern02 span:nth-of-type(2){
	transform: rotate(20deg);
}
.pattern02 span:nth-of-type(3){
	transform: rotate(40deg);
}
.pattern02 span:nth-of-type(4){
	transform: rotate(60deg);
}
.pattern02 span:nth-of-type(5){
	transform: rotate(80deg);
}
.pattern02 span:nth-of-type(6){
	transform: rotate(100deg);
}
.pattern02 span:nth-of-type(7){
	transform: rotate(120deg);
}
.pattern02 span:nth-of-type(8){
	transform: rotate(140deg);
}
.pattern02 span:nth-of-type(9){
	transform: rotate(160deg);
}
.pattern02 span:nth-of-type(10){
	transform: rotate(180deg);
}
.pattern02 span:nth-of-type(11){
	transform: rotate(200deg);
}
.pattern02 span:nth-of-type(12){
	transform: rotate(220deg);
}
.pattern02 span:nth-of-type(13){
	transform: rotate(240deg);
}
.pattern02 span:nth-of-type(14){
	transform: rotate(260deg);
}
.pattern02 span:nth-of-type(15){
	transform: rotate(280deg);
}
.pattern02 span:nth-of-type(16){
	transform: rotate(300deg);
}
.pattern02 span:nth-of-type(17){
	transform: rotate(320deg);
}
.pattern02 span:nth-of-type(18){
	transform: rotate(340deg);
}
</style>

<div class="pattern02">
	<span>P</span>
	<span>r</span>
	<span>o</span>
	<span>t</span>
	<span>e</span>
	<span>g</span>
	<span>o</span>
	<span> </span>
	<span>H</span>
	<span>o</span>
	<span>r</span>
	<span>r</span>
	<span>i</span>
	<span>b</span>
	<span>i</span>
	<span>l</span>
	<span>i</span>
	<span>s</span>
</div>

```
</div></details>

ここを行った直後の状態がコレ。
![1582633697492.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/57e64629-f171-d001-be84-c0c1d0e68105.jpeg)

ここでは「上が外向き」になるように並んでいるが、逆に「下が外向き」の状態にすることも可能だ。

```css:css

.pattern02 span{
    position: absolute;
    top: 50%;
    bottom: 0;
    left: 49%;
    color: #ffffff;
    padding-top: 44%;
    transform-origin: top center;
}

```

![1582639027901.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/824625e3-03bc-15b8-e6fe-be29da0a1d8d.jpeg)


※位置や形状を調整するときはbackgroundで正方形を表示させて行うとよい。

なお、この部分は[別記事で、Jsを用いて自動化できるようにしてある。](https://qiita.com/yomogenium/items/5be72f68d8a9391416c5)



#フォント（文字の書体）の変更

魔法陣を作るうえで要となるのが、判読不可能な謎言語、だろう。
どうせ作るなら~~厨二臭い~~カッコいいディティールにこだわりたい、と思って探していたら、なんと**ルーン文字のフォントが配布されていた。しかも無料で。**
あるものは使うべし、というわけで、筆者はここからフォントをダウンロードして使うことにした。

以下配布サイト's。
https://coliss.com/articles/freebies/free-font-which-cannot-read.html
https://sitebk.com/summary/ancient-font/


フォントの適用方法は[こちらのサイト](https://01earth.jp/web-create/coding/web-font/)に記載されていたので割愛。
とりあえず手元のサーバー、あるいはパソコンに置き、その上で@font-faceをかければどうにかなるだろう。
ただ、拡張子が`.otf`や`.ttf`のままではうまく動作しないので、きちんと`.woff`に変換することは忘れずに。[woffファイルへの変換はこちらのサイトから可能だ。](https://convertio.co/ja/otf-woff/)
一応、コードも貼っておく。

```css:css

@font-face {
  font-family: 'runefont';
  src: url('./rune.woff') format('woff');
}
.rune{
	font-family: runefont;
}

```

あ、フォント適用したら以下のようになった。

![1582633899884.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/1ca6a909-1940-ea09-3068-3b69ccd82ea0.jpeg)


#内側の円
「外側の円」と仕組みは同じ。だが、外側の円に比べて幅を小さくしてある。

```html:html
<style>
.pattern03{
	border: 2px solid white;
    border-radius: 50%;
    width: 83%;
    height: 83%;
}
</style>

<!-- 内側の輪 -->
<div class="pattern03"></div>

```

![1582634245395.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/871fe0c1-0dcd-5500-6991-211d7a0a2220.jpeg)

なんだかそれっぽくなってきたぞ。



#六芒星(ヘキサグラム)の描画

※Javascriptで自動化済み。詳しくは[こちらのページで](https://qiita.com/yomogenium/items/d38d4ab49d973ef42802)。

仕組み自体は上に挙げた「円形に並ぶ文字」と大差ない。
星型多角形……通称「n芒星」は、辺の本数自体は通常の正多角形と変わらないので、傾ける角度さえ正しければ、あとは辺の長さ(＝width)と中心からの距離(＝height）を調整してやればよいのだ。

```html:html
<style>
.pattern04{
	width: 83%;
    height: 83%;	
}
.pattern04 p{
    border-top: 2px solid white;
    width: 86%;
    height: 50%;
    transform-origin: center;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
}
.pattern04 p:first-of-type{
	transform: rotate(0deg);
}
.pattern04 p:nth-of-type(2){
	transform: rotate(60deg);
}
.pattern04 p:nth-of-type(3){
	transform: rotate(120deg);
}
.pattern04 p:nth-of-type(4){
	transform: rotate(180deg);
}
.pattern04 p:nth-of-type(5){
	transform: rotate(240deg);
}
.pattern04 p:nth-of-type(6){
	transform: rotate(300deg);
}
</style>

<!-- ヘキサグラム -->
<div class="pattern04">
	<p></p>
	<p></p>
	<p></p>
	<p></p>
	<p></p>
	<p></p>
</div>

```

完成するとこのようになる。
![1582634573542.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/7ec233d1-11d0-8a21-c7f2-2951a3c0c3fd.jpeg)

ふつうの多角形を生成したい場合であっても、基本的にwidthとheight以外は変える必要がない。
ノーマルな六角形verにしたのが以下のコードである。

```css:css
<style>
.pattern04{
	width: 83%;
    height: 83%;	
}
.pattern04 p{
    border-top: 2px solid white;
    width: 50%;
    height: 86%;
    transform-origin: center;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
}
.pattern04 p:first-of-type{
	transform: rotate(0deg);
}
.pattern04 p:nth-of-type(2){
	transform: rotate(60deg);
}
.pattern04 p:nth-of-type(3){
	transform: rotate(120deg);
}
.pattern04 p:nth-of-type(4){
	transform: rotate(180deg);
}
.pattern04 p:nth-of-type(5){
	transform: rotate(240deg);
}
.pattern04 p:nth-of-type(6){
	transform: rotate(300deg);
}
```

![1582651192128.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/d04371d6-9cb2-0f15-161e-013ccc49921b.jpeg)



※ここには書いていないが、五芒星、七芒星でも同様の仕組みで作成できた。


#アクセントの作成

実際の魔法陣を見てみるとわかるが、ただ単にきれいな図形を並べただけのものは少ない。
むしろモノホンの魔法陣ほど、幾何学性とはかけ離れたデザインをしている気もしなくはない。
というわけで、魔法陣に華を添えるアクセントも作成していく。


作るのはこの月のようなパーツ。（スピログラフ、というらしい。）

![118ed03f-033d-3a6c-f672-5b53e55c7f82.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/5b9a3c9f-e43d-6090-6195-0aff05d42e0a.jpeg)

これは２つの円を重ねて月のように見せているもの。特に特殊な技術は使っていない……はず。

```html:html
<style>
.pattern05{
    position: absolute;
    top: 40%;
    left: 40%;
    border: 2px solid white;
    border-radius: 50%;
    width: 18%;
    height: 18%;
    background: white;
}
.pattern05 div{
    border: 2px solid white;
    border-radius: 50%;
    width: 73%;
    height: 73%;
    position: absolute;
    top: 0%;
    left: 0%;
    background: black;
}
.pattern05 div p{
	color: white;
    font-size: 22px;
    text-align: center;
    height: 1em;
    width: 1em;
    margin: auto;
    vertical-align: baseline;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}
</style>

<!-- アクセント -->
<div class="pattern05">
	<div>
		<p class="rune">v</p>
	</div>
</div>

```

完成。

![1582636266722.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416995/118ed03f-033d-3a6c-f672-5b53e55c7f82.jpeg)


#おわりに

CSSで魔法陣を作るにあたり、色々見て回っていた。
**もう既に作ってる人がいて、激しく落ち込んだ。**

https://coliss.com/articles/build-websites/operation/design/alchemy-circles-generator.html


#参考文献

https://mail.conifer.jp/csstest/css-circle-text.html

http://slpr.sakura.ne.jp/qp/polygon-spirograph/

https://www.ho-yu.ed.jp/club-news/science/1688.html

https://ja.wikipedia.org/wiki/%E6%98%9F%E5%9E%8B%E5%A4%9A%E8%A7%92%E5%BD%A2

https://theorthodoxworks.com/study/various-polygon-in-css/