How can I let a hexagon morph into a triangle (animation) - css

I have a question on how I can morph a hexagon into a triangle. So the animation it starts off as a hexagon, it's transforms or morphs into a triangle which goes then back to the hexagon (infinite iteration)
<div class="hexagon"></div>
<div id="triangle-up"></div>
<div id="triangle-down"></div>
My CSS code
.hexagon {
position: relative;
width: 130px;
height: 75.06px;
background-color: #2196F3;
margin: 0 auto;
margin-top: 50px;
}
.hexagon:before,
.hexagon:after {
content: "";
position: absolute;
width: 0;
border-left: 65px solid transparent;
border-right: 65px solid transparent;
}
.hexagon:before {
bottom: 100%;
border-bottom: 37.53px solid #2196F3;
}
.hexagon:after {
top: 100%;
width: 0;
border-top: 37.53px solid #2196F3;
}
#triangle-up {
width: 0;
height: 0;
margin: 0 auto;
margin-top: -86px;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid #2196F3;
animation: triangle-up_show;
animation-duration: 4s;
animation-timing-function: linear;
animation-play-state: paused;
animation-delay: 3s;
}
#triangle-down {
width: 0;
height: 0;
margin: 0 auto;
margin-top: -100px;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-top: 100px solid #2196F3;
animation: triangle-down_show;
animation-duration: 6s;
animation-timing-function: linear;
animation-play-state: paused;
}
#keyframes hexagon_hide {
0% { opacity: 1; }
100% { opacity: 0; }
}
#keyframes triangle-up_show {
0% { opacity: 0 }
50% { opacity: 1 }
100% { opacity: 0 }
}
#keyframes triangle-down_show {
0% { opacity: 0 }
50% { opacity: 1 }
100% { opacity: 0 }
}

In css this can be done with the polygon clip and animation:
.shape {
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
background: red;
width: 300px;
height: 300px;
animation: morph 2s infinite;
}
#keyframes morph {
0% {clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);}
50% {clip-path: polygon(50% 0%, 50% 0, 100% 0, 50% 100%, 0 0, 50% 0);}
100% {clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);}
}
<div class="shape">
</div>
I find this site http://bennettfeely.com/clippy/ a good tool for morphing polygon clips in css

I'm aware this isn't css but this could be done using an svg animation:
<svg id="color-fill" xmlns="http://www.w3.org/2000/svg" version="1.1" width="300" height="300" xmlns:xlink="http://www.w3.org/1999/xlink">
<polygon id="shape" class="hex">
<animate
dur="2.5s"
repeatCount="indefinite"
attributeName="points"
values="300,150 225,280 75,280 0,150 75,20 225,20;
300,20 150,280 150,280 0,20 75,20 225,20;
300,20 150,280 150,280 0,20 75,20 225,20;
300,150 225,280 75,280 0,150 75,20 225,20;
300,150 225,280 75,280 0,150 75,20 225,20;"/>
</polygon>
</svg>
I hope this helps anyway :)
https://css-tricks.com/svg-shape-morphing-works/

Related

Constructing a 3D pyramid with CSS but just need the final touch

I'm almost there, I found the perfect CSS pyramid: https://codepen.io/SL20XX/pen/NZLGjx
But I want to apply this gradient instead of the single "#00B4FF" color:
background-image: linear-gradient(39deg, #12103E 0%, #721B34 100%);
I tried many tweaks but doesn't work. I'm confused with the "$color" variable.
How would you do?
Thanks a lot!
You can put a border-image on each surface rather than a border color.
This snippet does this but has to clip each surface back into a triangle shape.
Note: to get the shading effect you need to decide what linear-gradient you want for each of the lighten/darken colors in your original and subsitute those for the one linear-gradient used here.
<style>
.container {
--color: #00B4FF;
--speed: 5s;
}
.container {
width: 400px;
height: 400px;
margin: 0 auto;
position: relative;
perspective: 300px;
perspective-origin: 50% 40%;
}
.side {
position: absolute;
left: 140px;
top: 150px;
width: 0;
height: 0;
border-left: 60px solid transparent;
border-right: 60px solid transparent;
border-bottom: 120px solid #ccc;
transform-origin: 50% 0%;
animation: spin var(--speed) infinite linear;
}
.back {
animation-delay: calc(var(--speed) / -2);
}
.right {
animation-delay: calc(var(--speed) / -4);
}
.left {
animation-delay: calc(var(--speed) * -0.75);
}
#keyframes spin {
0% {
transform: rotateY(0deg) rotateX(30deg);
/*border-bottom-color: lighten(#0000FF, 5%);*/
border-image: linear-gradient(red, yellow);
clip-path: polygon(0 100%, 100% 100%, 50% 0);
}
25% {
transform: rotateY(90deg) rotateX(30deg);
/*border-bottom-color: darken(#0000FF, 5%);*/
border-image: linear-gradient(red, yellow);
clip-path: polygon(0 100%, 100% 100%, 50% 0);
opacity: 1;
}
25.1% {
opacity: 0;
}
50% {
transform: rotateY(180deg) rotateX(30deg);
/*border-bottom-color: darken(#0000FF, 12%);*/
border-image: linear-gradient(red, yellow);
clip-path: polygon(0 100%, 100% 100%, 50% 0);
}
74.9% {
opacity: 0;
}
75% {
transform: rotateY(270deg) rotateX(30deg);
/*border-bottom-color: darken(#0000FF, 15%);*/
border-image: linear-gradient(red, yellow);
clip-path: polygon(0 100%, 100% 100%, 50% 0);
opacity: 1;
}
100% {
transform: rotateY(360deg) rotateX(30deg);
/*border-bottom-color: lighten(#0000FF, 5%);*/
border-image: linear-gradient(red, yellow);
clip-path: polygon(0 100%, 100% 100%, 50% 0);
}
}
.shadow {
position: absolute;
top: 300px;
left: 175px;
width: 50px;
height: 50px;
background-color: #bbb;
box-shadow: 0 0 40px 40px #bbb;
animation: shadow var(--speed) infinite linear;
}
#keyframes shadow {
0% {
transform: rotateX(90deg) rotateZ(0deg);
}
100% {
transform: rotateX(90deg) rotateZ(-360deg);
}
}
</style>
<div class="container">
<div class="side left"></div>
<div class="side front"></div>
<div class="side right"></div>
<div class="side back"></div>
<div class="shadow"></div>
</div>

Two CSS animation interfere with each other

I've created this snippet on Codepen: the earth rotates and the car moves. However, when car moves it makes the earth rotate too. I want all elements to go their own path.
Why does the car affect the earth, and how can that be avoided?
body {
background: url(https://news.vanderbilt.edu/files/NASA_SMBH1.jpg);
background-size: 1000px;
}
#firstimg {
background-image: url(http://www.21tech.ir/dfxhfgh.gif);
position: absolute;
background-repeat: no-repeat;
background-size: 100px;
animation: anim1 14s infinite linear;
margin: 40px;
}
#earth {
margin-left: 100px;
width: 500px;
height: 500px;
background: url(http://www.drodd.com/images14/map-of-earth1.jpg);
border-radius: 50%;
background-size: 1000px;
box-shadow: inset 16px 0 40px 6px rgb(0, 0, 0), inset -3px 0 6px 2px rgba(255, 255, 255, 0.2);
animation-name: rotate;
animation-duration: 30s;
animation-iteration-count: infinite;
animation-timing-function: linear;
filter: brightness(50%);
}
#keyframes rotate {
from {
background-position-x: 0px;
}
to {
background-position-x: 1000px;
}
}
#keyframes anim1 {
0%,
100% {
transform: translate(0, 0) rotate(0deg)
}
50% {
transform: translate(20px, 20px) rotate(10deg)
}
}
<div id="firstimg">
<div>
<div id="earth"></div>
You have not closed you firstimg div tag, hence it runs under a single div
<div id="firstimg"></div>
<div id="earth"></div>
Follow Codepen

Faded border loading spinner in CSS

How can I make the last part of the spinner lighter (ie. fading):
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 5px solid transparent;
border-top-color: #aaa;
border-right-color: #aaa;
animation: spin 2s linear infinite;
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div id="loader-wrapper">
<div id="loader"></div>
</div>
I tried using gradient but it converts it to a square
You can apply the gradient to a pseudo-element like so:
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 5px solid transparent;
border-top-color: #aaa;
border-right-color: #aaa;
animation: spin 2s linear infinite;
}
#loader::after {
content: '';
width: 85%;
height: 85%;
background: linear-gradient(45deg, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 1) 40%, rgba(255, 255, 255, 0.7) 60%, rgba(255, 255, 255, 0) 100%);
position: absolute;
top: 0;
left: 0;
transform: translate(-5%, -5%);
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div id="loader-wrapper">
<div id="loader"></div>
</div>
Here is another idea with less code and without using pseudo element.
.loader {
--border-width: 5px;
height: 150px;
width: 150px;
border-radius: 50%;
/* 0.5px's are needed to avoid hard-stopping */
--mask: radial-gradient(
farthest-side,
transparent calc(100% - var(--border-width) - 0.5px),
#000 calc(100% - var(--border-width) + 0.5px)
);
-webkit-mask: var(--mask);
mask: var(--mask);
background: linear-gradient(#aaa 30%, transparent 80%) 0 0/50% 100% no-repeat; /* this is our border image */
animation: spin 2s linear infinite;
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="loader"></div>
And this is the comparison of my answer with #Ricky's answer by setting background to body:
#Ricky's way:
body {
background: pink; /* just added this */
}
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 5px solid transparent;
border-top-color: #aaa;
border-right-color: #aaa;
animation: spin 2s linear infinite;
}
#loader::after {
content: '';
width: 85%;
height: 85%;
background: linear-gradient(45deg, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 1) 40%, rgba(255, 255, 255, 0.7) 60%, rgba(255, 255, 255, 0) 100%);
position: absolute;
top: 0;
left: 0;
transform: translate(-5%, -5%);
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div id="loader-wrapper">
<div id="loader"></div>
</div>
My way:
body {
background: pink; /* just added this */
}
.loader {
--border-width: 5px;
height: 150px;
width: 150px;
border-radius: 50%;
/* 0.5px's are needed to avoid hard-stopping */
--mask: radial-gradient(
farthest-side,
transparent calc(100% - var(--border-width) - 0.5px),
#000 calc(100% - var(--border-width) + 0.5px)
);
-webkit-mask: var(--mask);
mask: var(--mask);
background: linear-gradient(#aaa 30%, transparent 80%) 0 0/50% 100% no-repeat; /* this is our border image */
animation: spin 2s linear infinite;
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="loader"></div>

How to make a smooth dashed border rotation animation like 'marching ants'

I'm working on a css animation that uses 'cogs and chains', but am unable to create a 'smooth' border rotation sequence.
You can see in this fiddle How (currently) I'm using a pseudo element to generate a 'rotation' effect. This is done by 'switching' between a dashed white and dashed gold colored border, making it seem like the 'border is rotating'.
What I have
#one{
-webkit-animation: rotateClockwiseAnimation 5s linear infinite; /* Safari 4+ */
-moz-animation: rotateClockwiseAnimation 5s linear infinite; /* Fx 5+ */
-o-animation: rotateClockwiseAnimation 5s linear infinite; /* Opera 12+ */
animation: rotateClockwiseAnimation 5s linear infinite; /* IE 10+, Fx 29+ */
}
#two{
-webkit-animation: rotateAntiClockwiseAnimation 5s linear infinite; /* Safari 4+ */
-moz-animation: rotateAntiClockwiseAnimation 5s linear infinite; /* Fx 5+ */
-o-animation: rotateAntiClockwiseAnimation 5s linear infinite; /* Opera 12+ */
animation: rotateAntiClockwiseAnimation 5s linear infinite; /* IE 10+, Fx 29+ */
position:absolute;
top:30px;
left:42px;
width:80px;
}
#-webkit-keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-moz-keyframes rotateClockwiseAnimation{
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-o-keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-webkit-keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
#-moz-keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
#-o-keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
#keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
/******************************************************************************/
.chain{
height:70px;
width:80%;
border:5px dashed gold;
border-radius:30px;
position:absolute;
top:30px;
left:40px;
-webkit-animation: switchGoldBlackBorder 0.8s infinite; /* Safari 4+ */
-moz-animation: switchGoldBlackBorder 0.8s infinite; /* Fx 5+ */
-o-animation: switchGoldBlackBorder 0.8s infinite; /* Opera 12+ */
animation: switchGoldBlackBorder 0.8s infinite; /* IE 10+, Fx 29+ */
}
#-webkit-keyframes switchBlackGoldBorder {
0% { border: 5px dashed transparent; }
49% { border: 5px dashed transparent; }
50% { border: 5px dashed gold; }
100% { border: 5px dashed gold; }
}
#-moz-keyframes switchBlackGoldBorder{
0% { border: 5px dashed transparent; }
49% { border: 5px dashed transparent; }
50% { border: 5px dashed gold; }
100% { border: 5px dashed gold; }
}
#-o-keyframes switchBlackGoldBorder {
0% { border: 5px dashed transparent; }
49% { border: 5px dashed transparent; }
50% { border: 5px dashed gold; }
100% { border: 5px dashed gold; }
}
#keyframes switchBlackGoldBorder {
0% { border: 5px dashed transparent; }
49% { border: 5px dashed transparent; }
50% { border: 5px dashed gold; }
100% { border: 5px dashed gold; }
}
.chain:after{
content:"";
position:absolute;
height:70px;
border-radius:30px;
width:100%;
top:-5px;
left:-5px;
border:5px solid gold;
z-index:-1;
-webkit-animation: switchBlackGoldBorder 0.8s infinite; /* Safari 4+ */
-moz-animation: switchBlackGoldBorder 0.8s infinite; /* Fx 5+ */
-o-animation: switchBlackGoldBorder 0.8s infinite; /* Opera 12+ */
animation: switchBlackGoldBorder 0.8s infinite; /* IE 10+, Fx 29+ */
}
#-webkit-keyframes switchGoldBlackBorder {
0% { border: 5px solid gold; }
49% { border: 5px solid gold; }
50% { border: 5px solid white; }
100% { border: 5px solid white; }
}
#-moz-keyframes switchGoldBlackBorder{
0% { border: 5px solid gold; }
49% { border: 5px solid gold; }
50% { border: 5px solid white; }
100% { border: 5px solid white; }
}
#-o-keyframes switchGoldBlackBorder {
0% { border: 5px solid gold; }
49% { border: 5px solid gold; }
50% { border: 5px solid white; }
100% { border: 5px solid white; }
}
#keyframes switchGoldBlackBorder {
0% { border: 5px solid gold; }
49% { border: 5px solid gold; }
50% { border: 5px solid white; }
100% { border: 5px solid white; }
}
<svg id="one" style="width:50px" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100">
<defs>
<circle id="c" cx="50" cy="50" r="30" stroke="#808080" fill="none" stroke-width="25"/>
<path id="d" stroke="#808080" stroke-width="16" d="M50 0, V15 M50 100, V85 M0 50, H15 M100 50, H85"/>
</defs>
<use xlink:href="#c"/>
<use xlink:href="#d"/>
<use xlink:href="#d" transform="rotate(45, 50, 50)"/>
</svg>
<svg id="two" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100">
<use xlink:href="#one"/>
</svg>
<div class="chain"></div>
So, the lower section of the snippet, you can see how I've generated the 'rotating chain effect' through using keyframes.
What I would like
My overall wish would be to generate something like:
Think of a cross section of a conveyor belt, and how the 'gears at the end drive the belt'. I'm trying to reproduce that. (i.e. the dashed border's gold bits should be within the troughs of the gear, and 'be pulled' by it)
#one{
-webkit-animation: rotateClockwiseAnimation 5s linear infinite; /* Safari 4+ */
-moz-animation: rotateClockwiseAnimation 5s linear infinite; /* Fx 5+ */
-o-animation: rotateClockwiseAnimation 5s linear infinite; /* Opera 12+ */
animation: rotateClockwiseAnimation 5s linear infinite; /* IE 10+, Fx 29+ */
border:5px dashed gold;
border-radius:50%;
}
#-webkit-keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-moz-keyframes rotateClockwiseAnimation{
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-o-keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
<svg id="one" style="width:50px" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100">
<defs>
<circle id="c" cx="50" cy="50" r="30" stroke="#808080" fill="none" stroke-width="25"/>
<path id="d" stroke="#808080" stroke-width="16" d="M50 0, V15 M50 100, V85 M0 50, H15 M100 50, H85"/>
</defs>
<use xlink:href="#c"/>
<use xlink:href="#d"/>
<use xlink:href="#d" transform="rotate(45, 50, 50)"/>
</svg>
but with the gold dashes to fit within the gear's troughs, as well as being 80% width of the screen (if that makes sense).
In the end, I would like to generate something like this image portrays:
See how i want the chain to 'rotate'?
My Current Issues
Since the animation is 'hacked' via the use of a pseudo element, I've found it quite hard to actually sync the rotation of this 'chain'.
I'm still learning keyframe animation, so I'm sure that isn't the best method for this
Again, svg is a new concept for me, so bear with my reluctance to use it (hence why I'm using css for the 'chain')
In the end, I want to 'make it look like' the gear is turning the chain, but right now they look like completely (and badly done) separate element animations
Cog and chain animation :
I totaly refactored the code (CSS and HTML), it is now :
shorter (especialy the css)
simpler
more realistic: corrected the synchronisation issue bteween the chain and the cogs and added a missing cog on the right because your chain seemed to be floating in the air :
DEMO
The approach is the same, animating the rotation angle for the cogs and dash-offset for the chain path. I tweaked the timing between both animations to make it look as if the cogs are pulling the chain.
Browser support :
As IE doesn't support the svg animate element I also made this version of the animation with the snap.svg library that also supports IE9 and over (tested in IE9 with crossbrowsertesting).
DEMO with IE support
var cont = new Snap('#svg'),
chain = cont.select('#chain'),
cogAcw = cont.select('#cog_acw'),
cogCw = cont.select('#cog_cw'),
speed = 500; // Lower this number to make the animation faster
function infChain(el) {
var len = el.getTotalLength();
el.attr({"stroke-dasharray": len/62,"stroke-dashoffset": 0});
el.animate({"stroke-dashoffset": -len/31}, speed, mina.linear, infChain.bind(null, el));
}
function rotateAcw(el) {
el.transform('r22.5,20,20');
el.animate({ transform: 'r-22.5,20,20' }, speed, mina.linear, rotateAcw.bind( null, el));
}
function rotateCw(el) {
el.transform('r0,20,20');
el.animate({ transform: 'r45,20,20' }, speed, mina.linear, rotateCw.bind( null, el));
}
infChain(chain);
rotateAcw(cogAcw);
rotateCw(cogCw);
svg {
width:100%;
}
<script src="http://thisisa.simple-url.com/js/snapsvg.js"></script>
<svg id="svg" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 30">
<defs>
<circle id="c" cx="20" cy="20" r="4" stroke="#808080" fill="none" stroke-width="4" />
<path id="d" stroke="#808080" stroke-width="2" d="M20 13 V16 M27 20 H24 M20 27 V24 M13 20 H16" />
<g id="cog_acw">
<use xlink:href="#c" /><use xlink:href="#d" />
<use xlink:href="#d" transform="rotate(45 20 20)" />
</g>
<g id="cog_cw">
<use xlink:href="#c" /><use xlink:href="#d" />
<use xlink:href="#d" transform="rotate(45 20 20)" />
</g>
</defs>
<path id="chain" stroke-width="1" stroke="#000" fill="transparent"
d="M21.3 13.5 H20 C11.4 13.5 11.4 26.5 20 26.5 H80 C89.4 26.5 89.4 13.5 80.8 13.5z" />
<use xlink:href="#cog_acw" />
<use transform="translate(60.5 0), rotate(19,20,20)" xlink:href="#cog_acw" />
<use transform="translate(-4.5 -4.5),scale(.8), rotate(0,20,20)" xlink:href="#cog_cw" />
</svg>
svg{width:100%;}
#chain_st{
-webkit-animation: dash 1s infinite linear;
-moz-animation: dash 1s infinite linear;
-o-animation: dash 1s infinite linear;
animation: dash 1s infinite linear;
}
#-webkit-keyframes dash {
to { stroke-dashoffset: -5; }
}
#-moz-keyframes dash {
to { stroke-dashoffset: -5; }
}
#-o-keyframes dash {
to { stroke-dashoffset: -5; }
}
#keyframes dash {
to { stroke-dashoffset: -5; }
}
<svg id="one" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 30">
<defs>
<circle id="c" cx="20" cy="20" r="4" stroke="#808080" fill="none" stroke-width="4"/>
<path id="d" stroke="#808080" stroke-width="2" d="M20 13 V16 M27 20 H24 M20 27 V24 M13 20 H16"/>
<g id="cog">
<use xlink:href="#c"/>
<use xlink:href="#d"/>
<use xlink:href="#d" transform="rotate(45 20 20)"/>
</g>
</defs>
<g transform="translate(0,-7), scale(0.8), rotate(22.5 8 8)">
<use xlink:href="#cog">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="-22.5 20 20" to="337.5 20 20" dur="8s" repeatCount="indefinite"/>
</use>
</g>
<path id="chain_st" stroke-width="1" stroke="#000" fill="transparent" stroke-dasharray="2.6 2.45" d="M21.3 13.5 H20 C11.4 13.5 11.4 26.5 20 26.5 H80 C89 26.5 89 13.5 80.8 13.5z" />
<use class="rot" xlink:href="#cog">
<animateTransform attributeType="xml" attributeName="transform" type="rotate"from="22.5 20 20" to="-337.5 20 20" dur="8s" repeatCount="indefinite"/>
</use>
<g transform="translate(60.3 0)">
<use class="" xlink:href="#cog">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="22.5 20 20" to="-337.5 20 20" dur="8s" repeatCount="indefinite"/>
</use>
</g>
</svg>
Original answer :
You could use an other svg dashed path and animate the dash-offset property with a keyframe animation.
This can and should be simplified/tweaked for a "real world" use :
all elements can be contained into one <svg> tag (this would make it simpler and both cogs + chain could resize together)
The sync between the chain and the cog isn't perfect and speed/size of chain needs to be tweaked.
#one {
-webkit-animation: rotateClockwiseAnimation 5s linear infinite;
/* Safari 4+ */
-moz-animation: rotateClockwiseAnimation 5s linear infinite;
/* Fx 5+ */
-o-animation: rotateClockwiseAnimation 5s linear infinite;
/* Opera 12+ */
animation: rotateClockwiseAnimation 5s linear infinite;
/* IE 10+, Fx 29+ */
}
#two {
-webkit-animation: rotateAntiClockwiseAnimation 5s linear infinite;
/* Safari 4+ */
-moz-animation: rotateAntiClockwiseAnimation 5s linear infinite;
/* Fx 5+ */
-o-animation: rotateAntiClockwiseAnimation 5s linear infinite;
/* Opera 12+ */
animation: rotateAntiClockwiseAnimation 5s linear infinite;
/* IE 10+, Fx 29+ */
position: absolute;
top: 30px;
left: 42px;
width: 80px;
}
#-webkit-keyframes rotateClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#-moz-keyframes rotateClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#-o-keyframes rotateClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#keyframes rotateClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#-webkit-keyframes rotateAntiClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
#-moz-keyframes rotateAntiClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
#-o-keyframes rotateAntiClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
#keyframes rotateAntiClockwiseAnimation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
/******************************************************************************/
#chain {
width: 650px;
position: absolute;
top: 24px;
left: 35px;
}
.chain_st {
stroke-dasharray: 1.5;
stroke-dashoffset: 10;
-webkit-animation: dash 18s infinite linear;
-moz-animation: dash 18s infinite linear;
-o-animation: dash 18s infinite linear;
animation: dash 18s infinite linear;
}
#-webkit-keyframes dash {
to {
stroke-dashoffset: 100;
}
}
#-moz-keyframes dash {
to {
stroke-dashoffset: 100;
}
}
#-o-keyframes dash {
to {
stroke-dashoffset: 100;
}
}
keyframes dash {
to {
stroke-dashoffset: 100;
}
}
<svg id="one" style="width:50px" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100">
<defs>
<circle id="c" cx="50" cy="50" r="30" stroke="#808080" fill="none" stroke-width="25" />
<path id="d" stroke="#808080" stroke-width="16" d="M50 0, V15 M50 100, V85 M0 50, H15 M100 50, H85" />
</defs>
<use xlink:href="#c" />
<use xlink:href="#d" />
<use xlink:href="#d" transform="rotate(45, 50, 50)" />
</svg>
<svg id="two" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 100">
<use xlink:href="#one" />
</svg>
<svg id="chain" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 70 10">
<path class="chain_st" stroke-width="0.5" stroke="#000" fill="transparent" d="M60 1 Q65 1 65 5 Q65 9 60 9 H6 Q1 9 1 5 Q1 1 6 1z" />
</svg>
How about this approach? I'm using SVG for both the gears and the conveyor. The gears rotate as per your example, but I am using stroke-dasharray and animating stroke-dash-offset to make the conveyor belt move.
It took a bit of fiddling to get the conveyor length and dash timing right, which you would need to tweak again if you change the gear size or conveyor length.
#one{
-webkit-animation: rotateClockwiseAnimation 4s linear infinite; /* Safari 4+ */
-moz-animation: rotateClockwiseAnimation 4s linear infinite; /* Fx 5+ */
-o-animation: rotateClockwiseAnimation 4s linear infinite; /* Opera 12+ */
animation: rotateClockwiseAnimation 4s linear infinite; /* IE 10+, Fx 29+ */
}
#two{
-webkit-animation: rotateAntiClockwiseAnimation 4s linear infinite; /* Safari 4+ */
-moz-animation: rotateAntiClockwiseAnimation 4s linear infinite; /* Fx 5+ */
-o-animation: rotateAntiClockwiseAnimation 4s linear infinite; /* Opera 12+ */
animation: rotateAntiClockwiseAnimation 4s linear infinite; /* IE 10+, Fx 29+ */
position:absolute;
top:30px;
left:42px;
width:80px;
}
#-webkit-keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-moz-keyframes rotateClockwiseAnimation{
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-o-keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#keyframes rotateClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#-webkit-keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
#-moz-keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
#-o-keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
#keyframes rotateAntiClockwiseAnimation {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
/******************************************************************************/
#chain
{
-webkit-animation: conveyor 0.5s linear infinite; /* Safari 4+ */
-moz-animation: conveyor 0.5s linear infinite; /* Fx 5+ */
-o-animation: conveyor 0.5s linear infinite; /* Opera 12+ */
animation: conveyor 0.5s linear infinite; /* IE 10+, Fx 29+ */
}
#-webkit-keyframes conveyor {
0% { stroke-dashoffset: -9; }
100% { stroke-dashoffset: 20.06; }
}
#-moz-keyframes conveyor {
0% { stroke-dashoffset: -9; }
100% { stroke-dashoffset: 20.06; }
}
#-o-keyframes conveyor {
0% { stroke-dashoffset: -9; }
100% { stroke-dashoffset: 20.06; }
}
#keyframes conveyor {
0% { stroke-dashoffset: -9; }
100% { stroke-dashoffset: 20.06; }
}
<svg width="100%" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 800 100">
<defs>
<circle id="c" cx="0" cy="0" r="30" stroke="#808080" fill="none" stroke-width="25"/>
<path id="d" stroke="#808080" stroke-width="16" d="M0,-50 v15 M0,50 v-15 M-50,0 h15 M50,0 h-15"/>
<g id="gear">
<use xlink:href="#c"/>
<use xlink:href="#d"/>
<use xlink:href="#d" transform="rotate(45)"/>
</g>
</defs>
<rect id="chain2"
x="43" y="23" width="598" height="74" rx="37"
stroke="gold" stroke-width="2" fill="none"/>
<g transform="translate(27,27) scale(0.5)">
<g id="one">
<use xlink:href="#gear"/>
</g>
</g>
<g transform="translate(80,60) scale(0.8)">
<g id="two">
<use xlink:href="#gear"/>
</g>
</g>
<rect id="chain"
x="43" y="23" width="598" height="74" rx="37"
stroke="gold" stroke-width="5" fill="none"
stroke-dasharray="14 15.06"/>
</svg>
Note: I have remade the whole animation in box-shadow, because using dashed borders doesn't have consistent output on all the browsers.
Working
.. and Works cross-browser.
FF 5+, GC 4+, IE9+, Safari 4+, Opera 12.1+
You can try this using box-shadow :
To make the gears teeth, use box-shadow with negative spread radius. The size of my gear was 50px for example, so to get round box-shadow with d=8px, I used -46px as spread radius.
I positioned the teeth using coordinate geo, and only used 8 teeth to simplify.
Now for the straight conveyor, we need to know the distance between the teeth. We get that by the following :
2*pi*(gear radius) / no. of teeth = (pi * r) / 4
Mine = (55 * 3.1415) / 4 = 43 (approx.)
I took the radius as 55 because the teeth have 4px radius and are lying 1px away from gear circumference.
For aligning the top and bottom straight conveyors, they need to be translated by any multiple of their distance. For my gear, I translate them by 43px.
The Scaffolding
FIDDLE
body {
background: rgba(25,80,175, 0.4);
}
.rect {
height: 116px;
width: 401px;
border-radius: 58px;
position: relative;
overflow: hidden;
}
.rect:before, .rect:after {
content: '';
position: absolute;
left: 46px; /*50-half width*/
height: 8px;
width: 8px;
border-radius: 50%;
background: transparent;
box-shadow: 43px 0 0 0 white, 86px 0 0 0 white, 129px 0 0 0 white, 172px 0 0 0 white, 215px 0 0 0 white, 258px 0 0 0 white, 301px 0 0 0 white;
-webkit-animation: apple 0.3s linear infinite;
-moz-animation: apple 0.3s linear infinite;
animation: apple 0.3s linear infinite;
}
.rect:before {
top: 0px;
}
.rect:after {
bottom: 0px;
-webkit-animation-direction: reverse;
-moz-animation-direction: reverse;
animation-direction: reverse;
}
#-webkit-keyframes apple {
0% {-webkit-transform: translatex(0px);}
100% {-webkit-transform: translateX(-43px);}
}
#-moz-keyframes apple {
0% {-moz-transform: translatex(0px);}
100% {-moz-transform: translateX(-43px);}
}
#keyframes apple {
0% {transform: translatex(0px);}
100% {transform: translateX(-43px);}
}
.left, .right {
content: '';
position: relative;
height: 100px;
width: 100px;
border-radius: 50px;
background-color: #222;
box-shadow: 0 55px 0 -46px white, 55px 0 0 -46px white, 0 -55px 0 -46px white, -55px 0 0 -46px white,
39px 39px 0 -46px white, -39px -39px 0 -46px white, 39px -39px 0 -46px white, -39px 39px 0 -46px white;
-webkit-animation: mango 2.4s linear infinite;
-moz-animation: mango 2.4s linear infinite;
animation: mango 2.4s linear infinite;
}
.left {
top: -108px;
left: 0px;
}
.right {
top: -208px;
left: 301px;
}
#-webkit-keyframes mango {
0% {-webkit-transform: rotate(0deg);}
100% {-webkit-transform: rotate(-360deg);}
}
#-moz-keyframes mango {
0% {-moz-transform: rotate(0deg);}
100% {-moz-transform: rotate(-360deg);}
}
#keyframes mango {
0% {transform: rotate(0deg);}
100% {transform: rotate(-360deg);}
}
<div class="rect"></div>
<div class="left"></div>
<div class="right"></div>
Final version
... with gears. The chain currently is dotted dashed!
FIDDLE
body {
background-color: white;
}
.rect {
height: 120px;
width: 401px;
border-radius: 58px;
position: relative;
}
.rect:before, .rect:after {
content: '';
position: absolute;
left: 40px; /*50-half width*/
height: 10px;
width: 20px;
background: transparent;
box-shadow: 43px 0 0 0 gold, 86px 0 0 0 gold, 129px 0 0 0 gold, 172px 0 0 0 gold, 215px 0 0 0 gold, 258px 0 0 0 gold, 301px 0 0 0 gold, 344px 0 0 0 gold; /*keep adding 43 to x-axis*/
-webkit-animation: apple 0.6s linear infinite;
-moz-animation: apple 0.6s linear infinite;
animation: apple 0.6s linear infinite;
overflow: hidden;
}
.rect:before {
top: 0px;
}
.rect:after {
bottom: 0px;
-webkit-animation-direction: reverse;
-moz-animation-direction: reverse;
animation-direction: reverse;
}
#-webkit-keyframes apple {
0% {-webkit-transform: translatex(0px);}
100% {-webkit-transform: translateX(-43px);}
}
#-moz-keyframes apple {
0% {-moz-transform: translatex(0px);}
100% {-moz-transform: translateX(-43px);}
}
#keyframes apple {
0% {transform: translatex(0px);}
100% {transform: translateX(-43px);}
}
.left, .right {
content: '';
position: relative;
height: 100px;
width: 100px;
border-radius: 50px;
-webkit-animation: mango 4.8s linear infinite;
-moz-animation: mango 4.8s linear infinite;
animation: mango 4.8s linear infinite;
}
.left {
top: -110px;
left: 0px;
}
.right {
top: -210px;
left: 344px;
}
.left:before, .left:after, .right:before, .right:after {
height: 20px;
width: 20px;
content: '';
position: absolute;
background-color: gold;
}
.left:before, .right:before {
box-shadow: 50px 50px 0 0 gold, -50px 50px 0 0 gold, 0 100px 0 0 gold;
top: -10px;
left: 40px;
}
.left:after, .right:after {
transform: rotate(45deg);
top: 5px;
left: 76px;
box-shadow: 0px 100px 0 0 gold, 50px 50px 0 0 gold, -50px 50px 0 0 gold;
}
#-webkit-keyframes mango {
0% {-webkit-transform: rotate(0deg);}
100% {-webkit-transform: rotate(-360deg);}
}
#-moz-keyframes mango {
0% {-moz-transform: rotate(0deg);}
100% {-moz-transform: rotate(-360deg);}
}
#keyframes mango {
0% {transform: rotate(0deg);}
100% {transform: rotate(-360deg);}
}
.cover {
height: 104px;
width: 446px;
border-radius: 50px;
position: relative;
background: rgba(255,255,255,1);
top: -312px;
left; -2px;
}
.gear, .gear2 {
height: 100px;
width: 100px;
background: dimgray;
border-radius: 50%;
position: relative;
-webkit-animation: gear 4.8s linear infinite;
-moz-animation: gear 4.8s linear infinite;
animation: gear 4.8s linear infinite;
}
.gear {
top: -414px;
}
.gear2 {
top: -514px;
left: 345px;
}
.gear:before, .gear:after, .gear2:before, .gear2:after {
height: 20px;
width: 20px;
content: '';
position: absolute;
background-color: dimgray;
}
.gear:before, .gear2:before {
box-shadow: 50px 50px 0 0 dimgray, -50px 50px 0 0 dimgray, 0 100px 0 0 dimgray;
top: -10px;
left: 40px;
}
.gear:after, .gear2:after {
transform: rotate(45deg);
top: 5px;
left: 76px;
box-shadow: 0px 100px 0 0 dimgray, 50px 50px 0 0 dimgray, -50px 50px 0 0 dimgray;
}
#-webkit-keyframes gear {
0% {-webkit-transform: rotate(22.5deg);}
100% {-webkit-transform: rotate(-337.5deg);}
}
#-moz-keyframes gear {
0% {-moz-transform: rotate(22.5deg);}
100% {-moz-transform: rotate(-337.5deg);}
}
#keyframes gear {
0% {transform: rotate(22.5deg);}
100% {transform: rotate(-337.5deg);}
}
<div class="rect"></div>
<div class="left"></div>
<div class="right"></div>
<div class="cover"></div>
<div class="gear"></div>
<div class="gear2"></div>
Final version (Rounded cog-teeth)
.rect {
height: 120px;
width: 401px;
border-radius: 58px;
position: relative;
}
.rect:before, .rect:after {
content: '';
position: absolute;
left: 40px; /*50-half width*/
height: 10px;
width: 20px;
box-shadow: 43px 0 0 0 gold, 86px 0 0 0 gold, 129px 0 0 0 gold, 172px 0 0 0 gold, 215px 0 0 0 gold, 258px 0 0 0 gold, 301px 0 0 0 gold, 344px 0 0 0 gold; /*keep adding 43 to x-axis*/
-webkit-animation: translate 0.6s linear infinite;
-moz-animation: translate 0.6s linear infinite;
animation: translate 0.6s linear infinite;
overflow: hidden;
}
.rect:before {top: 0px;}
.rect:after {
bottom: 0px;
-webkit-animation-direction: reverse;
-moz-animation-direction: reverse;
animation-direction: reverse;
}
#-webkit-keyframes translate {
0% {-webkit-transform: translatex(0px);}
100% {-webkit-transform: translateX(-43px);}
}
#-moz-keyframes translate {
0% {-moz-transform: translatex(0px);}
100% {-moz-transform: translateX(-43px);}
}
#keyframes translate {
0% {transform: translatex(0px);}
100% {transform: translateX(-43px);}
}
.left, .right {
position: relative;
height: 100px;
width: 100px;
border-radius: 50px;
-webkit-animation: rotate 4.8s linear infinite;
-moz-animation: rotate 4.8s linear infinite;
animation: rotate 4.8s linear infinite;
}
.left {
top: -110px; left: 0px;
}
.right {
top: -210px; left: 344px;
}
.left:before, .left:after, .right:before, .right:after {
height: 20px;
width: 20px;
content: '';
position: absolute;
background: gold;
}
.left:before, .right:before {
box-shadow: 50px 50px 0 0 gold, -50px 50px 0 0 gold, 0 100px 0 0 gold;
top: -10px;
left: 40px;
}
.left:after, .right:after {
transform: rotate(45deg);
top: 5px;
left: 76px;
box-shadow: 0px 100px 0 0 gold, 50px 50px 0 0 gold, -50px 50px 0 0 gold;
}
#-webkit-keyframes rotate {
0% {-webkit-transform: rotate(0deg);}
100% {-webkit-transform: rotate(-360deg);}
}
#-moz-keyframes rotate {
0% {-moz-transform: rotate(0deg);}
100% {-moz-transform: rotate(-360deg);}
}
#keyframes rotate {
0% {transform: rotate(0deg);}
100% {transform: rotate(-360deg);}
}
.cover {
height: 104px;
width: 446px;
border-radius: 50px;
position: relative;
background: rgba(255,255,255,1);
top: -312px;
left; -2px;
}
.gear, .gear2, .gear3 {
height: 100px;
width: 100px;
background: transparent;
box-shadow: inset 0 0 0px 35px dimgray, inset 0 0 0px 40px #444;
border-radius: 50%;
position: relative;
-webkit-animation: rotate 4.8s linear infinite;
-moz-animation: rotate 4.8s linear infinite;
animation: rotate 4.8s linear infinite;
-webkit-animation-delay: 0.3s;
-moz-animation-delay: 0.3s;
animation-delay: 0.3s;
}
.gear {top: -414px;}
.gear2 {top: -514px; left: 345px;}
.gear:before, .gear:after, .gear2:before, .gear2:after, .gear3:before, .gear3:after {
height: 20px;
width: 20px;
content: '';
border-radius: 20%;
position: absolute;
background: dimgray;
}
.gear:before, .gear2:before, .gear3:before {
box-shadow: 50px 50px 0 0 dimgray, -50px 50px 0 0 dimgray, 0 100px 0 0 dimgray;
top: -10px; left: 40px;
}
.gear:after, .gear2:after, .gear3:after {
transform: rotate(45deg);
top: 5px; left: 76px;
box-shadow: 0px 100px 0 0 dimgray, 50px 50px 0 0 dimgray, -50px 50px 0 0 dimgray;
}
.gear3 {
-webkit-animation-direction: reverse;
-moz-animation-direction: reverse;
animation-direction: reverse;
top: -504px;
-webkit-animation-delay: 0s;
-moz-animation-delay: 0s;
animation-delay: 0s;
}
<div class="rect"></div>
<div class="left"></div>
<div class="right"></div>
<div class="cover"></div>
<div class="gear"></div>
<div class="gear2"></div>
<div class="gear3"></div>
FIDDLE - ROUNDED TEETH
NOTE : To increase the speed of animation, you simply have to decrease the animation duration of each element proportionally.
Fiddle (fast)
Here is a different method on how to achieve cog animation using CSS. This method has been tested in IE11, IE10, Firefox, Chrome, Opera and Safari.
Two circular elements for gears/cogs with inset box-shadow to produce the inner circle. The teeth are produced by child elements (normal + pseudo) which are rotated around the axis.
The curved part of the belt is achieved using the same technique as the spokes of the gear and are positioned such that they are always in between the teeth.
One rectangular container element whose top and bottom borders are mimicked using linear-gradient. The background of this element (other than the gradient on top and bottom) is a solid color which is sort of a drawback. This solid color is used to hide half of the circular element on either side.
The animation is achieved in two ways (a) constantly rotating both the circular elements and (b) constantly changing the background-position of the gradient backgrounds.
.chain {
margin: 45px auto;
height: 100px;
width: 310px;
position: relative;
background: -webkit-linear-gradient(0deg, gold 50%, transparent 50%), -webkit-linear-gradient(0deg, gold 50%, transparent 50%), white;
background: -moz-linear-gradient(90deg, gold 50%, transparent 50%), -moz-linear-gradient(90deg, gold 50%, transparent 50%), white;
background: linear-gradient(90deg, gold 50%, transparent 50%), linear-gradient(90deg, gold 50%, transparent 50%), white;
background-size: 41px 5px;
background-repeat: repeat-x;
background-position: 20px 0px, 20px 95px;
-webkit-animation: bgPos 1s infinite linear;
-moz-animation: bgPos 1s infinite linear;
animation: bgPos 1s infinite linear;
}
.belt, .belt-after, .belt .spokes, .belt .spokes:before, .belt .spokes:after, .belt-after .spokes, .belt-after .spokes:before, .belt-after .spokes:after {
position: absolute;
content:'';
height: 90px;
width:15px;
top: 0px;
border-top: 5px solid gold;
border-bottom: 5px solid gold;
z-index: -1;
}
.belt, .belt-after {
-webkit-animation: borderAnim 8s infinite linear;
-moz-animation: borderAnim 8s infinite linear;
animation: borderAnim 8s infinite linear;
}
.belt .spokes, .belt-after .spokes {
top: -5px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.belt .spokes:before, .belt-after .spokes:before {
top: -5px;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg);
}
.belt .spokes:after, .belt-after .spokes:after {
top: -5px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.belt {
left: -16px;
}
.belt-after {
right: -16px;
}
.gear {
content:'';
position: absolute;
top: 5px;
height: 90px;
width: 90px;
border-radius: 50%;
-webkit-animation: borderAnim 8s infinite linear;
-moz-animation: borderAnim 8s infinite linear;
animation: borderAnim 8s infinite linear;
box-shadow: inset 0px 0px 0px 30px gray;
z-index: 4;
}
.gear:before, .gear .spokes, .gear .spokes:before, .gear .spokes:after {
position: absolute;
content:'';
height: 88px;
width:15px;
top: -5px;
border-top: 6px solid gray;
border-bottom: 6px solid gray;
}
.gear:before {
left: 37px;
-webkit-transform: rotate(22.5deg);
-moz-transform: rotate(22.5deg);
transform: rotate(22.5deg);
}
.gear .spokes {
left: 37px;
-webkit-transform: rotate(67.5deg);
-moz-transform: rotate(67.5deg);
transform: rotate(67.5deg);
}
.gear .spokes:before {
top: -6px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.gear .spokes:after {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg);
}
.chain .belt + .gear {
left:-52px;
}
.chain .belt-after + .gear {
right: -52.5px;
}
.gear-small {
content:'';
position: absolute;
left: -92px;
top: -20px;
height: 50px;
width: 50px;
border-radius: 50%;
-webkit-animation: borderAnim 6s infinite linear reverse;
-moz-animation: borderAnim 6s infinite linear reverse;
animation: borderAnim 6s infinite linear reverse;
box-shadow: inset 0px 0px 0px 20px gray;
z-index: -2;
}
.gear-small:before {
position: absolute;
content:'';
left: 21px;
top: -3px;
height: 48px;
width: 10px;
border-top:4px solid gray;
border-bottom: 4px solid gray;
}
.gear-small .spokes, .gear-small .spokes:before, .gear-small .spokes:after {
position: absolute;
content:'';
left: 21px;
top: -3px;
height: 48px;
width: 10px;
border-top:4px solid gray;
border-bottom: 4px solid gray;
}
.gear-small .spokes {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.gear-small .spokes:before {
left: 0px;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg);
}
.gear-small .spokes:after {
left: 0px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
#-webkit-keyframes borderAnim {
0% {
-webkit-transform: rotate(360deg);
}
100% {
-webkit-transform: rotate(0deg);
}
}
#-moz-keyframes borderAnim {
0% {
-moz-transform: rotate(360deg);
}
100% {
-moz-transform: rotate(0deg);
}
}
#keyframes borderAnim {
0% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
#-webkit-keyframes bgPos {
0% {
background-position: 20px 0px, -20px 95px;
}
100% {
background-position: -20px 0px, 20px 95px;
}
}
#-moz-keyframes bgPos {
0% {
background-position: 20px 0px, -20px 95px;
}
100% {
background-position: -20px 0px, 20px 95px;
}
}
#keyframes bgPos {
0% {
background-position: 20px 0px, -20px 95px;
}
100% {
background-position: -20px 0px, 20px 95px;
}
}
<div class="chain">
<div class="gear-small">
<div class="spokes"></div>
</div>
<div class="belt">
<div class="spokes"></div>
</div>
<div class="gear">
<div class="spokes"></div>
</div>
<div class="belt-after">
<div class="spokes"></div>
</div>
<div class="gear">
<div class="spokes"></div>
</div>
</div>
Bonus: Here is the whole animation with an on/off switch :) Click (pull) the chain handle to switch the animation on or off.
.container {
position: relative;
}
.chain {
margin: 45px 100px;
height: 100px;
width: 310px;
position: relative;
background: -webkit-linear-gradient(0deg, gold 50%, transparent 50%), -webkit-linear-gradient(0deg, gold 50%, transparent 50%), white;
background: -moz-linear-gradient(90deg, gold 50%, transparent 50%), -moz-linear-gradient(90deg, gold 50%, transparent 50%), white;
background: linear-gradient(90deg, gold 50%, transparent 50%), linear-gradient(90deg, gold 50%, transparent 50%), white;
background-size: 41px 5px;
background-repeat: repeat-x;
background-position: 20px 0px, 20px 95px;
-webkit-animation: bgPos 1s infinite linear;
-moz-animation: bgPos 1s infinite linear;
animation: bgPos 1s infinite linear;
}
.belt,
.belt-after,
.belt .spokes,
.belt .spokes:before,
.belt .spokes:after,
.belt-after .spokes,
.belt-after .spokes:before,
.belt-after .spokes:after {
position: absolute;
height: 90px;
width: 15px;
top: 0px;
border-top: 5px solid gold;
border-bottom: 5px solid gold;
z-index: -1;
}
.belt,
.belt-after {
-webkit-animation: borderAnim 8s infinite linear;
-moz-animation: borderAnim 8s infinite linear;
animation: borderAnim 8s infinite linear;
}
.belt .spokes,
.belt-after .spokes {
top: -5px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.belt .spokes:before,
.belt .spokes:after,
.belt-after .spokes,
.belt-after .spokes:before,
.belt-after .spokes:after {
content: '';
}
.belt .spokes:before,
.belt-after .spokes:before {
top: -5px;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg);
}
.belt .spokes:after,
.belt-after .spokes:after {
top: -5px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.belt {
left: -16px;
}
.belt-after {
right: -16px;
}
.gear {
position: absolute;
top: 5px;
height: 90px;
width: 90px;
border-radius: 100%;
-webkit-animation: borderAnim 8s infinite linear;
-moz-animation: borderAnim 8s infinite linear;
animation: borderAnim 8s infinite linear;
box-shadow: inset 0px 0px 0px 30px gray, inset 0px 0px 0px 40px white, inset 0px 0px 0px 50px tomato;
z-index: 4;
}
.gear:before,
.gear .spokes,
.gear .spokes:before,
.gear .spokes:after {
position: absolute;
content: '';
height: 88px;
width: 15px;
top: -5px;
border-top: 6px solid gray;
border-bottom: 6px solid gray;
}
.gear:before {
left: 37px;
-webkit-transform: rotate(22.5deg);
-moz-transform: rotate(22.5deg);
transform: rotate(22.5deg);
}
.gear .spokes {
left: 37px;
-webkit-transform: rotate(67.5deg);
-moz-transform: rotate(67.5deg);
transform: rotate(67.5deg);
}
.gear .spokes:before {
top: -6px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.gear .spokes:after {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg);
}
.chain .belt + .gear {
left: -52px;
}
.chain .belt-after + .gear {
right: -52.5px;
}
.gear-small {
position: absolute;
left: -91px;
top: -20px;
height: 50px;
width: 50px;
border-radius: 50%;
-webkit-animation: borderAnim 8s 0.4s infinite linear;
-moz-animation: borderAnim 6s infinite linear;
animation: borderAnim 6s infinite linear;
-webkit-animation-direction: reverse;
-moz-animation-direction: reverse;
animation-direction: reverse;
box-shadow: inset 0px 0px 0px 20px gray;
z-index: -2;
}
.gear-small:before {
position: absolute;
content: '';
left: 21px;
top: -3px;
height: 48px;
width: 10px;
border-top: 4px solid gray;
border-bottom: 4px solid gray;
}
.gear-small .spokes,
.gear-small .spokes:before,
.gear-small .spokes:after {
position: absolute;
content: '';
left: 21px;
top: -3px;
height: 48px;
width: 10px;
border-top: 4px solid gray;
border-bottom: 4px solid gray;
}
.gear-small .spokes {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.gear-small .spokes:before {
left: 0px;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg);
}
.gear-small .spokes:after {
left: 0px;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
#-webkit-keyframes borderAnim {
0% {
-webkit-transform: rotate(360deg);
}
100% {
-webkit-transform: rotate(0deg);
}
}
#-moz-keyframes borderAnim {
0% {
-moz-transform: rotate(360deg);
}
100% {
-moz-transform: rotate(0deg);
}
}
#keyframes borderAnim {
0% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
#-webkit-keyframes bgPos {
0% {
background-position: 20px 0px, -20px 95px;
}
100% {
background-position: -20px 0px, 20px 95px;
}
}
#-moz-keyframes bgPos {
0% {
background-position: 20px 0px, -20px 95px;
}
100% {
background-position: -20px 0px, 20px 95px;
}
}
#keyframes bgPos {
0% {
background-position: 20px 0px, -20px 95px;
}
100% {
background-position: -20px 0px, 20px 95px;
}
}
#pull-switch {
display: none;
/* no need to display checkbox */
}
#switch {
position: absolute;
left: 77px;
top: 50px;
border-right: 2px dotted tomato;
height: 200px;
width: 15px;
-webkit-transition: height 0.5s;
-moz-transition: height 0.5s;
transition: height 0.5s;
z-index: 10;
}
#handle {
display: block;
position: absolute;
/* left: width of chain div (15px) + half of border (1px) - radius of handle (8px)*/
left: 8px;
bottom: 0%;
background-color: tomato;
width: 16px;
height: 16px;
border-radius: 50%;
cursor: pointer
}
#pull-switch:checked + #switch > #handle {
background-color: seagreen;
}
#pull-switch:checked + #switch {
height: 225px;
border-color: seagreen;
}
#pull-switch ~ .chain .gear-small,
#pull-switch ~ .chain .belt,
#pull-switch ~ .chain .belt-after,
#pull-switch ~ .chain .gear,
#pull-switch ~ .chain {
-webkit-animation-play-state: paused;
-moz-animation-play-state: paused;
animation-play-state: paused;
}
#pull-switch:checked ~ .chain .gear-small,
#pull-switch:checked ~ .chain .belt,
#pull-switch:checked ~ .chain .belt-after,
#pull-switch:checked ~ .chain .gear,
#pull-switch:checked ~ .chain {
-webkit-animation-play-state: running;
-moz-animation-play-state: running;
animation-play-state: running;
}
#pull-switch:checked ~ .chain .belt + .gear,
#pull-switch:checked ~ .chain .belt-after + .gear {
box-shadow: inset 0px 0px 0px 30px gray, inset 0px 0px 0px 40px white, inset 0px 0px 0px 50px seagreen;
}
<div class="container">
<input type="checkbox" id="pull-switch" />
<div id="switch">
<label for="pull-switch" id="handle"></label>
</div>
<div class="chain">
<div class="gear-small">
<div class="spokes"></div>
</div>
<div class="belt">
<div class="spokes"></div>
</div>
<div class="gear">
<div class="spokes"></div>
</div>
<div class="belt-after">
<div class="spokes"></div>
</div>
<div class="gear">
<div class="spokes"></div>
</div>
</div>
</div>
Original Answer: (Doesn't work on Firefox due to dashed border bug and dashes are more closer in IE making it look ugly).
You could achieve the border rotation animation by using a combination of the following:
Two circular elements (using border-radius: 50%) with dashed border on either side to form the curved part of the border.
One rectangular container element whose top and bottom borders are mimicked using linear-gradient. The background of this element (other than the gradient on top and bottom) is a solid color which is sort of a drawback. This solid color is used to hide half of the circular element on either side.
The animation is achieved in two ways (a) constantly rotating both the circular elements and (b) constantly changing the background-position of the gradient backgrounds.
The cogs are also circular elements where the spokes are made with dashed borders and the solid inner part is generated using an inset box-shadow. The cog is rotated in such a way that the chain's border is always in between the cog's border.
.chain {
margin: 45px auto;
height: 100px;
width: 300px;
position: relative;
background: -webkit-linear-gradient(0deg, gold 50%, transparent 50%), -webkit-linear-gradient(0deg, gold 50%, transparent 50%), white;
background: -moz-linear-gradient(90deg, gold 50%, transparent 50%), -moz-linear-gradient(90deg, gold 50%, transparent 50%), white;
background: linear-gradient(90deg, gold 50%, transparent 50%), linear-gradient(90deg, gold 50%, transparent 50%), white;
background-size: 30px 5px;
background-repeat: repeat-x;
background-position: 0px 0px, 5px 95px;
-webkit-animation: bgPos 4s infinite linear;
-moz-animation: bgPos 4s infinite linear;
animation: bgPos 4s infinite linear;
}
.chain .before,
.chain .after {
position: absolute;
content: '';
height: 90px;
width: 90px;
top: 0px;
border-radius: 50%;
border: 5px dashed gold;
-webkit-animation: borderAnim 2s infinite linear;
-moz-animation: borderAnim 2s infinite linear;
animation: borderAnim 2s infinite linear;
z-index: -2;
}
.chain .before {
left: -45px;
}
.chain .after {
right: -45px;
}
.chain .gear {
content: '';
position: absolute;
top: 0px;
height: 90px;
width: 90px;
border-radius: 50%;
border: 5px dashed gray;
-webkit-transform: rotate(16deg);
-moz-transform: rotate(16deg);
transform: rotate(16deg);
-webkit-animation: gearAnim 2s infinite linear;
-moz-animation: gearAnim 2s infinite linear;
animation: gearAnim 2s infinite linear;
box-shadow: inset 0px 0px 0px 30px gray;
z-index: 4;
}
.chain .before + .gear {
left: -45px;
}
.chain .after + .gear {
right: -45px;
}
.gear-small {
content: '';
position: absolute;
left: -95px;
top: -23px;
height: 60px;
width: 60px;
border-radius: 50%;
border: 3px dashed gray;
-webkit-transform: rotate(16deg);
-moz-transform: rotate(16deg);
transform: rotate(16deg);
-webkit-animation: gearAnim 6s infinite linear reverse;
-moz-animation: gearAnim 6s infinite linear reverse;
animation: gearAnim 6s infinite linear reverse;
box-shadow: inset 0px 0px 0px 20px gray;
z-index: -2;
}
#-webkit-keyframes borderAnim {
0% {
-webkit-transform: rotate(360deg);
}
100% {
-webkit-transform: rotate(0deg);
}
}
#-moz-keyframes borderAnim {
0% {
-moz-transform: rotate(360deg);
}
100% {
-moz-transform: rotate(0deg);
}
}
#keyframes borderAnim {
0% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
#-webkit-keyframes bgPos {
0% {
background-position: 610px 0px, 0px 95px;
}
100% {
background-position: 0px 0px, 600px 95px;
}
}
#-moz-keyframes bgPos {
0% {
background-position: 610px 0px, 0px 95px;
}
100% {
background-position: 0px 0px, 600px 95px;
}
}
#keyframes bgPos {
0% {
background-position: 610px 0px, 0px 95px;
}
100% {
background-position: 0px 0px, 600px 95px;
}
}
#-webkit-keyframes gearAnim {
0% {
-webkit-transform: rotate(376deg);
}
100% {
-webkit-transform: rotate(16deg);
}
}
#-moz-keyframes gearrAnim {
0% {
-moz-transform: rotate(376deg);
}
100% {
-moz-transform: rotate(16deg);
}
}
#keyframes gearAnim {
0% {
transform: rotate(376deg);
}
100% {
transform: rotate(16deg);
}
}
<div class="chain">
<div class="gear-small"></div>
<div class="before"></div>
<div class="gear"></div>
<div class="after"></div>
<div class="gear"></div>
</div>
Last but not least, I would still recommend using the SVG approach for this because beyond a certain point such animations with CSS would become very messy :)
You could try and edit cog so it fits better instead of tweaking div border to fall into place on cog. Its easier to manipulate graphics than css.
And from there maybe to split chain animation in three or four parts to make it more robust.
Then you could tweak speeds of cog and chain to match, hide a half of chain, add onto it div only with top and bottom border and do the same but opposite on other end. (using cliping, position and z-index).
Something like this:
In theory at least, that would be my approach (not to mention that I would use JS instead of this workflow).
Using Canvas
The shapes (cog and chain) and the marching ants animation effect (dashed border) can also be achieved by using a Canvas drawing. The browser support for Canvas is quite good.
While Canvas has the disadvantage of being raster based (as opposed to SVG, which is shape based), it is not a big problem as long as the canvas is not scaled too much. Canvas is expected to be better when handling a large number of objects and real-time animations. Here is an interesting article from the MSDN on when to use Canvas or SVG.
Construction of Shapes
The following are the key parts/shapes involved in this animation:
Chain
Left Cog
Right Cog
Top Cog
Chain: The chain is created by drawing two horizontal lines (using the lineTo commands) that are connected at either end by semicircles (drawn using the arc command). The dashed border effect is achieved by using setLineDash method for the stroke. setLineDash method takes two parameters where the first represents the length of the dash and the second represents the gap between dashes.
Below snippet shows the minimal code required to create the chain:
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var chain = {
offset: 0,
paint: function() {
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(533, 50);
ctx.arc(533, 100, 50, (Math.PI * 1.5), (Math.PI * 0.5), false);
ctx.lineTo(75, 150);
ctx.arc(75, 100, 50, (Math.PI * 0.5), (Math.PI * 1.5), false);
ctx.lineWidth = 5;
ctx.fillStyle = 'transparent';
ctx.setLineDash([12, 14.16]);
ctx.lineDashOffset = this.offset;
ctx.fill();
ctx.stroke();
}
};
chain.paint();
}
/* CSS needed only for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
canvas {
margin: 50px auto;
}
<canvas id='canvas' width='650' height='300'></canvas>
Cogs: All the three cogs (left, right and top) are achieved using the same commands and the only difference is their positioning on screen (and radius for the top one).
The spokes or teeth of the cogs are created by using the arc command (as done for the semicircles of the chain), and use the same radius. Their lineDashoffset is adjusted such that they occupy the exact space left between the dashes of the chain.
The body of the cogs are made up of two circles with the outer one having a bigger radius than the inner. The evenodd fill parameter is used to set the background color (tan in this example) only on the outer circle and leaving the inner one transparent.
Below snippet shows the minimal code required to create the cogs:
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cog = {
paint: function(x, y, r, offset) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2, true);
ctx.closePath();
ctx.lineWidth = 5;
ctx.setLineDash([12, 14.16]);
ctx.lineDashOffset = offset;
ctx.strokeStyle = 'tan';
ctx.stroke();
ctx.beginPath();
ctx.arc(x, y, (r - 2), 0, Math.PI * 2, true);
ctx.arc(x, y, (r / 2.5), 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = 'tan';
ctx.fill('evenodd');
}
};
function paint() {
var cog_radius = 50;
var cog_t_x = 30,
cog_t_y = 40,
cog_t_offset = 20.5,
cog_l_x = 75,
cog_l_y = 100,
cog_l_offset = 24.25,
cog_r_x = 533,
cog_r_offset = 11.25;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
cog.paint(cog_t_x, cog_t_y, (cog_radius / 2), cog_t_offset);
ctx.restore();
ctx.save();
cog.paint(cog_l_x, cog_l_y, cog_radius, cog_l_offset);
ctx.restore();
ctx.save();
cog.paint(cog_r_x, cog_l_y, cog_radius, cog_r_offset);
ctx.restore();
}
paint();
}
/* CSS needed only for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
canvas {
margin: 50px auto;
}
<canvas id='canvas' width='650' height='300'></canvas>
Animation
The animation is achieved by shifting the lineDashOffset of the strokes in each frame of the animation. The animation itself is triggered using the window.requestAnimationFrame method which calls the paint function (passed as an argument) at regular intervals. The rate of callback is generally 60 times per second (quoting MDN). Shifting the offset during every repaint of the canvas gives the appearance of it being animated.
The animation can be stopped at any point of time by calling the cancelAnimationFrame method. This can be done either based on some user interaction (like click, hover etc), or based on a time-out.
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var anim, onState = false,
counter = 0;
var chain = {
offset: 0,
paint: function() {
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(533, 50);
ctx.arc(533, 100, 50, (Math.PI * 1.5), (Math.PI * 0.5), false);
ctx.lineTo(75, 150);
ctx.arc(75, 100, 50, (Math.PI * 0.5), (Math.PI * 1.5), false);
ctx.lineWidth = 5;
ctx.fillStyle = 'transparent';
ctx.setLineDash([12, 14.16]);
ctx.lineDashOffset = this.offset;
ctx.fill();
ctx.stroke();
}
};
function paint(type) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
chain.offset += (6.54 / 10);
ctx.save();
chain.paint();
ctx.restore();
if (type) {
anim = window.requestAnimationFrame(function() {
paint(type);
})
}
}
paint(true);
}
/* CSS needed only for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
canvas {
margin: 50px auto;
}
<canvas id='canvas' width='650' height='300'></canvas>
Complete Picture
Putting all the parts together, the below snippet provides the complete picture of the chain and cogs along with the animation:
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var anim, onState = false,
counter = 0;
var cog_radius = 50;
var cog_t_x = 30,
cog_t_y = 40,
cog_t_offset = 20.5,
cog_l_x = 75,
cog_l_y = 100,
cog_l_offset = 24.25,
cog_r_x = 533,
cog_r_offset = 11.25;
var chain = {
offset: 0,
paint: function() {
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(533, 50);
ctx.arc(533, 100, 50, (Math.PI * 1.5), (Math.PI * 0.5), false);
ctx.lineTo(75, 150);
ctx.arc(75, 100, 50, (Math.PI * 0.5), (Math.PI * 1.5), false);
ctx.lineWidth = 5;
ctx.fillStyle = 'transparent';
ctx.setLineDash([12, 14.16]);
ctx.lineDashOffset = this.offset;
ctx.fill();
ctx.stroke();
}
};
var cog = {
paint: function(x, y, r, offset) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2, true);
ctx.closePath();
ctx.lineWidth = 5;
ctx.setLineDash([12, 14.16]);
ctx.lineDashOffset = offset;
ctx.strokeStyle = 'tan';
ctx.stroke();
ctx.beginPath();
ctx.arc(x, y, (r - 2), 0, Math.PI * 2, true);
ctx.arc(x, y, (r / 2.5), 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = 'tan';
ctx.fill('evenodd');
}
};
function paint(type) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
chain.offset += (6.54 / 10);
cog_l_offset -= (6.54 / 10);
cog_r_offset -= (6.54 / 10);
cog_t_offset += (6.54 / 10);
ctx.save();
cog.paint(cog_t_x, cog_t_y, (cog_radius / 2), cog_t_offset);
ctx.restore();
ctx.save();
chain.paint();
ctx.restore();
ctx.save();
cog.paint(cog_l_x, cog_l_y, cog_radius, cog_l_offset);
ctx.restore();
ctx.save();
cog.paint(cog_r_x, cog_l_y, cog_radius, cog_r_offset);
ctx.restore();
if (type) {
anim = window.requestAnimationFrame(function() {
paint(type);
})
}
}
paint(true);
}
/* CSS needed only for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
canvas {
margin: 50px auto;
}
<canvas id='canvas' width='650' height='300'></canvas>
User Interaction
As mentioned earlier, user interaction can also be added using event listeners (addEventListener). If the action needs to be triggered by user action on a specific shape or section of the canvas then the pointInPath method can be used to verify if the point is within the required section of the canvas.
Here is the link to a CodePen demo which has these user interactions (and some other extra stuff) also added.
Note: Explanation on how to add user interactions etc is beyond the scope of this particular answer. However, if you need any help you can find me in this chat room.

CSS radial / circular progress indicator with a transparent middle

I'd like to make a radial progress indicator with css that has it's middle circle transparent. See here: http://codepen.io/geedmo/pen/InFfd – it's a perfect example of what I want to do but the middle (.overlay) has background-color which overlays the bigger circle. However, I'd like to have it transparent (the bigger circle would have transparent middle too). How to do it?
<div class="wrap">
<div class="progress-radial progress-25">
<div class="overlay">25%</div>
</div>
<div class="progress-radial progress-50">
<div class="overlay">50%</div>
</div>
<div class="progress-radial progress-75">
<div class="overlay">75%</div>
</div>
<div class="progress-radial progress-90">
<div class="overlay">90%</div>
</div>
</div>
SASS:
// Colors
$barColor: tomato
$overlayColor: #fffde8
$backColor: #2f3439
#import url(http://fonts.googleapis.com/css?family=Noto+Sans)
body
padding: 30px 0
background-color: $backColor
font-family: 'Noto Sans', sans-serif
.wrap
width: 600px
margin: 0 auto
/* -------------------------------------
* Bar container
* ------------------------------------- */
.progress-radial
float: left
margin-right: 30px
position: relative
width: 100px
height: 100px
border-radius: 50%
border: 2px solid $backColor // remove gradient color
/* -------------------------------------
* Optional centered circle w/text
* ------------------------------------- */
.progress-radial .overlay
position: absolute
width: 60px
height: 60px
background-color: $overlayColor
border-radius: 50%
margin-left: 20px
margin-top: 20px
text-align: center
line-height: 60px
font-size: 16px
/* -------------------------------------
* Mixin for progress-% class
* ------------------------------------- */
$step: 5 // step of % for created classes
$loops: round(100 / $step)
$increment: 360 / $loops
$half: round($loops / 2)
#for $i from 0 through $loops
.progress-#{$i*$step}
#if $i < $half
$nextdeg: 90deg + ( $increment * $i )
border-image: linear-gradient(90deg, $backColor 50%, transparent 50%, transparent), linear-gradient($nextdeg, $barColor 50%, $backColor 50%, $backColor)
#else
$nextdeg: -90deg + ( $increment * ( $i - $half ) )
border-image: linear-gradient($nextdeg, $barColor 50%, transparent 50%, transparent), linear-gradient(270deg, $barColor 50%, $backColor 50%, $backColor)
This is the result I'd like to get:
html code :
<div class="wrapper">
<div class="pie spinner lightBlue"></div>
<div class="pie filler lightBlue"></div>
<div class="mask"></div>
</div>
css code :
body {
background-color: #f3f3f4;
}
.lightBlue {
border: 10px solid #a8d2d2;
}
.wrapper {
width: 250px;
height: 250px;
margin: 10px auto;
position: relative;
background: white;
background-color: #f3f3f4;
-webkit-transition: width 0.5s, height 0.5s;
transition: width 0.5s, height 0.5s;
-webkit-animation: finalRota 2s 10s linear forwards;
animation: finalRota 2s 10s linear forwards;
}
.wrapper .pie {
width: 50%;
height: 100%;
position: absolute;
background-color: radial-gradient(left center, circle, #00ccff 0px, #000088 100%);
-webkit-transform-origin: 100% 50%;
-ms-transform-origin: 100% 50%;
transform-origin: 100% 50%;
}
.wrapper .spinner {
border-radius: 100% 0 0 100% / 50% 0 0 50%;
z-index: 200;
background-color: radial-gradient(right center, circle, #00ccff 0px, #000088 100%);
border-right: none;
-webkit-animation: rota 10s linear forwards;
animation: rota 10s linear forwards;
}
.wrapper .filler {
border-radius: 0 100% 100% 0 / 0 50% 50% 0;
left: 50%;
border: 10px solid #8dbdbb;
opacity: 0;
z-index: 100;
border-left: none;
-webkit-animation: fill 10s steps(1, end) forwards;
animation: fill 10s steps(1, end) forwards;
}
.wrapper .mask {
width: 50%;
height: 100%;
position: absolute;
background: inherit;
opacity: 1;
z-index: 300;
-webkit-animation: mask 10s steps(1, end) forwards;
animation: mask 10s steps(1, end) forwards;
}
#-webkit-keyframes opoFinalRota {
100% {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}
}
#keyframes opoFinalRota {
100% {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}
}
#-webkit-keyframes rota {
0% {
-webkit-transform: rotate(300deg);
transform: rotate(300deg);
}
100% {
-webkit-transform: rotate(60deg);
transform: rotate(60deg);
}
}
#keyframes rota {
0% {
-webkit-transform: rotate(300deg);
transform: rotate(300deg);
}
100% {
-webkit-transform: rotate(60deg);
transform: rotate(60deg);
}
}
#-webkit-keyframes mask {
0% {
opacity: 1;
}
50%, 100% {
opacity: 0;
}
}
#keyframes mask {
0% {
opacity: 1;
}
50%, 100% {
opacity: 0;
}
}
#-webkit-keyframes fill {
0% {
opacity: 0;
}
50%, 100% {
opacity: 1;
}
}
#keyframes fill {
0% {
opacity: 0;
}
50%, 100% {
opacity: 1;
}
}
and a demo : http://jsfiddle.net/usrs01ye/2/
Just set your $overlayColor variable to transparent
$overlayColor: transparent
Here's a working codepen

Resources