html - 环形工艺微调器,在环周围具有渐变渐变效果

标签 html css css-animations

我想用 CSS3 或 JavaScript 创建一个环形进程微调器,类似于 Android 中的加载进度微调器。

微调器应连续旋转并填充沿边缘淡出的纯色(即圆锥形渐变),如下图所示:

A thin ring on a white background with the colour fading counter-clockwise from fully opaque cyan to fully transparent.

我怎样才能做到这一点?

最佳答案

如果只有 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 和 transformanimation 属性。


SVG 解决方案

@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 上放一个生成器。

SVG 版本的工作原理

那一大堆乱码只是一个 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 中使用。


纯 CSS 解决方案

此解决方案在每个象限中使用单独的线性渐变,并依靠视觉相似性来掩盖接缝。环形是使用伪元素形成的。

@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 解决方案不同,这仅适用于纯色背景。如果你想改变那种颜色,它还需要在几个地方进行修改,这很痛苦。

纯 CSS 版本的工作原理

  1. 首先,微调器的样式设置为具有统一背景色的圆圈。这将是旋转渐变的颜色。

    .spinner {
        background: cyan;
        border-radius: 50%;
        /* ... */
    }
    
  2. 进行设置,以便我们可以将伪元素叠加在微调器的顶部:

    .spinner {
        /* ... */
        position: relative;
    }
    
    .spinner::before,
    .spinner::after {
        content: '';
        position: absolute;
    }
    
  3. 这是棘手的一点。 :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;
    }
    

    它的位置使其稍微越过微调器的边缘,因为如果我们将它放置在边缘的右边,背景颜色的微弱边缘是可见的。

  4. 最后,使用 ::after 伪元素隐藏中间位以形成环形:

    .spinner::after {
        background: white;
        border-radius: 50%;
        top: 3%;
        bottom: 3%;
        left: 3%;
        right: 3%;
    }
    

Et voilá!

关于html - 环形工艺微调器,在环周围具有渐变渐变效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49520226/

相关文章:

python - 将 HTML 中的 Python 代码与传入的变量组合在一起

html - 在 CSS 圆圈内居中图标的更好方法

javascript - CesiumJS 点和 CSS 关键帧动画

html - 字体大小是否有不可见的填充/边距?

css - 混合混合模式与动画之间的冲突

javascript - 在 ng-repeat 中使用 AngularJS 从一种状态到另一种状态进行动画处理

HTML + CSS 文本容器调整

html - 扩展 html5 微数据事件模式

java - 使用 JSoup 仅删除 HTML 标签,而不删除 '<' 和 '>' 标签内的数据

javascript - 使用 html 从变量中删除样式标签