Items on a Circle Using CSS

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.

See also  Customizable Creative Buttons For The Web - sbuttons


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);

Leave a Reply

Your email address will not be published. Required fields are marked *