CSS 带有完全交互式和可访问的饼图的圆圈?

CSS Circle with fully interactive & accessible pie wedges?

目标:

如何在不使用图表库的情况下使用可访问的交互式饼图在 CSS 中创建一个圆圈 (通常会创建完全不可交互或不可访问的饼图)

如果您需要将按钮创建为圆楔形怎么办?

欢迎所有回答,但我写这个 Jeopardy style 问题是为了帮助其他人解决我的问题。

解决方案:

我到处搜索,找到了很多解决方案 - 所有这些都非常肤浅,它们填充了设计方面,但最终没有给你任何可用或可访问的元素。

[tl;dr] Codepen

以最简单的形式创建一个容器,并确保它的溢出是隐藏的,并且它是 border-radius: 50%

的完美圆

在标记中,您可以添加内部元素 - 它们可以是按钮、div、带有列表的 ul/ol 等...您放在那里什么并不重要,它是 CSS计算即算。这是我的例子 HTML

<div class="pie">
  <button>
    <span class="text">1</span>    
  </button>
  <button>
    <span class="text">2</span>
  </button>
  <button>
    <span class="text">3</span>
  </button>
</div>

在我的示例中,我将容器命名为 .pie,这里是重要的 CSS:

.pie {
  border-radius: 50%;
  height: 150px;
  overflow: hidden;
  position: relative;
  width: 150px;
}

高度和宽度显然只需要彼此匹配,但可以是任何值。

然后给内部元素 CSS 使它们最初都显示为饼图容器的第一四分之一象限。

button {
  bottom: 50%;
  height: 100%;
  left: 50%;
  position: absolute;
  transform-origin: bottom left;
  width: 100%;
}

您可以将目前所拥有的概念化为:

那里的transform-origin可能看起来不合时宜,但后来就有意义了,而且是整件事的关键...

制作楔形的最后一个关键是将每个正方形变成楔形的计算。这是通过使用以下的有序组合完成的:

  • transform: rotate()
  • transform: skeyY()

为了进行计算,我们需要知道每个楔形在圆中的度数。比方说 share = 120 这对于我们的例子来说是正确的,有 3 个相等的份额,我们需要一个迭代器,让我们使用 i = 0 (我相信您可以看到这将如何转化为任意数量的楔形的动态 JS 函数...)

现在每个楔子按出现顺序计算如下:

rotate = (i * share)deg skeyY = (share - 90)deg i++

负 90 因为楔形一开始是正方形

基本上,旋转将其左下角(即饼图的中心)上的楔形旋转为它之前所有楔形的度数。 skewY 将楔形从矩形倾斜为正确度数的楔形。

然后我们必须抵消内部元素的 skewY 和旋转(特别是如果你想要那里的文本),计算是:

rotate = (share / 2)deg skewY(-(share - 90)deg

这将反转转换并将文本旋转 相对于包含 'wedge'.

的内容 45 度

现在您的标记将如下所示:

<div class="pie">
  <button style="transform: rotate(0deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)" class="text">1</span>    
  </button>
  <button style="transform: rotate(120deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)" class="text">2</span>
  </button>
  <button style="transform: rotate(240deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)"class="text">3</span>
  </button>
</div>

一般警告 顺序或转换属性很重要。尝试切换顺序,它不会工作。我没有足够的时间来解决这个问题,所以如果这里有人想解释一下 - 去吧!

这是最后的样子,还有一些额外的东西 css 这样您就可以更好地看到结果。

.pie {
  background-color: rgba(0,0,0,0.5);
  position: relative;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  overflow: hidden;
}
.pie button,
.pie button:focus {
  outline: none;
  background-color: lightgreen;
  border: thin solid white;
  position: absolute;
  cursor: pointer;
  width: 100%;
  height: 100%;
  left: 50%;
  bottom: 50%;
  transform-origin: bottom left;
  transition: all 200ms ease-out;
}
.pie button:hover,
.pie button:focus:hover {
  box-shadow: 0px 0px 10px 5px #515151;
  z-index: 1;
}
.pie button .text,
.pie button:focus .text {
  position: absolute;
  bottom: 30px;
  padding: 0px;
  color: #333;
  left: 30px;
}
<div class="pie">
  <button style="transform: rotate(0deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)" class="text">1</span>    
  </button>
  <button style="transform: rotate(120deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)" class="text">2</span>
  </button>
  <button style="transform: rotate(240deg) skewY(30deg)">
    <span style="transform: skewY(-30deg) rotate(60deg)"class="text">3</span>
  </button>
</div>

如果您有兴趣让它动态化,这里有一个非常简单的实现:

codepen

响应能力

- 你只需要改变饼图的宽度和高度。可以是 css var,或者带有媒体查询...

@media (min-width: 1920px) {
  .pie {
    height: 350px;
    width: 350px;
  }
}

注意事项和想法...

唯一真正需要注意的是,您最多只能使用三个楔子。最大值实际上取决于楔形的内部内容以及 'pie'...

的整体大小

如果您确实需要 1 和 2 楔形支撑,我在自己的项目中写了一些条件,我很乐意与您分享。

如果您有兴趣,这很可能很容易被改编成一个简单的饼图引擎 - 但我没有时间弄清楚细节。

希望有需要的人能找到这个,它会有所帮助:-)