上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

CSS编程 (Expert CSS: The CPU Hack)

[复制链接]
  • TA的每日心情
    擦汗
    2026-1-10 12:23
  • 签到天数: 1 天

    [LV.1]初来乍到

    8

    主题

    19

    回帖

    44

    积分

    初级工程师

    积分
    44
    发表于 昨天 14:20 | 显示全部楼层 | 阅读模式

    本帖最后由 cyfung1031 于 2026-2-25 14:23 编辑

    本内容取自 2023年 Jane Ori 所编写的 Expert CSS: The CPU Hack


    专家级 CSS:CPU Hack

    “CPU Hack” 的含义是解锁 CSS 在不依赖 JavaScript 的情况下持续处理数据并重新评估状态的能力。

    例如,如果循环变量在 CSS 中不会自动回到无效 (initial) 状态,那么下面的代码会持续递增 --frame-count 的值:

    body {
      --input-frame: var(--frame-count, 0);
      --frame-count: calc(var(--input-frame) + 1);
    }

    剧透:实际上你可以仅用 CSS 实现这一点,而不需要任何 JS,我会在下文展示如何做到!


    🧠 5 个可观察现象(The 5 Observables)

    在正式演示之前,我们先了解 CSS 动画的一些高级行为,这样最终演示不会显得太突兀。


    1. 动画状态优先于所有选择器状态(几乎总是)

    动画状态中定义的属性会覆盖所有选择器状态中的属性。例如:

    body {
      animation: example 1s infinite;
      --color: blue;
      background: var(--color);
    }
    
    body:hover {
      --color: green;
    }
    
    body:has(div:hover) {
      --color: red;
    }
    
    @keyframes example {
      0%, 100% { --color: hotpink; }
    }

    在这个例子里,即使期待 :hover 改变背景色,最终背景仍然是 hotpink,因为动画状态总是优先覆盖

    这也是为什么 CSS 不允许你直接在动画中改变动画控制属性,例如 animation-play-state


    2. 在 keyframe 中可以使用 var() 赋值属性

    你可以在 @keyframes 内使用 CSS 自定义变量:

    @keyframes example {
      0%, 100% { background: var(--color); }
    }

    如果针对不同选择器改变 --color,动画会反映这些交互状态。


    3. keyframe 结果中对 --var 的赋值会被缓存

    例如:

    body {
      animation: example 1s infinite;
      --color: blue;
      background: var(--bg);
    }
    
    @keyframes example {
      0%, 100% { --bg: var(--color); }
    }

    在这个例子中,无论后续变量 --color 如何改变,缓存的背景色保持第一次计算的值——不会重新计算。即使动画被暂停,缓存值仍然不会更新。


    4. 改变动画属性会打破缓存机制

    如果在不同状态下改变动画时长,例如:

    body:hover {
      animation-duration: 2s;
    }

    浏览器会重新计算动画缓存,这样你仍然可以根据用户状态得到不同结果。

    注意:某些浏览器(例如 Safari)目前无法触发这种缓存重新计算。


    5. 使用两个动画来组合逻辑

    一个动画产生基础值,另一个动画负责修改变量,然后捕获值保存。这种组合可以根据状态和不同动画阶段重新计算变量。


    🚀 CPU Hack 的核心实现

    通过上面的观察我们知道:

    • 从动画中获取的缓存值不会强制重新计算;
    • 如果控制好时序,让两个动画不同时运行,那么可以避免循环依赖问题;
    • 关键在于“捕获(capture)”并再次将值抛回输入(hoist)。

    基本架构示例

    body {
      animation: hoist 1ms infinite,
                 capture 1ms infinite;
      animation-play-state: paused, paused;
    
      --input-frame: var(--frame-hoist, 0);
      --frame-count: calc(var(--input-frame) + 1);
    }
    
    @keyframes hoist {
      0%, 100% { --frame-hoist: var(--frame-captured, 0); }
    }
    
    @keyframes capture {
      0%, 100% { --frame-captured: var(--frame-count); }
    }

    这个设计通过两个短时动画来捕获和提升帧计数值,从而绕过循环依赖。


    🌀 用 DOM 交互控制动画状态

    为了让动画阶段按顺序触发,可以使用 .phase-* HTML 结构和 :hover 触发不同动画状态:

    <ol class="cpu">
      <li class="phase-0"></li>
      <li class="phase-1"></li>
      <li class="phase-2"></li>
      <li class="phase-3"></li>
    </ol>

    结合 CSS 判断层叠状态,就可以在不同阶段从捕获状态跳转到下一个阶段。


    🧩 每个阶段的逻辑总结

    阶段 状态 作用
    phase-0 hoist paused, capture 运行 捕获原始输出值
    phase-1 两者 paused 冻结捕获值
    phase-2 hoist 运行, capture paused 将捕获的值提升回输入
    phase-3 两者 paused 再次冻结提升值,并回到 phase-0

    🎉 CPU Hack 的结果与可能性

    这个技术展示了:

    • 完全使用 CSS 来“计算”整数;
    • 根据屏幕尺寸执行逻辑;
    • 捕获鼠标坐标;
    • 实现类似游戏的逻辑,比如 CSS 实现的生命游戏或打砖块;

    实际示例

    游标于红蓝方块移动触发计算

    https://codepen.io/propjockey/pen/wvRqWEy/86fc64e923093e4ce9e865bd0c9b8da7

    hover 触发的按钮事件

    https://codepen.io/propjockey/pen/ExGvgWy/9fbc3990ce135b77c2af8267dbd14a0c

    简易CSS游戏

    CSS Conway's Game of Life Simulator - Infinite Generations, 42x42
    https://codepen.io/propjockey/pen/NWEYdjY

    3D CSS游戏

    https://garethheyes.co.uk/

    x86 CSS模拟器

    https://lyra.horse/x86css/

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表