在 CSS 和 HTML 中构建坐标系统
我开发了一个动态笛卡尔坐标系。它可能有点基础,但我觉得它很有趣,因为你可以插入许多不同的函数并正确显示点。同时它还具有一些有趣的特性:
- 可定制:选择颜色、尺寸、范围、系统中心等。
- 响应式:默认情况下为父宽度的 100%,但可以具有相对/绝对大小。
- 易于使用:直接将功能转换为 CSS。
- 轻量级:每个要显示的点仅需 35 行 CSS 和一行 HTML。无需 JavaScript。
是的,你没看错:它没有使用 JavaScript 进行函数计算。相反,它全部用 CSS 中的calc()
方法来实现。
文章内容:
介绍
九月的一个周末——是的,我从那时起就写好了文章,但一直没发表过😳——我早早醒来,趁着家里其他人还在睡觉,我决定玩玩HTML和CSS。在Twitter上,我看到了Lea Verou的这条推文:
她用它calc()
来生成一系列遵循线性函数的值。这是一种结合calc()
自定义属性的有趣方法(我也见过Ana Tudor和Temani Afif等人这样做)。我也想尝试类似的方法。或许可以用二次函数创建一个示例。然后,一件事引出了另一件事,演示开始逐渐发展。
首先,我仅用 HTML 和 CSS 构建了一个包含二次函数的笛卡尔系统基本图。所有值都是硬编码的,因此过于具体。然后,我尝试使其越来越通用,以匹配尽可能多的函数:线性、二次、三次等等,最终成功了。它能够很好地适应新的运算。而且,这也不是一个复杂的演示。
代码
笛卡尔坐标系的整个代码不到40行CSS代码!这还考虑到了CSS自定义属性的使用,这会让整个代码略显冗长(但可定制性更强,所以这是一个取舍的过程。)
以下是 CSS 代码:
.css-ccs {
--c: 10;
--cx: 5;
--cy: 5;
--dsize: 10;
--dcolor: #369;
--size: 100%;
position: relative;
width: var(--size);
height: 0;
padding-top: var(--size);
box-sizing: border-box;
aspect-ratio: 1/1;
background-image:
linear-gradient(#0000 calc(var(--cy) * 100% / var(--c) - 1px), #0008 0 calc(var(--cy) * 100% / var(--c) + 1px), transparent 0),
linear-gradient(to right, #0000 calc(var(--cx) * 100% / var(--c) - 1px), #0008 0 calc(var(--cx) * 100% / var(--c) + 1px), transparent 0),
repeating-linear-gradient(#0002 0 0.5px, #0000 0 calc(100% / var(--c) - 0.5px), #0002 0 calc(100% / var(--c))),
repeating-linear-gradient(to right, #0002 0 0.5px, #0000 0 calc(100% / var(--c) - 0.5px), #0002 0 calc(100% / var(--c)));
}
.css-ccs.no-overflow {
overflow: hidden;
}
.css-css .dot {
--translationUnit: 100% / var(--c);
--translationX: var(--translationUnit) * var(--cx);
--translationY: var(--translationUnit) * var(--cy);
/* Vertical is "flipped" in CSS: higher values go down! Do negative! */
--y: calc(var(--translationY) - var(--translationUnit) * var(--function));
width: calc(var(--dsize) * 1px);
height: calc(var(--dsize) * 1px);
background: var(--dcolor);
border-radius: 50%;
position: absolute;
transform: translate(-50%, -50%);
left: calc(var(--translationX) + var(--x) * var(--translationUnit));
top: var(--y);
}
该.css-ccs
代码将生成轴和指导线,同时为.dot
稍后的功能做好准备。
至于 HTML,我们需要一个带有类css-ccs
(CSS 笛卡尔坐标系)的元素,该元素将包含其他带有类的元素dot
,这些元素将设置x
中的值style
。像这样:
<div class="css-ccs">
<div class="dot" style="--x: -3;"></div>
<div class="dot" style="--x: 0;"></div>
<div class="dot" style="--x: 1;"></div>
<div class="dot" style="--x: 2;"></div>
<!-- ... -->
</div>
理想情况下,我希望有这样的东西:
<figure>
<figcaption>Graph Title</figcaption>
<output data-x="-3"></output>
<output data-x="0"></output>
<output data-x="1"></output>
<output data-x="2"></output>
</figure>
虽然我最终会修改这些标签,但并非所有修改都是可行的。data-x
指示值的最佳方式是x
:使用数据属性来表示数据,而不是使用“样式变量”。遗憾的是,CSS 目前不支持读取数据属性并将值传递给自定义属性。所以目前只能使用自定义属性。
最后,我们需要将函数代入.dot
图中。它会作用于类,并且(有点)简单:我们将--function
在点号处定义一个calc()
带有函数的自定义属性。就是这样。
问题是什么?CSS 没有幂运算(或者说许多其他类型的运算),所以要做像 x 2这样的操作,我们需要将 x 乘以 x (x*x)。我们的--x
自定义属性中有 x,所以我们需要这样做:
.my-chart .dot {
/**
* x^2 = x * x = var(--x) * var(--x)
*/
--function: calc(var(--x) * var(--x));
}
有点冗长和冗长,但仍然简单且不太难阅读。
变量
我们可以自定义图表,将一些 CSS 变量传递给图表本身(容器)并单独传递给每个点。
这些是容器的变量:
姓名 | 默认 | 描述 |
---|---|---|
--c |
10 | 数量。图表的大小(以“单元格”总数计)。必须为正数。 |
--cx |
5 | 数字。图表中 x 轴的位置。必须是整数,且应为正数,且小于或等于--c 。 |
--cy |
5 | 数字。图表中 y 轴的位置。必须为整数,且应为正数,且小于或等于--c 。 |
--dsize |
10 | 数字。点的大小(以像素为单位)。它必须为大于零的正数。 |
--dcolor |
#369 | 颜色。点的颜色(任何颜色格式)。 |
--size |
100% | 长度。坐标系的宽度。可以是绝对的,也可以是相对于父级的。 |
得益于 CSS 级联,我们可以为每个点重新定义一些值。此外,我们还必须为这些点传递 x 值:
姓名 | 默认 | 描述 |
---|---|---|
--dsize |
10 | 数字。点的大小(以像素为单位)。它必须为大于零的正数。 |
--dcolor |
#369 | 颜色。点的颜色(任何颜色格式)。 |
--x |
不适用 | x 数字。必需。要传递给函数并在图表中表示的值。 |
示例和演示
以下是使用此方法用 CSS 绘制图形的一些示例:
线性函数:x - 3
#axis_x-3 .dot {
/**
* f(x) = x - 3
* x = var(--x)
*/
--function: calc(var(--x) - 3);
}
二次函数:x 2 - 5
#axis_x2-5 .dot {
/**
* f(x) = x^2 - 5
* x^2 = var(--x) * var(--x)
*/
--function: calc(var(--x) * var(--x) - 5);
}
三次函数:0.4x 3 - 5.25x - 4
#axis_04x3_525x_4 .dot {
/**
* f(x) = 0.4x^3 - 5.25x - 4
* 0.4x^3 = var(--x) * var(--x) * var(--x)
* 5.25x = 5.25 * var(--x)
*/
--function: calc(0.4 * var(--x) * var(--x) * var(--x) - 5.25 * var(--x) - 4);
}
倒数平方函数:1 / x 2
#axis_1_x2 .dot {
/**
* f(x) = 1 / x^2
* x^2 = var(--x) * var(--x)
*/
--function: calc(1 / (var(--x) * var(--x)));
}
可访问性
这些图表可能看起来不错,但它们带来了一些可访问性挑战。整个图表都是空的,所以我们至少应该添加一个aria-label
带有内容描述的。此外,添加一个角色也不错。添加role
“img”或“figure”将有助于向辅助技术正确地显示图表。
更好的是,我们可以使用<figure>
/<figcaption>
标签。但是,我们需要做一些 CSS 操作,因为背景将占据容器的 100%,并且可能会发生一些重叠。
至于数据点,目前它们是<div>
,但更多语义标签可以更好地描述这些元素是什么。(例如,,<output>
或<data>
。<samp>
)
<div class="css-ccs"
role="img"
aria-label="Cartesian coordinate system representing the function ... with points at ...">
<!-- ... -->
</div>
除此之外,这些点没有任何信息,如果能提供一些关于悬停/聚焦的数据就更好了。如果我们这样做,就需要考虑这两种状态的可访问性,这样辅助技术用户就有更好的替代方案了。
下一步
虽然 CSS 运行良好,而且这是一个很好的实验,但它缺少许多关键功能。其中一些功能可以通过 HTML 和 CSS 添加或模拟,但其他一些功能则需要 JavaScript。不过,我们的小型坐标系统轻量且直观。
CSS 的局限性也限制了图表的绘制。CSS 数学函数列表正在不断增长(例如min
,,,等等),我们可以模拟一些常见的操作(正如 Ana Tudor 在她的文章中所展示的),但仍有许多数学计算无法仅用 CSS 完成,这会限制我们的计算能力。max
clamp
它可能不适合继续构建成库,但它可能有助于绘制一些小示例,而且不需要繁重的外部库(我只需要 40 行简短的 CSS 代码,而不是 100KB 的 JS 包)。而且,开发和探索它的过程也很有趣。
文章来源:https://dev.to/alvaromontoro/building-a-cooperative-system-in-css-and-html-pc7