25

I am trying to draw a circle with border-radius, and animate it. I can do this, but what i can't do is overlay elements and set the circles background to transparent, without unhiding the mask. I am not able to make it transparent over elements because the mask needs to be applied to hide the left half of the circle as it rotates to mimic the draw effect.

HTML

<div class="background">
    <div class="wrapper">
        <div class="pie spinner"></div>
        <div class="pie filler"></div>
        <div class="mask"></div>
    </div>
</div>

CSS

.background{
    background:green;
    z-index: 1000;
}
.wrapper {
  width: 250px;
  height: 250px;
  position: relative;
  margin: 40px auto;
  background: rgba(0,0,255,1);

}

.wrapper, .wrapper * {
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}
.wrapper .pie {
  width: 50%;
  height: 100%;
  transform-origin: 100% 50%;
  position: absolute;
  background: transparent;
  border: 5px solid rgba(0,0,0,0.9);
}

.wrapper .spinner {
  border-radius: 100% 0 0 100% / 50% 0 0 50%;
  z-index: 0;
  border-right: none;
  -webkit-animation: rota 5s linear infinite;
}

.wrapper:hover .spinner,
.wrapper:hover .filler,
.wrapper:hover .mask {
  animation-play-state: running;
}

.wrapper .filler {
  border-radius: 0 100% 100% 0 / 0 50% 50% 0;
  left: 50%;
  opacity: 0;
  -webkit-animation: opa 5s steps(1, end) infinite reverse;
  border-left: none;
}

.wrapper .mask {
  width: 50%;
  height: 100%;
  position: absolute;
  background: inherit;
  opacity: 1;
  -webkit-animation: opa 5s steps(1, end) infinite;
}

@-webkit-keyframes rota {
  0% {transform: rotate(0deg);border-color:red;}
  100% {transform: rotate(360deg);z-index:0;}
}
@-webkit-keyframes opa {
  0% {opacity: 1;}
  50%, 100% {opacity: 0;}
}

http://jsfiddle.net/BuzzSmarter/gmvban4p/

In my example, I need to change the blue background to transparent, without unhiding the border-radius before it starts rotating.

Excuse the colors, these are not what I will be working with, but provide a clearer approach to the issue.

This is my temporary product where I have to remove the draw to accomplish the transparency. http://jsfiddle.net/BuzzSmarter/gmvban4p/

BuzzSmarter
  • 291
  • 2
  • 4
  • 7
  • related http://stackoverflow.com/questions/23385924/css-animate-circle-border-filling-with-color – Nikos M. Dec 20 '14 at 15:49
  • Thanks for the suggestion @NikosM. but the related question does not attempt to solve my question. I need the inner part of the circle to be transparent. The related question does not mention background transparency. – BuzzSmarter Dec 21 '14 at 18:17
  • Well i think you can use sth like the solution in that question and add any other content **inside** the animated circle (so it covers the background of the disc and only the perimeter is visible) – Nikos M. Dec 21 '14 at 19:01
  • i dont think it would be possible with current css only. Else you can use vector graphics in css like SVG and animate an arc in svg – Nikos M. Dec 21 '14 at 19:03

1 Answers1

60

This is my solution.

I set a background on body to show it is transparent

body {
  background: repeating-linear-gradient(45deg, white 0px, lightblue 100px);
  height: 500px;
  background-size: 500px 500px;
  background-repeat: no-repeat;
}

html {
  height: 100%;
}

#container {
  position: absolute;
  width: 400px;
  height: 400px;
   border: solid red 1px;
   animation: colors 4s infinite;
}

#halfclip {
  width: 50%;
  height: 100%;
  right: 0px;
  position: absolute;
   overflow: hidden;
   transform-origin: left center;
   animation: cliprotate 16s steps(2) infinite;
   -webkit-animation: cliprotate 16s steps(2) infinite;
}

.halfcircle {
  box-sizing: border-box;
  height: 100%;
  right: 0px;
  position: absolute;
  border: solid 25px transparent;
   border-top-color: blue;
   border-left-color: blue;
   border-radius: 50%;
}
#clipped {
  width: 200%;
   animation: rotate 8s linear infinite;
   -webkit-animation: rotate 8s linear infinite;
}
#fixed {
  width: 100%;
    transform: rotate(135deg);  
   animation: showfixed 16s steps(2) infinite;
   -webkit-animation: showfixed 16s linear infinite;
}

@-webkit-keyframes cliprotate {
  0% {transform: rotate(0deg);}
  100% {transform: rotate(360deg);}
}

@keyframes cliprotate {
  0% {transform: rotate(0deg);}
  100% {transform: rotate(360deg);}
}


@-webkit-keyframes rotate {
  0% {transform: rotate(-45deg);}
  100% {transform: rotate(135deg);}
}

@keyframes rotate {
  0% {transform: rotate(-45deg);}
  100% {transform: rotate(135deg);}
}

@-webkit-keyframes showfixed {
  0% {opacity: 0;}
  49.9% {opacity: 0;}
  50% {opacity: 1;}
 100% {opacity: 1;}
}
<div id="container">
    <div id="halfclip">
        <div class="halfcircle" id="clipped">
        </div>
    </div>
    <div class="halfcircle" id="fixed">
    </div>
</div>

And this is a variation on the solution, to make it run only once on hover

body {
  background: repeating-linear-gradient(45deg, white 0px, lightblue 100px);
  height: 500px;
  background-size: 500px 500px;
  background-repeat: no-repeat;
}

html {
  height: 100%;
}

#container {
  position: absolute;
  width: 300px;
  height: 300px;
   border: solid red 1px;
}

#halfclip {
    width: 50%;
    height: 100%;
    right: 0px;
    position: absolute;
    overflow: hidden;
    transform-origin: left center;
}

#container:hover #halfclip {
    animation: cliprotate 6s 1;
    transform: rotate(180deg);
} 

@keyframes cliprotate {
  0% {transform: rotate(0deg);}
  50% {transform: rotate(0deg);}
  50.01% {transform: rotate(180deg);}
  100% {transform: rotate(180deg);}
}

.halfcircle {
  box-sizing: border-box;
  height: 100%;
  right: 0px;
  position: absolute;
  border: solid 25px transparent;
   border-top-color: blue;
   border-left-color: blue;
   border-radius: 50%;
}

#clipped {
    width: 200%;
    transform: rotate(-45deg);
}
#container:hover #clipped {
    transform: rotate(135deg);
    animation: rotate 3s linear 2;
}


@keyframes rotate {
  0% {transform: rotate(-45deg);}
  100% {transform: rotate(135deg);}
}


#fixed {
  width: 100%;
    transform: rotate(135deg);  
    opacity: 0;
}

#container:hover #fixed {
    opacity: 1;
    animation: showfixed 6s 1;
}



@keyframes showfixed {
  0% {opacity: 0;}
  49.99% {opacity: 0;}
  50% {opacity: 1;}
 100% {opacity: 1;}
}
<div id="container">
    <div id="halfclip">
        <div class="halfcircle" id="clipped">
        </div>
    </div>
    <div class="halfcircle" id="fixed">
    </div>
</div>
vals
  • 61,425
  • 11
  • 89
  • 138
  • Exactly what I was looking for. Curious as to why it hasn't been marked as answer. –  Mar 12 '15 at 20:21
  • Wow this is awesome and exactly what i was looking for. How would you go about making this run only once, and when completed stay as a full circle? I tried to develop a way using javascript event listener to listen for when the animation is complete and rotate the half circle accordingly to get the full circle, but the problem I'm having is there is some lag time for when the event hits and the javascript to run the transform.... the animation will complete, then the css will give it's initial values, then after a second or two the javascript will run and the circle look whole – nyduss Sep 05 '15 at 02:30
  • 1
    @nyduss I have added another example, based on changing the properties on hover of the container, and running only once the animation – vals Sep 05 '15 at 19:41
  • So i took all of this a step further added some cool new features. I added a track and some buttons to control the animations play state with jquery. Here's a link to all new stuff i was "fiddling" with https://jsfiddle.net/3hwoxxpp/ sorry if the animation doesnt work with your browser... i only added the webkit animation cause im kind of lazy >.< Enjoy! – nyduss Sep 08 '15 at 22:39
  • this is great (I'm playing with this on codepen trying to understand what is happening here); – L777 Mar 30 '16 at 14:09
  • it became easier to understand with these colors/outlines: [codepen link](http://codepen.io/freestock/pen/qZXoOq?editors=1100) – L777 Mar 30 '16 at 14:20