css3如何实现这样的圆环效果?

8个扇形组成一个中间镂空的圆环,每个扇形之间有几个角度的空白间隙。
如何实现这样的效果

阅读 1.3k
avatarAI BotBETA
.ring {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: conic-gradient(
    #ff6b6b 0% 25%,
    #4ecdc4 25% 50%,
    #45b7d1 50% 75%,
    #96ceb4 75% 100%
  );
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ring::after {
  content: "";
  position: absolute;
  width: 90px;
  height: 90px;
  background: white;
  border-radius: 50%;
}

实现原理分步说明:

  1. 使用conic-gradient锥形渐变创建四等分颜色
  2. 通过百分比控制颜色分布(每个颜色占25%)
  3. 伪元素::after创建中心白色圆形实现环状效果
  4. flex布局实现内容居中

支持动画的改进版(添加旋转动画):

.ring {
  animation: rotate 3s linear infinite;
}

@keyframes rotate {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

如果需要不同比例的分段,调整conic-gradient的百分比值即可。此方案兼容现代浏览器,如需支持老旧浏览器可改用transform拼接方案。

4 个回答

问了下ChatGPT,代码我试了能实现划入高亮,手动设置高亮,使用vue代码能更少。

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <title>扇区内部正中醒目三角效果</title>
    <style>
      svg {
        display: block;
        margin: 50px auto;
      }
      .segment {
        stroke: #fff;
        stroke-width: 1px;
      }
      .segment, .triangle {
        fill: #bbb;
        transition: fill 0.3s, stroke 0.3s;
        cursor: pointer;
      }
      .triangle {
        fill: #e3aa9c;
      }
      /* 鼠标悬停或 active 状态下改变颜色 */
      .segment-group:hover .segment,
      .segment-group:hover .triangle,
      .segment-group.active .segment,
      .segment-group.active .triangle {
        fill: #ff6600;
        stroke: #ff3300;
      }
    </style>
  </head>
  <body>
    <svg width="200" height="200" viewBox="0 0 200 200">
      <!-- 通过 JavaScript 动态生成 8 个扇区及其内部醒目的三角 -->
    </svg>

    <div style="text-align: center; margin-top: 20px;">
      <button onclick="toggleSegment(0)">切换第一块状态</button>
    </div>

    <script>
      const svg = document.querySelector('svg');
      const cx = 100, cy = 100;       // 圆心坐标
      const outerR = 100, innerR = 60;  // 外圈和内圈半径
      const segments = 8;

      // 调整三角形参数:增大尺寸和底边角度偏移,使三角更醒目
      const midRadius = (outerR + innerR) / 2;  // 扇区中间半径
      const triangleHalfHeight = 12;            // 增大三角形高度的一半
      const deltaAngle = 6;                     // 增大角度偏移,使底边更宽

      svg.innerHTML = ''; // 清空内容

      // 极坐标转换函数:使 0°在正上方
      function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
        const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
        return {
          x: centerX + radius * Math.cos(angleInRadians),
          y: centerY + radius * Math.sin(angleInRadians)
        };
      }

      for (let i = 0; i < segments; i++) {
        // 创建分组,每个分组包含一个扇区路径和一个内部三角形
        const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
        group.setAttribute("class", "segment-group");
        group.setAttribute("id", "segment-" + i);

        const startAngle = i * 45;
        const endAngle = (i + 1) * 45;

        // 计算扇区外圈和内圈的起始与结束点
        const outerStart = polarToCartesian(cx, cy, outerR, startAngle);
        const outerEnd = polarToCartesian(cx, cy, outerR, endAngle);
        const innerStart = polarToCartesian(cx, cy, innerR, endAngle);
        const innerEnd = polarToCartesian(cx, cy, innerR, startAngle);
        const largeArcFlag = 0; // 45°小于180°

        // 构造环形扇区路径
        const d = [
          "M", outerStart.x, outerStart.y,
          "A", outerR, outerR, 0, largeArcFlag, 1, outerEnd.x, outerEnd.y,
          "L", innerStart.x, innerStart.y,
          "A", innerR, innerR, 0, largeArcFlag, 0, innerEnd.x, innerEnd.y,
          "Z"
        ].join(" ");

        const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        path.setAttribute("d", d);
        path.setAttribute("class", "segment");
        group.appendChild(path);

        // 计算当前扇区的中间角度
        const midAngle = startAngle + 22.5;
        // 计算三角形顶点所在的半径:
        // tipRadius:三角形尖端(向外)的半径;baseRadius:底边所在的半径
        const tipRadius = midRadius + triangleHalfHeight;
        const baseRadius = midRadius - triangleHalfHeight;

        // 计算三角形三个顶点
        const tip = polarToCartesian(cx, cy, tipRadius, midAngle);
        const leftBase = polarToCartesian(cx, cy, baseRadius, midAngle - deltaAngle);
        const rightBase = polarToCartesian(cx, cy, baseRadius, midAngle + deltaAngle);

        // 构造三角形点集
        const points = `${leftBase.x},${leftBase.y} ${tip.x},${tip.y} ${rightBase.x},${rightBase.y}`;
        const triangle = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
        triangle.setAttribute("points", points);
        triangle.setAttribute("class", "triangle");
        // 添加描边增强视觉效果
        triangle.setAttribute("stroke", "#666");
        triangle.setAttribute("stroke-width", "1");

        group.appendChild(triangle);

        // 添加鼠标事件,实现 hover 时添加/移除 active 状态
        group.addEventListener('mouseenter', () => {
          group.classList.add('active');
        });
        group.addEventListener('mouseleave', () => {
          group.classList.remove('active');
        });

        svg.appendChild(group);
      }

      // 数据状态控制:通过按钮切换指定扇区的 active 类
      function toggleSegment(index) {
        const group = document.getElementById('segment-' + index);
        if (group) {
          group.classList.toggle('active');
        }
      }
    </script>
  </body>
</html>

样式你可以再调整下。

说个思路吧,配合clip-path,代码就不写了,费时

新手上路,请多包涵

用8个div实现了,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .hollow-ring {
          width: 200px;
          height: 200px;
          position: relative;
          border-radius: 50%;
          overflow: hidden;
        }
        
        /* 扇形基础样式 */
        .sector {
          position: absolute;
          width: 100%;
          height: 100%;
          background: #4a90e2;
          /* 通过改动最后的45%可以调整扇形角度 */
          clip-path: polygon(50% 50%, 100% 0%, 100% 45%);
          transform-origin: 50% 50%;
        }
        
        /* 8个扇形旋转角度 */
        .sector:nth-child(1) { transform: rotate(0deg); }
        .sector:nth-child(2) { transform: rotate(45deg); }
        .sector:nth-child(3) { transform: rotate(90deg); }
        .sector:nth-child(4) { transform: rotate(135deg); }
        .sector:nth-child(5) { transform: rotate(180deg); }
        .sector:nth-child(6) { transform: rotate(225deg); }
        .sector:nth-child(7) { transform: rotate(270deg); }
        .sector:nth-child(8) { transform: rotate(315deg); }
        
        /* 中间镂空 */
        .inner-circle {
          position: absolute;
          width: 100px;
          height: 100px;
          background: white;
          border-radius: 50%;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
        }
        </style>
</head>
<body>
    <div class="hollow-ring">
        <!-- 8个扇形 -->
        <div class="sector"></div>
        <div class="sector"></div>
        <div class="sector"></div>
        <div class="sector"></div>
        <div class="sector"></div>
        <div class="sector"></div>
        <div class="sector"></div>
        <div class="sector"></div>
        <!-- 中心镂空 -->
        <div class="inner-circle"></div>
      </div>
</body>
</html>

【技术探索者之路】

一位专注务实的92年摩羯座开发者,2018年获得软件工程硕士学位。深耕全栈开发领域五载,现立足上海打造数字世界的桥梁。

技术图谱:
🔹 前端架构:精通Vue/React生态体系,构建优雅交互体验
🔹 后端引擎:SpringBoot/SpringCloud微服务架构专家
🔹 数据智造:Python自动化处理能手,打造高效数据管道
🔹 空间智能:正在拓展地理信息系统的开发新边疆

持续深耕技术领域,在个人公众号「当默默无声」定期分享:
• 全栈开发实战经验
• 微服务架构深度解析
• GIS与空间智能开发探索
• 前沿技术趋势解读
工重浩耳位麻
以代码丈量世界,用技术创造价值,期待与您在数字世界的交汇点相遇。

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>镂空圆环效果</title>
    <style>
        .circle-container {
            width: 200px;
            height: 200px;
            position: relative;
            margin: 50px auto;
        }
        
        .circle {
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background: conic-gradient(
                #3498db 0deg 40deg,
                transparent 40deg 45deg,
                #3498db 45deg 85deg,
                transparent 85deg 90deg,
                #3498db 90deg 130deg,
                transparent 130deg 135deg,
                #3498db 135deg 175deg,
                transparent 175deg 180deg,
                #3498db 180deg 220deg,
                transparent 220deg 225deg,
                #3498db 225deg 265deg,
                transparent 265deg 270deg,
                #3498db 270deg 310deg,
                transparent 310deg 315deg,
                #3498db 315deg 355deg,
                transparent 355deg 360deg
            );
            position: relative;
        }
        
        .inner-circle {
            width: 60%;
            height: 60%;
            background-color: white;
            border-radius: 50%;
            position: absolute;
            top: 20%;
            left: 20%;
        }
    </style>
</head>
<body>
    <div class="circle-container">
        <div class="circle">
            <div class="inner-circle"></div>
        </div>
    </div>
</body>
</html>

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>可配置的镂空圆环效果</title>
    <style>
        :root {
            --circle-size: 200px;
            --gap-angle: 5deg;
            --sector-angle: 40deg;
            --circle-color: #3498db;
            --inner-circle-ratio: 0.6;
        }
        
        .circle-container {
            width: var(--circle-size);
            height: var(--circle-size);
            position: relative;
            margin: 50px auto;
        }
        
        .circle {
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background: conic-gradient(
                var(--circle-color) 0deg calc(var(--sector-angle)),
                transparent calc(var(--sector-angle)) calc(var(--sector-angle) + var(--gap-angle)),
                var(--circle-color) calc(var(--sector-angle) + var(--gap-angle)) calc(2*var(--sector-angle) + var(--gap-angle)),
                transparent calc(2*var(--sector-angle) + var(--gap-angle)) calc(2*var(--sector-angle) + 2*var(--gap-angle)),
                var(--circle-color) calc(2*var(--sector-angle) + 2*var(--gap-angle)) calc(3*var(--sector-angle) + 2*var(--gap-angle)),
                transparent calc(3*var(--sector-angle) + 2*var(--gap-angle)) calc(3*var(--sector-angle) + 3*var(--gap-angle)),
                var(--circle-color) calc(3*var(--sector-angle) + 3*var(--gap-angle)) calc(4*var(--sector-angle) + 3*var(--gap-angle)),
                transparent calc(4*var(--sector-angle) + 3*var(--gap-angle)) calc(4*var(--sector-angle) + 4*var(--gap-angle)),
                var(--circle-color) calc(4*var(--sector-angle) + 4*var(--gap-angle)) calc(5*var(--sector-angle) + 4*var(--gap-angle)),
                transparent calc(5*var(--sector-angle) + 4*var(--gap-angle)) calc(5*var(--sector-angle) + 5*var(--gap-angle)),
                var(--circle-color) calc(5*var(--sector-angle) + 5*var(--gap-angle)) calc(6*var(--sector-angle) + 5*var(--gap-angle)),
                transparent calc(6*var(--sector-angle) + 5*var(--gap-angle)) calc(6*var(--sector-angle) + 6*var(--gap-angle)),
                var(--circle-color) calc(6*var(--sector-angle) + 6*var(--gap-angle)) calc(7*var(--sector-angle) + 6*var(--gap-angle)),
                transparent calc(7*var(--sector-angle) + 6*var(--gap-angle)) calc(7*var(--sector-angle) + 7*var(--gap-angle)),
                var(--circle-color) calc(7*var(--sector-angle) + 7*var(--gap-angle)) calc(8*var(--sector-angle) + 7*var(--gap-angle)),
                transparent calc(8*var(--sector-angle) + 7*var(--gap-angle)) 360deg
            );
            position: relative;
        }
        
        .inner-circle {
            width: calc(var(--inner-circle-ratio) * 100%);
            height: calc(var(--inner-circle-ratio) * 100%);
            background-color: white;
            border-radius: 50%;
            position: absolute;
            top: calc((1 - var(--inner-circle-ratio)) * 50%);
            left: calc((1 - var(--inner-circle-ratio)) * 50%);
        }
    </style>
</head>
<body>
    <div class="circle-container">
        <div class="circle">
            <div class="inner-circle"></div>
        </div>
    </div>
</body>
</html>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题