1. The obvious solution (with bad performance)
You could do this with box-shadow and triangular before and after pseudo elements. The bad thing here is the performance. The good thing is that if pseudo elements OR transitions are not supported, you still get a nice result (a purple box shadow).
.imgholder {display: inline-block; position: relative; left: 0; bottom: 0; box-shadow: 0px 0px 0px 0px #9147ff;}
.imgholder img {display: block; width: 200px; height: 100px;}
.imgholder:hover {box-shadow: -6px 6px 0px 0px #9147ff; position: relative; left: 6px; bottom: 6px;}
.imgholder::after {content: ""; position: absolute; right: 0; width: 0; height: 0; border: 0px solid transparent; border-top: 0px solid #9147ff;}
.imgholder:hover::after {border: 6px solid transparent; border-top: 6px solid #9147ff;}
.imgholder::before {content: ""; position: absolute; top: 0;left: 0; width: 0; height: 0; border: 0px solid transparent; border-right: 0px solid #9147ff; margin-left: 0px;}
.imgholder:hover::before {border: 6px solid transparent; border-right: 6px solid #9147ff; margin-left: -12px;}
.imgholder, .imgholder::before, .imgholder::after {transition: all 0.1s linear;}
<br /><div class="imgholder"><img src="https://i.imgur.com/ukqAxha.gif" /></div>
2. The solution Twitch used (with good performance)
This one is really clever. It uses 'scale' and a small rotated square (45 degrees). Note that the squares have a different transform-origin and a different rotation (direction). Performance and graceful degredation are both pretty good. This seems like the optimal solution to me.
*{font-size: 14px;}
.imgholder {
background: #9147ff;
display: inline-block;
position: relative;
}
.imgholder img {
transition: all 0.1s ease;
display: block;
width: 200px;
height: 100px;
transform: translate3d(0,0,0);
}
.imgholder:hover img {
transform: translate3d(.6rem,-.6rem,0);
transition-delay: 75ms;
}
.corner_bottom_right, .corner_top_left {
left: 0;
top: 0;
width: .8rem;
height: .8rem;
transition: all 0.1s ease;
transform: rotate(-45deg) scale(0);
background: #9147ff;
position: absolute; z-index: 0;
transform-origin: 0% 0%;
}
.corner_bottom_right {
left: auto;
top: auto;
right: 0;
bottom: 0;
transform: rotate(45deg) scale(0);
transform-origin: 100% 100%;
}
.imgholder:hover .corner_bottom_right,
.imgholder:hover .corner_top_left {
transform: rotate(-45deg) scale(1);
transition-delay: 75ms;
}
.imgholder:hover .corner_bottom_right {
transform: rotate(45deg) scale(1);
}
<br /><div class="imgholder">
<div class="corner_top_left"></div>
<div class="corner_bottom_right"></div>
<img src="https://i.imgur.com/ukqAxha.gif" />
</div>
3. Minimum amount of code (with some glitches)
The previous solutions required a lot of code. This one uses a minimum amount of code and uses the box-shadow property. I like the simplicity, but note that this solution might not look smooth on a retina display. Additionally, hovering the bottom shadow glitches and the timing seems a bit off in Firefox.
img {width: 200px; height: 100px; transition: all 0.1s ease;}
img:hover {
transform: translate(8px, -8px);
box-shadow: -1px 1px #9147ff,
-2px 2px #9147ff,
-3px 3px #9147ff,
-4px 4px #9147ff,
-5px 5px #9147ff,
-6px 6px #9147ff,
-7px 7px #9147ff,
-8px 8px #9147ff;
}
<br /><img src="https://i.imgur.com/ukqAxha.gif" />
4. Using clip-path (great performance)
The question really inspired me to create a clip-path solution. I used fixed sizes to make it easier to understand. The solution requires some smart cropping, using overflow: hidden
.
.imgholder {
position: relative;
display: inline-block;
width: 200px;
height: 100px;
overflow: hidden;
transition: all 0.1s ease;
bottom: 0;
}
.imgholder img {
margin-top: -8px;
margin-right: -8px;
position: relative;
display: block;
width: 200px;
height: 100px;
transition: all 0.1s ease;
border-right: 8px solid transparent;
border-top: 8px solid transparent;
}
.clippath {
margin-top: -8px;
margin-right: -8px;
position: absolute;
top: 0;
left: 0;
width: 208px;
height: 108px;
background-color: #9147ff;
clip-path: polygon(0px 108px, 200px 108px, 208px 100px, 208px 0px, 8px 0px, 0px 8px);
transition: all 0.1s ease;
}
.imgholder:hover img,
.imgholder:hover .clippath {
margin-top: 0;
}
.imgholder:hover img {
transform: translate(8px, -8px);
}
.imgholder:hover {
width: 208px;
height: 108px;
bottom: 8px;
margin-bottom: -8px;
}
<br />
<div class="imgholder">
<div class="clippath"></div>
<img src="https://i.imgur.com/ukqAxha.gif">
</div>
<br /><br />
<div class="clippath" style="position: relative;"></div>