css奇技淫巧box-shadow实现圆环进度条(代码片段)

XianZhe_ XianZhe_     2022-12-30     451

关键词:

CSS 奇技淫巧Box-shadow实现圆环进度条

文章目录


一、Box-shadow圆环进度条

实现圆环进度条的方法用很多种,比较容易想到的可能是通过 border属性实现,在本文将使用 Box-shadow盒子阴影呈现,一般来说还真的难想到这个方法,说这种方法是一个奇技淫巧也不为过,让我们接着来看。


二、效果预览

<div class="container">
    <div class="ring-wrap">
        <div class="ring">Hover</div>
    </div>
</div>
$borderColor: #ff5d8f;

// 设置阴影
@function setShadow($x: 0, $y: 0, $fuzzy: 0, $spread: 0, $color: $borderColor) 
  @return #$xpx #$ypx #$fuzzypx #$spreadpx $color;


.container 
  display: flex;
  background-color: #6C6C6C;
  height: 500px;


.ring-wrap 
  display: flex;
  overflow: hidden;
  width: 156px;
  height: 156px;
  margin: auto;
  border-radius: 50%;

  .ring 
    // 宽高需要预留边框大小
    width: 150px;
    height: 150px;
    line-height: 150px;
    margin: auto;
  border-radius: 50%;
  font-size: 25px;
  text-align: center;
  color: #fff;
  box-shadow: setShadow(75, -75, $color: transparent), setShadow(-75, -75), setShadow(75, -75), setShadow(-75, 75), setShadow(75, 75);
  background-color: #2894FF;
  cursor: pointer;

  &:hover 
    animation: ring-border 2s ease-in-out forwards;
  



@keyframes ring-border 
  0% 
    box-shadow: setShadow(75, -75, $color: transparent), setShadow(-75, -75), setShadow(75, -75), setShadow(-75, 75), setShadow(75, 75), setShadow($spread: 3, $color: transparent);
  
  25% 
    box-shadow: setShadow(75, -75, $color: transparent), setShadow(-75, -75), setShadow(0, -160), setShadow(-75, 75), setShadow(75, 75), setShadow($spread: 3, $color: #FFF);
  
  50% 
    box-shadow: setShadow(75, -75, $color: transparent), setShadow(-160, 0), setShadow(0, -160), setShadow(-75, 75), setShadow(75, 75), setShadow($spread: 3, $color: #FFF);
  
  75% 
    box-shadow: setShadow(75, -75, $color: #fff), setShadow(-160, 0), setShadow(0, -160), setShadow(0, 160), setShadow(75, 75), setShadow($spread: 3, $color: #FFF);
  
  100% 
    box-shadow: setShadow(75, -75, $color: #fff), setShadow(-160, 0), setShadow(0, -160), setShadow(0, 160), setShadow(160, 0), setShadow($spread: 3, $color: #FFF);
  



三、原理刨析

原理很简单,最重要的是控制阴影按照顺序延时移动,除此之外,还需要一层父元素使用 overflow:hidden 对额外的阴影进行隐藏,父子宽度高不能一致,需要留足阴影填充边框的间隙。

特别注意的是box-shadow属性使用逗号进行分割多个值,每个值的顺序并不是固定的,其意义简单干脆,就是为元素设置多个不同的阴影。
现在网上很多教程往往在注释或则文中为每个值表明上下左右,为每个值表明顺序,但其实就是不同阴影的xy轴位置不同,本意上是为了标识每个阴影的位置,但好心办坏事造成新手固有思维,不知道的话千万别被误导了

.ring-wrap 
	// ......
  
  .ring 
    // ......
    box-shadow:
      // 左上
      setShadow(-75, -75),
      // 右上
      setShadow(75, -75),
      // 左下
      setShadow(-75, 75),
      // 右下
      setShadow(75, 75);
    // ......
  

使用Box-shadow实现圆环进度条,其实使用四个阴影之间的移动即可完成,网上很多教程是这样,最初的设想也是这样,但最后的效果有点出乎意料。以下是最初的样式。

$borderColor: #ff5d8f;

// 设置阴影
@function setShadow($x: 0, $y: 0, $fuzzy: 0, $spread: 0, $color: $borderColor) 
  @return #$xpx #$ypx #$fuzzypx #$spreadpx $color;


.container 
  display: flex;
  background-color: #6C6C6C;
  height: 500px;


.ring-wrap 
  display: flex;
  overflow: hidden;
  width: 156px;
  height: 156px;
  margin: auto;
  border-radius: 50%;

  .ring 
    // 宽高需要预留边框大小
    width: 150px;
    height: 150px;
    line-height: 150px;
    margin: auto;
    border-radius: 50%;
    font-size: 25px;
    text-align: center;
    color: #fff;
    box-shadow: setShadow(-75, -75), setShadow(75, -75), setShadow(-75, 75), setShadow(75, 75);
    background-color: #2894FF;
    cursor: pointer;

    &:hover 
      animation: ring-border 5s ease-in-out forwards;
    
  


@keyframes ring-border 
  0% 
    box-shadow: setShadow(-75, -75), setShadow(75, -75), setShadow(-75, 75), setShadow(75, 75), setShadow($spread: 3, $color: transparent);
  
  25% 
    box-shadow: setShadow(-75, -75), setShadow(0, -160), setShadow(-75, 75), setShadow(75, 75), setShadow($spread: 3, $color: #FFF);
  
  50% 
    box-shadow: setShadow(-160, 0), setShadow(0, -160), setShadow(-75, 75), setShadow(75, 75), setShadow($spread: 3, $color: #FFF);
  
  75% 
    box-shadow: setShadow(-160, 0), setShadow(0, -160), setShadow(0, 160), setShadow(75, 75), setShadow($spread: 3, $color: #FFF);
  
  100% 
    box-shadow: setShadow(-160, 0), setShadow(0, -160), setShadow(0, 160), setShadow(160, 0), setShadow($spread: 3, $color: #FFF);
  


为了解决这个问题,通过新增一个阴影进行改进越前书写的阴影其优先级越高,通过在前书写的阴影覆盖移除的阴影移动,覆盖的阴影要在动画进行到75%或之前完成覆盖以实现效果

点击查看【juejin】

ps:使用码上掘金线上代码编辑器查看效果~


四、实际应用

在悬浮上展示进度条的场景估计很少,一般在与用户交互的场景下使用的会多些。

说了这么多也没有实际用用上,并不知道实际好坏,那咱们简单编写一个轮播图场景进行应用,看看实际效果如何。

<div class="container">
        <div class="swipe">
            <div class="swipe-img">
                <img src="https://w.wallhaven.cc/full/1p/wallhaven-1p398w.jpg" alt class="active">
                <img src="https://w.wallhaven.cc/full/7p/wallhaven-7p3we9.png" alt>
                <img src="https://w.wallhaven.cc/full/rr/wallhaven-rr2yow.jpg" alt>
            </div>
            <div class="swipe-btn">
                <div class="left-btn">
                    <b class="btn"> < </b>
                </div>
                <div class="right-btn">
                    <b class="btn"> > </b>
                </div>
            </div>
        </div>
    </div>
const opts = 
    // 控制延迟
    interval: 3000,
    // 控制方向
    direction: "right",
    _indexImg: 0,
;

const leftBtn = document.querySelector(".left-btn .btn");
const rightBtn = document.querySelector(".right-btn .btn");
const imgList = document.querySelectorAll(".swipe-img img");

// 获取激活图片索引
function getImgIndex() 
    for (let index in imgList) 
        const item = imgList[index];
        if (Array.from(item.classList).includes("active")) 
            return index;
        
    
    return 0;


/**
 * 不同方向处理
 * @param Function left 左方向处理回调
 * @param Function right 右方向处理回调
 */
function directionHandle(left, right) 
    if (/^left$/i.test(opts.direction)) 
        left();
     else 
        right();
    


function switchSwipe(direction = "auto") 
    imgList[opts._indexImg]?.classList?.remove?.("active");

    switch (true) 
        case /^auto$/i.test(direction):
            directionHandle(
                () => opts._indexImg--,
                () => opts._indexImg++
            );
            break;
        case /^left$/i.test(direction):
            opts._indexImg--;
            break;
        default:
            opts._indexImg++;
    

    switch (true) 
        case opts._indexImg > imgList.length - 1:
            opts._indexImg = 0;
            break;
        case opts._indexImg < 0:
            opts._indexImg = imgList.length - 1;
            break;
    
    imgList[opts._indexImg]?.classList.add("active");


function autoPlay() 
    opts._indexImg = getImgIndex();
    // const
    directionHandle(
        () => 
            leftBtn.style.animationDuration = `$opts.interval / 1000s`;
            leftBtn.classList.add("active");
        ,
        () => 
            rightBtn.style.animationDuration = `$opts.interval / 1000s`;
            rightBtn.classList.add("active");
        
    );
    return setInterval(() => switchSwipe(), opts.interval);


function execute() 
    // 清除自动播放辅助函数
    const clearAuto = (atimer, dtimer) => 
        atimer && clearInterval(atimer);
        dtimer && clearTimeout(dtimer);
        leftBtn.classList.remove("active");
        rightBtn.classList.remove("active");
    ;

    let [autoTimer, delayTimer] = [autoPlay(), null];
    leftBtn.addEventListener("click", () => 
        clearAuto(autoTimer, delayTimer);
        switchSwipe("left");
        delayTimer = setTimeout(() => 
            timer = autoPlay();
        , opts.interval);
    );
    rightBtn.addEventListener("click", () => 
        clearAuto(autoTimer, delayTimer);
        switchSwipe("right");
        delayTimer = setTimeout(() => 
            timer = autoPlay();
        , opts.interval);
    );


execute();

$borderColor: #ff5d8f;

// 设置阴影
@function setShadow($x: 0, $y: 0, $fuzzy: 0, $spread: 0, $color: $borderColor) 
  @return #$xpx #$ypx #$fuzzypx #$spreadpx $color;


.swipe 
  position: relative;
  width: 100%;
  height: 350px;
  display: flex;

  &-img 
    img 
      display: none;
      width: 100%;
      height: 100%;
      position: absolute;
   

两种css3圆环进度条详解

...容易理解,只需要一层一层的嵌套,即可得到效果,但是实现起来较为繁琐,HTML的结构也比较冗余。先看HTML结构:<divclas 查看详情

圆环进度条两种实现方式(代码片段)

...口的,终点圆口,并且有一个圆;列举了两种实现方式:第一种纯的CSS实现;原理是叠加和旋转而成。缺点在某些机型上面应为遮罩没有对齐(uniapp半个像素不显示的问题,其他平台没有这问题ÿ 查看详情

css3圆环状进度条

HTML:<divclass="wrap"><divclass="progress-radialprogress-25"><divclass="overlay">25%</div></div><divclass="progress-radialprogress-50"><divclass="overlay">50% 查看详情

实现环形进度条的几种方法(代码片段)

...;-webkit-box-align:center;margin:50pxauto;background:fff;border-radius:50%;box-shadow:00010pxredinset;2、添加两个子元素div,分别设置border来实现两个半圆环并遮盖背景圆环<divclass="demo1-bg1"><divid="J_bg2_1"class="demo1-bg2-1"></div><divid="J_bg2_2"cla... 查看详情

qt第三方圆形进度条-及其改进

Qt第三方圆形进度条的改进要实现一个圆形的进度条功能,在网上找到一个比较出名的第三方封装类:QRoundProgressBar,地址:sourceforge的QRoundProgressBar 功能封装的还是不错,提供了3种模式,线形、圆环、饼状。使用过程中发现... 查看详情

小tip:使用svg寥寥数行实现圆环loading进度效果

...片上传圆环loading进度效果。如下截图:首先,CSS3是可以实现的,以前写过一篇转大饼的文章:“CSS3实现鸡蛋饼饼状图loading等待转转转”。原理跟这个一模一样,两个半区的矩形,然后不同时机巧妙显隐实现。但是呢,CSS3实现... 查看详情

自定义圆环形进度条实现(代码片段)

最近项目里边要用进度条,进度条中间展示进度,底部展示label,因为这个组件用的地方多,所以我就直接封装了一个通用组件。先看一下效果图:功能有:圆环的颜色和进度可以自定义;中间文字可... 查看详情

ios圆环,环形渐变进度条的封装

参考技术Ahttps://github.com/alexgaosun/AGSCircleProgressDemo 查看详情

纯css实现进度条效果

...度条;    斜纹进度条用线性渐变 linear-gradient类实现,原理很好理解,2个参数:      1、角度;      2、关键点(包含2个参数,1是颜色,2是长度位置)    displ 查看详情

纯css3实现圆形进度条动画

悄悄地,GIF格式的进度条已经越来越少,CSS进度条如雨后春笋般涌现。今天要介绍的这个CSS3进度条,效果和FlymeOS4上的加载动画一样。首先,来看下最终的效果:  查看详情

学习|css3实现进度条加载

...种交互效果,这样做的目的是提高用户体验。进度条的的实现分为3大部分:1、页面布局,2、进度条动效,3、何时进度条增加。文件目录加载文件顺序<linkrel="stylesheet/less"href="./index.less"><scriptsrc="./zepto.min.js"></script>... 查看详情

微信小程序canvas2d绘制圆环进度条组件

参考技术Ahttps://developers.weixin.qq.com/miniprogram/dev/component/canvas.htmlCanvas2D接口(type="2d"),支持同层渲染的一个圆环进度条。(wx.createCanvasContext已废弃)https://gitee.com/susuhhhhhh/componentshttps://gitee.com/susuhhhhhh/wxmini_demo 查看详情

自定义圆环形进度条实现(代码片段)

最近项目里边要用进度条,进度条中间展示进度,底部展示label,因为这个组件用的地方多,所以我就直接封装了一个通用组件。先看一下效果图:功能有:圆环的颜色和进度可以自定义;中间文字可... 查看详情

利用clip-path实现环形进度条

参考技术A  昨天逛网页时看到有用css与js实现环形进度条的(那位博主在面试时被要求当场写出环形进度条π_π),然后就想尝试下写出来(感觉好尴尬),说实话春节后遗症真可怕haha~  看了网上的三种方法实... 查看详情

用svg实现一个环形进度条(代码片段)

svg实现环形进度条需要用到的知识:1、会使用path的d属性画一个圆环2、熟悉stroke,stroke-linecap,stroke-width,stroke-dasharray、stroke-dashoffset 话不多说,直接上代码<divstyle="width:200px;height:200px;"><svgviewBox="00100100">&l 查看详情

ycprogress自定义百分比进度条(代码片段)

目录介绍1.本库优势亮点2.使用介绍2.1圆环百分比进度条2.2直线百分比进度条2.3仿杀毒类型百分比进度条3.注意要点4.效果展示5.其他介绍1.本库优势亮点圆环百分比进度条简便且小巧,支持设置多种属性。可以设置内圆和外圆的颜... 查看详情

纯css实现顶部进度条随滚动条滚动

一、效果图二、直接复制粘贴<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><metahttp-equiv="X-UA-Compatibl 查看详情

css实现炫酷进度条

实现效果:代码内容:<divclassName=styles.progressBox><divclassName=styles.progress></div><divclassName=styles.progress_barstyle=width:"40%" 查看详情