我们刚刚发布了 Studio——一个美丽的新代理网站模板,我们过去几个月为了 Tailwind UI 一直在努力工作。
我们使用 Next.js、MDX 和当然还有 Tailwind CSS 构建了它,并且这是我们发布的第一个使用新 Next.js App Router 的模板。
设计一个代理模板是一个有趣的项目,因为创意代理通常使用他们自己的网站展示一些非常闪耀的、定制的想法,而使用模板在目标是展示自己公司能做到什么时,感觉有些奇怪。
因此,我们尝试在这里以两个目标为导向,真正使其对人们有用:
- 教人们如何做一些你在闪亮代理网站上看到的酷东西——我一直相信我们的模板不仅仅是模板,而且作为教育资源同样(如果不是更)有价值,因此我们希望利用这个模板来展示我们如何构建你在这些网站上看到的许多酷炫的互动和动画细节。
- 为不出售设计的代理设计它——有很多代理专注于工程工作,很多时候这些公司在设计方面很难脱颖而出。我们试图以一种不依赖于众多设计工作截图等东西来让它看起来好的方式设计这个模板,以便一个专注于代码的代理可以将其作为自己网站的起点。
我认为我们想出的方案达到了这两个目标,我对它的结果感到非常自豪。
像往常一样,查看 实时预览 以获得完整体验——这个模板中有许多酷炫的细节,你必须在浏览器中查看才能真正欣赏。
令人愉悦的动画
代理网站的一个不成文的规则是它们必须闪耀。我们没有完全替换鼠标光标或使用 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 上工作的最佳方法,使我们能够在未来几年继续构建精彩的东西。