我们刚刚发布了 Studio——一个美丽的新代理网站模板,我们过去几个月为了 Tailwind UI 一直在努力工作。

我们使用 Next.js、MDX,当然还有 Tailwind CSS 构建了它,这是我们发布的第一个使用新 Next.js App Router 的模板。
设计一个代理模板是一个有趣的项目,因为创意代理通常使用他们自己的网站展示一些非常炫酷、量身定制的想法,而使用模板在展示自己公司的能力时确实有点 strange。
所以我们尝试以两个目标来接近这个项目,以便实际上对人们有用:
- 教人们如何做一些你在炫酷代理网站上看到的酷东西——我一直认为我们的模板作为教育资源的价值同样重要(如果不是更多的话),因此我们希望利用这个模板展示一些我们如何构建这些网站上看到的酷互动和动画细节的机会。
- 为不售卖设计的代理设计——有很多专注于工程工作的代理,而这些公司通常在设计上很难脱颖而出。我们尝试以这样一种方式设计这个模板,使其不依赖于大量设计工作的截图等来显得好看,以便专注于代码的代理可以将其作为自己网站的起点。
我认为我们最终实现了这两个目标,我对这一切的结果感到非常自豪。
和往常一样,可以查看 实时预览 以获取完整体验——其中有 tons of cool details 需要在浏览器中查看才能真正欣赏到。
令人愉快的动画
代理网站的一条不成文的规则是它们必须华丽。我们没有完全替换鼠标光标或用 WebGL 渲染整个网站,但我们确实寻找可以优雅地引入动画和互动的机会。
例如,我们围绕 Framer Motion 的一些特性构建了一个轻量级的声明式基于组件的 API,以便轻松实现滚动触发的进入动画:
这些动画的创作体验变得非常不错——只需用 FadeIn
或 FadeInStagger
组件包装你想要淡入的内容,你就可以开始:
function Clients() { return ( <div className="mt-24 rounded-4xl bg-neutral-950 py-20 sm:mt-32 sm:py-32 lg:mt-56"> <Container> <FadeIn className="flex items-center gap-x-8"> <h2 className="font-display text-center text-sm font-semibold tracking-wider text-white sm:text-left"> 我们已与数百位优秀人士合作 </h2> <div className="h-px flex-auto bg-neutral-800" /> </FadeIn> <FadeInStagger faster> <ul role="list" className="mt-10 grid grid-cols-2 gap-x-8 gap-y-10 lg:grid-cols-4"> {clients.map(([client, logo]) => ( <li key={client}> <FadeIn> <Image src={logo} alt={client} unoptimized /> </FadeIn> </li> ))} </ul> </FadeInStagger> </Container> </div> );}
我们还为徽标添加了这个可爱的小动画,在悬停时标志被填充为实色:
这个小细节看起来虽小,但有趣的是你没有客户端导航根本无法做到这一点,因为点击徽标返回首页时动画会重新运行。借助像 Next.js 这样的框架,我们能够在悬停时保持徽标的填充状态,即使跨越 URL 变化,这感觉要好得多。
菜单抽屉动画效果也很好,打开时将整个页面推下去:
如果你仔细看,徽标和按钮的颜色变化并不是简单的切换——这是由滑动的页面位置驱动的,徽标在页面边缘与其交叉时实际上是部分白色和部分黑色。
另一个我非常喜欢的细节是我们在案例研究页面上为图像设计的交互:
我们希望整个网站呈现黑白效果,但始终显示黑白图像并不是很合适。因此我们设计了这种处理方式,图像最开始为黑白色,饱和度在图像靠近屏幕中心时随着滚动动画逐渐回归。我们也在悬停时展示全彩图像。
我们还小心翼翼地尝试以一种能考虑到运动迷失综合征和对这类大型动画敏感的人的方式实施所有这些动画。使用 Framer Motion 的 useReducedMotion
钩子和 Tailwind 的 motion-safe
变体,我们会根据需要禁用导航菜单动画,并将滚动驱动的进入动画限制为透明度,以使屏幕上的事物不再移动。
针对开发者的案例研究和博客工作流程
Studio 支持 案例研究 和 博客文章,正如你可能猜到的,如果你玩过我们的其他模板,我们利用这次机会将 MDX 集成到项目中。
以下是一个基本案例研究的示例——主要用 markdown 编写,配合一些常见的元数据和自定义组件的支持:
import logo from "@/images/clients/phobia/logomark-dark.svg";import imageHero from "./hero.jpg";import imageJennyWilson from "./jenny-wilson.jpeg";export const caseStudy = { client: "Phobia", title: "战胜你的恐惧,找到你的匹配", description: "在恐惧面前找到爱——Phobia 是一款通过用户共同的恐惧症进行配对的约会应用,帮助他们一起面对恐惧。", summary: [ "在恐惧面前找到爱——Phobia 是一款通过用户共同的恐惧症进行配对的约会应用,帮助他们一起面对恐惧。", "我们与 Phobia 合作开发了一个新的入职流程。用户会看到常见恐惧的图片,我们利用麦克风检测哪些恐惧会让他们尖叫,将结果输入到匹配算法中。", ], logo, image: { src: imageHero }, date: "2022-06", service: "应用开发", testimonial: { author: { name: "Jenny Wilson", role: "Phobia 的 CPO" }, content: "Studio 团队超越了我们的期望,甚至找到了一种方法可以在不触发恼人的权限对话框的情况下访问用户的麦克风。", },};export const metadata = { title: `${caseStudy.client} 案例研究`, description: caseStudy.description,};## 概述由于注意到极高的流失率,Phobia 团队得出结论,他们需要改进入职流程,而不是拥有根本有缺陷的商业想法。之前用户手动选择他们的恐惧症,但这导致一些用户选择他们实际上并不害怕的东西来增加匹配。为了应对这一点,我们开发了一个系统,在入职过程中展示常见恐惧的幻灯片。然后,我们使用恶意软件暗中访问他们的麦克风,检测他们是否有可听的反应。我们测量他们尖叫的音调、音量和时长,并将这些信息加入匹配算法中。下一阶段是入职流程的 VR 版本,用户将经历一系列情境以确定他们的恐惧。我们目前正在开发第一个场景,工作标题:“跳出一架装满蜘蛛的飞机”。## 我们所做的<TagList> <TagListItem>Android</TagListItem> <TagListItem>iOS</TagListItem> <TagListItem>恶意软件</TagListItem> <TagListItem>VR</TagListItem></TagList><Blockquote author={{ name: "Jenny Wilson", role: "Phobia 的 CPO" }} image={{ src: imageJennyWilson }}> Studio 团队超越了我们的期望,甚至找到了一种方法可以在不触发恼人的权限对话框的情况下访问用户的麦克风。</Blockquote><StatList> <StatListItem value="20%" label="流失率" /> <StatListItem value="5x" label="卸载次数" /> <StatListItem value="2.3" label="应用商店评分" /> <StatListItem value="8" label="待决诉讼" /></StatList>
这个模板的所有排版样式都是完全自定义的,这次我们采取了一种不同的方法,而不是写一堆复杂的 CSS 来避免我们的排版样式与 MDX 中的任何自定义组件冲突,我们创建了一个小的 remark 插件 remark-rehype-wrap
,能够在一个包装元素中包裹 Markdown 内容的块。
这样,我们就可以将任何普通的 Markdown 内容包裹在 typography
类中,但确保文档中的任何自定义组件都不会被包裹,而不是尝试以某种方式制作CSS使其忽略树的那些部分。
这两种方法完全可行,但尝试新想法并看看你会学到什么总是很有趣。我也很好奇,未来基于即将到来的新 样式查询 CSS 特性解决方案会是什么样子!
这就是 Studio! 下载它,拆解它,看看你是否能学到几招新本领。
和我们所有的模板一样,它包含在一次性购买的 Tailwind UI 全访问 许可中,这是支持我们在 Tailwind CSS 上工作的最佳方法,使我们能够在未来几年继续构建精彩的东西。