Los menús radiales o de tipo rueda son una excelente solución de diseño para optimizar el espacio en interfaces modernas, especialmente en dispositivos móviles. Inspirados originalmente por el concepto de Floating Action Button (FAB) de Material Design de Google, estos elementos permiten agrupar múltiples acciones en un solo punto focal, desplegándolas de forma elegante y animada.
En esta guía, exploraremos cómo crear diferentes estilos de menús circulares utilizando exclusivamente CSS y HTML, con un toque mínimo de JavaScript para manejar las interacciones de clic. Veremos desde diseños minimalistas hasta opciones más avanzadas con imágenes.
Fundamentos de un Menú Circular
La lógica detrás de un menú de opciones tipo rueda es sencilla pero potente:
- Estado Inicial: Todas las opciones del menú están ocultas y posicionadas exactamente debajo del botón central (el "trigger").
- Activación: Al hacer clic o pasar el cursor, aplicamos una transición de CSS que mueve cada opción a una coordenada específica mediante
transform: translate(x, y). - Animación: Utilizamos
transitionpara que el movimiento sea fluido, creando ese efecto de "abanico" o "rueda".

1. Menú Radial con Interacción de Clic
Este primer diseño es el más fiel al concepto de Material Design. El menú se despliega únicamente cuando el usuario decide interactuar con él.
El JavaScript: Para este ejemplo, utilizamos un script sencillo que añade o quita la clase .open al contenedor principal.
// Manejador para abrir/cerrar el menú
document.querySelectorAll('.toggle-btn').forEach(btn => {
btn.addEventListener('click', () => {
const parent = btn.closest('.filter-btn');
parent.classList.toggle('open');
});
});
// Cerrar al seleccionar una opción
document.querySelectorAll('.filter-btn a').forEach(link => {
link.addEventListener('click', () => {
link.closest('.filter-btn').classList.remove('open');
});
});El CSS Principal: Definimos la base del botón y las transiciones. Es importante notar el uso de cubic-bezier para darle un efecto de rebote más natural.
.filter-btn {
position: absolute;
width: 40px;
height: 40px;
transition: all 0.4s ease;
}
.filter-btn a {
position: absolute;
background: #DE5513;
border-radius: 50%;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
z-index: 1;
transition: all .4s cubic-bezier(.68, -0.55, .265, 1.55);
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
}
/* Posicionamiento de las opciones al abrirse */
.filter-btn.open a:nth-child(1) { transform: translate(0, -60px); }
.filter-btn.open a:nth-child(2) { transform: translate(-55px, -35px); }
.filter-btn.open a:nth-child(3) { transform: translate(55px, -35px); }Como podemos ver, es un diseño básico en donde principalmente se definen forma, color y tamaño del botón; además de otros aspectos como la transiciones y posición de las opciones que forman el menú tipo rueda/circular definido con filter-btn a.
Y el segundo para mostrar el botón de rueda/circular ya desplegado:

.filter-btn.open a:nth-child(1) {
transform: translate(0,-55px);
}
.filter-btn.open a:nth-child(2) {
transform: translate(-50px,-34px);
}
.filter-btn.open a:nth-child(3) {
transform: translate(50px,-34px);
}
.filter-btn.open a:nth-child(4) {
transform: translate(50px,20px);
}
.filter-btn.open a:nth-child(5) {
transform: translate(-50px,20px);
}
.filter-btn.open a:nth-child(6) {
transform: translate(0,55px);
}
.filter-btn.open span.toggle-btn.ion-android-funnel {
background-color: #AC3D07;
}
.filter-btn.open .ion-android-funnel:before {
content: "\f2d7";
}Finalmente obtenemos:
2. Variante con Fondo Expansivo (Efecto "After")
Podemos añadir una capa extra de sofisticación utilizando el pseudoelemento ::after para crear un fondo circular que se expande detrás de los iconos, mejorando la visibilidad de las opciones.

.filter-btn::after {
content: '';
width: 170px;
height: 170px;
background-color: rgba(222, 85, 19, 0.9);
position: absolute;
top: -65px;
right: -65px;
border-radius: 50%;
transform: scale(0);
transition: transform 0.3s ease-in-out;
z-index: 0;
}
.filter-btn.open::after {
transform: scale(1);
}Finalmente obtenemos:
3. Menú Circular basado en Hover (Sin JavaScript)
Si prefieres una solución más ligera y rápida para escritorio, puedes utilizar el evento :hover. Esto elimina la necesidad de JavaScript, aunque debes tener cuidado con la experiencia en dispositivos táctiles.

En este modelo, el menú se encuentra rotado 180 grados por defecto y vuelve a su posición original al pasar el puntero:
.menu ul {
transform: rotate(180deg) translateY(-2em);
transition: 1s all ease;
opacity: 0;
}
.menu:hover ul {
transform: rotate(0deg) translateY(-1em);
opacity: 1;
}4. Menú Radial con Imágenes y Recortes
Este es uno de los diseños más creativos. En lugar de iconos simples, utilizamos imágenes que forman una circunferencia perfecta al desplegarse. Cada imagen es un sector del círculo.
.wrap a:nth-child(1) {
border-radius: 40vmin 0 0 0;
transform-origin: 110% 110%;
background-image: url('https://farm3.staticflickr.com/2827/10384422264_d9c7299146.jpg');
background-size: cover;
}Como podemos ver, (entre varias cosas) definimos el tamaño para cada ítem cuyo alto es de 1.4em:
.menu li {
/* ... */
height: 1.4em;
opacity: 0;
z-index: -1;
}También se especifica que todas las opciones no se muestren mediante la propiedad opacity establecida en cero; una vez que nos posicionamos sobre el menú circular (el círculo del medio) le cambiamos la opacidad a uno para que de esta forma sea visible:
.menu:hover li {
opacity: 1;
}Además que activamos la rotación del menú para que regrese a su posición original:
.menu:hover ul {
transform: rotate(0deg) translateY(-1em);
}Que por defecto el menú circular se encuentra rotado en 180 grados:
.menu ul {
transform: rotate(180deg) translateY(-2em);
transition: 1s all;
}Y de aquí podemos entender cómo funciona la transición de los elementos del menú cuando son mostrados, los cuales realizan un desplazamiento de unos 180 grados; por último como elemento fundamental es conocer la composición de cada ítem en el menú:
.menu li:nth-of-type(1) {
transform: rotate(-90deg);
position: absolute;
left: -1.2em;
top: -4.2em;
}
.menu li:nth-of-type(2) {
transform: rotate(-45deg);
position: absolute;
left: 2em;
top: -3em;
}
.menu li:nth-of-type(3) {
position: absolute;
left: 3.4em;
top: 0.3em;
}
.menu li:nth-of-type(4) {
transform: rotate(45deg);
position: absolute;
left: 2em;
top: 3.7em;
}
.menu li:nth-of-type(5) {
transform: rotate(90deg);
position: absolute;
left: -1.2em;
top: 5em;
}5. Menú tipo rueda/circular en base a imágenes y evento hover
El siguiente menú que veremos es de un tipo que despliega un conjunto de imágenes recortadas a través de una circunferencia:
Este menú presenta un funcionamiento similar al anterior y es que muestra el abanico de opciones al postrar el cursor encima de la sección visible del menú (evento hover) el cual es una circunferencia con el típico icono de menú de hamburguesa; el resto de las opciones se encuentran ocultas mediante la propiedad opacity establecida en cero:
.wrap{
position:relative;
width:80vmin; height:80vmin;
margin:0 auto;
background:inherit;
transform:scale(0.2) translatez(0px);
opacity:0;
transition:transform .5s, opacity .5s;
}Una vez que nos posicionamos encima del menú de hamburguesa se muestran todas las opciones:
span:hover + .wrap, .wrap:hover{
transform:scale(.8) translateZ(0px);
opacity:1;
}Las imágenes que se muestran al posicionar el cursor encima del ícono de tipo hamburguesa tienen la siguiente definición:
a:nth-child(1){
border-radius:40vmin 0 0 0;
transform-origin: 110% 110%;
transition:transform .4s .15s;
}
a:nth-child(1) div{
background-image:url('https://farm3.staticflickr.com/2827/10384422264_d9c7299146.jpg');
}
a:nth-child(2){
border-radius:0 40vmin 0 0;
left:52.5%;
transform-origin: -10% 110%;
transition:transform .4s .2s;
}
a:nth-child(2) div{
background-image:url('https://farm7.staticflickr.com/6083/6055581292_d94c2d90e3.jpg');
}
a:nth-child(3){
border-radius:0 0 0 40vmin;
top:52.5%;
transform-origin: 110% -10%;
transition:transform .4s .25s;
}Como podemos apreciar se varía la imagen según el enlace mediante la propiedad :nth-child que también ha sido tema en anteriores entradas:
La pseudo-class nth-child en CSS
Finalmente con las propiedades top, left desplazamos los figuras que componen el menú desplegado.
Modernización: Variables CSS y Accesibilidad
Uso de Variables CSS
En lugar de calcular manualmente cada translate(x, y), puedes usar variables para controlar la distancia y el ángulo, facilitando cambios globales:
.filter-btn {
--distancia: 80px;
}
.open a:nth-child(1) { transform: translateY(calc(-1 * var(--distancia))); }Accesibilidad (A11y)
No olvides que estos menús deben ser operables con el teclado. Asegúrate de:
- Utilizar etiquetas
<button>para el activador principal. - Añadir atributos
aria-expanded="false"que cambien atruevía JS. - Asegurar que el contraste de color entre el icono y el fondo sea suficiente (ratio 4.5:1).
Conclusión
Crear un menú de opciones tipo rueda con CSS y HTML no solo mejora la estética de tu sitio, sino que también ofrece una experiencia de usuario interactiva y fluida. Ya sea que elijas una implementación basada en clics o en hover, la clave está en el uso inteligente de las transformaciones y transiciones de CSS.