Solución 2020
Aquí hay una solución más moderna que uso en estos días.
Empiezo generando el HTML a partir de una serie de imágenes. Si el HTML se genera usando PHP, JS, algún preprocesador de HTML, lo que sea ... esto importa menos ya que la idea básica detrás es la misma.
Aquí está el código de Pug que haría esto:
//- 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)
El HTML generado se ve de la siguiente manera (y sí, también puede escribir el HTML manualmente, pero será complicado hacer cambios después):
<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>
En el CSS, decidimos el tamaño de las imágenes, digamos 8em
. Los --m
elementos se colocan en un círculo y es si están en el medio de los bordes de un polígono de --m
bordes, todos los cuales son tangentes al círculo.
Si tiene dificultades para imaginarse eso, puede jugar con esta demostración interactiva que construye el círculo y el círculo para varios polígonos cuyo número de bordes elige arrastrando el control deslizante.
Esto nos dice que el tamaño del contenedor debe ser el doble del radio del círculo más el doble de la mitad del tamaño de las imágenes.
Aún no conocemos el radio, pero podemos calcularlo si conocemos el número de aristas (y por lo tanto la tangente de la mitad del ángulo base, calculado previamente y establecido como una propiedad personalizada --tan
) y la arista del polígono. Probablemente queramos que el borde del polígono tenga al menos el tamaño de las imágenes, pero la cantidad que dejamos en los lados es arbitraria. Digamos que tenemos la mitad del tamaño de la imagen en cada lado, por lo que el borde del polígono es el doble del tamaño de la imagen. Esto nos da el siguiente 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% }
Consulte la solución anterior para obtener una explicación de cómo funciona la cadena de transformación.
De esta manera, agregar o eliminar una imagen de la matriz de imágenes organiza automáticamente la nueva cantidad de imágenes en un círculo de manera que estén igualmente espaciadas y también ajusta el tamaño del contenedor. Puede probar esto en esta demostración .
Solución ANTIGUA (conservada por razones históricas)
Sí, es muy posible y muy simple usando solo CSS. Solo necesita tener claro 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 pasa el mouse por uno de ellos).
Primero necesitas una envoltura. Configuré su diámetro para que sea 24em
( width: 24em; height: 24em;
hace eso), puede configurarlo como desee. Tu lo das position: relative;
.
Luego coloque sus enlaces con las imágenes en el centro de ese envoltorio, tanto horizontal como verticalmente. Puede hacerlo configurando position: absolute;
y luego top: 50%; left: 50%;
y margin: -2em;
(donde 2em
está la mitad del ancho del enlace con la imagen, que he configurado para ser 4em
) nuevamente, puede cambiarlo a lo que desee, pero no olvide cambiar el margen en Ese caso).
A continuación, decide sobre los ángulos en los que desea tener sus enlaces con las imágenes y se agrega una clase deg{desired_angle}
(por ejemplo, deg0
o deg45
, o lo que sea). Luego, para cada clase de este tipo, aplica transformaciones CSS encadenadas, como esta:
.deg{desired_angle} {
transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}
donde se reemplaza {desired_angle}
con 0
, 45
y así sucesivamente ...
La primera transformación de rotación gira el objeto y sus ejes, la transformación de traslación traslada el objeto a lo largo del eje X girado y la segunda transformación de rotación devuelve el objeto a su posición.
La ventaja de este método es que es flexible. Puede agregar nuevas imágenes en diferentes ángulos sin alterar la estructura actual.
FRAGMENTO DE CÓDIGO
.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>
Además, podría simplificar aún más el HTML utilizando imágenes de fondo para los enlaces en lugar de utilizar img
etiquetas.
EDITAR : ejemplo con respaldo para IE8 y versiones anteriores (probado en IE8 e IE7)
Aquí está la solución fácil sin posicionamiento absoluto:
http://jsfiddle.net/mD6H6/
fuente
Partiendo de la excelente respuesta de @ Ana, creé esta versión dinámica que le permite agregar y eliminar elementos del DOM y mantener un espacio proporcionado entre los elementos; consulte mi violín: https://jsfiddle.net/skwidbreth/q59s90oy/
fuente
var rotateAngle = zero_start + (offsetAngle * i || 0);
. También agregué una variable para zero_start, por lo que si desea comenzar en el punto 270 en lugar de 0, o algo similar. jsfiddle.net/q59s90oy/13 . Por último, cambié el CSS para que los elementos de la lista usen márgenes negativos. En serio, gracias por compartir el trabajo, ayudó mucho.No hay forma de colocar mágicamente elementos en los que se puede hacer clic en un círculo alrededor de otro elemento con CSS. La forma en que haría esto es usando un contenedor con
position:relative;
. Y luego coloque todos los elementos conposition:absolute;
y usandotop
yleft
para apuntar a su lugar.Aunque no hayas colocado jquery en sus etiquetas, puede ser mejor usar jQuery / javascript para esto.
El primer paso es colocar su imagen central perfectamente en el centro del contenedor usando
position:relative;
.Después de eso, puede colocar los otros elementos a su alrededor usando un
offset()
de centerImage menos eloffset()
del contenedor. Dándote lo exactotop
yleft
de la imagen.Lo que he hecho aquí es colocar los elementos en relación con centerImage. Espero que esto ayude.
fuente
Ciertamente puede hacerlo con CSS puro o usar JavaScript. Mi sugerencia:
Si ya sabe que el número de imágenes nunca cambiará, simplemente calcule sus estilos y vaya con CSS simple (ventajas: mejores rendimientos, muy confiable)
Si el número puede variar dinámicamente en su aplicación o simplemente puede variar en el futuro, elija una solución Js (ventajas: más preparada para el futuro)
Tenía un trabajo similar que hacer, así que creé un script y lo abrí aquí en Github para cualquiera que pudiera necesitarlo. Simplemente acepta algunos valores de configuración y simplemente genera el código CSS que necesita.
Si desea optar por la solución Js, aquí hay un puntero simple que puede serle útil. Usando este html como punto de partida, siendo
#box
el contenedor y.dot
la imagen / div en el medio, desea todas sus otras imágenes:Inicio de html:
Iniciando CSS:
Puede crear una función rápida a lo largo de estas líneas:
Puedes ver un ejemplo en vivo aquí.
fuente
Usando la solución propuesta por @Ana:
Creé el siguiente jsFiddle que coloca círculos dinámicamente usando JavaScript simple (la versión jQuery también está disponible).
La forma en que funciona es bastante simple:
fuente
Aquí hay una versión que hice en React a partir de los ejemplos aquí.
Ejemplo de CodeSandbox
fuente
Podrías hacerlo así: violín
No importa el posicionamiento, es un ejemplo rápido
fuente