I am currently trying to make a square be 4 triangles of equal size that have hover events on them.
I am creating the triangles like this,
.right, left, .top, .bottom {
position: relative;
width: 26px;
}
.right:before{
position: absolute;
display: inline-block;
border-top: 26px solid transparent;
border-right: 26px solid #eee;
border-bottom: 26px solid transparent;
left: 26px;
top: 0px;
content: '';
}
What I am finding is that each triangle sits above one another meaning only one triangle can be hovered, here is my example,
http://codepen.io/anon/pen/qdmbKz
As you can see only the bottom triangle (hover at the bottom of the square) is hoverable. What am I doing wrong? Is there a better way of doing this?
As you have already indicated in your question, the reason why the hover
works only on the bottom triangle and not the others is because the container of the bottom triangle is placed on top of the container of the other three triangles.
While using the border trick to produce triangles, the actual shape is still a square. It gets the triangle appearance only because the other three borders are transparent. Now when you hover on the shape you are actually hovering the transparent areas of the bottom triangle and not the containers of the other triangles which is why their respective hover
events don't get triggered.
I would personally recommend using SVG for these type of things but the shape is not all that complex to achieve with CSS either.
SVG:
In SVG, you could make use of the polygon
elements to create four triangles within the square and each polygon
is hover-able separately. If they should have their own target links, you can also enclose the polygons within an a
(anchor) tag.
In the snippet, I have implemented the anchor only for one triangle
.square {
height: 400px;
width: 400px;
overflow: hidden;
}
svg {
height: 100%;
width: 100%;
}
polygon {
fill: aliceblue;
stroke: crimson;
stroke-linejoin: round;
}
polygon:hover {
fill: cornflowerblue;
}
<div class='square'>
<svg viewBox='0 0 100 100'>
<a xlink:href='http://google.com'>
<polygon points='5,5 50,50 95,5' />
</a>
<polygon points='5,5 50,50 5,95' />
<polygon points='5,95 50,50 95,95' />
<polygon points='95,5 50,50 95,95' />
</svg>
</div>
CSS:
This is an adaptation of the answer posted by here by web-tiki. I am posting a separate answer because the shape in this question is much simpler and doesn't require as much work as the other one.
The square is split into four equal sized hover-able triangles using the following method:
- The container is a square and has borders on all its sides. The borders are required on the parent because diagonal lines on the triangle are much much more difficult to achieve with CSS.
- Four child elements are added to the container whose height and width are calculated using Pythagoras theorem. They are then positioned such that their top left corner is on the center point of the square (to help with the rotation).
- All the child elements are rotated by the appropriate angles to form the triangles. The
transform-origin
is set as top left
to have the rotation done with the parent square's center point as the axis.
- The parent has
overflow: hidden
to prevent the other half of each square from being visible.
- Note that adding text into the 4 triangles will not be straight-forward because they would also be rotated. The text would have to be put inside a child element which must either be counter rotated.
Note: The script included in the demo is the prefix free library which is used to avoid browser prefixes.
.square {
position: relative;
height: 200px;
width: 200px;
border: 2px solid crimson;
overflow: hidden;
transition: all 1s;
}
.top,
.left,
.right,
.bottom {
position: absolute;
height: calc(100% / 1.414);
width: calc(100% / 1.414);
top: 50%;
left: 50%;
border: 1px solid crimson;
transform-origin: 0% 0%;
}
.right {
transform: rotate(-45deg);
}
.bottom {
transform: rotate(45deg);
}
.top {
transform: rotate(-135deg);
}
.left {
transform: rotate(135deg);
}
.square > div:hover {
background: tomato;
}
/*Just for demo*/
.square:hover{
height: 300px;
width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='square'>
<div class="top"></div>
<div class="right"></div>
<div class="bottom"></div>
<div class="left"></div>
</div>
How about something like this: http://codepen.io/potterbm/pen/GJmoYj
HTML:
<div class="green">
<div class="top"></div><div class="left"></div><div class="right"></div><div class="bottom"></div>
</div>
CSS:
.green {
background-color: #cccccc;
display: block;
margin: 100px auto;
height:100px;
width:100px;
}
.right, .left, .top, .bottom {
border-color: transparent;
border-style: solid;
border-width: 50px;
display: block;
padding: 0;
width: 0;
height: 0;
}
.right, .left {
display: inline-block;
margin: 0;
vertical-align: middle;
}
.top, .bottom {
margin: 0 auto;
}
.top {
border-top-color: green;
margin-bottom: -100px;
}
.right {
border-right-color: blue;
margin-left: -50px;
}
.bottom {
border-bottom-color: steelblue;
margin-top: -100px;
}
.left {
border-left-color: red;
margin-right: -50px;
}
.right:hover {
border-right-color:red;
}
.left:hover {
border-left-color:red;
}
.top:hover {
border-top-color:red;
}
.bottom:hover {
border-bottom-color:red;
}
The basic idea is to put the top triangle on its own line, the left and right triangles on the same line, and the bottom triangle on its own line. Then you just snug them all up with negative margins. It's worth noting that the lack of whitespace in the HTML is intentional.