1. Top
  2. Blog
  3. コピペでOK!CSSだけで要素を円周上に並べる方法
コピペでOK!CSSだけで要素を円周上に並べる方法

コピペでOK!CSSだけで要素を円周上に並べる方法

  • Sasaki
  • 2024.07.26

Webページを制作していて、ボタンやアイコンを円周上に配置したいと思ったことはありませんか?
この記事では「CSSだけで要素を円周上に並べる方法」を実際のソースコードとともに紹介していきます。

使い回しの利くシンプルな設計ですので、ぜひ試してみてください!

目標のレイアウト

今回作るレイアウトの完成形はこちらです。

目標イメージ

ここから先はこの形を目指して一から作っていきます。
手順を飛ばしてソースコードだけを確認したい方は「これにて完成!」へどうぞ!

STEP1 - 円を配置する

まずは、親要素となる円を配置します。
このとき、円の半径をカスタムプロパティで設定しておくと後々便利です。

【参考】CSS カスタムプロパティ(変数)の使用|MDN
https://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_custom_properties

HTML

 <div class="circle" style="--r: 150">
 </div>

※ --r = radius のつもり

CSS

 .circle {
   width: calc(var(--r) * 2px);
   height: calc(var(--r) * 2px);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
 }

この時点のイメージ

STEP1のイメージ

STEP2 - 子要素を追加する

次に、円の中に子要素を追加します。
今回は1から12までの数字が入った12個のdiv要素を作ります。

HTML

 <div class="circle" style="--r: 150">
+  <div>1</div>
+  <div>2</div>
+  <div>3</div>
+  <div>4</div>
+  <div>5</div>
+  <div>6</div>
+  <div>7</div>
+  <div>8</div>
+  <div>9</div>
+  <div>10</div>
+  <div>11</div>
+  <div>12</div>
 </div>

CSS

 .circle {
   width: calc(var(--r) * 2px);
   height: calc(var(--r) * 2px);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
+  > div {
+   color: #555;
+   font: 700 50px / 1 Impact;
+  }
 }

この時点のイメージ

STEP2のイメージ

STEP3 - 子要素を円の中央に配置する

全ての子要素が円の中央に配置されるようにスタイルを追加します。
今回は子要素のスタイルを最小限にとどめるため、フレックスボックスと絶対配置の組み合わせで実現しました。

CSS

 .circle {
+  display: flex;
+  align-items: center;
+  justify-content: center;
   width: calc(var(--r) * 2px);
   height: calc(var(--r) * 2px);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
   > div {
+    position: absolute;
     color: #555;
     font: 700 50px / 1 Impact;
   }
 }

この時点のイメージ

STEP3のイメージ

STEP4 - 子要素に円周上の位置を設定する

三時の位置なら90度、六時の位置なら180度という具合に、
それぞれの子要素の位置を角度で指定します。

HTML

 <div class="circle" style="--r: 150">
-  <div>1</div>
-  <div>2</div>
-  <div>3</div>
-  <div>4</div>
-  <div>5</div>
-  <div>6</div>
-  <div>7</div>
-  <div>8</div>
-  <div>9</div>
-  <div>10</div>
-  <div>11</div>
-  <div>12</div>
+  <div style="--a: 30">1</div>
+  <div style="--a: 60">2</div>
+  <div style="--a: 90">3</div>
+  <div style="--a: 120">4</div>
+  <div style="--a: 150">5</div>
+  <div style="--a: 180">6</div>
+  <div style="--a: 210">7</div>
+  <div style="--a: 240">8</div>
+  <div style="--a: 270">9</div>
+  <div style="--a: 300">10</div>
+  <div style="--a: 330">11</div>
+  <div style="--a: 360">12</div>
 </div>

※ --a = angle のつもり

この時点のイメージ(STEP3から変化なし)

STEP4のイメージ

STEP5 - 座標を計算して円周上に配置する

STEP4で設定した角度を用いて円周上の点の座標を計算し、
translate プロパティで子要素を配置します。

CSS

 .circle {
   display: flex;
   align-items: center;
   justify-content: center;
   width: calc(var(--r) * 2px);
   height: calc(var(--r) * 2px);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
   > div {
+    --a2: calc(var(--a) * 1deg - 90deg);
+    --x: calc(cos(var(--a2)) * var(--r) * 1px);
+    --y: calc(sin(var(--a2)) * var(--r) * 1px);
     position: absolute;
     color: #555;
     font: 700 50px / 1 Impact;
+    translate: var(--x) var(--y);
   }
 }


ここではCSSの三角関数が活躍しています。
詳しい解説は省略しますが、sin関数で円周上の点のY座標を、cos関数でX座標を求めることができます。

TrigFunctionDiagram
PAR, CC0, via Wikimedia Commons

ちなみに、JavaScript等で三角関数を扱う際は、角度をラジアンに変換する必要がありますが、CSSの三角関数では「deg」「turn」などの角度をそのまま渡すことができます。便利!

なお、CSSの世界と数学の世界では以下の違いがありますので、
コードを読み解く際はご注意ください!

■ CSS
Y軸の正の方向:下
回転の方向:時計回り

■ 数学
Y軸の正の方向:上
回転の方向:反時計回り

これにて完成!

完成イメージ

これで目標の形が完成しました!
最終的なソースコードは以下の通りです。

HTML

<div class="circle" style="--r: 150">
  <div style="--a: 30">1</div>
  <div style="--a: 60">2</div>
  <div style="--a: 90">3</div>
  <div style="--a: 120">4</div>
  <div style="--a: 150">5</div>
  <div style="--a: 180">6</div>
  <div style="--a: 210">7</div>
  <div style="--a: 240">8</div>
  <div style="--a: 270">9</div>
  <div style="--a: 300">10</div>
  <div style="--a: 330">11</div>
  <div style="--a: 360">12</div>
</div>
 
 

 

 

CSS

.circle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--r) * 2px);
  height: calc(var(--r) * 2px);
  border: 20px solid #ddd;
  border-radius: 50%;
  box-sizing: border-box;
  > div {
    --a2: calc(var(--a) * 1deg - 90deg);
    --x: calc(cos(var(--a2)) * var(--r) * 1px);
    --y: calc(sin(var(--a2)) * var(--r) * 1px);
    position: absolute;
    color: #555;
    font: 700 50px / 1 Impact;
    translate: var(--x) var(--y);
  }
}

レイアウトのバリエーション

スタイルを少し変更するだけで、
以下のようなバリエーションにも対応できます!

円に沿って子要素を回転

バリエーションその1

CSS

 .circle {
   display: flex;
   align-items: center;
   justify-content: center;
   width: calc(var(--r) * 2px);
   height: calc(var(--r) * 2px);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
   > div {
     --a2: calc(var(--a) * 1deg - 90deg);
     --x: calc(cos(var(--a2)) * var(--r) * 1px);
     --y: calc(sin(var(--a2)) * var(--r) * 1px);
     position: absolute;
     color: #555;
     font: 700 50px / 1 Impact;
     translate: var(--x) var(--y);
+    rotate: calc(var(--a) * 1deg);
   }
 }

親要素を楕円に変更

バリエーションその2

CSS

 .circle {
   display: flex;
   align-items: center;
   justify-content: center;
   width: calc(var(--r) * 2px);
-  height: calc(var(--r) * 2px);
+  height: calc(var(--r) * 2px * .7);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
   > div {
     --a2: calc(var(--a) * 1deg - 90deg);
     --x: calc(cos(var(--a2)) * var(--r) * 1px);
-    --y: calc(sin(var(--a2)) * var(--r) * 1px);
+    --y: calc(sin(var(--a2)) * var(--r) * 1px * .7);
     position: absolute;
     color: #555;
     font: 700 50px / 1 Impact;
     translate: var(--x) var(--y);
   }
 }

子要素をborderの中央に配置

ssk_01_10

CSS

 .circle {
   display: flex;
   align-items: center;
   justify-content: center;
   width: calc(var(--r) * 2px);
   height: calc(var(--r) * 2px);
   border: 20px solid #ddd;
   border-radius: 50%;
   box-sizing: border-box;
   > div {
     --a2: calc(var(--a) * 1deg - 90deg);
-    --x: calc(cos(var(--a2)) * var(--r) * 1px);
-    --y: calc(sin(var(--a2)) * var(--r) * 1px);
+    --x: calc(cos(var(--a2)) * (var(--r) - 10) * 1px);
+    --y: calc(sin(var(--a2)) * (var(--r) - 10) * 1px);
     position: absolute;
     color: #555;
     font: 700 50px / 1 Impact;
     translate: var(--x) var(--y);
   }
 }

 

あとは自由にカスタマイズ!

ここまでの内容で、大半のレイアウトに対応できる土台は整ったかと思います。
あとは自由にカスタマイズして、お好みのレイアウトを作ってみてください!

カスタマイズ例その1

カスタマイズ例その2

カスタマイズ例その3

おわりに

以上、「CSSだけで要素を円周上に並べる方法」のご紹介でした。
頑張ってシンプルなコードにまとめたので、少しでも参考にしてもらえたら嬉しいです!

今回は基本的な内容にとどめましたが、工夫次第でもっともっと面白い表現ができると思います。
複数の円を組み合わせたり、アニメーションと組み合わせたり、インタラクティブな要素を加えてみたり...いくらでも応用できるので、ぜひ色々と試してみてください!