-->

Why doesn't this radial-gradient complete the

2020-03-03 04:59发布

问题:

I'm trying to use a radial gradient to create a border within circle elements that are radio buttons. The basic CSS is shown below. I cannot figure out why the red gradient does not circle the entire circumference of the circles.

As the white color-stop approaches 100%, gaps appear in the red at the top, right, left, and bottom.

Why does this happen, and how would I fix it while still using a radial gradient?

.container {
  background: #ddd;
  width: 400px;
  height: 200px;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 2px solid transparent;
  width: 20px;
  height: 20px;
  margin-right: 20px;
}

.radio1 { background: radial-gradient(circle closest-side, white 75%, red 100%); }
.radio2 { background: radial-gradient(circle closest-side, white 90%, red 100%); }
.radio3 { background: radial-gradient(circle closest-side, white 95%, red 100%); }
.radio4 { background: radial-gradient(circle closest-side, white 99%, red 100%); }
<div class="container">
  <div class="radio"></div>
  <div class="radio radio1"></div>
  <div class="radio radio2"></div>
  <div class="radio radio3"></div>
  <div class="radio radio4"></div>
</div>

Also on JSFiddle: https://jsfiddle.net/zvgcs80f/

回答1:

Your percentage will be converted to pixel relatively to the width/height of your element. In your case, your element is small thus 99% and 100% will most likely be converted to the same value or very close values and you will have subpixel rendring issue.

Instead you can rely on calc() where you can easily define the thickness as a pixel value independently of the element size.

You need to also adjust background-origin and make it border-box so that you draw the gradient considering the border area and you will have a perfect circle.

.container {
  background: #ddd;
  width: 400px;
  height: 200px;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 2px solid transparent;
  width: 20px;
  height: 20px;
  margin-right: 20px;
  background-origin:border-box;
}

.radio1 { background-image: radial-gradient(circle closest-side, white calc(100% - 1px), red 100%); }
.radio2 { background-image: radial-gradient(circle closest-side, white calc(100% - 2px), red 100%); }
.radio3 { background-image: radial-gradient(circle closest-side, white calc(100% - 3px), red 100%); }
.radio4 { background-image: radial-gradient(circle closest-side, white calc(100% - 4px), red 100%); }
<div class="container">
  <div class="radio"></div>
  <div class="radio radio1"></div>
  <div class="radio radio2"></div>
  <div class="radio radio3"></div>
  <div class="radio radio4"></div>
</div>


Here is an example with big values of border to better illustrate the issue related to background-origin

.container {
  background: #ddd;
  width: 400px;
  height: 200px;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 20px solid rgba(0,0,0,0.2);
  width: 50px;
  height: 50px;
  margin-right: 20px;
 background-image: radial-gradient(circle closest-side, white calc(100% - 4px), red 100%); }
<div class="container">
  <div class="radio radio4"></div>
</div>

The background is drawn on the padding box then it's getting repeated over all the area (border box).

If you disable the repeat you will have this:

.container {
  background: #ddd;
  width: 400px;
  height: 200px;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 20px solid rgba(0,0,0,0.2);
  width: 50px;
  height: 50px;
  margin-right: 20px;
 background-image: radial-gradient(circle closest-side, white calc(100% - 4px), red 100%); 
  background-repeat:no-repeat;
 }
<div class="container">
  <div class="radio"></div>
</div>

Here is if we repeat only on the X axis

.container {
  background: #ddd;
  width: 400px;
  height: 200px;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 20px solid rgba(0,0,0,0.2);
  width: 50px;
  height: 50px;
  margin-right: 20px;
 background-image: radial-gradient(circle closest-side, white calc(100% - 4px), red 100%); 
  background-repeat:repeat-x;
 }
<div class="container">
  <div class="radio"></div>
</div>

And here is what is happening when using 100% for both colors which is similar to your situation and you will better understand why you have coloration only on the corners.

.container {
  background: #ddd;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 20px solid rgba(0, 0, 0, 0.2);
  width: 50px;
  height: 50px;
  margin-right: 20px;
  background-image: radial-gradient(circle closest-side, white 100%, red 100%);
}

.one {
  background-repeat: no-repeat;
}

.two {
  background-repeat: repeat;
}

.three {
  border-width: 5px;
}
.four {
  width:20px;
  height:20px;
  border-width: 2px;
}
<div class="container">
  <div class="radio one"></div>
  <div class="radio two"></div>
  <div class="radio three"></div>
  <div class="radio four"></div>
</div>


And if we change the origin it's fine:

.container {
  background: #ddd;
  width: 400px;
  height: 200px;
  padding: 20px;
}

.radio {
  display: inline-block;
  background: white;
  border-radius: 50%;
  border: 20px solid rgba(0,0,0,0.2);
  width: 50px;
  height: 50px;
  margin-right: 20px;
 background-image: radial-gradient(circle closest-side, white calc(100% - 4px), red 100%); 
  background-origin:border-box;
 }
<div class="container">
  <div class="radio"></div>
</div>