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' --m
arê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ù 2em
est 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 deg0
ou deg45
ou 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
, 45
et 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 img
balises.
EDIT : exemple avec fallback pour IE8 et plus ancien (testé dans IE8 et IE7)
Voici la solution simple sans positionnement absolu:
http://jsfiddle.net/mD6H6/
la source
En m'appuyant sur l'excellente réponse de @ Ana, j'ai créé cette version dynamique qui vous permet d'ajouter et de supprimer des éléments du DOM et de maintenir un espacement proportionné entre les éléments - consultez mon violon: https://jsfiddle.net/skwidbreth/q59s90oy/
la source
var rotateAngle = zero_start + (offsetAngle * i || 0);
je l'ai changé pour cela, j'ai également ajouté une variable pour zero_start, donc si vous voulez commencer au point 270 plutôt qu'à 0, ou quelque chose de similaire. jsfiddle.net/q59s90oy/13 . Enfin, j'ai changé le css pour les éléments de liste pour utiliser des marges négatives. Sérieusement, merci de partager le travail, cela m'a beaucoup aidé.Il n'y a aucun moyen de placer par magie des éléments cliquables dans un cercle autour d'un autre élément avec CSS. La façon dont je ferais cela est d'utiliser un conteneur avec
position:relative;
. Et puis placez tous les éléments avecposition:absolute;
et en utilisanttop
etleft
pour cibler sa place.Même si vous n'avez pas placé jquery dans vos balises, il peut être préférable d'utiliser jQuery / javascript pour cela.
La première étape consiste à placer parfaitement votre image centrale au centre du conteneur en utilisant
position:relative;
.Après cela, vous pouvez placer les autres éléments autour de lui en utilisant un
offset()
de centerImage moins leoffset()
du conteneur. Vous donnant l'exacttop
etleft
de l'image.Ce que j'ai fait ici, c'est de placer les éléments par rapport à centerImage. J'espère que cela t'aides.
la source
Vous pouvez certainement le faire avec du CSS pur ou utiliser JavaScript. Ma suggestion:
Si vous savez déjà que le nombre d'images ne changera jamais, calculez simplement vos styles et optez pour le CSS (pour: meilleures performances, très fiable)
Si le nombre peut varier de manière dynamique dans votre application ou peut simplement varier à l'avenir, optez pour une solution Js (avantages: plus à l'épreuve du temps)
J'avais un travail similaire à faire, alors j'ai créé un script et l'ai open source ici sur Github pour tous ceux qui pourraient en avoir besoin. Il accepte simplement certaines valeurs de configuration et génère simplement le code CSS dont vous avez besoin.
Si vous souhaitez opter pour la solution Js, voici un simple pointeur qui peut vous être utile. En utilisant ce html comme point de départ étant
#box
le conteneur et.dot
l'image / div au milieu, vous voulez toutes vos autres images autour:Démarrage html:
Démarrage de Css:
Vous pouvez créer une fonction rapide en suivant ces lignes:
Vous pouvez voir un exemple en direct ici
la source
En utilisant la solution proposée par @Ana:
J'ai créé le jsFiddle suivant qui place les cercles de manière dynamique à l'aide de JavaScript brut (version jQuery également disponible).
La façon dont cela fonctionne est assez simple:
la source
Voici une version que j'ai créée dans React à partir des exemples ici.
Exemple de CodeSandbox
la source
Vous pouvez le faire comme ceci: violon
Ne vous inquiétez pas du positionnement, c'est un exemple rapide
la source