革新设计:Reform Collective新网站如何用AI与CSS黑科技打造极致体验

Reform Collective技术负责人详解新网站开发过程:使用v0 AI生成波纹背景原型,GSAP实现鼠标跟踪动画,纯CSS创建3D方块滚动效果,并解决Safari z-fighting和Firefox子网格粘性定位等浏览器兼容性问题。

Reform Collective:全新网站,为视觉而生

Reform Collective的新网站摒弃干扰,专注于清晰度、性能和结构——技术负责人详细介绍了如何利用AI、GSAP和CSS技巧将其变为现实。

设计理念

我们之前的网站已不再适用。它无法反映我们正在从事的工作类型,更重要的是,它造成了使用障碍。导航复杂,结构过深,视觉风格与我们在提案或对话中向客户展示的内容不一致。

重新设计是一次重置。我们将网站精简到 essentials:简洁的布局、宽松的间距、极简的结构。目标是创造一种开放、自信且易于浏览的体验。

作品展示方式

我们做出的最 deliberate 改变之一是展示作品的方式。传统的案例研究充斥着摘要、时间线和过程描述。我们意识到人们不再以这种方式消费作品集内容。

因此,我们停止为阅读而写作,开始为视觉而设计。

我们移除了所有 fluff:没有介绍文案,没有策略分解,没有“这是我们学到的”。只有干净的视觉效果、简洁的项目标题和无摩擦的浏览体验。

导航设计

全局菜单设计具有结构感。它不是浮动在网站上方或作为图层淡入,而是将整个布局向下推,物理移动页面以腾出空间。这是一个 deliberate 的手势:空间的,而不仅仅是视觉的。

运动干净且具有建筑感:一个全宽面板从顶部滑下,精确地 snap 到位。没有模糊,没有视差,没有视觉 fluff。只有 sharp 对比、bold 排版和三个主要路径:Our Work、About Us 和 Reform Nova。

技术细节(来自首席工程师)

Webby奖部分

我从v0中的AI原型开始,用于波浪线背景。v0在解释模糊指令方面出奇地好。我 literally 可以告诉它“make it goopier”,它会吐出代码,让事物感觉更 goopy。我最终得到了一个相当 snazzy 的原型。因为它使用了react-three-fiber,我基本上可以直接复制粘贴到我们的代码中,安装依赖项,就完成了80%!比手动设置Three.js场景要快得多,也更有趣。

不过,这种工作流程有其 quirks。AI在 initial vibe check 方面很棒,但在 specific feedback 方面会 choke。用文本描述视觉错误非常困难,而且由于模型无法看到输出,它基本上大部分时间都在猜测。我还注意到它倾向于“over-edit”,有时会为一个小改动重构整个组件。我最终自己修复了几个错误,因为v0无法处理它们。

接下来是鼠标跟随器。我想要一个跟随光标的视频,出现在波浪背景之上但位于标题文本之下。当它经过文本后面时,文本的颜色会反转以保持可见。

“跟随鼠标”部分很容易!反转效果有点棘手。我的 first thought 是使用 mix-blend-mode 搭配 backdrop-filter。这似乎是个好主意,应该完美工作——或者至少,如果它 actually had 的话我会这么说。我最终尝试了各种随机方法,以找到在所有浏览器中都有效的方法。

突破出现在我停止尝试让一个元素完成所有事情时。我将效果分成两个完美同步的div:

  • <Inverter>:一个没有内容的 ghost div。它的唯一工作是携带 backdrop-filter: invert(1),用于翻转文本颜色。
  • <Video>:包含实际视频。使用 z-index: -1 放置在较低的堆叠上下文中,因此它滑到文本下方但保持在页面背景之上。

我使用GSAP的quickTo来同步动画它们。对用户(也就是你)来说,它看起来像一个单一元素。感觉有点像 hack,但它在所有浏览器中都 flawless 工作。

代码概要:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// animate both refs at the same time so they appear as one element
const moveX = gsap.quickTo([videoRef.current, inverter.current], "x", { /* ... */ });
const moveY = gsap.quickTo([videoRef.current, inverter.current], "y", { /* ... */ });

// in the JSX
<Wrapper>
    {/* other content here, ofc */}
    <Video ref={videoRef} {...video?.data} />
    <Inverter ref={inverter} />
</Wrapper>

// and the styles...
const Video = styled(BackgroundVideo, {
    position: "fixed",
    zIndex: -1, // pushed behind the text
    filter: "invert(1) contrast(0.5)",
    /* ... */
});

const Inverter = styled("div", {
    position: "fixed",
    pointerEvents: "none", // for text selection
    backdropFilter: "invert(1) contrast(2)",
    /* ... */
});

这里的样式使用了https://www.restyle.dev/,顺便说一下——这是一个仅运行时的CSS库(即不需要打包器配置),这很酷。

Nova方块部分

这个功能是一个滚动驱动的动画,其中3D方块网格从相机前 zoom past。有趣的是,这一切都是用纯CSS变换完成的——不需要WebGL或threejs。

设置涉及一个具有 perspective 的容器和一堆“block”div,每个都使用 transform-style: preserve-3d。每个块包含几个子div,旋转到位以形成立方体。为了性能,我只动画父块的变换,这比移动数百个单独的面更高效。我使用MDN演示立方体作为 inspiration。

当然,这样做让我直接进入了浏览器错误的 weird world。(我似乎经常 end up there…)

  1. Safari的渲染故障:
  • 手动剔除:作为优化,我已经只渲染基于立方体网格象限可见的面。这基本上是手动背面剔除,有助于减少Safari必须计算的层数。它可能无论如何都会提高性能,所以…谢谢,Safari,我猜。
  • 强制堆叠:我根据每个立方体的行和列分配特定的z-index。感觉有点 brute-force,但它确切地告诉Safari如何堆叠事物——并且完全消除了 flicker。

Block.tsx组件的概要:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
export default function Block({
  vertical,
  horizontal,
  row,
  column,
}: {
  // vertical/horizontal basically represents the 'quadrant' on-screen
  vertical: "top" | "bottom";
  horizontal: "left" | "right";
  row: number;
  column: number;
}) {
  // Explicitly set z-index based on grid position to prevent z-fighting in Safari
  // This was basically trial and error to figure out
  const style =
    vertical === "top" && horizontal === "left"
      ? { zIndex: -row - column }
      : vertical === "bottom" && horizontal === "right"
        ? { zIndex: -1 }
        : horizontal === "left"
          ? { zIndex: -column }
          : { zIndex: -row };

  // Conditionally render only the necessary faces
  return (
    
      {horizontal === "left" && }
      {horizontal === "right" && }
      {vertical === "top" && }
      {vertical === "bottom" && }
    
  );
}

const Wrapper = styled("div", {
  transformStyle: "preserve-3d", // the magic property for the cube
  /* ... */
});
  1. Firefox的固定问题 我们的网站使用CSS子网格进行全局对齐,我认为这很棒,因为它缩小了设计和开发之间的差距。如果设计中的某些东西与网格对齐,现在它也可以在代码中 literally 与网格对齐。

注意:我发现在Firefox中,position: sticky在子网格容器内完全 broken。一个固定元素会开始固定但永远不会取消固定,因为它的定位上下文被解析到错误的网格容器。

遇到奇怪的错误是令人沮丧的,但当你构建酷炫的东西时,这是交易的一部分。你只需要在时间表中 plan for it。如果你在某个奇怪的边缘案例中发现错误,我大力主张花时间创建最小测试案例并报告它。它有助于 pinpoint 到底出了什么问题,从而 leads to 更好的解决方案——并且有助于让网络对每个人都更好。

结语

感谢阅读!准备好与我们合作构建一些东西了吗?我们一直在寻找优秀的公司和个人合作新项目。开始吧→

Reform Co.团队 附:我们也在招聘,请随时查看我们的招聘页面。❤️

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计