文档
开始设置
要求
Tailwind Plus 中的所有组件都为最新版本的 Tailwind CSS 而设计,目前是 Tailwind CSS v4.0。要确保您使用的是最新版本的 Tailwind,请通过 npm 更新
npm install tailwindcss@latest
如果您是 Tailwind CSS 的新手,您还需要阅读 Tailwind CSS 文档,以便充分利用 Tailwind Plus。
添加 Inter 字体系列
我们在所有 Tailwind Plus 示例中都使用了 Inter,因为它是一种用于 UI 设计的漂亮字体,并且完全开源且免费。使用自定义字体的好处是它可以使组件在所有浏览器和操作系统上看起来都相同。
当然,您可以在自己的项目中使用任何您想要的字体,但如果您想使用 Inter,最简单的方法是首先通过 CDN 添加它
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
然后在您的 Tailwind 主题中将 "InterVariable" 添加到您的 "sans" 字体系列中
@theme {
--font-sans: InterVariable, sans-serif;
}
如果您仍在使用 Tailwind CSS v3.x,您可以在您的 tailwind.config.js
文件中执行此操作
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['InterVariable', ...defaultTheme.fontFamily.sans],
},
},
},
// ...
}
使用 HTML
自带 JavaScript
Tailwind Plus 中的所有组件均以三种格式提供:React、Vue 和原生 HTML。
React 和 Vue 示例是完全开箱即用的,并且由 Headless UI 提供支持——我们设计的一个无样式组件库,旨在与 Tailwind CSS 完美集成。
原生 HTML 示例不包含任何 JavaScript,专为喜欢自己编写任何必要的 JavaScript,或者希望与 React 或 Vue 以外的框架集成的人员而设计。
绝大多数组件根本不需要 JavaScript,并且完全可以开箱即用,但是诸如下拉菜单、对话框等交互式组件需要您编写一些 JS 才能使其按您期望的方式工作。
在这些情况下,我们在 HTML 中提供了一些简单的注释,以解释诸如您需要为不同状态使用哪些类(例如,切换开关的开启或关闭状态),或者我们推荐哪些类用于将元素过渡到屏幕上或屏幕外(例如,对话框打开)。
辅助功能考虑事项
我们已尽力确保 Tailwind Plus 中的所有标记都尽可能地易于访问,但是当您构建交互式组件时,许多辅助功能最佳实践只能通过 JavaScript 实现。
例如
- 确保组件可以正确地通过键盘访问(应该使用向上/向下箭头键导航下拉菜单,当您按下 escape 键时应该关闭对话框,应该使用向左/向右箭头键选择选项卡,等等)
- 正确处理焦点(您不应该能够跳到对话框后面的元素,下拉菜单中的第一个项目应该在下拉菜单打开时自动聚焦,等等)
- 将 ARIA 属性与组件状态同步(在下拉菜单打开时添加
aria-expanded="true"
,在切换开关开启时将aria-checked
设置为 true,在导航自动完成中的选项时更新aria-activedescendant
,等等) - ...以及许多其他问题。
如果您将 Tailwind Plus 与 React 或 Vue 一起使用,则所有这些复杂性都由 Headless UI 为您自动处理,但是如果您提供自己的 JS,则由您负责在添加交互行为时遵循辅助功能最佳实践。
要了解有关构建可访问的 UI 组件的更多信息,我们建议您学习 W3C 发布的 WAI-ARIA 创作实践。
动态类
当元素需要根据某些状态应用不同的类(例如,切换开关的开启或关闭状态)时,我们会将每个状态的类列在元素正上方的注释中
<!-- On: "bg-indigo-600", Off: "bg-gray-200" -->
<span
aria-checked="false"
class="focus:shadow-outline relative inline-block h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-gray-200 transition-colors duration-200 ease-in-out focus:outline-none"
role="checkbox"
tabindex="0"
>
<!-- On: "translate-x-5", Off: "translate-x-0" -->
<span
aria-hidden="true"
class="inline-block size-5 translate-x-0 transform rounded-full bg-white shadow transition duration-200 ease-in-out"
></span>
</span>
我们提供的 HTML 始终针对定义的某个状态进行了预配置,并且您在切换状态时需要更改的类始终位于类列表的最前面,以便于查找。
例如,要使此 HTML 适应 Alpine.js,您可以根据您在 x-data
中声明的某些状态,有条件地使用 :class
指令应用正确的类
<span
x-data="{ isOn: false }"
@click="isOn = !isOn"
:aria-checked="isOn"
:class="{'bg-indigo-600': isOn, 'bg-gray-200': !isOn }"
class="focus:shadow-outline relative inline-block h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent bg-gray-200 transition-colors duration-200 ease-in-out focus:outline-none"
role="checkbox"
tabindex="0"
>
<span
aria-hidden="true"
:class="{'translate-x-5': isOn, 'translate-x-0': !isOn }"
class="inline-block size-5 translate-x-0 transform rounded-full bg-white shadow transition duration-200 ease-in-out"
></span>
</span>
我们在此处包含了一个基本的点击处理程序来演示总体思路,但是在构建此类组件时,请参考 WAI-ARIA 创作实践,以确保您实现所有必要的键盘交互并正确管理任何必需的 ARIA 属性。
过渡效果
对于应该动态显示或隐藏的元素(例如,下拉菜单上的面板),我们在动态元素正上方的注释中包含了推荐的过渡样式
<div class="relative ...">
<button type="button" class="...">Options</button>
<!--
Show/hide this element based on the dropdown state
Entering: "transition ease-out duration-100 transform"
From: "opacity-0 scale-95"
To: "opacity-100 scale-100"
Closing: "transition ease-in duration-75 transform"
From: "opacity-100 scale-100"
To: "opacity-0 scale-95"
-->
<div class="absolute right-0 mt-2 w-56 origin-top-right rounded-md shadow-lg">
<div class="rounded-md bg-white shadow-xs">
<!-- Snipped -->
</div>
</div>
</div>
例如,要使此 HTML 适应 Alpine.js,您可以使用 x-transition
指令在过渡生命周期的每个点应用正确的类
<div x-data="{ isOpen: false }" class="relative ...">
<button type="button" @click="isOpen = !isOpen" class="...">Options</button>
<div
x-show="isOpen"
x-transition:enter="transition ease-out duration-100 transform"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75 transform"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="absolute right-0 mt-2 w-56 origin-top-right rounded-md shadow-lg"
>
<div class="rounded-md bg-white shadow-xs">
<!-- Snipped -->
</div>
</div>
</div>
我们在此处包含了一个基本的点击处理程序来演示总体思路,但是在构建此类组件时,请参考 WAI-ARIA 创作实践,以确保您实现所有必要的键盘交互并正确管理任何必需的 ARIA 属性。
创建局部/组件
由于 Tailwind Plus 中包含的原生 HTML 示例无法利用循环之类的内容,因此存在很多重复,而在真实世界的项目中,HTML 是从某些动态数据源生成的,因此实际上不会存在这种重复。例如,我们可能会为您提供一个包含 5 个列表项的列表组件,每个列表项上都重复了所有实用程序,而在您的项目中,您实际上将通过循环遍历数组来生成这些列表项。
在使我们的示例适应您自己的项目时,我们建议根据需要创建可重用的模板局部或 JS 组件,以管理任何重复。
在 Tailwind CSS 网站上的 “使用组件”文档中了解有关此内容的更多信息。
使用 React
安装依赖项
React 版 Tailwind Plus 依赖于 Headless UI 来驱动所有交互行为,并依赖于 Heroicons 来提供图标,因此您需要将这两个库添加到您的项目中
npm install @headlessui/react @heroicons/react
这些库和 Tailwind Plus 本身都需要 React >= 16.
创建组件
所有 React 示例都作为简单的单个组件提供,并且不对您希望如何分解事物、希望公开哪些 prop API 或从何处获取任何数据做出任何假设。
某些数据已被提取到基本局部变量中,只是为了清理重复并使代码更易于阅读和理解,但是我们已尽力做到尽可能少地避免强加任何不必要的僵化意见。
当您要使 Tailwind Plus 中的代码适应您自己的项目时,您应该根据需要将示例分解为更小的组件,以实现您的项目所需的任何级别的重用。
例如,您可以从这个堆叠列表组件开始
const people = [
{
name: 'Calvin Hawkins',
email: 'calvin.hawkins@example.com',
image:
'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Kristen Ramos',
email: 'kristen.ramos@example.com',
image:
'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Ted Fox',
email: 'ted.fox@example.com',
image:
'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
]
export default function Example() {
return (
<ul className="divide-y divide-gray-200">
{people.map((person) => (
<li key={person.email} className="flex py-4">
<img className="size-10 rounded-full" src={person.image} alt="" />
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">{person.name}</p>
<p className="text-sm text-gray-500">{person.email}</p>
</div>
</li>
))}
</ul>
)
}
在使内容适应您自己的项目、将其分解为单独的组件以及连接数据源之后,它可能看起来更像这样
function HockeyTeamItem({ team }) {
return (
<li className="flex py-4">
<img className="size-10 rounded-full" src={team.logo} alt="" />
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">{team.name}</p>
<p className="text-sm text-gray-500">{team.city}</p>
</div>
</li>
)
}
export default function HockeyTeamList({ teams }) {
return (
<ul className="divide-y divide-gray-200">
{teams.map((team) => (
<HockeyTeamItem key={team.id} team={team} />
))}
</ul>
)
}
Tailwind Plus 更像是蓝图、模式和想法的集合,而不是僵化的 UI 套件。最终您得到的代码是您自己的,您可以随意分解它。
使用 Vue
安装依赖项
Vue 版 Tailwind Plus 依赖于 Headless UI 来驱动所有交互行为,并依赖于 Heroicons 来提供图标,因此您需要将这两个库添加到您的项目中
npm install @headlessui/vue @heroicons/vue
创建组件
所有 Vue 示例都作为简单的单个组件提供,并且不对您希望如何分解事物、希望公开哪些 prop API 或从何处获取任何数据做出任何假设。
某些数据已被提取到基本局部变量中,只是为了清理重复并使代码更易于阅读和理解,但是我们已尽力做到尽可能少地避免强加任何不必要的僵化意见。
当您要使 Tailwind Plus 中的代码适应您自己的项目时,您应该根据需要将示例分解为更小的组件,以实现您的项目所需的任何级别的重用。
例如,您可以从这个堆叠列表组件开始
<template>
<ul class="divide-y divide-gray-200">
<li v-for="person in people" :key="person.email" class="flex py-4">
<img class="size-10 rounded-full" :src="person.image" alt="" />
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">{{ person.name }}</p>
<p class="text-sm text-gray-500">{{ person.email }}</p>
</div>
</li>
</ul>
</template>
<script>
const people = [
{
name: 'Calvin Hawkins',
email: 'calvin.hawkins@example.com',
image:
'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Kristen Ramos',
email: 'kristen.ramos@example.com',
image:
'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Ted Fox',
email: 'ted.fox@example.com',
image:
'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
]
export default {
setup() {
return {
people,
}
},
}
</script>
在使内容适应您自己的项目、将其分解为单独的组件以及连接数据源之后,它可能看起来更像这样
<!-- HockeyTeamList.vue -->
<template>
<ul class="divide-y divide-gray-200">
<HockeyTeamItem v-for="team in teams" :key="team.id" :team="team" />
</ul>
</template>
<script>
export default {
props: {
teams: Array,
},
}
</script>
<!-- HockeyTeamListItem.vue -->
<template>
<li class="flex py-4">
<img class="size-10 rounded-full" :src="team.logo" alt="" />
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">{{ team.name }}</p>
<p class="text-sm text-gray-500">{{ team.city }}</p>
</div>
</li>
</template>
<script>
export default {
props: {
team: Object,
},
}
</script>
Tailwind Plus 更像是蓝图、模式和想法的集合,而不是僵化的 UI 套件。最终您得到的代码是您自己的,您可以随意分解它。
资源和资产
图标
我们在 Tailwind Plus 中使用的所有图标都来自 Heroicons,这是一个免费的 MIT 许可图标集,我们在开始开发 Tailwind Plus 时自己设计和开发的。
图片
Tailwind Plus 中的图像几乎完全来自 Unsplash。如果您需要可免费使用的摄影作品用于您的项目,这是一个很好的资源。
插画
Tailwind Plus 中的某些示例使用了免费 Lucid Illustrations 包中的插画,该包由 Pixsellz 提供。您可以获取整套插画,并在 他们的网站上查看他们的其他设计资源。
Figma 资产
我们曾经为 Tailwind Plus 提供 Figma 资产,但是维护它们的工作量非常大,而且很少有人使用它们。我们做出了非常艰难的决定,停止提供它们,以便我们可以将更多时间花在实际代码上,我们认为这才是我们可以提供最大价值的地方。
Tailwind Plus 的客户可以下载我们发布的最终 Figma 文件,但请注意Figma 文件不会收到更新,并且不包含 2021 年 7 月 14 日之后发布的任何示例。