手记

用纯CSS技术获取IP地址及其他32位API响应,无需JavaScript!

大约一周前的一个周五下班后,我在刷YouTube短视频找点什么看的时候,这段35秒的视频完全吸引了我的注意力。

玩了一多半后,我暂停了游戏,仰头思索,脑海里冒出很多想法。

"我可以使用 CSS 和 CPU Hack 来实现国际象棋。"

"没有 JS 的情况下,我能不能连接到那个棋局库?"

"CSS 与服务器通信的唯一方式是通过背景图---!!!"

另外 CSS 还可以将 url() 作为伪元素的 content,通过这种方法可以调整父元素的大小,接着可以使用 inset: 0px 把绝对定位的 container 放进父元素里,并使用 tan(atan2()) 来测量 aaand 这就是我 GET 请求的响应数据了您好,看起来您还没有提供英文原文。为了帮助您进行翻译,请提供需要翻译的英文文本,好吗?能否请您提供需要翻译的英文原文?这将帮助我更好地完成翻译工作。感谢您的配合!

如果元素的大小根据内容进行调整,最好将这些内容放在屏幕之外,以避免出现滚动条——而且如果它不需要那种奇怪的一次性设置,那么使用起来会更方便……那么我该怎么把数据取出来呢——

我从 CPU Hack 就知道怎么把数据传递到 :root

我停了一下,眼睛四处扫视,完全没注意到周围的环境,寻找我在组装组件中的特殊情况——这里有什么不能做的呢?

...

"我得把我的 URL 用 @container style(--x: N) 包裹起来,这样游戏状态才能选择使用哪些 URL,但我只能有一个固定的端点列表,直到我们能用上 url() param()……
啊,等一下!我也可以生成必要的请求 URL,并提示玩家将其 SMEAR 到页面上,使它看起来像是用户界面的一部分,以确认他们的操作……"

我往后一靠,张开手指和手掌,目光缓缓扫过房间,心里越来越激动。

"宽度和高度都是16位,虽然很大,但还是可行的……"

"我想就这么定了!我能做到!"

这个情节的其余部分对当前的情境来说不太重要,但我现在挺享受的,所以我会把这部分文字留在这里,供跟着看的人参考。

所以我开始在我的棋盘项目上进行构建,在CodePen,我所有想法的起点

"我想现在是时候学棋了,这样我才知道怎么弄清楚如何构建API请求,并且确定32位的响应数据是否足够传递CPU的移动信息了。"

十几岁的时候,我热爱在IRC聊天室里聊天,还喜欢破解游戏和作弊。在那段短暂玩了一阵国际象棋的日子里,我在一连串失败之后,用近乎歇斯底里的笑声结束了那局游戏。当时我找到了一种作弊的方法,每步都作弊,还是输了。我让朋友先走,然后用他在IRC中写的那步棋来对付着我下载的国际象棋游戏里的“专家”电脑玩家,再把电脑的回应告诉我的朋友,让他走下一步。

我完全不知道自己对棋有多少不懂的地方。

我查找了可以简单使用的现有API,假设我会在我的服务器上生成图像,并将高度和宽度作为响应数据返回。我很快找到了chess-api.com这个网站,它可以通过输入"FEN"来给出下一步棋的建议。

我学习了FEN,这让我发现我对国际象棋还有很多不了解的地方。我知道我可以生成SMEAR Hack来构建FEN格式的局面,最重要的是,我确认可以将重要响应数据move: "b7b8q"压缩到32位。(棋盘是8x8的,我知道棋盘上的每个棋子在哪里,响应中不需要提供太多基本信息,因为棋盘情况已经很清楚了。)

现在,我更加确信我能完全用CSS编程国际象棋对战CPU。

那一刻我也知道,我一定要再看一遍《后翼弃兵》,因为我非常喜欢它,迫不及待想发现更多细节。

我把这种兴奋付诸行动,让这个循环持续运转。

是时候测试一下 CSS API URL GET ALL CAPS TRAIN 的想法,看看它是否有效。

演示基本步骤

先来设置合适的背景音,《后翼弃兵》(The Queen's Gambit)

接下来,确认一下图像的测量。

很简单!只要确保里面的元素都是绝对定位的,就不会影响容器的大小了。

添加一个测试,用来改一下我们要 GET 的 URL

概念验证成功,下一步是将响应数据移动到 :root,这样我就能让所有的设置变得隐形,并将它们至少移出屏幕65535px(约216.25厘米)到最上方和最左侧。

我知道这会涉及到复杂的CSS和HTML,所以我从一开始就知道这会很沉重和深奥。我帮助人们制作东西(请参见此处的代码),因此,从一开始就打算让它成为一个易于使用的库。

版本 1 中,在页面中复制一些特定的(较大的)HTML,带有少量内置选项来发起请求并执行 :root 提取。

导入所需的库,并在您的CSS中指定API的端点,

    @import url(https://unpkg.com/css-api-fetch@1/api-fetch.css);

    @container style(--api-id: 1) {
      .api-fetch { --api-fetch: url(https://css-api.propjockey.io/ip-address.php); }
    }

全屏模式;退出

一旦数据准备就绪,应用的其余部分可以在 :root 中找到。

不过情况很快就变棒了!

首次展示:仅限 Chrome :,root

通过 CSS 获取用户的 IP 地址。

(https://codepen.io/propjockey/pen/pvzrWyG "代码笔示例页面")

在这篇帖子中,我不会深入讲解那个原始公开演示中 CSS+HTML 如何将数据提升到 :root 的具体实现,因为有几个热爱 CSS 的朋友为我找到了一个更简单的途径,这是我之前没有学过的,所以没有详细说明。

但我在这里快速总结一下,有兴趣的人可以看一下。

:root:has(.specific-element:hover) { ..状态.. }

/ 这里的状态指代特定元素悬停时的状态 /

如果某个特定的某个元素的后代知道它处于:hover状态,它可以将另一个元素放置在其当前位置之上,导致下一个元素被悬停,然后:root:has(...:hover)也会根据那个元素的状态进行变化。

[CPU Hack]: 让我们可以 在不同的元素被 :hover 时 积累状态。

假如我们要处理的数据是'512',我们可以按千位、百位、十位和个位的顺序来读,告诉孩子显示0到9之间的数字,代表该位置上具体的数值。

.api-transfer-value-0:hover...5:hover12

孩子知道我们要找的是哪个数值位置,级联状态让我们知道,:has() 拿出值,因为孩子展示了对应的数字,我们可以在 :hover 时在 :root 处读取。

CPU Hack将其累积成一个值,在个位保存后,会通知孩子停止汇报。

上面链接的 demo 的 HTML 展示了一些必要的设置。它的 CSS 代码如下:v1 of css-api-fetch

第二次公开演示:跨浏览器兼容性,不使用 \:root

这里唯一的区别是我不把它提升到:root,而是把它留在容器里,DX要求你把所有需要访问数据的内容包在一个绝对定位的元素里,该元素位于这个hack的内部。

在我最初的阐述中,我提到过我原本想避免这种情况,但这是跨浏览器的,它其实也有它的用处。当然也不是不行,在特定的HTML结构中构建你的整个应用。

看看这个HTML标签的内容,就知道其实简单多了。

只需要在跨浏览器版本中使用这四个特定的嵌套HTML元素,然后你可以用你的响应数据构建任何你想要的东西。

第三次公开演示会 - 仅支持 Chrome, :root, 简单示例

Kizu提到可能可以简化,所以我开始调查。虽然还没有完全理解,T. Afif展示了可能的一个方向,从那篇文章中学到了很多,但对文章中的划分和精度损失感到不满意。于是我又深入研究了文章和Bramus制作的神奇工具,最终找到了一个能满足我需求的变体。

如你可以在 CodePen 的 HTML 代码中看到(https://codepen.io/propjockey/pen/JoPyxrK),设置如此简单,用一行 HTML 就可以实现数据获取(https://github.com/propjockey/css-api-fetch/tree/0289b936fd583b71234728d303a89f9c6abe25?tab=readme-ov-file#adding-the-html),响应数据就会出现在 :root 变量中。在这个例子中,我还用第二个元素来展示数据。真的是太棒了!

我已经把它打包为 v3 版本,让所有交接变得非常简单,并且把那些已经预先设置好的测量工具移到屏幕外,因为这些并不重要。

我发了一条关于这个发布的信息,然后,T. Afif 链接了另一篇文章展示了和我设计的时间线配置类似——没有分割的哦! :)

我非常推荐阅读我链接的所有作品,一些富有才华的 CSS 专家分享他们的想法——了解某事可行,就能打开一扇通往充满创意世界的门。

css-api-fetch 是用来做什么的?

导入css-api-fetch并添加一行HTML,你就可以轻松地在CSS中进行API请求,而无需自己考虑视图的时间线复杂性。我让它变得简单,无需你担心,但对于那些好奇的人来说,如果您感兴趣,下面将介绍该库内部的概念和设置。

  1. 创建两个动画,将它们从你 API 返回的最大值动画到 0。
  2. 将这些动画及其时间线挂载到 :root
  3. 创建一个测量元素,其大小根据 API 返回的最大值调整,并设置非静态位置、隐藏溢出等,使其适合作为视图/滚动位置的参考。
  4. 将它绝对定位到屏幕左上角,避免它在应用中产生滚动条。
  5. 在嵌套的 size 容器 的伪元素的 content 中加载图像 url(),并为 inlineblock 设置 view-timeline,对应于步骤 1 和 2 中的动画。
  6. 这些动画现在会将图像的尺寸传递给整个页面。

以下将展示上面提到的6个步骤,步骤4被注释掉了,这样你就能看到它了。我们将使用Lorem Picsum轻松模拟特定高度和宽度的API返回结果。

这些是基础内容,但该库设置了四个独立的API接口,而无需了解其内部工作原理,你可以同时使用它们。更多信息请参阅此链接。

css-bin-bits 是啥?

这三个公开发布的版本都使用了我很久以前做的一款库 css-bin-bits,这个库可以让你非常轻松地用100%的CSS对16位整数进行位操作,你通常不需要自己编写任何calc()函数——这个库会帮你搞定一切。针对32位的IP地址,使用css-bin-bits,我能够将图像的尺寸精确地限制在一个维度上为16位。

不将32位IP地址打包成两个16位值,T. Afif展示了你可以使用一个255255px by 255255px的容器,并通过十进制运算来处理响应数据——绕过css-bin-bitscss-api-fetch支持你设置任何最大值,默认值为99999,这远远超过16位(65535),但还不完全达到255255,哈哈。

如何让API以图像中的数据作为回复?

将数据嵌入到图像的宽度和高度中最轻量且简单的方法是让服务器返回最简单的SVG。

这里是如何在PHP中处理和返回IP地址的一个例子,比如:

    <?php
      header('Content-type: image/svg+xml');

      $adr = $_SERVER['REMOTE_ADDR'] ?: '255.255.255.255';
      $hex = str_pad(implode(array_map('dechex', explode('.', preg_replace('/[^\d\.]/', '', $adr), 4))), 8, '0', STR_PAD_LEFT);
      /* 正则表达式返回前4个十六进制字符,去掉最多3个前导0 */
      $width = hexdec(preg_replace('/(^0{0,3})|(.{4}$)/', '', $hex) ?: '0');
      /* 正则表达式返回最后4个十六进制字符,去掉最多3个前导0 */
      $height = hexdec(preg_replace('/^.{4}0{0,3}/', '', $hex) ?: '0');

      echo '<svg xmlns="http://www.w3.org/2000/svg" width="' . $width . 'px" height="' . $height . 'px"></svg>';
    ?>

点击全屏显示 点击退出全屏

这些 API 请求可以轻松完成一些简单易得的任务,这些任务纯 CSS 难以实现,但可以通过 JavaScript 实现。

  • 随机数生成器(RNG)
  • 时间区域
  • 国家编码
  • 操作系统
  • 或当你把它包装起来,比如连接到其他 API — 如 chess-api
接下来会发生什么?

国际象棋?!

还不行!而且,Lilian 已经用 CSS 制作出了国际象棋。

我不太清楚它是怎么运作的,也不太清楚是否有演示版本,但她肯定乐意回答任何问题! :)

……

目前,我暂时的激动的地方在别的地方。

我想要每个请求的位数大于32位。

我希望每个请求512比特。

GIF图

不支持JavaScript。

    • *(此处省略了部分内容)
通讯录 👽

如果您需要帮助、有任何功能请求、想要分享您的成果或想了解更多,请随时联系我。

PropJockey.io CodePen DEV Blog GitHub Mastodon
(官网) (作品集) (博客) (社交网络)

🦋@JaneOri.PropJockey.io (蓝线)

@Jane0ri

0人推荐
随时随地看视频
慕课网APP