Positionner les icons dans le cercle

Comment puis-je positionner plusieurs éléments dans un cercle autour d’un autre et que ces éléments soient tous des liens cliquables? Je veux que cela ressemble à l’image ci-dessous, mais je ne sais pas comment atteindre cet effet.

Résultat désiré

Est-ce seulement possible?

Oui, c’est très possible et très simple en utilisant simplement CSS. Il vous suffit de garder à l’esprit les angles sous lesquels vous voulez les liens avec les images (j’ai ajouté un morceau de code à la fin pour montrer les angles à chaque fois que vous en survolez un).

démo

Vous devez d’abord un wrapper. J’ai fixé son diamètre à 24em ( width: 24em; height: 24em; ça fait), vous pouvez le régler comme bon vous semble. Vous lui donnez une position: relative; .

Vous positionnez ensuite vos liens avec les images au centre de cette enveloppe, à la fois horizontalement et verticalement. Vous faites cela en définissant la position: absolute; et puis en top: 50%; left: 50%; top: 50%; left: 50%; et margin: -2em; (où 2em correspond à la moitié de la largeur du lien avec l’image, que j’ai définie comme étant 4em – encore une fois, vous pouvez le changer comme vous le souhaitez, mais n’oubliez pas de modifier la marge dans ce cas).

Vous décidez ensuite des angles auxquels 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} par 0 , 45 , etc.

La première transformation de rotation fait pivoter l’object et ses axes, la transformation de translation traduit l’object le long de l’axe X pivoté et la deuxième transformation de rotation ramène l’object en position – démonstration illustrant son fonctionnement .

L’avantage de cette méthode est qu’elle est flexible. Vous pouvez append de nouvelles images sous différents angles sans modifier la structure actuelle.

HTML :

 

CSS pertinent:

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

En outre, vous pouvez simplifier davantage le code HTML en utilisant des images d’arrière-plan pour les liens au lieu d’utiliser des balises img .


EDIT : exemple avec repli pour IE8 et plus ancien (testé dans IE8 et IE7)

Voici la solution simple sans positionnement absolu:

 .container .row { margin: 20px; text-align: center; } .container .row img { margin: 0 20px; } 
 

À partir de l’excellente réponse de @ Ana, j’ai créé cette version dynamic qui vous permet d’append et de supprimer des éléments du DOM et de conserver un espace proportionné entre les éléments – consultez mon violon: https://jsfiddle.net/skwidbreth/q59s90oy/

 var list = $("#list"); var updateLayout = function(listItems) { for (var i = 0; i < listItems.length; i++) { var offsetAngle = 360 / listItems.length; var rotateAngle = offsetAngle * i; $(listItems[i]).css("transform", "rotate(" + rotateAngle + "deg) translate(0, -200px) rotate(-" + rotateAngle + "deg)") }; }; $(document).on("click", "#add-item", function() { var listItem = $("
  • Things go here"); list.append(listItem); var listItems = $(".list-item"); updateLayout(listItems); }); $(document).on("click", ".remove-item", function() { $(this).parent().remove(); var listItems = $(".list-item"); updateLayout(listItems); });
  •  #list { background-color: blue; height: 400px; width: 400px; border-radius: 50%; position: relative; } .list-item { list-style: none; background-color: red; height: 50px; width: 50px; position: absolute; top: 50%; left: 50%; } 
      

      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 le ferais est en utilisant un conteneur avec la position:relative; . Et puis placez tous les éléments avec la position:absolute; et en utilisant le top et la left pour cibler sa place.

      Même si vous n’avez pas placé jquery dans vos balises, il est préférable d’utiliser jQuery / javascript pour cela.

      La première étape consiste à placer votre image centrale parfaitement au centre du conteneur en utilisant la position:relative; .

       #centerImage { position:absolute; top:50%; left:50%; width:200px; height:200px; margin: -100px 0 0 -100px; } 

      Après cela, vous pouvez placer les autres éléments autour de lui en utilisant un offset() de centerImage moins le offset() du conteneur. Vous donnant le top et le left exact de l’image.

       var left = $('#centerImage').offset().left - $('#centerImage').parent().offset().left; var top = $('#centerImage').offset().top - $('#centerImage').parent().offset().top; $('#surroundingElement1').css({ 'left': left - 50, 'top': top - 50 }); $('#surroundingElement2').css({ 'left': left - 50, 'top': top }); $('#surroundingElement3').css({ 'left': left - 50, 'top': top + 50 }); 

      Ce que j’ai fait ici est de placer les éléments par rapport à centerImage. J’espère que cela t’aides.

      Vous pouvez certainement le faire avec un 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 du CSS simple (avantages: meilleures performances, très fiable)

      • Si le nombre peut varier dynamicment dans votre application ou simplement varier dans le futur, optez pour une solution Js (avantages: plus à l’épreuve du futur)

      J’avais un travail similaire à faire, alors j’ai créé un script et je l’ai ouvert ici sur Github pour quiconque en aurait besoin. Il accepte simplement certaines valeurs de configuration et affiche simplement le code CSS dont vous avez besoin.

      Si vous voulez opter pour la solution Js, voici un simple pointeur qui peut vous être utile. Utiliser ce HTML comme sharepoint départ étant #box le conteneur et .dot l’image / div au milieu vous voulez toutes vos autres images autour:

      Html de départ:

       

      Css de départ:

        #box{ width: 400px; height: 400px; position: relative; border-radius: 100%; border: 1px solid teal; } .dot{ position: absolute; border-radius: 100%; width: 40px; height: 40px; left: 50%; top: 50%; margin-left: -20px; margin-top: -20px; background: rebeccapurple; } img{ width: 40px; height: 40px; position: absolute; } 

      Vous pouvez créer une fonction rapide en suivant ces lignes:

       var circle = document.getElementById('box'), imgs = document.getElementsByTagName('img'), total = imgs.length, coords = {}, diam, radius1, radius2, imgW; // get circle diameter // getBoundingClientRect outputs the actual px AFTER transform // using getComputedStyle does the job as we want diam = parseInt( window.getComputedStyle(circle).getPropertyValue('width') ), radius = diam/2, imgW = imgs[0].getBoundingClientRect().width, // get the dimensions of the inner circle we want the images to align to radius2 = radius - imgW var i, alpha = Math.PI / 2, len = imgs.length, corner = 2 * Math.PI / total; // loop over the images and assign the correct css props for ( i = 0 ; i < total; i++ ){ imgs[i].style.left = parseInt( ( radius - imgW / 2 ) + ( radius2 * Math.cos( alpha ) ) ) + 'px' imgs[i].style.top = parseInt( ( radius - imgW / 2 ) - ( radius2 * Math.sin( alpha ) ) ) + 'px' alpha = alpha - corner; } 

      Vous pouvez voir un exemple en direct ici

      Vous pourriez le faire comme ça: violon

      Ne faites pas attention au positionnement, c’est un exemple rapide