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é à l'aide de PHP, de JS, d'un préprocesseur HTML, etc... cela a moins d'importance car l'idée de base est la même.
Voici le code de Pug qui ferait cela :
//- 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é ressemble à ce qui suit (et oui, vous pouvez aussi écrire le HTML manuellement, mais il sera difficile de le modifier 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, par exemple 8em
. Le site --m
sont positionnés sur un cercle et c'est s'ils se trouvent au milieu des bords d'un polygone de --m
des bords, qui sont tous tangents au cercle.
Si vous avez du mal à l'imaginer, vous pouvez jouer avec ceci Démonstration interactive qui construit l'arc de cercle et le cercle circonscrit 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 égale à 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 une propriété personnalisée). --tan
) et le bord du polygone. Nous voulons probablement que le bord du polygone ait au moins la taille des images, mais la quantité que 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 fait 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.
Ainsi, l'ajout ou la suppression d'une image dans le tableau d'images permet de disposer automatiquement le nouveau nombre d'images sur un cercle de manière à ce qu'elles soient espacées de manière égale et d'ajuster également la taille du conteneur. Vous pouvez tester ceci dans cette démo .
Ancienne solution (préservée pour des raisons historiques)
Oui, c'est tout à fait possible et très simple en utilisant simplement CSS. Il suffit d'avoir clairement en tête les angles auxquels vous voulez que les liens avec les images (j'ai ajouté un bout de code à la fin juste pour montrer les angles lorsque vous survolez l'un d'eux).
Vous avez d'abord besoin d'une enveloppe. J'ai fixé son diamètre à 24em
( width: 24em; height: 24em;
fait cela), vous pouvez le définir comme vous le souhaitez. Vous lui donnez position: relative;
.
Vous positionnez ensuite vos liens avec les images au centre de ce wrapper, à la fois horizontalement et verticalement. Pour ce faire, vous devez définir position: absolute;
et ensuite top: 50%; left: 50%;
y margin: -2em;
(où 2em
correspond à la moitié de la largeur du lien avec l'image, que j'ai définie comme suit 4em
- Encore une fois, vous pouvez le modifier comme vous le souhaitez, mais n'oubliez pas de modifier la marge dans ce cas).
Vous décidez ensuite des angles auxquels vous voulez avoir vos liens avec les images et vous ajoutez une classe deg{desired_angle}
(par exemple deg0
ou deg45
ou autre). Ensuite, pour chacune de ces classes, vous appliquez des transformations CSS en chaîne, comme ceci :
.deg{desired_angle} {
transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}
où vous remplacez {desired_angle}
con 0
, 45
et ainsi de suite...
La première transformation de rotation fait pivoter l'objet et ses axes, la transformation de translation déplace l'objet le long de l'axe X pivoté et la deuxième 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 à des angles différents sans modifier la structure actuelle.
CODE SNIPPET
.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>
De plus, vous pourriez simplifier davantage le HTML en utilisant des images d'arrière-plan pour les liens au lieu d'utiliser la fonction img
tags.
EDITAR : exemple avec repli pour IE8 et plus anciens (testé dans IE8 et IE7)