答案 0 :(得分:23)
如果只有CSS或SVG具有锥形渐变,这将非常简单!在conic-gradient()
notation成熟并获得支持之前,我们可以通过切割渐变并以某种方式覆盖接缝来近似效果。
下面你会发现两个解决方案。第一个解决方案使用嵌入式SVG图像;第二个使用多个CSS渐变和伪元素。
两者都以单个div
开头,并应用了关键帧动画以使其旋转:
<强> HTML:强>
<div class="spinner"></div>
<强> CSS:强>
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: rotate 1s linear infinite;
height: 200px;
width: 200px;
}
如果您愿意,可以使用progress
元素,但您会发现风格很难。另请注意,除非您使用 prefixfree.js 之类的内容,否则您需要添加@keyframes
at-rule的供应商前缀版本和transform
以及animation
属性。
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: rotate 1s linear infinite;
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwLDAgMjAwLDIwMCI+PGRlZnM+PGNsaXBQYXRoIGlkPSJyaW5nIj48cGF0aCBkPSJNMjAwLDEwMEExMDAsMTAwLDAsMSwxLDE5Ny44MSw3OS4yMUwxODguMDMsODEuMjlBOTAsOTAsMCwxLDAsMTkwLDEwMHoiLz48L2NsaXBQYXRoPjxmaWx0ZXIgaWQ9ImJsdXIiIHg9IjAiIHk9IjAiPjxmZUdhdXNzaWFuQmx1ciBpbj0iU291cmNlR3JhcGhpYyIgc3RkRGV2aWF0aW9uPSIzIiAvPjwvZmlsdGVyPjxwYXRoIGlkPSJwIiBkPSJNMjUwLDEwMEExNTAsMTUwLDAsMCwxLDI0Ni43MiwxMzEuMTlMMTAwLDEwMEEwLDAsMCwwLDAsMTAwLDEwMHoiIGZpbGw9ImN5YW4iLz48L2RlZnM+PGcgY2xpcC1wYXRoPSJ1cmwoI3JpbmcpIj48ZyBmaWx0ZXI9InVybCgjYmx1cikiIHRyYW5zZm9ybT0icm90YXRlKC02IDEwMCAxMDApIj48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9IjAiIHRyYW5zZm9ybT0icm90YXRlKDAgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgdHJhbnNmb3JtPSJyb3RhdGUoMTIgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii4wNyIgdHJhbnNmb3JtPSJyb3RhdGUoMjQgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii4xIiB0cmFuc2Zvcm09InJvdGF0ZSgzNiAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjE0IiB0cmFuc2Zvcm09InJvdGF0ZSg0OCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjE3IiB0cmFuc2Zvcm09InJvdGF0ZSg2MCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjIiIHRyYW5zZm9ybT0icm90YXRlKDcyIDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuMjQiIHRyYW5zZm9ybT0icm90YXRlKDg0IDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuMjgiIHRyYW5zZm9ybT0icm90YXRlKDk2IDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuMzEiIHRyYW5zZm9ybT0icm90YXRlKDEwOCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjM0IiB0cmFuc2Zvcm09InJvdGF0ZSgxMjAgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii4zOCIgdHJhbnNmb3JtPSJyb3RhdGUoMTMyIDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuNDEiIHRyYW5zZm9ybT0icm90YXRlKDE0NCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjQ1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTYgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii40OCIgdHJhbnNmb3JtPSJyb3RhdGUoMTY4IDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuNTIiIHRyYW5zZm9ybT0icm90YXRlKDE4MCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjU1IiB0cmFuc2Zvcm09InJvdGF0ZSgxOTIgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii41OSIgdHJhbnNmb3JtPSJyb3RhdGUoMjA0IDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuNjIiIHRyYW5zZm9ybT0icm90YXRlKDIxNiAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjY2IiB0cmFuc2Zvcm09InJvdGF0ZSgyMjggMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii42OSIgdHJhbnNmb3JtPSJyb3RhdGUoMjQwIDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuNyIgdHJhbnNmb3JtPSJyb3RhdGUoMjUyIDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuNzIiIHRyYW5zZm9ybT0icm90YXRlKDI2NCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjc2IiB0cmFuc2Zvcm09InJvdGF0ZSgyNzYgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii43OSIgdHJhbnNmb3JtPSJyb3RhdGUoMjg4IDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuODMiIHRyYW5zZm9ybT0icm90YXRlKDMwMCAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iLjg2IiB0cmFuc2Zvcm09InJvdGF0ZSgzMTIgMTAwIDEwMCkiLz48dXNlIHhsaW5rOmhyZWY9IiNwIiBmaWxsLW9wYWNpdHk9Ii45MyIgdHJhbnNmb3JtPSJyb3RhdGUoMzI0IDEwMCAxMDApIi8+PHVzZSB4bGluazpocmVmPSIjcCIgZmlsbC1vcGFjaXR5PSIuOTciIHRyYW5zZm9ybT0icm90YXRlKDMzNiAxMDAgMTAwKSIvPjx1c2UgeGxpbms6aHJlZj0iI3AiIGZpbGwtb3BhY2l0eT0iMSIgdHJhbnNmb3JtPSJyb3RhdGUoMzQ4IDEwMCAxMDApIi8+PC9nPjwvZz48L3N2Zz4=') no-repeat;
height: 200px;
width: 200px;
}
<div class="spinner"></div>
在IE 10,Chrome和Firefox中经过测试和使用。
更改环的内半径或外半径比您想象的更痛苦,因为它需要编辑剪辑路径值。解释如何计算它不在这个答案的范围之内,但足以说它需要一些几何。如果我有时间的话,我会尝试在GitHub上放一个生成器。
这一大块乱码只是一个Base64编码的SVG图像。通过a Base64 decoder运行它,您将看到原始的SVG图像。
这里的完整图片很好地缩进和评论,因此您可以确切地看到它是如何工作的:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0 200,200">
<defs>
<!-- Ring shape centred on 100, 100 with inner radius 90px, outer
radius 100px and a 12 degree gap at 348. -->
<clipPath id="ring">
<path d="M 200, 100
A 100, 100, 0, 1, 1, 197.81, 79.21
L 188.03, 81.29
A 90, 90, 0, 1, 0, 190, 100 z"/>
</clipPath>
<!-- Very simple Gaussian blur, used to visually merge sectors. -->
<filter id="blur" x="0" y="0">
<feGaussianBlur in="SourceGraphic" stdDeviation="3" />
</filter>
<!-- A 12 degree sector extending to 150px. -->
<path id="p" d="M 250, 100
A 150, 150, 0, 0, 1, 246.72, 131.19
L 100, 100
A 0, 0, 0, 0, 0, 100, 100 z" fill="cyan"/>
</defs>
<!-- Clip the blurred sectors to the ring shape. -->
<g clip-path="url(#ring)">
<!-- Blur the sectors together to make a smooth shape and rotate
them anti-clockwise by 6 degrees to hide the seam where the
fully opaque sector blurs with the fully transparent one. -->
<g filter="url(#blur)" transform="rotate(-6 100 100)">
<!-- Each successive sector increases in opacity and is rotated
by a further 12 degrees. -->
<use xlink:href="#p" fill-opacity="0" transform="rotate( 0 100 100)"/>
<use xlink:href="#p" fill-opacity="0.03" transform="rotate( 12 100 100)"/>
<use xlink:href="#p" fill-opacity="0.07" transform="rotate( 24 100 100)"/>
<use xlink:href="#p" fill-opacity="0.1" transform="rotate( 36 100 100)"/>
<use xlink:href="#p" fill-opacity="0.14" transform="rotate( 48 100 100)"/>
<use xlink:href="#p" fill-opacity="0.17" transform="rotate( 60 100 100)"/>
<use xlink:href="#p" fill-opacity="0.2" transform="rotate( 72 100 100)"/>
<use xlink:href="#p" fill-opacity="0.24" transform="rotate( 84 100 100)"/>
<use xlink:href="#p" fill-opacity="0.28" transform="rotate( 96 100 100)"/>
<use xlink:href="#p" fill-opacity="0.31" transform="rotate(108 100 100)"/>
<use xlink:href="#p" fill-opacity="0.34" transform="rotate(120 100 100)"/>
<use xlink:href="#p" fill-opacity="0.38" transform="rotate(132 100 100)"/>
<use xlink:href="#p" fill-opacity="0.41" transform="rotate(144 100 100)"/>
<use xlink:href="#p" fill-opacity="0.45" transform="rotate(156 100 100)"/>
<use xlink:href="#p" fill-opacity="0.48" transform="rotate(168 100 100)"/>
<use xlink:href="#p" fill-opacity="0.52" transform="rotate(180 100 100)"/>
<use xlink:href="#p" fill-opacity="0.55" transform="rotate(192 100 100)"/>
<use xlink:href="#p" fill-opacity="0.59" transform="rotate(204 100 100)"/>
<use xlink:href="#p" fill-opacity="0.62" transform="rotate(216 100 100)"/>
<use xlink:href="#p" fill-opacity="0.66" transform="rotate(228 100 100)"/>
<use xlink:href="#p" fill-opacity="0.69" transform="rotate(240 100 100)"/>
<use xlink:href="#p" fill-opacity="0.7" transform="rotate(252 100 100)"/>
<use xlink:href="#p" fill-opacity="0.72" transform="rotate(264 100 100)"/>
<use xlink:href="#p" fill-opacity="0.76" transform="rotate(276 100 100)"/>
<use xlink:href="#p" fill-opacity="0.79" transform="rotate(288 100 100)"/>
<use xlink:href="#p" fill-opacity="0.83" transform="rotate(300 100 100)"/>
<use xlink:href="#p" fill-opacity="0.86" transform="rotate(312 100 100)"/>
<use xlink:href="#p" fill-opacity="0.93" transform="rotate(324 100 100)"/>
<use xlink:href="#p" fill-opacity="0.97" transform="rotate(336 100 100)"/>
<use xlink:href="#p" fill-opacity="1" transform="rotate(348 100 100)"/>
</g>
</g>
</svg>
这是缩小的,Base64 encoded并用作内联CSS背景图片。如果您愿意,也可以将其作为单独的文件提供。从技术上讲,它应该可以嵌入没有Base64编码的图像,但现在只能在Chrome中使用。
此解决方案在每个象限中使用单独的线性渐变,并依赖于视觉相似性来掩盖接缝。环形是使用伪元素形成的。
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: rotate 1s linear infinite;
background: cyan;
border-radius: 50%;
height: 200px;
width: 200px;
position: relative;
}
.spinner:before,
.spinner:after {
content: '';
position: absolute;
}
.spinner:before {
border-radius: 50%;
background:
linear-gradient(0deg, hsla(0, 0%, 100%, 1 ) 50%, hsla(0, 0%, 100%, 0.9) 100%) 0% 0%,
linear-gradient(90deg, hsla(0, 0%, 100%, 0.9) 0%, hsla(0, 0%, 100%, 0.6) 100%) 100% 0%,
linear-gradient(180deg, hsla(0, 0%, 100%, 0.6) 0%, hsla(0, 0%, 100%, 0.3) 100%) 100% 100%,
linear-gradient(360deg, hsla(0, 0%, 100%, 0.3) 0%, hsla(0, 0%, 100%, 0 ) 100%) 0% 100%
;
background-repeat: no-repeat;
background-size: 50% 50%;
top: -1px;
bottom: -1px;
left: -1px;
right: -1px;
}
.spinner:after {
background: white;
border-radius: 50%;
top: 3%;
bottom: 3%;
left: 3%;
right: 3%;
}
<div class="spinner"></div>
在IE 10,Chrome和Firefox中经过测试和使用。
与SVG解决方案不同,这仅适用于纯色背景色。如果你想改变那种颜色,它还需要在几个地方进行修改,这很痛苦。
首先,微调器的样式为具有均匀背景颜色的圆圈。这将是旋转渐变的颜色。
.spinner {
background: cyan;
border-radius: 50%;
/* ... */
}
进行设置,以便我们可以将伪元素叠加在微调器上:
.spinner {
/* ... */
position: relative;
}
.spinner:before,
.spinner:after {
content: '';
position: absolute;
}
这是一个棘手的问题。 :before
伪元素的每个象限被设置为不同的线性渐变,从不透明的白色开始逐渐变得越来越透明。在中心附近,很容易看到渐变的位置,但请注意外部颜色是否足够接近,以便它们看起来能够顺利连接。
.spinner:before {
border-radius: 50%;
background:
linear-gradient(0deg, hsla(0, 0%, 100%, 1 ) 50%, hsla(0, 0%, 100%, 0.9) 100%) 0% 0%,
linear-gradient(90deg, hsla(0, 0%, 100%, 0.9) 0%, hsla(0, 0%, 100%, 0.6) 100%) 100% 0%,
linear-gradient(180deg, hsla(0, 0%, 100%, 0.6) 0%, hsla(0, 0%, 100%, 0.3) 100%) 100% 100%,
linear-gradient(360deg, hsla(0, 0%, 100%, 0.3) 0%, hsla(0, 0%, 100%, 0 ) 100%) 0% 100%
;
background-repeat: no-repeat;
background-size: 50% 50%;
top: -1px;
bottom: -1px;
left: -1px;
right: -1px;
}
这个定位使得它在旋转器的边缘稍微,因为如果我们将它正确地定位到边缘,则可以看到背景颜色的微弱边缘。
最后,使用::after
伪元素隐藏中间位以形成环形:
.spinner:after {
background: white;
border-radius: 50%;
top: 3%;
bottom: 3%;
left: 3%;
right: 3%;
}
Etvoilá!
答案 1 :(得分:1)
我们只需一个 div 就可以轻松创建它。
.loader {
--border-width: 10px;
height: 200px;
width: 200px;
border-radius: 50%;
/* 0.5px's are needed to avoid hard-stopping */
--mask: radial-gradient(
farthest-side,
transparent calc(100% - var(--border-width) - 0.5px),
#000 calc(100% - var(--border-width) + 0.5px)
);
-webkit-mask: var(--mask);
mask: var(--mask);
/* we're using two half linear-gradient which is masked by the radial-gradient */
background: linear-gradient(to top, rgba(0,255,226, 1), rgba(0,255,226, 0.5)) 100% 0/50% 100% no-repeat,
linear-gradient(rgba(0,255,226, 0.5) 50%, transparent 95%) 0 0/50% 100% no-repeat;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="loader"></div>
这是我的答案与@Jordan Gray 通过将背景设置为正文的答案的比较:
@Jordan Gray 的回答:
body {
background: pink;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
animation: rotate 1s linear infinite;
background: cyan;
border-radius: 50%;
height: 200px;
width: 200px;
position: relative;
}
.spinner::before,
.spinner::after {
content: '';
position: absolute;
}
.spinner::before {
border-radius: 50%;
background:
linear-gradient(0deg, hsla(0, 0%, 100%, 1 ) 50%, hsla(0, 0%, 100%, 0.9) 100%) 0% 0%,
linear-gradient(90deg, hsla(0, 0%, 100%, 0.9) 0%, hsla(0, 0%, 100%, 0.6) 100%) 100% 0%,
linear-gradient(180deg, hsla(0, 0%, 100%, 0.6) 0%, hsla(0, 0%, 100%, 0.3) 100%) 100% 100%,
linear-gradient(360deg, hsla(0, 0%, 100%, 0.3) 0%, hsla(0, 0%, 100%, 0 ) 100%) 0% 100%
;
background-repeat: no-repeat;
background-size: 50% 50%;
top: -1px;
bottom: -1px;
left: -1px;
right: -1px;
}
.spinner::after {
background: white;
border-radius: 50%;
top: 3%;
bottom: 3%;
left: 3%;
right: 3%;
}
<div class="spinner"></div>
我的回答:
body {
background: pink;
}
.loader {
--border-width: 10px;
height: 200px;
width: 200px;
border-radius: 50%;
/* 0.5px's are needed to avoid hard-stopping */
--mask: radial-gradient(
farthest-side,
transparent calc(100% - var(--border-width) - 0.5px),
#000 calc(100% - var(--border-width) + 0.5px)
);
-webkit-mask: var(--mask);
mask: var(--mask);
/* we're using two half linear-gradient which is masked by the radial-gradient */
background: linear-gradient(to top, rgba(0,255,226, 1), rgba(0,255,226, 0.5)) 100% 0/50% 100% no-repeat,
linear-gradient(rgba(0,255,226, 0.5) 50%, transparent 95%) 0 0/50% 100% no-repeat;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="loader"></div>