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)