2012-10-10 19 views
75

¿Cómo puedo colocar varios elementos <img> en un círculo alrededor de otro y hacer que todos esos elementos sean enlaces clicables? Quiero que se vea como en la imagen siguiente, pero no tengo idea de cómo lograr ese efecto.Posiciona los iconos en el círculo

Desired Result

Es esto posible?

Respuesta

148

Sí, es muy posible y muy simple usar solo CSS. Solo debe tener en cuenta los ángulos en los que desea los enlaces con las imágenes (he agregado un fragmento de código al final solo para mostrar los ángulos cada vez que sobrevuela uno de ellos).

demo

primero tiene una envoltura. Establecí su diámetro para que sea 24em (width: 24em; height: 24em; hace eso), puede configurarlo para lo que desee. Usted le da position: relative;.

A continuación, ubique los enlaces con las imágenes en el centro de esa envoltura, tanto horizontal como verticalmente. Para ello, configure position: absolute; y luego top: 50%; left: 50%; y margin: -2em; (donde 2em es la mitad del ancho del enlace con la imagen, que configuré como 4em - nuevamente, puede cambiarlo a lo que desee, pero no lo olvide para cambiar el margen en ese caso).

A continuación, decide los ángulos en los que desea tener sus enlaces con las imágenes y agrega una clase deg{desired_angle} (por ejemplo, deg0 o deg45 o lo que sea). Luego, para cada clase de tales solicite beneficios encadenado transformaciones CSS, así:

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

donde se reemplaza con {desired_angle}0, 45, y así sucesivamente ...

La primera rotación gira a transformar el objeto y sus ejes , la transformación de traducción traduce el objeto a lo largo del eje X girado y la segunda transformación de rotación devuelve el objeto a su posición - demo to illustrate how this works.

La ventaja de este método es que es flexible. Puede agregar nuevas imágenes en diferentes ángulos sin alterar la estructura actual.

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

Además, se podría simplificar aún más el HTML utilizando imágenes de fondo para los enlaces en lugar de utilizar img etiquetas .


EDITAR: example with fallback for IE8 and older (probado en IE8 e IE7)

+1

Niza, pero lo que la gente ve cuando se accede desde dispositivos/navegadores sin CSS Transformar apoyo? – gkond

+1

Los únicos navegadores de escritorio que no son compatibles con las transformaciones CSS son IE8 y anteriores. Para aquellos, esto puede ser emulado usando transformaciones de filtro de matriz IE. En cuanto a los navegadores móviles, Opera Mini es el único que no admite las transformaciones CSS y, de todos modos, no usaría algo que desperdicie tanto espacio en una pantalla pequeña. – Ana

+0

He agregado un ejemplo con respaldo para IE8 y versiones anteriores. – Ana

4

No hay forma de ubicar mágicamente los elementos clicables en un círculo alrededor de otro elemento con CSS. La forma en que lo haría es mediante el uso de un contenedor con position:relative;. Y luego coloque todos los elementos con position:absolute; y usando top y left para apuntar a su ubicación.

Aunque no haya colocado en sus etiquetas, podría ser mejor usar jQuery/javascript para esto.

El primer paso es colocar su imagen central perfectamente en el centro del contenedor usando position:relative;.

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

Después de que se puede colocar los otros elementos a su alrededor utilizando una offset() del centerImage menos el offset() del contenedor. Te da la exacta top y left de la imagen.

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

Lo que he hecho aquí es colocar los elementos relativos a la centerImage. Espero que esto ayude.

14

Aquí es la solución fácil y sin posicionamiento absoluto:

.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

que podría hacerlo de esta manera: fiddle

No importa el posicionamiento, es un ejemplo rápido

2

Usted puede hacer ciertamente con css puro o el uso de JavaScript. Mi sugerencia:

  • Si ya sabe que el número de imágenes nunca va a cambiar simplemente el cálculo de sus estilos e ir con sencillo css (pros: un mejor rendimiento, muy fiable)

  • Si el número puede variar ya sea dinámicamente en su aplicación o simplemente puede variar en el futuro ir con una solución de Js (pros: más a prueba de futuro)

tenía un trabajo similar a hacer, así que creó un guión y de código abierto que here on Github de cualquiera que pueda necesitarlo Simplemente acepta algunos valores de configuración y simplemente genera el código CSS que necesita.

Si quieres ir a la solución Js, aquí tienes un puntero simple que puede ser útil para ti.html

de inicio:: El uso de este html como punto de partida siendo #box el recipiente y .dot la imagen/div en el medio donde todas sus otras imágenes alrededor

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

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

Puede crear una función rápida en estas líneas:

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

Se puede ver un ejemplo vivo here

4

Construido a partir @ excelente respuesta de Ana, he creado esta versión dinámica que le permite añadir y eliminar elementos del DOM y mantener el espaciado proporcional entre los elementos - pagar el violín: 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

funcionaba muy bien, y Apostaría más si pudiera. Un problema que tuve fue que si cambiaba 360 a cualquier otra cosa (quería un semicírculo), las cosas se iban de mal en peor. Lo remonté a la declaración de ángulo de rotación y lo cambié a este 'var rotateAngle = zero_start + (offsetAngle * i || 0);' También agregué una variable para zero_start así que si quieres comenzar en el punto 270 en lugar de 0, o algo similar. https://jsfiddle.net/q59s90oy/13/. Por último, cambié el CSS para los elementos de la lista para usar márgenes negativos. ** En serio, gracias por compartir el trabajo, ayudó mucho. ** –

+0

Eso es genial, me alegro de que hayas podido modificarlo según sea necesario. Buena variación! – skwidbreth

Cuestiones relacionadas