Solution 2020
Voici une solution plus moderne que j'utilise ces jours-ci.
Je commence par générer le HTML à partir d'un tableau d'images. Que le HTML soit généré en utilisant PHP, JS, un préprocesseur HTML, peu importe ... cela importe moins car l'idée de base derrière est la même.
Voici le code Pug qui ferait ceci:
//- 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)
Le HTML généré se présente comme suit (et oui, vous pouvez également écrire le HTML manuellement, mais il sera difficile d'apporter des modifications par la suite):
<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>
Dans le CSS, nous décidons d'une taille pour les images, disons 8em. Les --méléments sont positionnés sur un cercle et c'est s'ils sont au milieu des arêtes d'un polygone d' --marêtes, qui sont toutes tangentes au cercle.
Si vous avez du mal à imaginer cela, vous pouvez jouer avec cette démo interactive qui construit le cercle intérieur et le cercle circulaire pour divers polygones dont vous choisissez le nombre d'arêtes en faisant glisser le curseur.

Cela nous indique que la taille du conteneur doit être deux fois le rayon du cercle plus deux fois la moitié de la taille des images.
Nous ne connaissons pas encore le rayon, mais nous pouvons le calculer si nous connaissons le nombre d'arêtes (et donc la tangente de la moitié de l'angle de base, précalculée et définie comme propriété personnalisée --tan) et l'arête du polygone. Nous voulons probablement que le bord du polygone ait au moins la taille des images, mais combien nous laissons sur les côtés est arbitraire. Disons que nous avons la moitié de la taille de l'image de chaque côté, donc le bord du polygone est deux fois la taille de l'image. Cela nous donne le CSS suivant:
.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% }
Voir l'ancienne solution pour une explication du fonctionnement de la chaîne de transformation.
De cette façon, l'ajout ou la suppression d'une image du tableau d'images organise automatiquement le nouveau nombre d'images sur un cercle de manière à ce qu'elles soient également espacées et ajuste également la taille du conteneur. Vous pouvez tester cela dans cette démo .
ANCIENNE solution (préservée pour des raisons historiques)
Oui, c'est très possible et très simple en utilisant uniquement CSS. Vous devez juste avoir clairement à l'esprit les angles sous lesquels vous voulez les liens avec les images (j'ai ajouté un morceau de code à la fin juste pour montrer les angles chaque fois que vous survolez l'un d'eux).
Vous avez d'abord besoin d'un emballage. J'ai défini son diamètre pour être 24em( width: 24em; height: 24em;fait cela), vous pouvez le régler sur ce que vous voulez. Vous le donnez position: relative;.
Vous positionnez ensuite vos liens avec les images au centre de ce wrapper, à la fois horizontalement et verticalement. Vous faites cela en définissant position: absolute;et puis top: 50%; left: 50%;et margin: -2em;(où 2emest la moitié de la largeur du lien avec l'image, ce que j'ai défini pour être 4em- encore une fois, vous pouvez le changer comme vous le souhaitez, mais n'oubliez pas de changer la marge dans ce cas).
Vous décidez ensuite des angles sous lesquels vous souhaitez avoir vos liens avec les images et vous ajoutez une classe deg{desired_angle}(par exemple deg0ou deg45ou autre). Ensuite, pour chacune de ces classes, vous appliquez des transformations CSS chaînées, comme ceci:
.deg{desired_angle} {
transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}
où vous remplacez {desired_angle}avec 0, 45et ainsi de suite ...
La première transformation de rotation fait pivoter l'objet et ses axes, la transformation de translation traduit l'objet le long de l'axe X pivoté et la seconde transformation de rotation ramène l'objet en position.
L'avantage de cette méthode est qu'elle est flexible. Vous pouvez ajouter de nouvelles images sous différents angles sans modifier la structure actuelle.
EXTRAIT DE CODE
.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>
En outre, vous pouvez simplifier davantage le HTML en utilisant des images d'arrière-plan pour les liens au lieu d'utiliser des imgbalises.
EDIT : exemple avec fallback pour IE8 et plus ancien (testé dans IE8 et IE7)