2012-10-10 15 views
75

Wie kann ich mehrere Elemente in einem Kreis um einen anderen positionieren und diese Elemente alle auch anklickbare Links sein? Ich möchte, dass es wie das Bild unten aussieht, aber ich habe keine Ahnung, wie ich diesen Effekt erzielen kann.Position Symbole in Kreis

Desired Result

Ist das überhaupt möglich?

Antwort

148

Ja, es ist sehr viel möglich und sehr einfach mit nur CSS. Sie müssen nur die Winkel im Auge behalten, in denen Sie die Links zu den Bildern haben wollen (ich habe am Ende ein Stück Code hinzugefügt, nur um die Winkel zu zeigen, wenn Sie einen von ihnen schweben).

demo

Sie müssen zuerst einen Wrapper. Ich setze seinen Durchmesser auf 24em (width: 24em; height: 24em; tut das), Sie können es auf was auch immer Sie wollen einstellen. Sie geben es position: relative;.

Sie positionieren dann Ihre Links mit den Bildern in der Mitte des Wrappers, sowohl horizontal als auch vertikal. Sie tun dies, indem Sie position: absolute; und dann top: 50%; left: 50%; und margin: -2em; (wo 2em ist die halbe Breite der Verbindung mit dem Bild, das ich eingestellt habe, 4em - wieder, Sie können es zu was auch immer Sie wünschen, ändern, aber nicht vergessen die Marge in diesem Fall zu ändern).

Sie entscheiden dann über die Winkel, in denen Sie Ihre Links zu den Bildern haben möchten und fügen eine Klasse deg{desired_angle} hinzu (zum Beispiel deg0 oder deg45 oder was auch immer). Dann für jede solche Klasse, die Sie CSS-Transformationen verkettet gelten, wie folgt aus:

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

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

Die erste drehen Transformation dreht das Objekt und seine Achsen Die Translationstransformation übersetzt das Objekt entlang der gedrehten X-Achse und die zweite Rotationstransformation bringt das Objekt in die Position zurück - demo to illustrate how this works.

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.

HTML:

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

Relevante CSS:

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

Auch könnten Sie weiter die HTML vereinfachen, indem sie für die Links Hintergrundbilder verwenden anstelle von img Tags .


EDIT: example with fallback for IE8 and older (getestet in IE8 und IE7)

+1

Schön, aber was werden die Leute sehen, wenn sie von Geräten/Browsern ohne CSS Zugriff auf Support-Transformation? – gkond

+1

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. Wie für mobile Browser ist Opera Mini die einzige, die CSS-Transformationen nicht unterstützt, und ich würde wirklich nicht etwas verwenden, das ohnehin auf einem kleinen Bildschirm Platz verschwendet. – Ana

+0

Ich habe ein Beispiel mit Fallback für IE8 und älter hinzugefügt. – Ana

4

Es gibt keine Möglichkeit, anklickbare Elemente in einem Kreis um ein anderes Element mit CSS zu platzieren. Der Weg, wie ich dies tun würde, ist mit einem Container mit position:relative;. Platzieren Sie dann alle Elemente mit position:absolute; und verwenden Sie top und left als Ziel.

Obwohl Sie in Ihren Tags nicht platziert haben, könnte es am besten sein, hierfür jQuery/javascript zu verwenden.

Im ersten Schritt platzieren Sie Ihr Bild in der Mitte des Containers unter Verwendung von 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 offset() des CenterPressefotosErfolgsgeschichtenCan mit minus der offset() des Behälters. Ihnen die genaue top und left des Bildes geben.

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 wird Platzierung der Elemente relativ zum CenterPressefotosErfolgsgeschichtenCan. Hoffe das hilft. Hier

14

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/

0

Man könnte es wie folgt tun: fiddle

Sie nicht die Positionierung dagegen, es ist ein schnelles Beispiel

2

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

  • Wenn Sie bereits wissen, dass die Anzahl Bilder nie nur Ihre Stile berechnen ändern und gehen mit einfachen CSS (Profis: bessere Leistungen, sehr zuverlässig)

  • Wenn die Zahl entweder variieren (: mehr zukunftssichere Profis)

hatte ich eine ähnliche Arbeit zu tun, so habe ich ein Skript und Open Source es here on Github für dynamisch in Ihrer App oder einfach nur in der Zukunft geht mit einer Js Lösung kann variieren jeder, der es brauchen könnte. Es akzeptiert nur einige Konfigurationswerte und gibt einfach den benötigten CSS-Code aus.

Wenn Sie für die Js-Lösung gehen möchten, ist hier ein einfacher Zeiger, der für Sie nützlich sein kann.Mit diesen HTML als Punkt Start #box der Behälter und .dot das Bild/div in der Mitte zu sein Sie alle Ihre anderen Bilder um möchten:

Start html:

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

Start Css:

#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 schnelle Funktion entlang dieser Linien 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 ein anschauliches Beispiel here

4

Gebäude off @ Anas ausgezeichnete Antwort sehen können, habe ich diese dynamische Version, die Sie aus dem DOM hinzufügen und entfernen Elemente erlaubt und verhältnismäßig Abstand zwischen den Elementen halten - überprüfen meine Geige aus: https://jsfiddle.net/skwidbreth/q59s90oy/

html

<!DOCTYPE html> 
<html> 
<head> 
    <link rel="stylesheet" href="style.css" /> 
</head> 
<body> 
    <ul id="list"></ul> 
    <button id="add-item">Add item</button> 
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> 
    <script src="main.js"></script> 
</body> 
</html> 

style.css

#list{ 
    background-color: blue; 
    height: 30vw; 
    width: 30vw; 
    border-radius: 50%; 
    position: relative; 
} 

.list-item{ 
    list-style: none; 
    background-color: red; 
    height: 5vw; 
    width: 5vw; 
    position: absolute; 
    top: 50%; 
    left: 50%; 
} 

main.js

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, -15vw) 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); 
}); 
+1

Arbeitete großartig, und Ich würde mehr aufbieten, wenn ich könnte. Ein Problem, das ich hatte, war, dass, wenn ich 360 zu etwas anderem änderte (ich wollte einen Halbkreis), die Dinge aus dem Ruder liefen. Ich habe es auf die Deklaration des Rotationswinkels zurückverfolgt und zu diesem 'var rotateAngle = zero_start + (offsetAngle * i || 0) geändert;' Ich habe auch eine Variable für zero_start hinzugefügt. Wenn Sie also an Punkt 270 anstatt an 0 beginnen möchten, oder etwas ähnliches. https://jsfiddle.net/q59s90oy/13/. Zuletzt änderte ich die CSS für Listenelemente, um negative Ränder zu verwenden. ** Aber im Ernst, vielen Dank für das Teilen der Arbeit, hat mir sehr geholfen. ** –

+0

Das ist gut, froh, dass Sie es nach Bedarf optimieren konnten. Schöne Abwechslung! – skwidbreth