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

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

阅读 484
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拼接方案。

2 个回答

问了下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,代码就不写了,费时

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏