<div class="demo-container">
  <h2>Calculating circle placement</h2>
  <p>Using <code>sibling-index()</code> and <code>sibling-count()</code> to pass through some trigonometric functions using <code>@function</code></p>

  <section class="controls">
    <button id="add-item">Add Item</button>
    <button id="remove-item">Remove Item</button>
  </section>
  <section class="circle-wrapper">
    <div class="circle-container">
      <div>1</div>
      <div>2</div>
      <div>3</div>
      <div>4</div>
      <div>5</div>
    </div>
  </section>
</div>
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap");

@function --pos-x(--index, --count, --radius) {
  result: calc(var(--radius) * cos(360deg / var(--count) * (var(--index) - 1)));
}

@function --pos-y(--index, --count, --radius) {
  result: calc(var(--radius) * sin(360deg / var(--count) * (var(--index) - 1)));
}

:root {
  --item-size: 60px;
  --stage-size: calc(
    var(--item-size) * 6
  ); /* This is quite a static calculation for the maximum of 12 items, children-count() would be nice */

  /* Presentational vars */
  --bg-color: #f0f2f5;
  --text-color: #333;
  --items-bg: conic-gradient(
    at 0% 1% in oklch,
    oklch(62% 0.25 348) 0%,
    oklch(73% 0.28 241) 100%
  );
}

.circle-wrapper {
  width: var(--stage-size);
  height: var(--stage-size);
  display: grid;
  margin-inline: auto;
  place-content: center;
  background-color: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
}

/* The circle container is the size of one item, the items get place around it with transforms. it is the center point */
.circle-container {
  position: relative;
  width: var(--item-size);
  height: var(--item-size);

  div {
    --radius: calc(var(--item-size) * 2); /* The radius of the circle */
    position: absolute;
    top: 50%;
    left: 50%;

    /* Using functions in order to have a cleaner value output here 
  
  First a general center translate and then overrule, seems to work with the matrix :o
  */
    transform: translate(-50%, -50%)
      translateX(--pos-x(sibling-index(), sibling-count(), var(--radius)))
      translateY(--pos-y(sibling-index(), sibling-count(), var(--radius)));

    width: var(--item-size);
    height: var(--item-size);
    border-radius: 50%;
    background: var(--items-bg);
    display: grid;
    place-content: center;
    font-size: 1.5rem;
    font-weight: 600;
    color: white;
    transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55);
  }
}

@layer basestyles {
  :root {
    --bg-color: #f0f2f5;
    --text-color: #333;
    --accent-grad: linear-gradient(160deg, hotpink, indigo);
  }

  body {
    font-family: "Poppins", sans-serif;
    background-color: var(--bg-color);
    color: var(--text-color);
    margin: 0;
    padding: 3rem 1rem;
    display: grid;
    gap: 3.5rem;
    justify-items: center;
  }

  .demo-container {
    width: 100%;
    max-width: 650px;
    text-align: center;
  }

  h2 {
    margin-bottom: 0.5rem;
  }

  p {
    margin-top: 0;
    margin-bottom: 1.5rem;
    color: #666;
    max-width: 500px;
    margin-left: auto;
    margin-right: auto;
  }
  code {
    background-color: #e2e5e9;
    padding: 0.2em 0.4em;
    border-radius: 4px;
    font-size: 0.9em;
  }

  button {
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    padding: 0.75rem 1.5rem;
    border: none;
    border-radius: 8px;
    background-image: var(--accent-grad);
    color: white;
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    margin: 0 0.5rem 1.5rem;
    &:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px B20px rgba(138, 126, 255, 0.4);
    }
  }
}
const circleContainer = document.querySelector(".circle-container");
const addItemBtn = document.getElementById("add-item");
const removeItemBtn = document.getElementById("remove-item");
const MAX_COUNT = 12;

addItemBtn.addEventListener("click", () => {
  if (circleContainer.children.length < MAX_COUNT) {
    const newItem = document.createElement("div");
    newItem.textContent = circleContainer.children.length + 1;
    circleContainer.appendChild(newItem);
  }
});

removeItemBtn.addEventListener("click", () => {
  if (circleContainer.lastElementChild) {
    circleContainer.removeChild(circleContainer.lastElementChild);
  }
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.