HTML5 / CSS3 带有部分边框的圆形

32

是否可能仅使用HTML5/CSS3创建一个圆形,其边框仅部分环绕圆形?如果不行,有哪些技术可以实现这种效果?我更喜欢使用纯DOM元素,但如果必须的话,我可以在画布上绘制或启动SVG。


“part way”是什么意思?1/4、1/2、3/4?还是更随意的数值? - ultranaut
一些可以顺畅地从0%到100%围绕圆圈进行动画的东西。 - knpwrs
8个回答

51

2023解决方案

这种方法不需要JS,不需要额外的元素,甚至不需要任何伪元素,只需要一些CSS声明。即使元素除了这部分的border还有一个(半)透明的background,这种方法也适用。

它使用了两层mask,其中一层是conic-gradient,用于创建可见的饼状选择区域,其大小相对于border-box,第二层是一个简单的全覆盖层,限制在padding-box内。

首先,我们将元素设置为圆形(任意的widthaspect-ratio1border-radius设置为50%),并给它添加一个border

然后,我们设置一个mask,它是一个相对于border-boxconic-gradient(),覆盖了我们元素的百分比--p(默认从12点钟开始,顺时针方向)。

在这个遮罩层之上,我们设置了一个完全覆盖的层,限制在padding-box内。

.circular-progress {
  border: solid 1.5em hotpink;
  width: 50vmin;
  aspect-ratio: 1;
  border-radius: 50%;
  background: hsla(180, 100%, 50%, .5);
  --mask: 
    linear-gradient(red, red) padding-box, 
    conic-gradient(red var(--p, 17%), transparent 0%) border-box;
  -webkit-mask: var(--mask);
          mask: var(--mask)
}

/* just to make it obvious it works with semitrasparent background */
body {
  background: 
    url(https://images.unsplash.com/photo-1693483923875-cdd9ef4a8046?w=800) 
      50%/ cover
}
<div class='circular-progress'></div>

如果我们想要给这个添加动画效果,我们还需要注册--p

@property --p {
  syntax: '<percentage>';
  initial-value: 0%;
  inherits: true
}

.circular-progress {
  border: solid 1.5em hotpink;
  width: 50vmin;
  aspect-ratio: 1;
  border-radius: 50%;
  background: hsla(180, 100%, 50%, .5);
  --mask: 
    linear-gradient(red, red) padding-box, 
    conic-gradient(red var(--p), transparent 0%) border-box;
  -webkit-mask: var(--mask);
          mask: var(--mask);
  animation: p 4s linear infinite
}

@keyframes p { to { --p: 100% } }

/* just to make it obvious it works with semitrasparent background */
body {
  background: 
    url(https://images.unsplash.com/photo-1693483923875-cdd9ef4a8046?w=800) 
      50%/ cover
}
<div class='circular-progress'></div>

这种方式注册自定义属性以便进行动画在Chromium浏览器和Safari中得到支持,并且在Firefox Nightly中也即将推出。

2012年的原始答案(为了网络历史记录而保留)

是的,这是可能的 - 参见以下内容:

.circle {
  position: relative;
  margin: 7em auto;
  width: 16em;
  height: 16em;
  border-radius: 50%;
  background: lightblue;
}

.arc {
  overflow: hidden;
  position: absolute;
  /* make sure top & left values are - the width of the border */
  /* the bottom right corner is the centre of the parent circle */
  top: -1em;
  right: 50%;
  bottom: 50%;
  left: -1em;
  /* the transform origin is the bottom right corner */
  transform-origin: 100% 100%;
  /* rotate by any angle */
  /* the skew angle is 90deg - the angle you want for the arc */
  transform: rotate(45deg) skewX(30deg);
}

.arc:before {
  box-sizing: border-box;
  display: block;
  border: solid 1em navy;
  width: 200%;
  height: 200%;
  border-radius: 50%;
  transform: skewX(-30deg);
  content: '';
}
<div class='circle'>
  <div class='arc'></div>
</div>


18
用这种方法无法制作N度弧,只能是90度、180度或270度。 - gkond
2
请原谅我的无知,但是您如何更改弧的长度?KPthunder 提到他希望能够平滑地将其从0-100%沿着圆圈进行动画处理。 - ghstcode
3
您需要改变斜角度数。斜角度数等于 90度-弧线角度。但是为了填满整个圆,需要使用多个元素。 - Ana
1
我无法使其正常工作。请问,为了让弧形在圆周上从0%平滑地动画到100%,我应该更改哪个参数? - asnov
一直在寻找一种方法使圆形边框的一半透明。这是我能找到的唯一有效的方法。谢谢。 - Devin Carpenter

15

有可能。

  • 使用 border-radius 绘制两个圆,在上方放置一个圆。
  • 通过改变 border-color 使两个圆的一个或多个弧形透明。
  • 使用 transform 旋转第二个圆,这样你就会得到所需大小的弧形。

这里是演示http://jsfiddle.net/kJXwZ/2/

.wrapper {
  position: relative;
  margin: 20px;
}

.arc {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  border-radius: 100%;
  border: 1px solid;
}

.arc_start {
  border-color: transparent red red red;
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
}

.arc_end {
  border-color: red red red transparent;
  -webkit-transform: rotate(75deg);
  -moz-transform: rotate(75deg);
  -ms-transform: rotate(75deg);
  -o-transform: rotate(75deg);
  transform: rotate(75deg);
}
<div class="wrapper">
  <div class="arc arc_start"></div>
  <div class="arc arc_end"></div>
</div>


2
使用这种方法,您无法获得小于1/4圆的部分,因为其中一个边框季度将始终显示... - Justin
真的,如果您使用背景颜色而不是“透明”来实现此效果,则可以减少不到1/4。 - Erica Stockwell-Alpert

13

这也使用了JavaScript,因此它与原始要求不符 :(
但是它确实实现了目标。

这里有一个 >> 演示 <<

@gkond 谢谢,我从您的回答中得出了这个。

// create a circle using HTML5 / CSS3 / JS which has a border that only goes part-way around
// the circle .. and which can be smoothly animated from 0% to 100% around the circle

// this solution allows for animation and still results in relatively clean code
// we use four quarter-circles, all hidden away behind a white square to start with..
// all four are rotated out clockwise, and each quarter will stop at it's own maximum:
// q1 at 25%, q2 at 50% .. etc. once we reach a value at or over 25%, all four quarters
// should be out from behind the white square, and we can hide it.. it needs to be
// hidden if we display a value over 75%, or else q4 will end up going in behind it again
// .. also, since the top border will usually sit between the angles of  -45 to 45, we
// rotate everything by an extra -45 to make it all line up with the top nicely

var fromHidden = -90;

// utility function to align 0 degrees with top
// takes degrees and returns degrees - 45
function topAlign(degrees) {
  return degrees - 45
};

// utility function to rotate a jQuery element
// takes element and the degree of rotation (from the top) 
function rotate(el, degrees) {
  var degrees = topAlign(degrees || 0);
  el.css(
    'transform', 'rotate(' + degrees + 'deg)',
    '-webkit-transform', 'rotate(' + degrees + 'deg)',
    '-moz-transform', 'rotate(' + degrees + 'deg)',
    '-ms-transform', 'rotate(' + degrees + 'deg)',
    '-o-transform', 'rotate(' + degrees + 'deg)'
  )
}

// function to draw semi-circle
// takes a jQuery element and a value (between 0 and 1)
// element must contain four .arc_q elements
function circle(el, normalisedValue) {
  var degrees = normalisedValue * 360; // turn normalised value into degrees
  var counter = 1; // keeps track of which quarter we're working with
  el.find('.arc_q').each(function() { // loop over quarters..
    var angle = Math.min(counter * 90, degrees); // limit angle to maximum allowed for this quarter
    rotate($(this), fromHidden + angle); // rotate from the hiding place
    counter++; // track which quarter we'll be working with in next pass over loop
  });
  if (degrees > 90) { // hide the cover-up square soon as we can
    el.find('.arc_cover').css('display', 'none');
  }
}

// uses the the circle function to 'animate' drawing of the semi-circle
// incrementally increses the value passed by 0.01 up to the value required
function animate(el, normalisedValue, current) {
  var current = current || 0;
  circle(el, current);
  if (current < normalisedValue) {
    current += 0.01;
    setTimeout(function() {
      animate(el, normalisedValue, current);
    }, 1);
  }
}

// kick things off ..
animate($('.circle'), 0.69);
.circle {
  position: relative;
  margin: 20px;
  width: 120px;
  height: 120px;
}

.arc_q {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  border: 10px solid;
  border-color: transparent green transparent transparent;
  transform: rotate(-45deg);
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
}

.arc_cover {
  position: absolute;
  top: 0;
  left: 0;
  width: 60px;
  height: 60px;
  background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="circle">
  <div class="arc_q"></div>
  <div class="arc_q"></div>
  <div class="arc_q"></div>
  <div class="arc_q"></div>
  <div class="arc_cover"></div>
</div>


哦,太棒了 - 非常感谢!我刚在正在建设的网站上使用了它 - 将在代码中注明归属于您 :) - Abby Fichtner

5

锥形渐变解决方案(适用于任何角度):

:root{
--degree:80deg;
--smoothing:0.5deg;
--color:red;
}

.a{
  height:200px;
  width:200px;
border-radius:50%;
background: conic-gradient(
     var(--color) var(--degree), transparent calc(var(--degree) + var(--smoothing)) 100%);

}

.b{
  height:84%;
  width:84%;
  top:8%;
  left:8%;
  position:relative;
  border-radius:50%;
  background:#D3D3D3;
}
<div class ="a">
    <div class="b">
</div>


3

要实现这个,您可以使用简单的盒子边框属性、一个元素和一个类。这将是一个内联、内联块或块级处理,具体取决于您放置 easy-circle 类的位置以及如何/是否设置样式位置。

<!DOCTYPE html>
<html>
<head>
<style>
.easy-circle {
    background: transparent;
    border: 1em solid black; /* color not required, may show device fail */
    border-color: red green blue transparent;
    height: 10em;
    width: 10em;
    -moz-border-radius: 6em; /* height/2 + border thickness */
    -webkit-border-radius: 6em;
    border-radius: 50%; /* more than 50, shape-size adjustment irrelevant */
    -ms-transform: rotate(45deg); /* IE 9 */
    -webkit-transform: rotate(45deg); /* Chrome, Safari, Opera */
     transform: rotate(45deg); /* transform optional */
}
</style>
</head>
<body>
<div class="easy-circle">
</div>​
</body>
</html>

2

可以通过在透明圆周围设置透明边框,并使用 border-top-color: ; 为圆的一部分边框着色来实现此目标。

background-color:transparent;
border:3px solid transparent;
border-top-color: green;

这会创建一个只在顶部四分之一周围有边框的圆形;
你也可以使用

border-bottom-color:green;

除此之外,还可以使用左右边框来区分圆的周长的不同部分。

这里有一个示例,展示了在三个部分圆内相互交替地旋转,以显示其效果的加载器。

这是一个带有3个部分圆的加载器的示例,在其中它们相互交替地旋转。


0

最简单的动画方式是使用CSS关键帧。

http://jsfiddle.net/8SUPX/644/

/**
 * HTML5 / CSS3 Circle with Partial Border
 * https://dev59.com/Mmcs5IYBdhLWcg3wMhCz
 */
* { margin: 0; padding: 0; }
.circle {
 position: relative;
 margin: 6em auto;
 width: 12em; height: 12em;
 border-radius: 50%;
 background: transparent;
 border:20px solid #efefef;
 border-top-color: #efefef;
    border-right-color: #efefef;
    border-bottom-color: #efefef;
    border-left-color: #efefef;
    
    -webkit-transition:.5s;-moz-transition:.5s;transition:.5s;
}
.circle:hover{
      -webkit-animation:  animix 0.5s 1;
      -webkit-animation-fill-mode: forwards;
      -moz-animation:  animix 0.5s 1;
      -moz-animation-fill-mode: forwards;
      animation:  animix 0.5s 1;
      animation-fill-mode: forwards;
}



  //Animate
   @-webkit-keyframes animix {
    0% { 
      border-top-color: transparent;
      border-right-color: transparent;
      border-bottom-color: transparent;
      border-left-color: transparent;
    }
     25% { 
       border-top-color: red;
       border-right-color: transparent;
       border-bottom-color: transparent;
       border-left-color: transparent;
     }
     50% { 
       border-top-color: red;
       border-right-color: red;
       border-bottom-color: transparent;
       border-left-color: transparent;
     }
     75% { 
       border-top-color: red;
       border-right-color: red;
       border-bottom-color: red;
       border-left-color: transparent;
     }
     100% { 
       border-top-color: red;
       border-right-color: red;
       border-bottom-color: red;
       border-left-color: red;
     }
   }
   
      @keyframes animix {
    0% { 
      border-top-color: transparent;
      border-right-color: transparent;
      border-bottom-color: transparent;
      border-left-color: transparent;
    }
     25% { 
       border-top-color: red;
       border-right-color: transparent;
       border-bottom-color: transparent;
       border-left-color: transparent;
     }
     50% { 
       border-top-color: red;
       border-right-color: red;
       border-bottom-color: transparent;
       border-left-color: transparent;
     }
     75% { 
       border-top-color: red;
       border-right-color: red;
       border-bottom-color: red;
       border-left-color: transparent;
     }
     100% { 
       border-top-color: red;
       border-right-color: red;
       border-bottom-color: red;
       border-left-color: red;
     }
   }
<div class="circle"> </div>


0

if you want double border you can use it also

div
{
  background-color: #ddd;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 30px;
  margin:  40px auto;
  color: black; 
  width: 200px;
  height: 200px; 
  border-radius: 50%; 
  position: relative;
}

div::before
{ 
  content: "";
  width: 200px;
  height: 200px;
  border-radius: 50%;
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-10px, -10px);
  z-index: -1;
  border: 10px solid;
  border-color: red red red transparent;
}
body ::after
{
  content: "";
  width: 220px;
  height: 220px;
  border-radius: 50%;
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-21px, -22px);
  z-index: -8;
  border: 12px solid;
  background: transparent;
  border-color: blue transparent blue blue;
}
<div> </div>


这个很有用,为了缩小差距,你可以使用不同旋转的双圆。 - Biskrem Muhammad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接