<aside>CSS Trigonometric functions aren't supported in this browser :(</aside>
<section>
  <span class="text-ring"></span>
</section>
:root {
  --gray-0: #f8f9fa;
  --gray-1: #f1f3f5;
  --gray-2: #e9ecef;
  --gray-3: #dee2e6;
  --gray-4: #ced4da;
  --gray-5: #adb5bd;
  --gray-6: #868e96;
  --gray-7: #495057;
  --gray-8: #343a40;
  --gray-9: #212529;
  --gray-10: #16191d;
  --gray-11: #0d0f12;
  --gray-12: #030507;
  /* Surfaces */
  --text-1: var(--gray-12);
  --text-2: var(--gray-10);
  --text-3: var(--gray-8);
  --text-4: var(--gray-7);
  --surface-1: var(--gray-0);
  --surface-2: var(--gray-1);
  --surface-3: var(--gray-2);
  --surface-4: var(--gray-3);
}

@media (prefers-color-scheme: dark) {
  :root {
    --text-1: var(--gray-1);
    --text-2: var(--gray-3);
    --text-3: var(--gray-5);
    --text-4: var(--gray-6);
    --surface-1: var(--gray-10);
    --surface-2: var(--gray-9);
    --surface-3: var(--gray-8);
    --surface-4: var(--gray-7);
  }
}

*,
*:after,
*:before {
  box-sizing: border-box;
}

body {
  display: grid;
  place-items: center;
  min-height: 100vh;
  font-family: 'Google Sans', sans-serif, system-ui;
  overflow: hidden;
  background: var(--surface-3);
  color: var(--text-2);
}

aside {
  position: fixed;
  padding: 1rem;
  border: 2px solid hsl(45 80% 50%);
  background: #fff;
  color: #222;
  z-index: 2;
  top: 1rem;
  left: 1rem;
}

@supports (top: calc(sin(1) * 1px)) {
  aside { display: none; }
}

.text-ring {
  position: relative;
}

.text-ring [style*=--index] {
  /* In "ch" units */
  --inner-angle: calc((360 / var(--total)) * 1deg);
  --radius: calc((var(--character-width, 1) / sin(var(--inner-angle))) * -1ch);
  font-weight: bold;
  font-family: monospace;
  text-transform: uppercase;
  font-size: calc(var(--font-size, 2) * 1rem);
  position: absolute;
  top: 50%;
  left: 50%;
  transform:
    translate(-50%, -50%)
    rotate(calc(var(--inner-angle) * var(--index)))
    translateY(var(--radius, -5ch));
}

.dg :is(.cr.string, .cr.number) input[type=text] {
  color: white;
  line-height: 1;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}
import { GUI } from "https://cdn.skypack.dev/dat.gui@0.7.9"

const RING = document.querySelector('.text-ring')

const OPTIONS = {
  text: 'Circular text with CSS Trigonometric functions • ',
  size: 1,
  spacing: 1,
}

const CTRL = new GUI()

const onUpdate = () => {
  RING.innerHTML = ''
  const CHARS = OPTIONS.text.split('')
  RING.style.setProperty('--total', CHARS.length)
  RING.style.setProperty('--character-width', OPTIONS.spacing)
  RING.style.setProperty('--font-size', OPTIONS.size)
  const HIDDEN_CHARS = Object.assign(document.createElement('span'), {
    ariaHidden: true,
  })

  for (let c = 0; c < CHARS.length; c++) {
    HIDDEN_CHARS.innerHTML += `<span style="--index: ${c}">${CHARS[c]}</span>`
  }
  RING.appendChild(HIDDEN_CHARS)
  RING.innerHTML += `<span class="sr-only">${OPTIONS.text}</span>`
}

CTRL.add(OPTIONS, 'text').name('Text').onChange(onUpdate)
CTRL.add(OPTIONS, 'size', 1, 2, 0.1).name('Font size (rem)').onChange(onUpdate)
CTRL.add(OPTIONS, 'spacing', 1, 2, 0.1).name('Side (ch)').onChange(onUpdate)

onUpdate()
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.