使用圆锥渐变和CSS自定义属性创建一个Range Input控制的环形图

如果看完了还不过瘾?想和作者深聊相关话题,可以点击这里向作者提问!

特别声明:此篇文章内容来源于@Vicky.Ye翻译的《使用圆锥渐变和CSS变量创建一个Range Input控制的环形图》一文。英文原文来自于@Ana Tudor的《Using Conic Gradients and CSS Variables to Create a Doughnut Chart Output for a Range Input》一文。

最近我在 Codepen 上看到了一个例子,我的第一个想法是这个案例可以只用三个元素完成:一个容器,一个 range 类型的 input 和一个 output 。在 CSS 方面,涉及到使用一个把 CSS 自定义属性作为范围渲染参数的圆锥渐变函数 conic-gradient()

在2015年年中,@Lea Verou 在一次会议演讲中发布了一个 conic-gradient()的 polyfill,并演示了如何将它们用于创建饼图。这个 polyfill 非常适合 conic-gradient() 的入门学习,因为它使我们能够更全面的使用这个函数来构建我们想要的东西。不幸的是,它不适用于 CSS自定义属性,而 CSS自定义属性现在已成为编写高效代码的关键组成部分。

但好消息是,在过去的两年半时间里,情况有所转变。 一般来说,Chrome 浏览器和使用暴露标志的 Blink 引擎浏览器(例如 Opera )现在都支持原生的 conic-gradient(),这意味着已经有可能尝试以 CSS自定义属性作为 conic-gradient()的范围值 。 我们所需要做的就是在 chrome://flags 启用 Experimental Web Platform Features 标志(或者,如果您使用 Opera ,opera://flags ):

好吧,现在我们可以开始了!

初始结构

一开始我们需要一个容器和一个 range 类型的 input

<div class="wrap">
    <input id="r" type="range"/>
</div>

请注意,我们没有 output 元素。 因为当 JavaScript 由于某种原因被禁用或加载失败时,未更新元素就会出现在页面里,所以我们需要通过 JavaScript 来动态更新 output 标签的值。同样的也需要通过 JavaScript 来判断浏览器是否支持 conic-gradient(),并在容器上动态添加一个 class 作为标识。

如果我们的浏览器支持 conic-gradient() ,则容器将获得一个 .full 样式, .full 下的 output 样式将会显示到图表上。 否则,我们只有一个没有图表的简单滑动条, output 位于滑动条按钮上。

浏览器支持 conic-gradient()(上边)和浏览器不支持时的兜底方案(下边)

基本样式

在着手之前,我们希望滑动条在所有浏览器上显示都是没问题的。

我们先从最基本的样式重置开始,并设置 bodybackground

$bg: #3d3d4a;
* { 
    margin: 0 
}
body { 
    background: $bg 
}

第二步是准备滑动条在 WebKit 浏览器中的样式,这里我们要通过设置 -webkit-appearance: none 和其按钮样式(因为某种原因系统设置了该轨道的默认样式),为避免不同浏览器中默认属性的不一致,如 paddingbackgroundfont ,我们要给出明确值:

[type='range'] {
    &, &::-webkit-slider-thumb { 
        -webkit-appearance: none 
    }

    display: block;   
    padding: 0;
    background: transparent;
    font: inherit
}

如果您需要了解滑动条及其组件在各种浏览器中的工作方式,请查看我以前写的一篇有关于Rang Input的文章

现在我们可以进入更有趣的部分了。 设置轨道和按钮的尺寸,并通过相应的@mixin指令将它们绑到滑动条组件上。通过添加 background 让其在屏幕上可见,设置 border-radius 来对其进行美化。为了与预期的效果一致,我们将这两个元素的 border 设为 none

$k: .1;
$track-w: 25em;
$track-h: .02*$track-w;
$thumb-d: $k*$track-w;

@mixin track() {
    border: none;
    width: $track-w; 
    height: $track-h;
    border-radius: .5*$track-h;
    background: #343440
}

@mixin thumb() {
    border: none;
    width: $thumb-d; 
    height: $thumb-d;
    border-radius: 50%;
    background: #e6323e
}

[type='range'] {
    /* same styles as before */
    width: $track-w; 
    height: $thumb-d;

    &::-webkit-slider-runnable-track { 
        @include track 
    }
    &::-moz-range-track { 
        @include track 
    }
    &::-ms-track { 
        @include track 
    }

    &::-webkit-slider-thumb {
        margin-top: .5*($track-h - $thumb-d);
        @include thumb
    }
    &::-moz-range-thumb { 
        @include thumb 
    }
    &::-ms-thumb {
        margin-top: 0;
        @include thumb
    }
}

我们添加一些属性,如在容器上设置 margin ,给定明确的 widthfont

.wrap {
    margin: 2em auto;
    width: $track-w;
    font: 2vmin trebuchet ms, arial, sans-serif
}

我们不想让它变得太小或太大,所以我们限制了font-size

.wrap {
    @media (max-width: 500px), (max-height: 500px) { 
        font-size: 10px 
    }
    @media (min-width: 1600px), (min-height: 1600px) { 
        font-size: 32px 
    }
}

然后,现在我们有了一个不错的跨浏览器滑动条:

JavaScript

首先我们要获取到滑动条、容器和创建的 output 元素。

const _R = document.getElementById('r'), 
      _W = _R.parentNode, 
      _O = document.createElement('output');

创建一个变量 val ,用于存储 range 类型的 input 的当前值:

let val = null;

接下来,我们创建一个 update() 函数,用于检查当前滑块值是否等于已存的值。 如果不是,则更新 JavaScript 里 val变量、 output的文本内容和外框上的 CSS自定义属性 --val

function update() {
    let newval = +_R.value;

    if(val !== newval)
        _W.style.setProperty('--val', _O.value = val = newval)
};

在我们继续编写JavaScript之前,在 output 的 CSS 中设置一个 conic-gradient()

output {
    background: conic-gradient(#e64c65 calc(var(--val)*1%), #41a8ab 0%)
}

我们通过调用 update() 函数,将 output 作为子 DOM 元素添加到容器上,然后测试 outputbackground-image 是否可设置 conic-gradient() (注意,这步需要确定 DOM 元素添加之后,才可这么做)。

如果测试出的 background-image 不是 none (如果是 none ,则没有原生 conic-gradient() 支持),则在容器上添加一个 full 样式。 并通过 for 属性将 outputrange类型的input 绑在一起 。

通过事件监听器,我们确保每次移动滑块时都能调用 update() 函数。

_O.setAttribute('for', _R.id);
update();
_W.appendChild(_O);

if(getComputedStyle(_O).backgroundImage !== 'none')
    _W.classList.add('full');

_R.addEventListener('input', update, false);
_R.addEventListener('change', update, false);

现在我们有了一个滑动条和一个 output (如果我们的浏览器支持原生 conic-gradient() ,可以查看到它的值显示在 conic-gradient() 背景上)。 虽然在这个阶段仍然很丑,但它的功能基本实现——当我们拖动滑块时, output 的值会随着变化:

我们给 output 加了一个浅色值,以便我们可以更好地看到它,并通过 ::after 伪类在末尾添加 % 。 还需要 display 设置为 none 来隐藏 Edge 中的工具提示(::-ms-toolti

剩余70%内容付费后可查看
* 请输入阅读码(忘记阅读码?

如需转载,烦请注明出处:https://www.w3cplus.com/css/using-conic-gradients-css-variables-create-doughnut-chart-output-range-input.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部