使用纯 CSS 绘制动画弧

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18835477/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 00:24:46  来源:igfitidea点击:

Drawing animated arc with pure CSS

cssanimationcss-shapes

提问by Conqueror

I know it is possible to draw and animate arcs in svg and canvas. However, is it possible in css?

我知道可以在 svg 和 canvas 中绘制弧线并为其设置动画。但是,在 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;
}

Original Fiddle: http://jsfiddle.net/YGKWT/(Broken link)

原始小提琴:http: //jsfiddle.net/YGKWT/(断开的链接)

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?

但是,我怎样才能动画这个?我能想到的唯一方法是在它上面放一个纯白色的 div 并将该 div 向右滑动,逐渐显露弧线。有没有更好的办法?

Edit:

编辑:

Here is the type of animation I am looking for: http://jsfiddle.net/nQLY7/(Broken link)

这是我正在寻找的动画类型:http: //jsfiddle.net/nQLY7/(断开的链接)

回答by iConnor

You might want to check out this article, Chris Coyier has done a article on pie chart animation which is basically the same as your demo if you remove the light blue background.enter image description here

你可能想看看这篇文章,Chris Coyier 写了一篇关于饼图动画的文章,如果你去掉浅蓝色背景,它与你的演示基本相同。在此处输入图片说明

Article: http://css-tricks.com/css-pie-timer/

文章:http: //css-tricks.com/css-pie-timer/

Demo: http://codepen.io/HugoGiraudel/pen/BHEwo

演示:http: //codepen.io/HugoGiraudel/pen/BHEwo

回答by Vadim Ovchinnikov

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 answerbut doesn't have drawback of hardcoded background-color:

外观与iConnor 的答案相同,但没有硬编码的缺点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>

回答by Felype

If you need sole CSS3, then you can set a width+height, set border-radiusto 100%, disable the extra borders (use only 1 or 2) and add some good pixels to it.

如果您需要单独的 CSS3,那么您可以设置一个width+ height,设置border-radius100%,禁用额外的边框(仅使用 1 或 2)并为其添加一些好的像素。

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:

然后你可以使用animate: time animation ease timingFunction;声明动画本身来制作动画@-prefix-keyframes { . . . }(嗯,是的,看起来大多数浏览器引擎都需要这个前缀,chrome确实:S)我想我可能有一些接近你的意思:

.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

在 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.

随意使用和修改。或者,您可以使用 SVG 检查某些内容,它也相当不错,并且受到当今大多数浏览器的支持。

回答by Ben Hymanson

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/

http://jsfiddle.net/sPv4A/6/

Vendor prefixes not included for CSS:

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:

旧答案:也许用两个孩子div来掩盖它,然后让他们缩小以显露它:

.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>

回答by Conqueror

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:

根据 Chris B 对原始问题的建议,答案是将弧包含在另一个 div 中,然后为容器的宽度设置动画:

http://jsfiddle.net/AZb3X/

http://jsfiddle.net/AZb3X/

CSS:

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:

HTML:

<div class='hider'>
    <div class="arc"></div>
</div>

回答by apaul

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);
    }
}