円周上に複数の要素を配置する方法【CSSだけ・サンプルコード有】
- #CSS
- #HTML
- #Tips
複数の要素を円周上に等間隔で配置したいこと、ありませんか?あります…よね?この記事ではJavaScriptを使わずに実装できる方法をできるだけわかりやすく解説しました。
CSSのみでつくるデザインはコードがシンプルでページの読み込みが軽いのもメリットです。コピペで使えるサンプルコードも紹介しているので、参考になれば嬉しいです!
目次
コードの全体像
まずは完成形のサンプルコードをこちらでご紹介します。コードの詳細については後ほど説明していきますね。
今回は例として、円周上に5つの小さな円が等間隔に並ぶデザインを作成しました。
See the Pen Circular Positioning Using CSS Custom Properties by Aizawa Web Design (@AizawaWebDesign) on CodePen.
HTMLの詳細
HTMLでは全体を囲む枠<div class=”circle-wrapper”>と円の部分<div class=”circle-container”>、そして円周上に並べたい要素<div class=”circle-item”>をマークアップしています。
<div class="circle-wrapper">
<div class="circle-container" style="--radius: 100">
<div class="circle-item" style="--angle: 72"></div>
<div class="circle-item" style="--angle: 144"></div>
<div class="circle-item" style="--angle: 216"></div>
<div class="circle-item" style="--angle: 288"></div>
<div class="circle-item" style="--angle: 360"></div>
</div>
</div>HTMLミソとなるのは「style=”–**: ++”」の部分ですね!このあたりをもう少し詳しく見ていきます。
カスタムプロパティ(CSS変数)の指定
今回の例ではカスタムプロパティを使っています。カスタムプロパティとは、使い回しができて、かつ自分で好きな名前を付けられる値です。CSSで使用します。
CSS側で書いてもよいのですが、今回はHTML側で指定しています。例えば.circle-containerが複数あってそれぞれで変数の値を変えたいときには、以下のようにHTMLに直接書くと管理がしやすいです!
<div class="circle-container" style="--radius: 100"></div>
<div class="circle-container" style="--radius: 150"></div>HTMLここでは変数に「–radius」という名前を付けています。このあとCSSで「–radius」を円の半径として使っていきます。
「–angle」部分の考え方
HTML内でもう1箇所変数が指定されていますね。それが「–angle」の部分です。この変数は複数の要素を円周上で等間隔に並べるために使います。
360度を要素の数で割って(今回だと360/5=72)、要素一つひとつをその角度ずつずらして配置することで、等間隔に配置できるという仕組みです。
なので、もし配置したい要素が6つに増えた場合は360/6=60度ずつずらすので、以下のように指定すればOKです。
<div class="circle-item" style="--angle: 60"></div>
<div class="circle-item" style="--angle: 120"></div>
<div class="circle-item" style="--angle: 180"></div>
<div class="circle-item" style="--angle: 240"></div>
<div class="circle-item" style="--angle: 300"></div>
<div class="circle-item" style="--angle: 360"></div>HTMLCSSの詳細
続いてCSSを見ていきましょう!
円を画面の中央に配置
.circle-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
}CSS全体を囲む.circle-wrapperを調整することで、円の配置を決めます。この例では画面中央に円がくるよう指定しました。
- .circle-wrapperをflexboxにして中身を縦横いずれも中央に配置
- widthとheightには画面いっぱいの値を指定して、どのような画面サイズでも円が中央へくるように
円をつくる
.circle-container {
border: #222222 1px solid;
border-radius: 50%;
width: calc(var(--radius) * 1px);
height: calc(var(--radius) * 1px);
position: relative;
display: flex;
justify-content: center;
align-items: center;
}CSS次は要素を並べるベースとなる円を調整します。
border-radius: 50%;で正円をつくる- calc(var(–radius) * 1px)で、HTMLで指定された「–radius」の値を半径として使う
calc()は計算のできる関数で、width: calc(var(–radius)*1px);は、「–radius」というカスタムプロパティに1pxをかけてwidthのサイズを計算してくださいという意味です。
円周上に要素を並べる
.circle-item {
/* 計算用に角度を調整(-90度は上を基準にするため) */
--angle-adjusted: calc(var(--angle) * 1deg - 90deg);
/* X座標はcosで計算 */
--x-position: calc(cos(var(--angle-adjusted)) * var(--radius) * 0.5px);
/* Y座標はsinで計算 */
--y-position: calc(sin(var(--angle-adjusted)) * var(--radius) * 0.5px);
background-color: #4682B4;
width: 32px;
height: 32px;
border-radius: 50%;
position: absolute;
transform-origin: center center;
/* 計算したX・Y座標に丸を移動 */
transform: translate(var(--x-position), var(--y-position));
}CSSここが一番ごちゃごちゃしていますね。要素の配置を決めるために三角関数の計算を使っています。数学が苦手だった私は「cos」や「sin」を見ると心臓がドキドキしますが…でも計算はCSSが自動でやってくれるから大丈夫!何をしているのか順を追って見ていきましょう。
カスタムプロパティの指定
こちらでもカスタムプロパティが出てきました。要素の配置をX座標とY座標を使って指定したいので、その計算に必要な値を定義しています。
- –angle-adjusted:HTMLで指定した「–angle」の値を使って計算
- –x-position:cosによって横方向の位置(X座標)を計算
- –y-position:sinによって縦方向の位置(Y座標)を計算
–angle-adjustedの微調整
CSSの三角関数では0度=右方向(時計でいうと15時)を指します。今回は、5つの要素を並べる基準を上方向(時計でいうと12時)にしたかったので、最後に-90degを付けています。
–x-position、–y-positionの微調整
*0.5pxの部分で円に対してどのあたりに要素を配置するかを調整しています。この例だと*0.5pxでちょうど円周上に要素がきました。かける値が大きくなるほど円の外側に、小さくなるほど円の内側に要素が置かれるので、希望のデザインに合わせて調整してください!
transformで要素を動かす
最後に、要素を変形(移動・回転・拡大縮小など)させるtransformプロパティを使って、5つの要素を円周上に配置しています。
- translate(X,Y)で要素を横(X)と縦(Y)に移動
- 要素を自由に動かせるようposition: absolute;を指定
- きちんと円周上で並ぶようにtransform-origin: center center;を指定
親要素の.circle-containerにposition: relative;を書くのも忘れないようにしてくださいね〜
まとめ
カスタムプロパティやtransformプロパティを使って、CSSだけで円周上に要素を等間隔に並べる方法をご紹介しました。ローディングアニメーションや画像ギャラリー、ナビゲーションメニューなどさまざまなところで応用できるかなと思います。