Clean Markup

Circular Layouts and Smooth Curves with CSS sin and cos Functions

Circular Layouts and Smooth Curves with CSS sin and cos Functions

Distributing interface elements along a circle or curved path historically required heavy JavaScript calculations, hardcoded coordinate tables, or nested container hacks with opposing counter-rotations. Whenever the number of child elements changed or the circle expanded responsively, designers had to recalculate trigonometry in build scripts or script-driven inline styles.

The CSS Values and Units Module Level 4 introduces native mathematical functions including sin(), cos(), tan(), and their inverse and hyperbolic counterparts. These functions accept arbitrary angle values in degrees, radians, or turns, producing pure numbers that integrate seamlessly with calc(). When combined with modern CSS custom properties and transform functions, developers can position items radially with clean, declarative stylesheet rules.

By computing X and Y offsets as functions of radius and angle directly in the CSS engine, web layouts achieve hardware-accelerated animations and responsive geometry without dispatching layout recalculations through JavaScript.

Example

<nav class="radial-menu" style="--total: 6; --radius: 120px;">
  <button class="center-trigger" aria-label="Toggle navigation">Menu</button>
  <ul class="radial-items">
    <li style="--index: 0;"><a href="#home">Home</a></li>
    <li style="--index: 1;"><a href="#search">Search</a></li>
    <li style="--index: 2;"><a href="#profile">Profile</a></li>
    <li style="--index: 3;"><a href="#notifications">Alerts</a></li>
    <li style="--index: 4;"><a href="#messages">Inbox</a></li>
    <li style="--index: 5;"><a href="#settings">Settings</a></li>
  </ul>
</nav>

Implementation

/* Container establishing coordinate origin at center */
.radial-menu {
  position: relative;
  width: calc(var(--radius) * 2 + 60px);
  height: calc(var(--radius) * 2 + 60px);
  display: grid;
  place-items: center;
}

.radial-items {
  list-style: none;
  margin: 0;
  padding: 0;
  position: absolute;
  inset: 0;
}

.radial-items li {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  margin-left: -22px;

  /* Calculate angle per slot based on index and total count */
  --angle: calc((360deg / var(--total)) * var(--index));

  /* Trigonometric coordinate mapping: X = cos(angle) * r, Y = sin(angle) * r */
  --x: calc(cos(var(--angle)) * var(--radius));
  --y: calc(sin(var(--angle)) * var(--radius));

  /* Translate item directly to its radial position */
  translate: var(--x) var(--y);
  transition: translate 300ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.radial-items a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: #0f172a;
  color: #f8fafc;
  text-decoration: none;
  font-size: 0.75rem;
  font-weight: 600;
  box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
}

.radial-items a:focus-visible {
  outline: 2px solid #38bdf8;
  outline-offset: 2px;
}

Main Point: Native CSS trigonometric functions allow responsive circular positioning and smooth angular transitions without external mathematics libraries or inline coordinate scripting.

Credits

Photo by Robert Katzki on Unsplash

← Home