告别繁琐 CSS!Tailwind CSS 20天重塑你的前端开发工作流 (React/Vue 实战版)

第一周:基础入门与核心概念

第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.jspostcss.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 思想

  • 实战练习: 创建一个简单的个人简介卡片框架,只使用 divp 标签,为接下来的练习做准备。

    • 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> 上的 dark class。

    • 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 创建一个 .btn class。

    • 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>
        )
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nextera-void

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值