soy Kseso y esto EsCSS

Distribución uniforme de elementos alrededor de un círculo: mejor con transform que top/left

Para la distribución uniforme de elementos alrededor de un círculo mejor usar transformaciones Css que top/left. Demos.

Distribución uniforme de elementos alrededor de un círculo: mejor con transform que top/left

·Por Kseso ✎ 2

Distribución uniforme de elementos alrededor de un círculo: mejor con transform¿Cómo colocar varios elementos alrededor de otro distribuidos equitativamente y que conformen un círculo?

La primera respuesta o intención suele ser utilizar alguna de las propiedades de colocación 'top / right / bottom / left' junto al posicionamiento absoluto referente al elemento central.

Pero nada más comenzar se ven las dificultades de la vía elegida. Pues hay que acertar, no con un punto de ubicación, sino donde coinciden dos para cada elemento: el radio respecto al elemento central y el arco y su cuerda entre cada pareja de ellos.

Pero hay una forma mucho más sencilla y simple de lograrlo con puro Css. Sólo se necesita tener en cuenta el ángulo que han de formar.

¿Lo vemos con código?

Marcado html

Tengamos una serie de elementos contenidos en un div cualquiera. El primero (con clase 'center') es el que se colocará en el centro del círculo formado por los restantes:

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

Observa que los demás elementos tienen declarada una clase del tipo 'degNº' sólo a efectos didácticos y para una mejor comprensión. Se podría prescindir de las clases y utilizar selectores del tipo 'nth-child(nº)'.

El Css más relevante

Vamos con el inicial y preparatorio del terreno:

.circle-container { position: relative; width: 24em; height: 24em; padding: 2.8em; /*2.8em = 2em*1.4 (2em = mitad anchura del link con img, 1.4 = raíz cuadrada(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%; }

Lo primero es definir el diámetro del círculo: 24em en el ejemplo. Viene dado por la anchura y altura del contenedor ('.circle-container'). Y posicionarlo como 'relative' para que sea referente de sus hijos.

A continuación colocamos todos los enlaces con sus imágenes centrados en su caja padre, tanto en la horizontal como la vertical. Habiendo definido el mismo tamaño para todas ellas.

El padding del contenedor principal es para que las imágenes queden contenidas dentro de él en su totalidad. Recuerda que el modelo de caja en el ejemplo es el tradicional. Su valor es función del tamaño de las imágenes (= link que las contiene).

El Css del desplazamiento

Lo siguiente a decidir es el ángulo en el que queremos colocar cada uno de los enlaces (con su imagen dentro) y declararle su clase correspondiente del tipo class='degNº', donde Nº se sustituye por el valor del ángulo deseado para cada uno: 0, 45, 90... étc

Como indicaba antes, en el apartado del marcado html, estas clases se podrían evitar y usar los selectores de número de elemento.

Y vamos con la magia Css para desplazar de forma sencilla y sin cálculos añadidos cada elemento formando un círculo alrededor del central. Para ello construimos una declaración del tipo:

.degNº { transform: rotate(ángulo_deseado) translate(radio) rotate(-ángulo_deseado); }

El efecto del esta declaración es el que ves en el gif del inicio del artículo. O puedes verlo en código vivo aquí.

Vamos con una breve explicación de ésta declaración:
rotate(ángulo_deseado): esta primera transformación gira sobre sí mismo al elemento el ángulo deseado y a la vez también el eje de traslación o línea sobre la que se desplaza del centro al exterior (su eje X).
translate(radio): en nuestro ejemplo el valor 'radio' serían los 12em (mitad del tamaño de la caja padre) que es la distancia desde el centro a la que queremos situarlo.
rotate(-ángulo_deseado): con esta tercera transformación, cuyo valor es el de la primera pero con signo negativo, compensamos el giro sobre el propio elemento para "enderezarlo".

Así que aplicando esta fórmula a nuestro ejemplo quedaría así:

.deg0 { transform: translate(12em); }/* 12em = 1/2 anchura del contenedor */ .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); }

Todo lo anterior puesto junto a trabajar puedes verlo en:

Ver demo // Demo para =<IE8

Si por alguna razón, por ejemplo estética, quieres que las imágenes queden "mirando al centro", esto es, giradas sobre sí mismas, sólo tienes que prescindir de la última rotación compensatoria.

Créditos y autorías

thebabydino Mi escaso mérito en este artículo es poner con más o menos acierto en español lo que descubrí en un hilo de stackoverflow.
La idea, códigos y ejemplos son obra de Ana Tudor, aka: @thebabydino
Todas sus demos juntas: demo 1 // demo 2 // demo 3 // demo para los ie

Reconocimiento de autoría

avatar del Editor del blog

Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Don Kseso Kseso