Positionieren Sie die Symbole im Kreis

Lesezeit: 15 Minuten

Wie kann ich mehrere positionieren <img> Elemente in einem Kreis um ein anderes und sind diese Elemente alle auch anklickbare Links? Ich möchte, dass es wie das Bild unten aussieht, aber ich habe keine Ahnung, wie ich diesen Effekt erzielen kann.

Erwünschtes Ergebnis

Ist das überhaupt möglich?

Positionieren Sie die Symbole im Kreis
Anna

Lösung 2020

Hier ist eine modernere Lösung, die ich heutzutage verwende.

Ich beginne damit, den HTML-Code ausgehend von einem Array von Bildern zu generieren. Ob der HTML-Code mit PHP, JS, einem HTML-Präprozessor oder was auch immer generiert wird, spielt keine Rolle, da die Grundidee dahinter dieselbe ist.

Hier ist der Pug-Code, der dies tun würde:

//- 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)

Das generierte HTML sieht wie folgt aus (und ja, Sie können das HTML auch manuell schreiben, aber es wird mühsam sein, nachträglich Änderungen vorzunehmen):

<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>

Im CSS legen wir beispielsweise eine Größe für die Bilder fest 8em. Die --m Elemente sind auf einem Kreis positioniert und es ist, wenn sie in der Mitte der Kanten eines Polygons liegen --m Kanten, die alle den Kreis berühren.

Wenn Sie sich das schwer vorstellen können, können Sie damit spielen interaktive Demo der den Inkreis und Umkreis für verschiedene Polygone konstruiert, deren Anzahl von Kanten Sie durch Ziehen des Schiebereglers auswählen.

Inkreis und Umkreis eines Sechsecks

Dies sagt uns, dass die Größe des Containers doppelt so groß sein muss wie der Radius des Kreises plus doppelt so groß wie die Hälfte der Bilder.

Wir kennen den Radius noch nicht, aber wir können ihn berechnen, wenn wir die Anzahl der Kanten kennen (und damit den Tangens des halben Basiswinkels, vorberechnet und als benutzerdefinierte Eigenschaft festgelegt --tan) und der Polygonkante. Wir möchten wahrscheinlich, dass die Polygonkante mindestens die Größe der Bilder hat, aber wie viel wir an den Seiten lassen, ist willkürlich. Nehmen wir an, wir haben auf jeder Seite die halbe Bildgröße, also ist die Polygonkante doppelt so groß wie die Bildgröße. Dies gibt uns das folgende 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% }

Sehen Sie sich die alte Lösung an, um zu erfahren, wie die Transformationskette funktioniert.

Auf diese Weise ordnet das Hinzufügen oder Entfernen eines Bildes aus dem Array von Bildern automatisch die neue Anzahl von Bildern auf einem Kreis an, sodass sie gleichmäßig verteilt sind, und passt auch die Größe des Containers an. Sie können dies in testen diese demo.


ALTE Lösung (aus historischen Gründen erhalten)

Ja, es ist sehr gut möglich und sehr einfach, nur CSS zu verwenden. Sie müssen nur die Winkel im Kopf haben, in denen Sie die Links zu den Bildern haben möchten (ich habe am Ende ein Stück Code hinzugefügt, nur um die Winkel anzuzeigen, wenn Sie mit der Maus über einen von ihnen fahren).

Sie brauchen zuerst einen Wrapper. Ich setze seinen Durchmesser auf sein 24em (width: 24em; height: 24em; tut das), können Sie es einstellen, was Sie wollen. Du gibst es position: relative;.

Dann positionieren Sie Ihre Links mit den Bildern in der Mitte dieses Wrappers, sowohl horizontal als auch vertikal. Das machst du durch Einstellung position: absolute; und dann top: 50%; left: 50%; und margin: -2em; (wo 2em ist die halbe Breite des Links mit dem Bild, das ich eingestellt habe 4em – Auch hier können Sie es beliebig ändern, aber vergessen Sie in diesem Fall nicht, den Rand zu ändern).

Sie entscheiden dann über die Winkel, in denen Sie Ihre Verknüpfungen mit den Bildern haben möchten, und fügen eine Klasse hinzu deg{desired_angle} (zum Beispiel deg0 oder deg45 oder Wasauchimmer). Dann wenden Sie für jede solche Klasse verkettete CSS-Transformationen wie folgt an:

.deg{desired_angle} {
   transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}

wo Sie ersetzen {desired_angle} mit 0, 45und so weiter…

Die erste Rotate-Transformation dreht das Objekt und seine Achsen, die Translate-Transformation verschiebt das Objekt entlang der gedrehten X-Achse und die zweite Rotate-Transformation bringt das Objekt wieder in Position.

Der Vorteil dieser Methode ist, dass sie flexibel ist. Sie können neue Bilder in verschiedenen Winkeln hinzufügen, ohne die aktuelle Struktur zu ändern.

CODE-AUSZUG

    .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>

Außerdem könnten Sie das HTML weiter vereinfachen, indem Sie Hintergrundbilder für die Links verwenden, anstatt zu verwenden img Stichworte.


BEARBEITEN: Beispiel mit Fallback für IE8 und älter (getestet in IE8 und IE7)

  • Schön, aber was werden die Leute sehen, wenn sie von Geräten/Browsern ohne CSS-Transformationsunterstützung zugreifen?

    – gkond

    10. Oktober 2012 um 14:56 Uhr

  • Die einzigen Desktop-Browser, die CSS-Transformationen nicht unterstützen, sind IE8 und älter. Für diese kann dies mithilfe von IE-Matrixfiltertransformationen emuliert werden. Was mobile Browser betrifft, so ist Opera Mini der einzige, der keine CSS-Transformationen unterstützt, und ich würde sowieso nichts verwenden, das auf einem kleinen Bildschirm so viel Platz verschwendet.

    – Anna

    10. Oktober 2012 um 15:21 Uhr

  • Als ich die Demo sah, scrollte ich nach unten, weil ich wusste, dass Sie es sein würden, der eine solche Frage beantwortet. Gut gemacht @Ana. Wo zum Teufel bloggst du?

    – Ahmad Alfi

    23. Oktober 2013 um 12:55 Uhr

  • @Ana das ist großartig, habe dein CSS verwendet, um ein generisches Beispiel für n Elemente zu erstellen, falls interessiert.jsfiddle.net/sajjansarkar/zgcgq8cg

    – Sajjan Sarkar

    2. Januar 2015 um 21:42 Uhr

  • @Ana sehr cool! Sie haben mich dazu inspiriert, eine dynamische Version zu erstellen – jsfiddle.net/skwidbreth/q59s90oy

    – skwidbreth

    10. Januar 2017 um 19:50 Uhr

Positionieren Sie die Symbole im Kreis
gkond

Hier ist die einfache Lösung ohne absolute Positionierung:

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

.container .row img {
  margin: 0 20px;
}
<div class="container">
  <div class="row">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
  </div>
  <div class="row">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
  </div>
  <div class="row">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
    <img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
  </div>
</div>

http://jsfiddle.net/mD6H6/

1645710133 132 Positionieren Sie die Symbole im Kreis
schwidbreth

Aufbauend auf der hervorragenden Antwort von @Ana habe ich diese dynamische Version erstellt, mit der Sie Elemente zum DOM hinzufügen und entfernen und den proportionalen Abstand zwischen den Elementen beibehalten können – sehen Sie sich meine Geige an: 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 = $("<li class="list-item">Things go here<button class="remove-item">Remove</button></li>");
  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%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<ul id="list"></ul>
<button id="add-item">Add item</button>

  • Hat super funktioniert und ich würde mehr upvoten, wenn ich könnte. Ein Problem, das ich hatte, war, dass, wenn ich 360 in etwas anderes änderte (ich wollte einen Halbkreis), die Dinge aus dem Gleichgewicht gerieten. Ich habe es auf die Deklaration des Drehwinkels zurückgeführt und in diese geändert var rotateAngle = zero_start + (offsetAngle * i || 0); Ich habe auch eine Variable für zero_start hinzugefügt, wenn Sie also bei Punkt 270 statt bei 0 oder ähnlichem beginnen möchten. jsfiddle.net/q59s90oy/13. Zuletzt habe ich das CSS für Listenelemente geändert, um negative Ränder zu verwenden. Aber im Ernst, danke, dass du die Arbeit geteilt hast, hat sehr geholfen.

    – Normaler Jo

    16. Oktober 2017 um 4:16 Uhr

  • Das ist krass, froh, dass Sie es nach Bedarf optimieren konnten. Schöne Abwechslung!

    – skwidbreth

    16. Oktober 2017 um 15:46 Uhr

  • Yo, das ist ein ziemlich epischer Spiraleffekt 😅 i.imgur.com/1VrubKC.png

    – Ethan

    4. Januar 2019 um 6:33 Uhr


  • @Ethan Ha ha ja! Ich liebe es, das zu tun! Ich dachte, es könnte ein cooles Kunstwerk machen.

    – skwidbreth

    4. Januar 2019 um 13:58 Uhr

  • Das ist großartig, aber wenn es eine 0 beginnt und 360 macht, bewegen sich die hinzugefügten Divs in der horizontalen Mitte links und rechts nach innen (drift nach innen). Das Zentrum der hinzugefügten oberen und unteren Divs wird am Listenkreis ausgerichtet.

    – jdog

    4. Oktober 2021 um 22:52 Uhr

Verwenden der von @Ana vorgeschlagenen Lösung:

transform: rotate(${angle}deg) translate(${radius}px) rotate(-${angle}deg)

Folgendes habe ich erstellt jsFiddle die Kreise dynamisch mit einfachem JavaScript platziert (jQuery-Version ebenfalls verfügbar).

Die Funktionsweise ist ziemlich einfach:

document.querySelectorAll( '.ciclegraph' ).forEach( ( ciclegraph )=>{
  let circles = ciclegraph.querySelectorAll( '.circle' )
  let angle = 360-90, dangle = 360 / circles.length
  for( let i = 0; i < circles.length; ++i ){
    let circle = circles[i]
    angle += dangle
    circle.style.transform = `rotate(${angle}deg) translate(${ciclegraph.clientWidth / 2}px) rotate(-${angle}deg)`
  }
})
.ciclegraph {
  position: relative;
  width: 500px;
  height: 500px;
  margin: calc(100px / 2 + 0px);
}

.ciclegraph:before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  border: 2px solid teal;
  width: calc( 100% - 2px * 2);
  height: calc( 100% - 2px * 2 );
  border-radius: 50%;
}

.ciclegraph .circle {
  position: absolute;
  top: 50%; left: 50%;
  width: 100px;
  height: 100px;
  margin: calc( -100px / 2 );
  background: teal;
  border-radius: 50%;
}
<div class="ciclegraph">
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
  <div class="circle"></div>
</div>

Hier ist eine Version, die ich in React aus den Beispielen hier erstellt habe.

CodeSandbox-Beispiel

import React, { useRef, useEffect } from "react";

import "./styles.css";

export default function App() {
  const graph = useRef(null);

  useEffect(() => {
    const ciclegraph = graph.current;
    const circleElements = ciclegraph.childNodes;

    let angle = 360 - 90;
    let dangle = 360 / circleElements.length;

    for (let i = 0; i < circleElements.length; i++) {
      let circle = circleElements[i];
      angle += dangle;
      circle.style.transform = `rotate(${angle}deg) translate(${ciclegraph.clientWidth /
        2}px) rotate(-${angle}deg)`;
    }
  }, []);

  return (
    <div className="App">
      <div className="ciclegraph" ref={graph}>
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
        <div className="circle" />
      </div>
    </div>
  );
}

  • Tolle Antwort und toller Code, das einzige Problem ist, dass Sie es in einer Antwort gepostet haben, die nichts mit React zu tun hat!

    – Manchester ohne Marke

    19. Juni 2020 um 8:52 Uhr

  • Ich weiß, eine Antwort, nach der niemand gefragt hat, aber hier ist sie trotzdem, hehe 🙂

    – br3ntor

    19. Juni 2020 um 20:31 Uhr

  • Ich bin hierher gekommen, um nach einer Lösung zu suchen, die ich in React verwenden könnte, also immer noch sehr nützlich

    – Abhishek Kasireddy

    17. Juli 2020 um 1:46 Uhr

Sie können dies sicherlich mit reinem CSS tun oder JavaScript verwenden. Mein Vorschlag:

  • Wenn Sie bereits wissen, dass sich die Anzahl der Bilder nie ändern wird, berechnen Sie einfach Ihre Stile und verwenden Sie einfaches CSS (Profis: bessere Leistung, sehr zuverlässig).

  • Wenn die Anzahl entweder dynamisch in Ihrer App oder nur in Zukunft variieren kann, entscheiden Sie sich für eine Js-Lösung (Profis: zukunftssicherer)

Ich hatte einen ähnlichen Job zu erledigen, also habe ich ein Skript erstellt und es als Open Source veröffentlicht hier auf Github für alle, die es brauchen könnten. Es akzeptiert nur einige Konfigurationswerte und gibt einfach den CSS-Code aus, den Sie benötigen.

Wenn Sie sich für die Js-Lösung entscheiden möchten, finden Sie hier einen einfachen Hinweis, der für Sie nützlich sein kann. Verwenden Sie dieses HTML als Ausgangspunkt #box der Behälter u .dot das Bild/Div in der Mitte, um das alle anderen Bilder herum sein sollen:

HTML starten:

    <div id="box">
      <div class="dot"></div>
      <img src="my-img.jpg">
      <!-- all the other images you need-->
    </div>

CSS starten:

     #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;
    }

Sie können eine Schnellfunktion nach folgendem Schema erstellen:

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

Sie können ein Live-Beispiel sehen Hier

  • Tolle Antwort und toller Code, das einzige Problem ist, dass Sie es in einer Antwort gepostet haben, die nichts mit React zu tun hat!

    – Manchester ohne Marke

    19. Juni 2020 um 8:52 Uhr

  • Ich weiß, eine Antwort, nach der niemand gefragt hat, aber hier ist sie trotzdem, hehe 🙂

    – br3ntor

    19. Juni 2020 um 20:31 Uhr

  • Ich bin hierher gekommen, um nach einer Lösung zu suchen, die ich in React verwenden könnte, also immer noch sehr nützlich

    – Abhishek Kasireddy

    17. Juli 2020 um 1:46 Uhr

Es gibt keine Möglichkeit, anklickbare Elemente mit CSS auf magische Weise in einem Kreis um ein anderes Element zu platzieren. Die Art und Weise, wie ich dies tun würde, ist die Verwendung eines Containers mit position:relative;. Und platzieren Sie dann alle Elemente mit position:absolute; und verwenden top und left um seinen Platz anzuvisieren.

Auch wenn Sie jquery nicht in Ihren Tags platziert haben, ist es vielleicht am besten, dafür jQuery / Javascript zu verwenden.

Der erste Schritt besteht darin, Ihr zentrales Bild perfekt in der Mitte des Containers zu platzieren position:relative;.

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

Danach können Sie die anderen Elemente um ihn herum platzieren, indem Sie ein verwenden offset() des centerImage abzüglich der offset() des Behälters. Geben Sie das genaue top und left des Bildes.

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

Was ich hier getan habe, ist das Platzieren der Elemente relativ zum centerImage. Hoffe das hilft.

843660cookie-checkPositionieren Sie die Symbole im Kreis

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy