Рисуване на анимирана дъга с чист CSS

Знам, че е възможно да се рисуват и анимират дъги в svg и canvas. Възможно ли е обаче в css?

Създадох дъга, използвайки следния метод:

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

Оригинална цигулка: http://jsfiddle.net/YGKWT/ (Неработеща връзка)

Но как мога да анимирам това? Единственият начин, за който се сещам, е да имам чисто бял div над него и да плъзгам този div надясно, постепенно разкривайки дъгата. Има ли по-добър начин?

Редактиране:

Ето типа анимация, която търся: http://jsfiddle.net/nQLY7/ (Неработеща връзка)


person Conqueror    schedule 16.09.2013    source източник
comment
Не мисля, че е възможно да се направи чиста CSS дъга с дължина, която не е кратна на 90 градуса, освен като се покрие част от нея.   -  person SLaks    schedule 16.09.2013
comment
Добавих още една цигулка, за да покажа какво имам предвид   -  person Conqueror    schedule 16.09.2013
comment
Пример за jQuery, ако е необходимо jsfiddle.net/kevinPHPkevin/uhVj6/128   -  person Kevin Lynch    schedule 16.09.2013
comment
О, само CSS, без JS е ограничението   -  person Conqueror    schedule 16.09.2013
comment
Анимирайте ширината на съдържащия div, за да разкриете дъгата вътре в него.   -  person Chris Bier    schedule 17.09.2013
comment
+1 Крис Б за правилното решение   -  person Conqueror    schedule 17.09.2013


Отговори (6)


Може да искате да прегледате тази статия, Крис Койър е направил статия за анимация на кръгова диаграма, която по същество е същата като вашата демонстрация, ако премахнете светлосиния фон.въведете описание на изображението тук

Статия: http://css-tricks.com/css-pie-timer/

Демо: http://codepen.io/HugoGiraudel/pen/BHEwo

person iConnor    schedule 17.09.2013
comment
Няма да работи, ако задам фоново изображение на контейнер, напр. body. - person Vadim Ovchinnikov; 07.07.2017

Ето работеща демонстрация с минимум твърдо кодирани променливи. Това работи въз основа на анимирани половини на кръгове:

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

Също така изглежда по същия начин като отговора на 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>

person Vadim Ovchinnikov    schedule 07.07.2017
comment
това трябва да е приетият отговор, без разчитане на компас - person Pixelomo; 08.12.2017
comment
@Vadim : как да го завъртя по часовниковата стрелка?? - person Jyoti Duhan; 16.01.2018
comment
@JyotiDuhan Най-лесният начин е просто да добавите transform: scaleX(-1); към .circle, за да го обърнете хоризонтално. - person Vadim Ovchinnikov; 16.01.2018
comment
@VadimOvchinnikov : Благодаря Вадим. Наистина съм благодарен за бързия ви отговор. :) - person Jyoti Duhan; 16.01.2018

Ако имате нужда от единствен CSS3, тогава можете да зададете width+height, да зададете border-radius на 100%, да деактивирате допълнителните граници (използвайте само 1 или 2) и да добавите няколко добри пиксела към него.

След това можете да анимирате, като използвате 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>

В JSFiddle

Чувствайте се свободни да използвате и променяте. Като алтернатива можете да проверите нещо със SVG, той също е доста приличен и се поддържа от повечето съвременни браузъри.

person Felype    schedule 12.05.2015

РЕДАКТИРАНЕ: Използвайки две дъги, можете да накарате анимацията да рисува чисто отляво надясно И фонът да се показва през:

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

Префиксите на доставчика не са включени за 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>

СТАР ОТГОВОР: Може би с помощта на две дъщерни divs, за да го прикриете, и след това да ги накарате да се свият, за да го разкрият:

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

person Ben Jackson    schedule 16.09.2013
comment
Ще съм благодарен, ако използвате пълен CSS според въпроса. Освен това, това е значително по-сложно от оригиналния подход, но страда от същия проблем (работи само на същия цветен фон) - person Conqueror; 17.09.2013
comment
@Conqueror, току-що използвах JS като лесен начин за добавяне в класа appear, можете да го задействате от :hover или да използвате CSS анимации достатъчно лесно, за да избегнете JS. - person Ben Jackson; 17.09.2013

Според предложението на Chris B относно първоначалния въпрос, отговорът е да се съдържа дъгата в друг div и след това да се анимира ширината на контейнера:

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>
person Conqueror    schedule 16.09.2013

Може да съм малко закъснял, но мисля, че използването на два "скривателя" и превеждането на един нагоре и един надолу ще изглежда малко по-добре.

Работещ пример

<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);
    }
}
person apaul    schedule 17.09.2013