How to set starting point for SVG path - css
I'm working on an animated loading animation. I have 3 shapes that I want to follow a path and scale in size as they move along the path. The 3 shapes will follow a similar path but from different starting points. I created the shapes and paths in Illustrator and exported SVGs. Here's an example of the largest shape and its path.
My issue is without spending all day with trial and error changing the path points order, is there an easier way to set the starting point? My shape starts at the wrong point as you can see in this image.
.loading-wrap {
width:200px;
height:200px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.cir-3 {
width:50px;
height:50px;
border-radius: 50%;
background:cornflowerblue;
position: absolute;
top: 30%;
left: 30%;
offset-path: path("M147.33,108.45A49.76,49.76,0,0,0,97.57,58.69c-22.33,0-45.32,20.86-47.52,35-1.46,4.68-2.23,19.13,61,21.5-.79,14.37-43.76,9.63-61.5,6.39a49.77,49.77,0,0,0,97.78-13.09Z");
animation: move 3s ease-in-out infinite reverse;
}
#keyframes move {
100% {
offset-distance: 100%;
}
}
<div class="loading-wrap">
<div class="cir-1"></div>
<div class="cir-2"></div>
<div class="cir-3"></div>
</div>
EDIT: created a codepen https://codepen.io/CodeFreeze/pen/JjGNLRN
My solution is using 3 different animations for every div. Every div has a different initial offset-distance and the offset-distance is animated to a different value.
.loading-wrap {
width:100px;
height:100px;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border:1px solid silver;
position:absolute;
}
test{position:relative;}
.test div{
position:absolute;
offset-path: path("M97.78,49.76a49.76,49.76,0,0,0,-49.76,-49.76c-22.33,0,-45.32,20.86,-47.52,35c-1.46,4.68,-2.23,19.13,61,21.5c-0.79,14.37,-43.76,9.63,-61.5,6.39a49.77,49.77,0,0,0,97.78,-13.09z");
}
.cir-1 {
width:20px;
height:20px;
border-radius: 50%;
background:rgb(119, 30, 30);
animation: move 3s ease-in-out infinite;
}
.cir-2 {
width:30px;
height:30px;
border-radius: 50%;
background-color: blueviolet;
offset-distance: 10%;
animation: move2 3s ease-in-out infinite;
}
.cir-3 {
width:50px;
height:50px;
border-radius: 50%;
background:cornflowerblue;
offset-distance: 20%;
animation: move3 3s ease-in-out infinite;
}
#keyframes move {
100% {
offset-distance: 100%;
}
}
#keyframes move2 {
100% {
offset-distance: 110%;
}
}
#keyframes move3 {
100% {
offset-distance: 120%;
}
}
svg{position:absolute;}
<div class="loading-wrap">
<svg viewBox="0 0 100 100">
<path d="M97.78,49.76a49.76,49.76,0,0,0,-49.76,-49.76c-22.33,0,-45.32,20.86,-47.52,35c-1.46,4.68,-2.23,19.13,61,21.5c-0.79,14.37,-43.76,9.63,-61.5,6.39a49.77,49.77,0,0,0,97.78,-13.09z" fill="none" stroke="black"/>
</svg>
<div class="test">
<div class="cir-1"></div>
<div class="cir-2"></div>
<div class="cir-3"></div>
</div>
</div>
UPDATE
If you need the animation to run the other way round you have 2 solution:
You reverse the svg path, meaning that yoy are using this path M97.78,49.76L97.78,49.8A49.77,49.77 0 0 10,62.89C17.74,66.13 60.71,70.87 61.5,56.5C-1.73,54.123 -0.96,39.68 0.5,35C2.7,20.86 25.69,0 48.02,0A49.76,49.76 0 0 197.78,49.76z instead.
.loading-wrap {
width:100px;
height:100px;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
position:absolute;
border:1px solid silver;
}
test{position:relative;}
.test div{
position:absolute;
offset-path: path("M97.78,49.76L97.78,49.8A49.77,49.77 0 0 10,62.89C17.74,66.13 60.71,70.87 61.5,56.5C-1.73,54.123 -0.96,39.68 0.5,35C2.7,20.86 25.69,0 48.02,0A49.76,49.76 0 0 197.78,49.76z");
}
.cir-1 {
width:20px;
height:20px;
border-radius: 50%;
background:rgb(119, 30, 30);
animation: move 3s ease-in-out infinite;
}
.cir-2 {
width:30px;
height:30px;
border-radius: 50%;
background-color: blueviolet;
offset-distance: 10%;
animation: move2 3s ease-in-out infinite;
}
.cir-3 {
width:50px;
height:50px;
border-radius: 50%;
background:cornflowerblue;
offset-distance: 20%;
animation: move3 3s ease-in-out infinite;
}
#keyframes move {
100% {
offset-distance: 100%;
}
}
#keyframes move2 {
100% {
offset-distance: 110%;
}
}
#keyframes move3 {
100% {
offset-distance: 120%;
}
}
svg{position:absolute;}
<div class="loading-wrap">
<svg viewBox="0 0 100 100">
<path d="M97.78,49.76L97.78,49.8A49.77,49.77 0 0 10,62.89C17.74,66.13 60.71,70.87 61.5,56.5C-1.73,54.123 -0.96,39.68 0.5,35C2.7,20.86 25.69,0 48.02,0A49.76,49.76 0 0 197.78,49.76z" fill="none" stroke="black"/>
</svg>
<div class="test">
<div class="cir-1"></div>
<div class="cir-2"></div>
<div class="cir-3"></div>
</div>
</div>
You can use the same path but you animate the divs to negative offset distances.
.loading-wrap {
width:100px;
height:100px;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border:1px solid silver;
position:absolute;
}
test{position:relative;}
.test div{
position:absolute;
offset-path: path("M97.78,49.76a49.76,49.76,0,0,0,-49.76,-49.76c-22.33,0,-45.32,20.86,-47.52,35c-1.46,4.68,-2.23,19.13,61,21.5c-0.79,14.37,-43.76,9.63,-61.5,6.39a49.77,49.77,0,0,0,97.78,-13.09z");
}
.cir-1 {
width:20px;
height:20px;
border-radius: 50%;
background:rgb(119, 30, 30);
animation: move 3s ease-in-out infinite;
}
.cir-2 {
width:30px;
height:30px;
border-radius: 50%;
background-color: blueviolet;
offset-distance: -10%;
animation: move2 3s ease-in-out infinite;
}
.cir-3 {
width:50px;
height:50px;
border-radius: 50%;
background:cornflowerblue;
offset-distance: -20%;
animation: move3 3s ease-in-out infinite;
}
#keyframes move {
100% {
offset-distance: -100%;
}
}
#keyframes move2 {
100% {
offset-distance: -110%;
}
}
#keyframes move3 {
100% {
offset-distance: -120%;
}
}
svg{position:absolute;}
<div class="loading-wrap">
<svg viewBox="0 0 100 100">
<path d="M97.78,49.76a49.76,49.76,0,0,0,-49.76,-49.76c-22.33,0,-45.32,20.86,-47.52,35c-1.46,4.68,-2.23,19.13,61,21.5c-0.79,14.37,-43.76,9.63,-61.5,6.39a49.77,49.77,0,0,0,97.78,-13.09z" fill="none" stroke="black"/>
</svg>
<div class="test">
<div class="cir-1"></div>
<div class="cir-2"></div>
<div class="cir-3"></div>
</div>
</div>
Related
How to make an animate progress bar with startup animation using css
I am trying to implement an animated progress bar with startup animation. The problem is that I am using transform: translateX(-100%); that make ugly effect - progress bar is outside progress area. Core: #keyframes slideInFromLeft { 0% { transform: translateX(-100%); } 100% { transform: translateX(0); } } .progress { width:200px; height:50px; border:1px solid black; position:relative; } .child { background:black; width: 50%; height: 100%; animation: 1s ease-out 0s 1 slideInFromLeft; } <div class="progress"> <div class="child">x</div> </div> How can I fix this ugly effect? Or is there any better way?
Have a look at CSS position property, you need position relative and position absolute. Then the animation-fill-mode forwards The target will retain the computed values set by the last keyframe encountered during execution. The last keyframe depends on the value of animation-direction and animation-iteration-count: #keyframes slideInFromLeft { to{ width: 50%; } } .progress { width:200px; height:50px; border:1px solid black; position:relative; } .child { position:absolute; left:0; top:0; background:black; width: 0%; height: 100%; overflow:hidden; animation: slideInFromLeft 1s ease forwards; } <div class="progress"> <div class="child">x</div> </div> Now if you want to animate it using translate you have to add overflow:hidden to the parent element #keyframes slideInFromLeft { from { transform: translateX(-100%); } } .progress { width:200px; height:50px; border:1px solid black; position:relative; overflow:hidden } .child { background:black; width: 50%; height: 100%; transform: translateX(0%); animation: slideInFromLeft 1s ease; } <div class="progress"> <div class="child">x</div> </div>
Try this!! #keyframes slideInFromLeft { 0% { width: 0; /*transform: translateX(-100%);*/ } 100% { width: 90%; /*transform: translateX(0);*/ } } .progress { width:200px; height:50px; border:1px solid black; position:relative; overflow:hidden; } .child { background:black; width: 90%; height: 100%; animation: 1s ease-out 0s 1 slideInFromLeft; } Using CSS transition and Jquery <div class="progress"> <div class="child">x</div> </div> .progress { width: 200px; height: 50px; border: 1px solid black; position: relative; overflow: hidden; } .child { background: black; width: 0; height: 100%; transition: width 2s; } You can set de progress using this jquery code. $(".child").css('width','50%');
Animated dots with css, making them move forever
I can't seem to make this animation move forever without adding more dots in span. I would like the amount of dots not to be dependent on the "loading-dots" class, as it is adding more dots increases the duration but its a pain. Could it be possible to have a single dot but animate it forever. I like the ability to change the speed and direction. Here's the CodePen * { box-sizing: border-box; } body { padding: 50px; background: white; } .container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px 20px 0px 20px; } .loading-container { overflow: hidden; float: left; width: 200px; } .loading-dots { display: inline-block; animation-name: loading-dots; animation-duration: 5s; animation-timing-function: linear; font-size: 50px; position: relative; top: -27px; color: rgba(blue, 1); font-family: sans-serif; white-space: no-wrap; } .loading-title { overflow: display; position: relative; font-size: 30px; top: 10px; margin-right: 10px; font-family: monospace; color: rgba(white, 1); float: left; } #keyframes loading-dots { 0% { transform: translateX(-600px); } 100% { transform: translateX(0px); } } <div class="container"> <span class="loading-title"></span> <div class="loading-container"> <span class="loading-dots">................. </span> </div> </div>
You can do this with a simple background where it will be easy to control the animation and also the dimension of your dots: .dots { height:5px; /*to control the overall height*/ width:200px; /*to control the overall width*/ margin:50px; background-image: repeating-linear-gradient(to right, transparent,transparent 5px, /*5px of transparent*/ blue 5px,blue 10px); /*then 5px of blue */ background-size:200% 100%; animation:change 3s linear infinite; } #keyframes change{ to { background-position:right; } } <div class="dots"></div> To change the direction you simply change the position: .dots { height:5px; width:200px; margin:50px; background-image: repeating-linear-gradient(to right, transparent,transparent 5px, blue 5px,blue 10px); background-size:200% 100%; background-position:right; animation:change 3s linear infinite; } #keyframes change{ to { background-position:left; } } <div class="dots"></div> You can check this for more details about the different values used: Using percentage values with background-position on a linear gradient Another idea using animation on transform : .dots { height:5px; width:200px; margin:50px; position:relative; overflow:hidden; } .dots::before { content:""; position:absolute; top:0; left:0; right:-100%; bottom:0; background-image: repeating-linear-gradient(to right, transparent,transparent 5px, blue 5px,blue 10px); animation:change 3s linear infinite; } #keyframes change{ to { transform:translateX(-50%); } } <div class="dots"></div> Changing the direction: .dots { height:5px; width:200px; margin:50px; position:relative; overflow:hidden; } .dots::before { content:""; position:absolute; top:0; left:-100%; right:0; bottom:0; background-image: repeating-linear-gradient(to right, transparent,transparent 5px, blue 5px,blue 10px); animation:change 3s linear infinite; } #keyframes change{ to { transform:translateX(50%); } } <div class="dots"></div>
Reduce the negative pixel margin. -600px is pretty excessive for 16 dots. #keyframes loading-dots { 0% { transform: translateX(-50px); } 100% { transform: translateX(0px); } }
Is it possible to make CSS Pie timer run only once?
I use CSS Pie Timer, and I struggle to make my pie loading animation run only once. The order I want the animation to be in: the circle is not shown the circle is starting to fill up with a border color the circle get filled fully the circle stays filled (and doesn't repeat) Demo here <div class="wrapper"> <div class="pie spinner"></div> <div class="pie filler"></div> <div class="mask"></div> </div> Help will be appreciated!
You just have to remove animation-iteration-count - infinite and add animation-fill-mode as forwards. Here is the working code .wrapper { position: relative; margin: 40px auto; background: white; } .wrapper, .wrapper * { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } .wrapper { width: 250px; height: 250px; } .wrapper .pie { width: 50%; height: 100%; transform-origin: 100% 50%; position: absolute; background: #08C; border: 5px solid rgba(0,0,0,0.5); } .wrapper .spinner { border-radius: 100% 0 0 100% / 50% 0 0 50%; z-index: 200; border-right: none; animation: rota 5s linear forwards; } .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; z-index: 100; animation: opa 5s steps(1, end) forwards reverse; border-left: none; } .wrapper .mask { width: 50%; height: 100%; position: absolute; background: inherit; opacity: 1; z-index: 300; animation: opa 5s steps(1, end) forwards; } #keyframes rota { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } #keyframes opa { 0% { opacity: 1; } 50%, 100% { opacity: 0; } } <div class="wrapper"> <div class="pie spinner"></div> <div class="pie filler"></div> <div class="mask"></div> </div>
CSS Animation, hide overflow for initial part of animation
I am trying to create a CSS animation where I have a frame with a background image, then I have a crane that needs to slide into the frame from the bottom, so for that I would need overflow:hidden; so that you can't see the crane sliding into the frame. But then after it slides up into the frame, I need the arm of the crane to rotate down and extend out of the frame. However, since I have overflow:hidden; for the first part of the animation, I'm not sure how to make the second part work. Here's what I have so far: .frame { width:600px; height:300px; background:url('http://placehold.it/600x300'); overflow:hidden; } .crane-container { position:relative; } .crane { position:absolute; bottom:-500px; right:100px; height:200px; width:50px; animation:slideUp 3s ease-in-out; animation-fill-mode: forwards; } .arm { height:200px; width:50px; background:#000; animation:rotateArm 4s ease-in-out; animation-fill-mode: forwards; animation-delay: 3s; transform-origin:bottom left; } #keyframes slideUp { 0% { bottom: -500px; } 100% { bottom: -300px; } } #keyframes rotateArm { 0% { transform: rotate(0deg); } 100% { transform: rotate(-120deg); } } <div class="frame"> <div class="crane-container"> <div class="crane"> <div class="arm"></div> </div> </div> </div>
Think differently and instead of animating position you can animate the height and you don't need the overflow. Have a look: .frame { width: 600px; height: 300px; background: url('http://placehold.it/600x300'); overflow: visible; } .crane-container { position: relative; height:100%; } .crane { position: absolute; bottom: 0; right: 100px; height: 0; width: 50px; animation: slideUp 3s ease-in-out; animation-fill-mode: forwards; } .arm { height: 100%; width: 100%; background: #000; animation: rotateArm 4s ease-in-out; animation-fill-mode: forwards; animation-delay: 3s; transform-origin: bottom left; } #keyframes slideUp { 0% { height: 0; } 100% { height: 200px; } } #keyframes rotateArm { 0% { transform: rotate(0deg); } 100% { transform: rotate(-120deg); } } #keyframes over { 0%,100% { overflow:visible; } } <div class="frame"> <div class="crane-container"> <div class="crane"> <div class="arm"></div> </div> </div> </div>
Drawing animated arc with pure CSS
I know it is possible to draw and animate arcs in SVG and canvas. However, is it possible in CSS? I have created an arc using the following method: .arc{ width:150px; height:400px; border-radius:50%; border-right:1px solid black; border-left:1px solid black; border-top:1px solid black; border-bottom:1px solid white; } But, how can I animate this? The only way I can think of is having a pure white div over it and sliding that div to the right gradually revealing the arc. Is there a better way?
Here is working demo with minimum of hard-coded variables. This works based on animated circle halves: .circle { display: inline-flex; overflow: hidden; } .circle__half { height: 200px; width: 100px; position: relative; overflow: hidden; } .circle__half:before { height: inherit; width: inherit; position: absolute; content: ""; border-radius: 100px 0 0 100px; background-color: lime; transform-origin: 100% 50%; /* hidden by default */ transform: rotate(180deg); opacity: 0.65; animation-name: rotate-circle-half; animation-duration: 4s; animation-timing-function: linear; animation-iteration-count: infinite; } .circle__half--right { transform: scale(-1, -1); } .circle .circle__half--right:before { animation-name: rotate-circle-half--right; } /* show half of circle half of the time */ #keyframes rotate-circle-half { 0% { transform: rotate(180deg); } 50% { transform: rotate(0deg); } 100% { transform: rotate(0deg); } } #keyframes rotate-circle-half--right { 0% { transform: rotate(180deg); } 50% { transform: rotate(180deg); } 100% { transform: rotate(0deg); } } <div class="circle"> <div class="circle__half"></div> <div class="circle__half circle__half--right"></div> </div> Also the same look as iConnor's answer but doesn't have drawback of hardcoded background-color: *, *:before, *:after { box-sizing: border-box; } .circle { display: inline-flex; overflow: hidden; } .circle__half { height: 200px; width: 100px; position: relative; overflow: hidden; } .circle__half:before { height: inherit; width: inherit; position: absolute; content: ""; border-radius: 100px 0 0 100px; border: 10px solid #00507c; border-right-color: transparent; background-color: #0087cf; transform-origin: 100% 50%; /* hidden by default */ transform: rotate(180deg); opacity: 0.65; animation-name: rotate-circle-half; animation-duration: 4s; animation-timing-function: linear; animation-iteration-count: infinite; } .circle__half--right { transform: scale(-1, -1); } .circle .circle__half--right:before { animation-name: rotate-circle-half--right; } /* show half of circle half of the time */ #keyframes rotate-circle-half { 0% { transform: rotate(180deg); } 50% { transform: rotate(0deg); } 100% { transform: rotate(0deg); } } #keyframes rotate-circle-half--right { 0% { transform: rotate(180deg); } 50% { transform: rotate(180deg); } 100% { transform: rotate(0deg); } } <div class="circle"> <div class="circle__half"></div> <div class="circle__half circle__half--right"></div> </div>
If you need sole CSS3, then you can set a width+height, set border-radius to 100%, disable the extra borders (use only 1 or 2) and add some good pixels to it. Then you can animate using animate: time animation ease timingFunction; Declare the animation itself using #-prefix-keyframes { . . . } (Eh yea, looks like most browser engines require prefix for this one, chrome does :S) I think I might have something close to what you mean: .qLoader2 { border: 4px solid blue; width: 10vw; height: 10vw; width: 72px; height: 72px; position: absolute; top: 12vh; right: 45vw; left: 45vw; background: white; opacity: 0.45; border-right: none; border-top: none; border-left: none; z-index: 2000; background-color: transparent; border-radius: 100%; transform: rotateZ(0); -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite; } /* #-moz-keyframes spin { . . . } */ /* #-ms-keyframes spin { . . . } */ /* #-o-keyframes spin { . . . } */ #-webkit-keyframes spin { from { transform: rotateZ(0deg) scale(1); } 50% { transform: rotateZ(540deg) scale(0.9); border-color: #0099ff; } to { transform: rotateZ(1080deg) scale(1); } } #keyframes spin { from { transform: rotateZ(0deg) scale(1); } 50% { transform: rotateZ(540deg) scale(0.9); border-color: #0099ff; } to { transform: rotateZ(1080deg) scale(1); } } <div class="qLoader2"></div> On JSFiddle Feel free to use and modify. Alternatively you could check something with SVG it's fairly decent as well and supported by most nowadays browsers.
EDIT: Using two arcs, you can have the animation draw cleanly from left-to-right AND have the background show through: http://jsfiddle.net/sPv4A/6/ Vendor prefixes not included for CSS: .arcContain { width: 150px; height: 400px; position: relative; margin: 20px; } .arc { width: 150px; height: 400px; border-radius: 50%; border: 2px solid black; border-bottom: 2px solid transparent; position: absolute; top: 0; right: 0; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } .archideLeft .arc { top: auto; bottom: 0; right: auto; left: 0; } .archide { width: 50%; height: 0%; position: absolute; top: 0; right: 0; overflow: hidden; animation: appear 1.2s ease-in 1.2s forwards; } .archideLeft { top: auto; bottom: 0; right: auto; left: 0; animation: appear 1.2s ease-out forwards; } #keyframes appear { to { height: 100%; } } <div class="arcContain"> <div class="archide archideLeft"> <div class="arc"></div> </div> <div class="archide"> <div class="arc"></div> </div> </div> OLD ANSWER: Maybe using two child divs to cover it up, and then have them shrink away to reveal it: .arc { width: 150px; height: 400px; border-radius: 50%; border-right: 1px solid black; border-left: 1px solid black; border-top: 1px solid black; border-bottom: 1px solid white; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; position: relative; } .arcInner { background: white; height: 402px; width: 77px; position: absolute; } .arcLeft { top: -2px; left: -2px; -webkit-transition: height 2s linear; -moz-transition: height 2s linear; -ms-transition: height 2s linear; -o-transition: height 2s linear; transition: height 2s linear; } .arcRight { bottom: 0; right: -2px; -webkit-transition: height 2s 2s linear; -moz-transition: height 2s 2s linear; -ms-transition: height 2s 2s linear; -o-transition: height 2s 2s linear; transition: height 2s 2s linear; } .appear .arcInner { height: 0; } <div class="arc"> <div class="arcInner arcLeft"></div> <div class="arcInner arcRight"></div> </div>
As Per Chris B's suggestion on the original question, the answer is to contain the arc in another div and then animate the width of the container: http://jsfiddle.net/AZb3X/ CSS: body{ background:orange; } .arc{ width:150px; height:400px; border-radius:50%; border-right:1px solid black; border-left:1px solid black; border-top:1px solid black; border-bottom:1px solid white; float:left; } .hider{ width:0px; overflow:hidden; -webkit-animation:unhide 12s; } #-webkit-keyframes unhide{ 100%{width:400px} } HTML: <div class='hider'> <div class="arc"></div> </div>
I may be a little late, but I think using two "hiders" and translating one up and one down will look a little better. Working Example <div class="wrap"> <div class="arc"></div> </div> body { background:orange; } .wrap { position:absolute; height:400px; width:170px; overflow: hidden; } .arc { position:absolute; width:150px; height:400px; margin:10px; border-radius:50%; border-right:1px solid black; border-left:1px solid black; border-top:1px solid black; border-bottom:1px solid transparent; } .arc:before { content:""; position:absolute; left:-1px; top:-2px; background: orange; width:76px; height:375px; animation:unhide1 5s linear both; } .arc:after { content:""; position:absolute; left:75px; top:-2px; background: orange; float: right; width:76px; height:375px; animation: unhide2 5s linear 5s both; } #keyframes unhide1 { 100% { transform: translatey(-375px); } } #keyframes unhide2 { 100% { transform: translatey(375px); } }