Solução 2020
Aqui está uma solução mais moderna que uso atualmente.
Eu começo gerando o HTML a partir de uma série de imagens. Se o HTML é gerado usando PHP, JS, algum pré-processador HTML, seja o que for ... isso importa menos, pois a ideia básica por trás é a mesma.
Este é o código Pug que faria isso:
//- start with an array of images, described by url and alt text
- let imgs = [
- {
- src: 'image_url.jpg',
- alt: 'image alt text'
- } /* and so on, add more images here */
- ];
- let n_imgs = imgs.length;
- let has_mid = 1; /* 0 if there's no item in the middle, 1 otherwise */
- let m = n_imgs - has_mid; /* how many are ON the circle */
- let tan = Math.tan(Math.PI/m); /* tangent of half the base angle */
.container(style=`--m: ${m}; --tan: ${+tan.toFixed(2)}`)
- for(let i = 0; i < n_imgs; i++)
a(href='#' style=i - has_mid >= 0 ? `--i: ${i}` : null)
img(src=imgs[i].src alt=imgs[i].alt)
O HTML gerado tem a seguinte aparência (e sim, você também pode escrever o HTML manualmente, mas será uma dor fazer alterações depois):
<div class="container" style="--m: 8; --tan: 0.41">
<a href='#'>
<img src="image_mid.jpg" alt="alt text"/>
</a>
<a style="--i: 1">
<img src="first_img_on_circle.jpg" alt="alt text"/>
</a>
<!-- the rest of those placed on the circle -->
</div>
No CSS, decidimos um tamanho para as imagens, digamos 8em. Os --mitens são posicionados em um círculo e é se eles estão no meio das arestas de um polígono de --marestas, todos os quais são tangentes ao círculo.
Se você tiver dificuldade em imaginar isso, pode brincar com esta demonstração interativa que constrói o incircle e o circumcircle para vários polígonos cujo número de arestas você escolhe arrastando o controle deslizante.

Isso nos diz que o tamanho do contêiner deve ser duas vezes o raio do círculo mais duas vezes a metade do tamanho das imagens.
Ainda não sabemos o raio, mas podemos calculá-lo se soubermos o número de arestas (e, portanto, a tangente da metade do ângulo base, pré-calculado e definido como uma propriedade personalizada --tan) e a aresta do polígono. Provavelmente queremos que a borda do polígono tenha pelo menos o tamanho das imagens, mas o quanto deixamos nas laterais é arbitrário. Digamos que temos metade do tamanho da imagem em cada lado, então a borda do polígono tem o dobro do tamanho da imagem. Isso nos dá o seguinte CSS:
.container {
--d: 6.5em; /* image size */
--rel: 1; /* how much extra space we want between images, 1 = one image size */
--r: calc(.5*(1 + var(--rel))*var(--d)/var(--tan)); /* circle radius */
--s: calc(2*var(--r) + var(--d)); /* container size */
position: relative;
width: var(--s); height: var(--s);
background: silver /* to show images perfectly fit in container */
}
.container a {
position: absolute;
top: 50%; left: 50%;
margin: calc(-.5*var(--d));
width: var(--d); height: var(--d);
--az: calc(var(--i)*1turn/var(--m));
transform:
rotate(var(--az))
translate(var(--r))
rotate(calc(-1*var(--az)))
}
img { max-width: 100% }
Veja a solução antiga para uma explicação de como funciona a cadeia de transformação.
Dessa forma, adicionar ou remover uma imagem da matriz de imagens organiza automaticamente o novo número de imagens em um círculo de forma que fiquem igualmente espaçadas e também ajusta o tamanho do contêiner. Você pode testar isso nesta demonstração .
Solução ANTIGA (preservada por razões históricas)
Sim, é muito possível e muito simples usando apenas CSS. Você só precisa ter em mente os ângulos em que deseja os links com as imagens (adicionei um trecho de código no final apenas para mostrar os ângulos sempre que você passa o mouse sobre um deles).
Você primeiro precisa de um invólucro. Eu defini seu diâmetro para ser 24em( width: 24em; height: 24em;faz isso), você pode definir o que quiser. Você dá position: relative;.
Em seguida, você posiciona seus links com as imagens no centro desse wrapper, tanto horizontal quanto verticalmente. Você faz isso configurando position: absolute;e então top: 50%; left: 50%;e margin: -2em;(onde 2emé a metade da largura do link com a imagem, que eu defini para ser 4em- novamente, você pode alterá-lo para o que quiser, mas não se esqueça de alterar a margem em Aquele caso).
Você então decide os ângulos em que deseja ter seus links com as imagens e adiciona uma classe deg{desired_angle}(por exemplo, deg0ou deg45ou qualquer outra coisa). Em seguida, para cada classe, você aplica transformações CSS encadeadas, como esta:
.deg{desired_angle} {
transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}
onde você substitui {desired_angle}com 0, 45e assim por diante ...
A primeira transformação de rotação gira o objeto e seus eixos, a transformação de translação traduz o objeto ao longo do eixo X girado e a segunda transformação de rotação traz o objeto de volta à posição.
A vantagem desse método é que ele é flexível. Você pode adicionar novas imagens em ângulos diferentes sem alterar a estrutura atual.
FRAGMENTO DE CÓDIGO
.circle-container {
position: relative;
width: 24em;
height: 24em;
padding: 2.8em;
/*2.8em = 2em*1.4 (2em = half the width of a link with img, 1.4 = sqrt(2))*/
border: dashed 1px;
border-radius: 50%;
margin: 1.75em auto 0;
}
.circle-container a {
display: block;
position: absolute;
top: 50%; left: 50%;
width: 4em; height: 4em;
margin: -2em;
}
.circle-container img { display: block; width: 100%; }
.deg0 { transform: translate(12em); } /* 12em = half the width of the wrapper */
.deg45 { transform: rotate(45deg) translate(12em) rotate(-45deg); }
.deg135 { transform: rotate(135deg) translate(12em) rotate(-135deg); }
.deg180 { transform: translate(-12em); }
.deg225 { transform: rotate(225deg) translate(12em) rotate(-225deg); }
.deg315 { transform: rotate(315deg) translate(12em) rotate(-315deg); }
<div class='circle-container'>
<a href='#' class='center'><img src='image.jpg'></a>
<a href='#' class='deg0'><img src='image.jpg'></a>
<a href='#' class='deg45'><img src='image.jpg'></a>
<a href='#' class='deg135'><img src='image.jpg'></a>
<a href='#' class='deg180'><img src='image.jpg'></a>
<a href='#' class='deg225'><img src='image.jpg'></a>
<a href='#' class='deg315'><img src='image.jpg'></a>
</div>
Além disso, você pode simplificar ainda mais o HTML usando imagens de fundo para os links em vez de usar imgtags.
EDIT : exemplo com fallback para IE8 e mais antigo (testado no IE8 e IE7)