Remix Tailwind CSS #

一、Tailwind概述 #

Tailwind CSS 是一个功能类优先的 CSS 框架,提供原子化的 CSS 类,让你快速构建用户界面。

二、安装配置 #

2.1 安装依赖 #

bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

2.2 配置Tailwind #

编辑 tailwind.config.js

javascript
/** @type {import('tailwindcss').Config} */
export default {
  content: ["./app/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#eff6ff',
          100: '#dbeafe',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
        },
      },
    },
  },
  plugins: [],
};

2.3 创建CSS文件 #

创建 app/tailwind.css

css
@tailwind base;
@tailwind components;
@tailwind utilities;

2.4 在根组件中导入 #

编辑 app/root.tsx

tsx
import type { LinksFunction } from "@remix-run/node";
import stylesheet from "~/tailwind.css?url";

export const links: LinksFunction = () => [
  { rel: "stylesheet", href: stylesheet },
];

三、基本使用 #

3.1 布局 #

tsx
export default function Page() {
  return (
    <div className="min-h-screen bg-gray-100">
      <div className="container mx-auto px-4 py-8">
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
          {/* 卡片 */}
        </div>
      </div>
    </div>
  );
}

3.2 排版 #

tsx
export default function Article({ post }) {
  return (
    <article className="prose prose-lg max-w-none">
      <h1 className="text-3xl font-bold text-gray-900 mb-4">
        {post.title}
      </h1>
      <p className="text-gray-600 mb-6">{post.excerpt}</p>
      <div className="prose">
        {post.content}
      </div>
    </article>
  );
}

3.3 表单 #

tsx
export default function ContactForm() {
  return (
    <form className="space-y-4">
      <div>
        <label className="block text-sm font-medium text-gray-700 mb-1">
          姓名
        </label>
        <input
          type="text"
          className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
        />
      </div>
      <button
        type="submit"
        className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
      >
        提交
      </button>
    </form>
  );
}

四、自定义配置 #

4.1 扩展主题 #

javascript
export default {
  theme: {
    extend: {
      colors: {
        brand: {
          light: '#3fbaeb',
          DEFAULT: '#0fa9e6',
          dark: '#0c87b8',
        },
      },
      fontFamily: {
        sans: ['Inter', 'sans-serif'],
        mono: ['Fira Code', 'monospace'],
      },
      spacing: {
        '128': '32rem',
        '144': '36rem',
      },
    },
  },
};

4.2 添加插件 #

bash
npm install -D @tailwindcss/forms @tailwindcss/typography
javascript
import forms from '@tailwindcss/forms';
import typography from '@tailwindcss/typography';

export default {
  plugins: [
    forms,
    typography,
  ],
};

4.3 自定义组件类 #

css
/* app/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn {
    @apply px-4 py-2 rounded-md font-medium transition-colors;
  }
  
  .btn-primary {
    @apply btn bg-blue-600 text-white hover:bg-blue-700;
  }
  
  .btn-secondary {
    @apply btn bg-gray-200 text-gray-800 hover:bg-gray-300;
  }
  
  .card {
    @apply bg-white rounded-lg shadow-md p-6;
  }
}

五、响应式设计 #

5.1 断点 #

断点 最小宽度
sm 640px
md 768px
lg 1024px
xl 1280px
2xl 1536px

5.2 响应式组件 #

tsx
export default function Navbar() {
  return (
    <nav className="bg-white shadow">
      <div className="container mx-auto px-4">
        <div className="flex justify-between items-center h-16">
          <div className="flex-shrink-0">
            <span className="text-xl font-bold">Logo</span>
          </div>
          
          {/* 移动端隐藏,桌面端显示 */}
          <div className="hidden md:flex space-x-4">
            <a href="#" className="text-gray-700 hover:text-blue-600">
              首页
            </a>
            <a href="#" className="text-gray-700 hover:text-blue-600">
              关于
            </a>
          </div>
          
          {/* 移动端菜单按钮 */}
          <button className="md:hidden">
            <span>菜单</span>
          </button>
        </div>
      </div>
    </nav>
  );
}

六、深色模式 #

6.1 配置 #

javascript
export default {
  darkMode: 'class',
  // ...
};

6.2 使用 #

tsx
export default function Card() {
  return (
    <div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-white p-6 rounded-lg shadow">
      <h2 className="text-xl font-bold mb-2">标题</h2>
      <p className="text-gray-600 dark:text-gray-300">内容</p>
    </div>
  );
}

6.3 切换主题 #

tsx
import { useState, useEffect } from "react";

export function ThemeToggle() {
  const [isDark, setIsDark] = useState(false);
  
  useEffect(() => {
    if (isDark) {
      document.documentElement.classList.add('dark');
    } else {
      document.documentElement.classList.remove('dark');
    }
  }, [isDark]);
  
  return (
    <button
      onClick={() => setIsDark(!isDark)}
      className="p-2 rounded-lg bg-gray-200 dark:bg-gray-700"
    >
      {isDark ? '🌙' : '☀️'}
    </button>
  );
}

七、动画 #

7.1 内置动画 #

tsx
<button className="animate-pulse">脉冲</button>
<button className="animate-spin">旋转</button>
<button className="animate-bounce">弹跳</button>

7.2 自定义动画 #

javascript
export default {
  theme: {
    extend: {
      animation: {
        'fade-in': 'fadeIn 0.3s ease-in-out',
        'slide-up': 'slideUp 0.3s ease-out',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { transform: 'translateY(10px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
      },
    },
  },
};

八、最佳实践 #

8.1 提取组件 #

tsx
function Button({ variant = 'primary', children }) {
  const variants = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
    danger: 'bg-red-600 text-white hover:bg-red-700',
  };
  
  return (
    <button className={`px-4 py-2 rounded-md font-medium ${variants[variant]}`}>
      {children}
    </button>
  );
}

8.2 使用clsx #

tsx
import clsx from 'clsx';

function Card({ highlighted, children }) {
  return (
    <div
      className={clsx(
        'p-6 rounded-lg shadow-md',
        highlighted ? 'bg-blue-50 border-blue-200' : 'bg-white'
      )}
    >
      {children}
    </div>
  );
}

8.3 组织样式 #

tsx
const styles = {
  container: 'min-h-screen bg-gray-100',
  header: 'bg-white shadow',
  main: 'container mx-auto px-4 py-8',
  footer: 'bg-gray-800 text-white',
};

export default function Layout() {
  return (
    <div className={styles.container}>
      <header className={styles.header}>...</header>
      <main className={styles.main}>...</main>
      <footer className={styles.footer}>...</footer>
    </div>
  );
}

九、总结 #

本章我们学习了:

  1. 安装配置:设置Tailwind CSS
  2. 基本使用:布局、排版、表单
  3. 自定义配置:主题、插件、组件类
  4. 响应式:断点和响应式组件
  5. 深色模式:配置和使用

核心要点:

  • 使用原子类快速构建UI
  • 提取可复用组件
  • 使用clsx组合类名
  • 配置主题保持一致性
最后更新:2026-03-28