
第一周:基础入门与核心概念
第1天:初识 Tailwind CSS 与环境搭建
-
核心概念: 了解什么是“Utility-First (实用工具优先)”,以及它与传统 CSS (如 BEM) 或 CSS-in-JS 的区别。Tailwind 不是 UI 库,而是一个生成 CSS 的框架,它提供大量预设的、可组合的 class。
-
React/Vue 结合:
-
React:
npx create-react-app my-project && cd my-project -
Vue:
npm create vue@latest -
然后按照 Tailwind CSS 官方文档 的框架指南进行安装和配置。关键文件是
tailwind.config.js和postcss.config.js。
-
-
实战练习: 成功搭建项目,并使用一个 Tailwind class 来验证安装是否成功。
-
React 代码 (
App.js):function App() { return ( <div className="p-4"> <h1 className="text-3xl font-bold text-blue-600 underline"> Hello Tailwind in React! </h1> </div> ); } export default App; -
Vue 代码 (
代码段App.vue):<template> <div class="p-4"> <h1 class="text-3xl font-bold text-blue-600 underline"> Hello Tailwind in Vue! </h1> </div> </template>
-
第2天:核心理念:Utility-First 思想
-
实战练习: 创建一个简单的个人简介卡片框架,只使用
div和p标签,为接下来的练习做准备。-
React 代码:
function ProfileCard() { return ( <div> <div> <img src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> <div> <h2>Ada Lovelace</h2> <p>Full-Stack Developer</p> <p>The world's first computer programmer.</p> </div> </div> ); } -
Vue 代码:
代码段<template> <div> <div> <img src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> <div> <h2>Ada Lovelace</h2> <p>Full-Stack Developer</p> <p>The world's first computer programmer.</p> </div> </div> </template>
-
第3天:间距 (Spacing) 与尺寸 (Sizing)
-
实战练习: 为昨天的个人简介卡片添加内边距和外边距,并设定一个固定的宽度。
-
React 代码:
function ProfileCard() { return ( // m-8: 2rem margin, w-96: 24rem width, p-6: 1.5rem padding <div className="m-8 w-96 bg-gray-100 p-6"> {/* ... rest of the card ... */} </div> ); } -
Vue 代码:
<template> <div class="m-8 w-96 bg-gray-100 p-6"> </div> </template>
-
第4天:颜色 (Colors) 与排版 (Typography)
-
实战练习: 美化你的个人简介卡片。
-
React 代码:
function ProfileCard() { return ( <div className="m-8 w-96 bg-white p-6"> {/* Changed bg to white */} <div> <img src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> {/* Add margin-top to the text block */} <div className="mt-4"> {/* Name: large text, bold, dark gray */} <h2 className="text-xl font-bold text-gray-800">Ada Lovelace</h2> {/* Title: small text, medium gray */} <p className="text-sm text-gray-600">Full-Stack Developer</p> {/* Bio: normal text, normal gray, comfortable line height */} <p className="mt-2 text-gray-700 leading-relaxed"> The world's first computer programmer. </p> </div> </div> ); } -
Vue 代码:
<template> <div class="m-8 w-96 bg-white p-6"> <div> <img src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> <div class="mt-4"> <h2 class="text-xl font-bold text-gray-800">Ada Lovelace</h2> <p class="text-sm text-gray-600">Full-Stack Developer</p> <p class="mt-2 text-gray-700 leading-relaxed"> The world's first computer programmer. </p> </div> </div> </template>
-
第5天:Flexbox 布局
-
实战练习: 使用 Flexbox 将头像和文字信息左右排列。
-
React 代码:
function ProfileCard() { // flex: enable flexbox, items-center: vertically align items to center, gap-6: add space between items return ( <div className="m-8 flex w-96 items-center gap-6 bg-white p-6"> <div> <img src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> <div> {/* Text content now vertically centered with image */} <h2 className="text-xl font-bold text-gray-800">Ada Lovelace</h2> <p className="text-sm text-gray-600">Full-Stack Developer</p> <p className="mt-2 text-gray-700 leading-relaxed"> The world's first computer programmer. </p> </div> </div> ); } -
Vue 代码:
<template> <div class="m-8 flex w-96 items-center gap-6 bg-white p-6"> <div> <img src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> <div> <h2 class="text-xl font-bold text-gray-800">Ada Lovelace</h2> <p class="text-sm text-gray-600">Full-Stack Developer</p> <p class="mt-2 text-gray-700 leading-relaxed"> The world's first computer programmer. </p> </div> </div> </template>
-
第6天:Grid 布局
-
实战练习: 创建一个 3x2 的图片画廊,让第一张图片占据两列。
-
React 代码:
function ImageGallery() { return ( // grid: enable grid, grid-cols-3: 3 columns, gap-4: space between cells <div className="grid grid-cols-3 gap-4 p-4"> {/* col-span-2: make this item span 2 columns */} <div className="col-span-2 h-40 bg-sky-200"></div> <div className="h-40 bg-sky-200"></div> <div className="h-40 bg-sky-200"></div> <div className="h-40 bg-sky-200"></div> <div className="h-40 bg-sky-200"></div> </div> ); } -
Vue 代码:
<template> <div class="grid grid-cols-3 gap-4 p-4"> <div class="col-span-2 h-40 bg-sky-200"></div> <div class="h-40 bg-sky-200"></div> <div class="h-40 bg-sky-200"></div> <div class="h-40 bg-sky-200"></div> <div class="h-40 bg-sky-200"></div> </div> </template>
-
第7天:边框 (Borders) 与阴影 (Shadows)
-
实战练习: 为个人简介卡片添加圆角、阴影,并为头像添加圆形边框。
-
React 代码:
function ProfileCard() { return ( // rounded-xl: large border radius, shadow-lg: large shadow <div className="m-8 flex w-96 items-center gap-6 rounded-xl bg-white p-6 shadow-lg"> <div> {/* rounded-full: make it a circle, border-4: 4px border, border-violet-300: border color */} <img className="h-24 w-24 rounded-full border-4 border-violet-300" src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> {/* ... text content ... */} </div> ); } -
Vue 代码:
<template> <div class="m-8 flex w-96 items-center gap-6 rounded-xl bg-white p-6 shadow-lg"> <div> <img class="h-24 w-24 rounded-full border-4 border-violet-300" src="https://via.placeholder.com/150" alt="Profile avatar" /> </div> </div> </template>
-
第二周:响应式设计与交互性
第8天:响应式设计基础 (Responsive Design)
-
实战练习: 改造卡片,小屏垂直布局,中屏及以上水平布局。
-
React 代码:
function ResponsiveProfileCard() { return ( // default: flex-col, md(768px) and up: flex-row // default: text-center, md and up: text-left <div className="m-8 flex max-w-sm flex-col items-center rounded-xl bg-white p-6 shadow-lg md:max-w-md md:flex-row md:items-start md:gap-6"> <img className="h-24 w-24 flex-shrink-0 rounded-full border-4 border-violet-300 md:h-32 md:w-32" src="https://via.placeholder.com/150" alt="Profile avatar" /> <div className="mt-4 text-center md:mt-0 md:text-left"> {/* ... text content ... */} </div> </div> ); } -
Vue 代码:
<template> <div class="m-8 flex max-w-sm flex-col items-center rounded-xl bg-white p-6 shadow-lg md:max-w-md md:flex-row md:items-start md:gap-6"> <img class="h-24 w-24 flex-shrink-0 rounded-full border-4 border-violet-300 md:h-32 md:w-32" src="https://via.placeholder.com/150" alt="Profile avatar" /> <div class="mt-4 text-center md:mt-0 md:text-left"> </div> </div> </template>
-
第9天:状态伪类 (Hover, Focus, etc.)
-
实战练习: 创建一个交互式按钮。
-
React/Vue 代码 (Class 字符串相同):
<button class="rounded-lg bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700 active:bg-blue-900 focus:outline-none focus:ring focus:ring-blue-300"> Save Changes </button>
-
第10天:过渡 (Transitions) 与动画 (Animations)
-
实战练习: 为按钮添加平滑过渡效果。
-
React/Vue 代码 (Class 字符串相同):
<button class="... transition-all duration-300 ease-in-out hover:scale-105 active:scale-95"> Save Changes </button>
-
第11天:定位 (Positioning) 与 Z-Index
-
实战练习: 创建带“新消息”提示的头像。
-
React/Vue 代码 (Class 字符串相同):
<div class="relative inline-block"> <img class="h-16 w-16 rounded-full" src="https://via.placeholder.com/150" alt="User Avatar"/> <span class="absolute right-0 top-0 z-10 h-4 w-4 rounded-full bg-red-500 border-2 border-white"></span> </div>
-
第12天:分组 (group) 与对等元素 (peer)
-
实战练习:
group用于卡片悬浮,peer用于表单。-
group示例 (React/Vue):<a href="#" class="group block max-w-xs rounded-lg bg-white p-6 shadow-lg ring-1 ring-slate-900/5"> <h3 class="text-lg font-semibold text-slate-900 group-hover:text-sky-500"> Card Title </h3> <p class="text-slate-500 group-hover:text-slate-700"> When you hover the card, the text color changes. </p> </a> -
peer示例 (React/Vue):<div class="relative"> <input id="email" class="peer h-10 w-full rounded-md border border-gray-300 px-4 text-gray-900 placeholder-transparent focus:outline-none focus:ring-2 focus:ring-sky-500" placeholder="you@example.com" /> <label for="email" class="absolute left-2 -top-5 bg-white px-1 text-sm text-gray-600 transition-all peer-placeholder-shown:top-2 peer-placeholder-shown:text-base peer-focus:-top-5 peer-focus:text-sm peer-focus:text-sky-600"> Email </label> </div>
-
第13天:深色模式 (Dark Mode)
-
实战练习: 改造卡片以支持深色模式。提示: 你需要用 JS 切换
<html>上的darkclass。-
React/Vue 代码 (Class 字符串相同):
<div class="m-8 max-w-sm rounded-xl bg-white p-6 shadow-lg dark:bg-slate-800"> <div> <h2 class="text-xl font-bold text-gray-800 dark:text-white">Ada Lovelace</h2> <p class="text-sm text-gray-600 dark:text-slate-400">Full-Stack Developer</p> <p class="mt-2 text-gray-700 dark:text-slate-300"> The world's first computer programmer. </p> </div> </div>
-
第14天:Just-In-Time (JIT) 引擎与任意值
-
实战练习: 使用任意值创建自定义样式。
-
React/Vue 代码 (Class 字符串相同):
<div class="h-[120px] w-[250px] bg-[#bada55] mt-[17px] text-center text-[22px]"> Arbitrary Values Rock! </div>
-
第三周:组件化与自定义
第15天:组件化思维与 @apply
-
实战练习: 使用
@apply创建一个.btnclass。-
CSS 代码 (
./src/index.css):@tailwind base; @tailwind components; @tailwind utilities; @layer components { .btn-primary { @apply rounded-lg bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700; } } -
React/Vue 使用:
<button class="btn-primary"> Applied Button </button>
-
第16天:配置 tailwind.config.js - 自定义主题
-
实战练习: 添加自定义品牌颜色。
-
tailwind.config.js代码:module.exports = { theme: { extend: { colors: { brand: { primary: '#ff5733', secondary: '#33ff57', }, }, }, }, // ... other settings } -
React/Vue 使用:
<div class="bg-brand-primary p-4 text-white"> This has my brand's primary color! </div>
-
第17天:表单样式与 @tailwindcss/forms 插件
-
实战练习: 创建一个漂亮的表单。
-
React/Vue 代码 (Class 字符串相同):
<form class="space-y-4 rounded-lg bg-white p-6 shadow-md"> <div> <label for="name" class="block text-sm font-medium text-gray-700">Name</label> <input type="text" id="name" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" /> </div> <div> <label for="country" class="block text-sm font-medium text-gray-700">Country</label> <select id="country" class="mt-1 block w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"> <option>United States</option> <option>Canada</option> <option>Mexico</option> </select> </div> </form>
-
第19天:构建一个响应式导航栏 (Navbar)
-
实战练习: 构建一个完整的响应式导航栏。
-
React 代码:
import { useState } from 'react'; function Navbar() { const [isOpen, setIsOpen] = useState(false); return ( <nav className="bg-gray-800 p-4 text-white"> <div className="container mx-auto flex items-center justify-between"> <div className="font-bold">Logo</div> {/* Desktop Menu */} <div className="hidden space-x-4 md:flex"> <a href="#" className="hover:text-gray-300">Home</a> <a href="#" className="hover:text-gray-300">About</a> <a href="#" className="hover:text-gray-300">Contact</a> </div> {/* Mobile Menu Button */} <div className="md:hidden"> <button onClick={() => setIsOpen(!isOpen)}> <svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16m-7 6h7" /> </svg> </button> </div> </div> {/* Mobile Menu */} {isOpen && ( <div className="mt-4 md:hidden"> <a href="#" className="block py-2 hover:bg-gray-700">Home</a> <a href="#" className="block py-2 hover:bg-gray-700">About</a> <a href="#" className="block py-2 hover:bg-gray-700">Contact</a> </div> )} </nav> ); } -
Vue 代码:
<script setup> import { ref } from 'vue'; const isOpen = ref(false); </script> <template> <nav class="bg-gray-800 p-4 text-white"> <div class="container mx-auto flex items-center justify-between"> <div class="font-bold">Logo</div> <div class="hidden space-x-4 md:flex"> <a href="#" class="hover:text-gray-300">Home</a> </div> <div class="md:hidden"> <button @click="isOpen = !isOpen"> </button> </div> </div> <div v-if="isOpen" class="mt-4 md:hidden"> <a href="#" class="block py-2 hover:bg-gray-700">Home</a> </div> </nav> </template>
-
第20天:构建一个卡片 (Card) 组件
-
实战练习: 设计并实现一个可复用的产品卡片组件。
-
React 代码:
// Component Definition: Card.js function Card({ imageUrl, title, price }) { return ( <div className="max-w-xs overflow-hidden rounded-lg shadow-lg"> <img className="w-full" src={imageUrl} alt={title} /> <div className="px-6 py-4"> <div className="mb-2 text-xl font-bold">{title}</div> <p className="text-base text-gray-700">${price}</p> </div> <div className="px-6 pb-4 pt-2"> <button className="w-full rounded-full bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"> Add to Cart </button> </div> </div> ); } // Usage in another component <Card imageUrl="https://via.placeholder.com/300" title="Cool Gadget" price="49.99" /> -
Vue 代码:
<script setup> defineProps({ imageUrl: String, title: String, price: [String, Number] }) </script> <template> <div class="max-w-xs overflow-hidden rounded-lg shadow-lg"> <img class="w-full" :src="imageUrl" :alt="title" /> <div class="px-6 py-4"> <div class="mb-2 text-xl font-bold">{{ title }}</div> <p class="text-base text-gray-700">${{ price }}</p> </div> <div class="px-6 pb-4 pt-2"> <button class="w-full rounded-full bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"> Add to Cart </button> </div> </div> </template>
-
第四周:高级技巧与生态系统
第22天:任意变体 (Arbitrary Variants)
-
实战练习: 创建一个折叠面板 (Accordion)。
-
React/Vue 代码:
<div class="group" data-state="closed"> <button class="flex w-full items-center justify-between"> <span>Accordion Title</span> <svg class="h-6 w-6 transition-transform duration-300 group-data-[state=open]:rotate-180">...</svg> </button> <div class="overflow-hidden transition-all duration-300 grid grid-rows-[0fr] group-data-[state=open]:grid-rows-[1fr]"> <div class="min-h-0"> Lorem ipsum dolor sit amet... </div> </div> </div>
-
第23天:插件 (Plugins) 的使用与编写基础
-
实战练习: 使用
@tailwindcss/typography插件。-
React/Vue 代码:
<article class="prose lg:prose-xl p-8 dark:prose-invert"> <h1>My Blog Post</h1> <p>This is a paragraph styled automatically by the typography plugin.</p> <ul> <li>List item 1</li> <li>List item 2</li> </ul> </article>
-
第25天:与 Headless UI / Radix UI 集成
-
实战练习: 使用 Headless UI 创建下拉菜单。
-
React (Headless UI) 代码:
import { Menu, Transition } from '@headlessui/react' import { Fragment } from 'react' function MyDropdown() { return ( <Menu as="div" className="relative inline-block text-left"> <Menu.Button className="inline-flex w-full justify-center rounded-md bg-black/20 px-4 py-2 text-sm font-medium text-white hover:bg-black/30"> Options </Menu.Button> <Transition as={Fragment} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" leave="transition ease-in duration-75" leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95"> <Menu.Items className="absolute right-0 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 focus:outline-none"> <div className="px-1 py-1 "> <Menu.Item>{({ active }) => (<button className={`${active ? 'bg-violet-500 text-white' : 'text-gray-900'} group flex w-full items-center rounded-md px-2 py-2 text-sm`}>Edit</button>)}</Menu.Item> <Menu.Item>{({ active }) => (<button className={`${active ? 'bg-violet-500 text-white' : 'text-gray-900'} group flex w-full items-center rounded-md px-2 py-2 text-sm`}>Duplicate</button>)}</Menu.Item> </div> </Menu.Items> </Transition> </Menu> ) }
-

352

被折叠的 条评论
为什么被折叠?



