I\'m trying to create a circular menu in CSS for a school project.
This is what the menu would look like:
The following is a way to do it with HTML canvas, and it detects where the mouse is perfectly. It doesn't look the exact same as yours though, and I didn't add the icons or dividing lines (although anti-aliasing allows the background to show through a little between regions creating the illusion of lines being drawn).
http://jsfiddle.net/jcubed111/xSajL/
Edit - Bug Fix: http://jsfiddle.net/jcubed111/xSajL/2/
With more work you could make the canvas version look the same as your mock-up, my version is only to get the functionality down.
You could also make it look right with css, then overlay a clear a
to detect mouse position and provide linking functionality. Of course, then you couldn't use :hover
to change the look of the regions.
I've tested in Chrome 19 only.
Here's the full code below in case the link goes down:
HTML:
<a id='link'><canvas id='c' width='224' height='224' onmousemove="update(event);"></canvas></a>
<input id='i' />
CSS:
#c{
width:224px;
height:224px;
}
JS (run on page load and uses jquery):
ctx = $('#c')[0].getContext('2d');
function update(E) {
ctx.clearRect(0, 0, 224, 224);
if (E === false) {
mx = 112;
my = 112;
} else {
mx = E.clientX;
my = E.clientY;
}
mangle = (-Math.atan2(mx-112, my-112)+Math.PI*2.5)%(Math.PI*2);
mradius = Math.sqrt(Math.pow(mx - 112, 2) + Math.pow(my - 112, 2));
$('#i').val("Not over any region");
$('#link').attr('href', '');
for (i = 0; i < 8; i++) {
angle = -Math.PI / 8 + i * (Math.PI / 4);
if (((mangle > angle && mangle < (angle + Math.PI / 4)) || (mangle > Math.PI*15/8 && i==0)) && mradius<=112 && mradius>=69) {
ctx.fillStyle="#5a5a5a";
$('#i').val("In region "+i);
$('#link').attr('href', '#'+i);
} else {
ctx.fillStyle="#4c4c4c";
}
ctx.beginPath();
ctx.moveTo(112, 112);
//ctx.lineTo(112+Math.cos(angle)*112, 112+Math.sin(angle)*112);
ctx.arc(112, 112, 112, angle, angle + Math.PI / 4, false);
ctx.lineTo(112, 112);
ctx.fill();
}
ctx.fillStyle = "#f2f2f2";
ctx.beginPath();
ctx.arc(112, 112, 69, 0, 2 * Math.PI, false);
ctx.fill();
}
update(false);
HTML Code
<a class='button ctrl' href='#' tabindex='1'>★</a>
<ul class='tip ctrl'>
<li class='slice'><div>✦</div></li>
<li class='slice'><div>✿</div></li>
<li class='slice'><div>✵</div></li>
<li class='slice'><div>✪</div></li>
<li class='slice'><div>☀</div></li>
</ul>
CSS Code
.ctrl {
position: absolute;
top: 75%; left: 50%;
font: 1.5em/1.13 Verdana, sans-serif;
transition: .5s;
}
a.ctrl, .ctrl div {
display: block;
opacity: .56;
background: #c9c9c9;
color: #7a8092;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px dimgrey;
cursor: pointer;
}
.button {
z-index: 2;
margin: -.625em;
width: 1.25em; height: 1.25em;
border-radius: 50%;
box-shadow: 0 0 3px 1px white;
}
.tip {
z-index: 1;
/**outline: dotted 1px white;/**/
margin: -5em;
width: 10em; height: 10em;
transform: scale(.001);
list-style: none;
opacity: 0;
}
.slice {
overflow: hidden;
position: absolute;
/**outline: dotted 1px yellow;/**/
width: 50%; height: 50%;
transform-origin: 100% 100%;
}
Full code : CSSCodeLab
It could be done with regular HTML+CSS, but for the sake of your sanity, don't even try. It's not worth it.
You'd be far better off doing stuff like this in Canvas or SVG. Especially if you don't need to support older versions of IE.
For both Canvas and SVG solutions, I recommend finding a suitable library. In the SVG world, I strongly recommend Raphael. For Canvas, mayby try Paper. You could get the basics up and running with either of these libraries in just a handful of lines of code.
If you must do this in CSS (maybe that's the criteria for your project, or maybe you're just a glutton for punishment), you'll need to start with using border-radius
to make the circle. Then draw the segmentation line using 1px-wide boxes, and rotate them using transform
. You get the picture; it's not easy, as you've probably already discovered. And getting the thing animated is going to be complete nightmare. It can be done, and as a demonstration piece of what can be achieved in CSS, it would be very clever. But when all your target browsers support SVG and Canvas, doing stuff like this in CSS really is just being clever for the sake of being clever.
It depends on a couple of things. First, do you need the menu to be animated? Second do you need to strictly use css? Do you need the menu to work perfectly aligned?
If you don't need something 100% exact you could use divide the circle into small squares and use only css to accomplish it.
If you need it to be 100% exact and you don't have animations, you can try <map>
map
If you want animations and 100% exact then you most likely be needing something like RaphaelJS
Hope it helps you out.