Placing Items on a Circle

Avatar of Kitty Giraudel
Kitty Giraudel on (Updated on )

It can be quite challenging to place items on a circle with CSS. Usually, we end up relying on JavaScript because some plugins do it all right away. However more often than not there is no good reason to do it in JavaScript rather than CSS. This is presentational purpose, let’s go the CSS way.

The Mixin

Ana Tudor explained how she managed to do it in a Stack Overflow answer, using chained CSS transforms. Thereafter I turned her solution into a Sass mixin to make everything a breeze.

/// Mixin to place items on a circle
/// @author Kitty Giraudel
/// @author Ana Tudor
/// @param {Integer} $item-count - Number of items on the circle
/// @param {Length} $circle-size - Large circle size
/// @param {Length} $item-size - Single item size
@mixin on-circle($item-count, $circle-size, $item-size) {
  position: relative;
  width:  $circle-size;
  height: $circle-size;
  padding: 0;
  border-radius: 50%; 
  list-style: none;       
  > * {
    display: block;
    position: absolute;
    top:  50%; 
    left: 50%;
    width:  $item-size;
    height: $item-size;
    margin: -($item-size / 2);
    $angle: (360 / $item-count);
    $rot: 0;

    @for $i from 1 through $item-count {
      &:nth-of-type(#{$i}) {
          rotate($rot * 1deg) 
          translate($circle-size / 2) 
          rotate($rot * -1deg);

      $rot: $rot + $angle;

Caution! Vendor prefixes have been omitted from this code snippet. Be sure to prefix transform if you do not use Autoprefix.


For demo purposes, we’ll consider a list of 8 images but basically anything could work.

<ul class='circle-container'>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
  <li><img src='' alt="..." /></li>
.circle-container {
  @include on-circle($item-count: 8, $circle-size: 20em, $item-size: 6em); 
  margin: 5em auto 0;
  border: solid 5px tomato;
  img { 
    display: block; 
    max-width: 100%; 
    border-radius: 50%;
    filter: grayscale(100%);
    border: solid 5px tomato;
    transition: .15s;
    &:active {
      filter: grayscale(0);