Tailwind CSS 自定义样式学习笔记

一、自定义样式的层次结构

┌──────────────────────────────────────────────────────┐
│  tailwind.config.js  →  设计系统 Token(颜色/间距/字号) │
│  @layer base         →  全局基础样式重置               │
│  @layer components   →  组件级自定义类                  │
│  @layer utilities    →  自定义工具类                    │
│  @layer 外部          →  第三方/覆盖样式                 │
│  arbitrary values    →  一次性行内自定义值               │
└──────────────────────────────────────────────────────┘

二、方法一:Arbitrary Values(任意值)

无需修改配置,直接在类名中使用方括号语法写入任意 CSS 值。

基本语法

<!-- 间距 -->
<div class="mt-[17px] w-[calc(100%-3rem)] p-[2.5rem]">

<!-- 颜色 -->
<span class="text-[#1da1f2] bg-[rgb(59,130,246,0.5)]">

<!-- 字体 -->
<p class="text-[22px] leading-[27px] font-[500] tracking-[0.01em]">

<!-- 动画 -->
<div class="animate-[spin_1.5s_linear_infinite]">

<!-- 背景图 -->
<div class="bg-[url('/hero-pattern.png')] bg-[size:100px_100px]">

任意变体(Arbitrary Variants)

<!-- 任意媒体查询 -->
<div class="@[supports(display:grid)]:grid">

<!-- 任意选择器 -->
<div class="[&:nth-child(3)]:underline">
<div class="[&::before]:content-['→'] [&::before]:mr-2">

<!-- 子元素选择器 -->
<nav class="[&>li]:flex [&>li]:items-center">

<!-- 父级上下文 -->
<div class="[.dark_&]:text-white">

注意事项

  • 任意值中的空格用 _ 代替:animate-[spin_1s_linear_infinite]
  • 任意值中的逗号用 _ 代替:grid-cols-[repeat(3,1fr)]grid-cols-[repeat(3,1fr)]
  • 仅用于一次性场景,频繁出现应提取到配置中

三、方法二:扩展 Theme 配置

2.1 扩展 vs 覆盖

// tailwind.config.js
module.exports = {
  theme: {
    // ❌ 覆盖 — 完全替换默认值,丢失 Tailwind 默认色板
    colors: {
      brand: '#3b82f6',
    },

    // ✅ 扩展 — 在默认值基础上追加
    extend: {
      colors: {
        brand: '#3b82f6',
      },
    },
  },
};

2.2 自定义颜色

module.exports = {
  theme: {
    extend: {
      colors: {
        // 简单值
        'brand': '#3b82f6',

        // 色阶对象(生成 text-brand-50 ~ text-brand-950)
        brand: {
          50:  '#eff6ff',
          100: '#dbeafe',
          200: '#bfdbfe',
          300: '#93c5fd',
          400: '#60a5fa',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
          800: '#1e40af',
          900: '#1e3a8a',
          950: '#172554',
        },

        // CSS 变量引用
        surface: 'var(--color-surface)',
        on: {
          surface: 'var(--color-on-surface)',
        },
      },
    },
  },
};
<button class="bg-brand-500 text-white hover:bg-brand-600">品牌按钮</button>
<div class="bg-surface text-on-surface">主题卡片</div>

2.3 自定义间距 / 尺寸

extend: {
  spacing: {
    '4.5': '1.125rem',
    '18':  '4.5rem',
    '128': '32rem',
  },
  width: {
    '1/7': '14.2857%',
    '2/7': '28.5714%',
  },
  height: {
    'screen/2': '50vh',
  },
}

2.4 自定义字体

extend: {
  fontFamily: {
    sans: ['Inter', 'system-ui', 'sans-serif'],
    mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
    display: ['Cal Sans', 'sans-serif'],
  },
  fontSize: {
    'xxs': ['0.625rem', { lineHeight: '0.875rem' }],
    '2xl': ['1.25rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }],
  },
}
<h1 class="font-display text-2xl">标题</h1>
<code class="font-mono text-xxs">代码</code>

2.5 自定义动画

extend: {
  keyframes: {
    'fade-in': {
      '0%':   { opacity: '0', transform: 'translateY(10px)' },
      '100%': { opacity: '1', transform: 'translateY(0)' },
    },
    'slide-in-right': {
      '0%':   { transform: 'translateX(100%)' },
      '100%': { transform: 'translateX(0)' },
    },
    'shimmer': {
      '100%': { transform: 'translateX(100%)' },
    },
  },
  animation: {
    'fade-in':         'fade-in 0.3s ease-out forwards',
    'slide-in-right':  'slide-in-right 0.4s ease-out',
    'shimmer':         'shimmer 2s infinite',
  },
}
<div class="animate-fade-in">淡入效果</div>
<div class="animate-slide-in-right">右侧滑入</div>

2.6 自定义阴影 / 边框圆角 / 过渡

extend: {
  boxShadow: {
    'glow': '0 0 15px rgba(59, 130, 246, 0.5)',
    'inner-lg': 'inset 0 2px 4px 0 rgb(0 0 0 / 0.1)',
  },
  borderRadius: {
    '4xl': '2rem',
    '5xl': '2.5rem',
  },
  transitionTimingFunction: {
    'bounce-in': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
  },
}

四、方法三:@layer 指令

4.1 Base 层 — 全局基础样式

@tailwind base;

@layer base {
  /* 全局字体平滑 */
  html {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }

  /* CSS 变量定义 */
  :root {
    --color-surface: #ffffff;
    --color-on-surface: #1a1a2e;
    --header-height: 4rem;
  }

  .dark {
    --color-surface: #1a1a2e;
    --color-on-surface: #e2e8f0;
  }

  /* 重置或覆盖默认样式 */
  h1 {
    @apply text-2xl font-bold tracking-tight;
  }
  h2 {
    @apply text-xl font-semibold;
  }

  /* 焦点样式 */
  *:focus-visible {
    @apply outline-2 outline-offset-2 outline-blue-500;
  }
}

4.2 Components 层 — 组件级样式

@tailwind components;

@layer components {
  /* 使用 @apply 聚合 */
  .btn {
    @apply inline-flex items-center justify-center
           rounded-md px-4 py-2 text-sm font-medium
           transition-colors focus-visible:outline-none
           focus-visible:ring-2 focus-visible:ring-offset-2
           disabled:pointer-events-none disabled:opacity-50;
  }

  .btn-primary {
    @apply btn bg-blue-600 text-white hover:bg-blue-700
           focus-visible:ring-blue-500;
  }

  /* 也可以写原生 CSS */
  .input-field {
    @apply w-full rounded-md border border-gray-300 bg-white
           px-3 py-2 text-sm transition-colors;
  }
  .input-field:focus {
    @apply border-blue-500 ring-1 ring-blue-500 outline-none;
  }

  /* 响应式组件 */
  .container-narrow {
    @apply mx-auto w-full px-4 sm:px-6 lg:max-w-3xl;
  }
}

4.3 Utilities 层 — 自定义工具类

@tailwind utilities;

@layer utilities {
  /* 自定义工具类 */
  .text-balance {
    text-wrap: balance;
  }

  .scrollbar-hide {
    -ms-overflow-style: none;
    scrollbar-width: none;
    &::-webkit-scrollbar {
      display: none;
    }
  }

  .line-clamp-4 {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
  }
}

Layer 优先级

base < components < utilities < 无 layer 的样式
  • utilities 层优先级最高,可以覆盖 components
  • 不在 @layer 中的样式优先级最高(慎用)

五、方法四:Plugin 插件

5.1 内联插件

// tailwind.config.js
const plugin = require('tailwindcss/plugin');

module.exports = {
  plugins: [
    // 添加自定义工具类
    plugin(function ({ addUtilities, theme }) {
      const newUtilities = {
        '.text-shadow': {
          textShadow: '0 2px 4px rgba(0,0,0,0.1)',
        },
        '.text-shadow-lg': {
          textShadow: '0 4px 8px rgba(0,0,0,0.15)',
        },
        '.text-shadow-none': {
          textShadow: 'none',
        },
      };
      addUtilities(newUtilities);
    }),

    // 添加自定义组件
    plugin(function ({ addComponents, theme }) {
      addComponents({
        '.card': {
          backgroundColor:  theme('colors.white'),
          borderRadius:     theme('borderRadius.xl'),
          padding:          theme('spacing.6'),
          boxShadow:        theme('boxShadow.lg'),
          border:           `1px solid ${theme('colors.gray.200')}`,
        },
        '.card-compact': {
          padding: theme('spacing.4'),
        },
      });
    }),

    // 添加基础样式
    plugin(function ({ addBase, theme }) {
      addBase({
        'h1': { fontSize: theme('fontSize.2xl') },
        'h2': { fontSize: theme('fontSize.xl') },
      });
    }),

    // 动态生成工具类
    plugin(function ({ addUtilities, e, theme }) {
      const gradients = theme('gradients', {});
      Object.entries(gradients).forEach(([name, value]) => {
        addUtilities({
          [`.bg-gradient-${e(name)}`]: {
            backgroundImage: value,
          },
        });
      });
    }),
  ],
  theme: {
    gradients: {
      'blue':   'linear-gradient(to right, #3b82f6, #8b5cf6)',
      'green':  'linear-gradient(to right, #10b981, #3b82f6)',
      'sunset': 'linear-gradient(to right, #f97316, #ec4899)',
    },
  },
};

5.2 独立插件包

// my-tailwind-plugin/index.js
const plugin = require('tailwindcss/plugin');

module.exports = plugin.withOptions(
  function (options = {}) {
    return function ({ addUtilities, theme }) {
      const prefix = options.prefix ?? 'my';
      addUtilities({
        [`.${prefix}-text-gradient`]: {
          backgroundImage: `var(--gradient, ${theme('gradients.blue', 'linear-gradient(to right, #3b82f6, #8b5cf6)')})`,
          WebkitBackgroundClip: 'text',
          WebkitTextFillColor: 'transparent',
        },
      });
    };
  },
  function (options) {
    return {
      theme: {
        gradients: {
          blue:   'linear-gradient(to right, #3b82f6, #8b5cf6)',
          sunset: 'linear-gradient(to right, #f97316, #ec4899)',
        },
      },
    };
  }
);
// 使用
module.exports = {
  plugins: [
    require('./my-tailwind-plugin')({ prefix: 'app' }),
  ],
};

六、方法五:CSS 变量 + Tailwind 联动

6.1 定义 CSS 变量

@layer base {
  :root {
    --color-background: #ffffff;
    --color-foreground: #171717;
    --color-primary:    #2563eb;
    --color-muted:      #f5f5f5;
    --radius:           0.5rem;
  }

  .dark {
    --color-background: #0a0a0a;
    --color-foreground: #ededed;
    --color-primary:    #3b82f6;
    --color-muted:      #262626;
  }
}

6.2 在 Tailwind 配置中引用

module.exports = {
  theme: {
    extend: {
      colors: {
        background: 'var(--color-background)',
        foreground: 'var(--color-foreground)',
        primary:    'var(--color-primary)',
        muted:      'var(--color-muted)',
      },
      borderRadius: {
        DEFAULT: 'var(--radius)',
      },
    },
  },
};
<div class="bg-background text-foreground">
  <button class="bg-primary text-white rounded-md">按钮</button>
  <div class="bg-muted p-4">静音区域</div>
</div>

6.3 运行时切换主题

// 切换暗色模式
document.documentElement.classList.toggle('dark');

// 动态修改变量(如用户自定义主题色)
document.documentElement.style.setProperty('--color-primary', '#ec4899');

七、方法六:Important 修饰符与优先级控制

<!-- ! 前缀强制 important -->
<p class="!text-red-500 font-bold">

<!-- 生成: color: #ef4444 !important; -->
// 全局开启 important(避免与第三方 CSS 冲突)
module.exports = {
  important: true,  // 所有工具类都加 !important

  // 或指定选择器(推荐,避免与第三方库冲突)
  important: '#app',
};
/* 生成结果 */
#app .text-red-500 {
  color: #ef4444;
}

八、完整配置示例

// tailwind.config.js
const plugin = require('tailwindcss/plugin');

module.exports = {
  content: ['./src/**/*.{html,js,jsx,ts,tsx,vue}'],
  important: '#app',

  theme: {
    extend: {
      // 颜色系统
      colors: {
        brand: {
          50:  '#eff6ff',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
        },
        surface: 'var(--color-surface)',
      },

      // 字体
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
        mono: ['JetBrains Mono', 'monospace'],
      },

      // 动画
      keyframes: {
        'fade-in': {
          '0%':   { opacity: '0' },
          '100%': { opacity: '1' },
        },
      },
      animation: {
        'fade-in': 'fade-in 0.3s ease-out',
      },

      // 自定义间距
      spacing: {
        '18': '4.5rem',
      },
    },
  },

  plugins: [
    // 自定义工具类插件
    plugin(function ({ addUtilities }) {
      addUtilities({
        '.text-balance': { textWrap: 'balance' },
        '.scrollbar-hide': {
          '-ms-overflow-style': 'none',
          'scrollbar-width': 'none',
          '&::-webkit-scrollbar': { display: 'none' },
        },
      });
    }),
  ],
};

九、决策速查表

需求 推荐方案 示例
一次性特殊值 Arbitrary Values top-[17px]
设计系统级颜色/间距 theme.extend colors.brand.500
全局基础样式 @layer base 字体平滑、CSS 变量
组件级样式聚合 @layer components + @apply .btn-primary
自定义工具类 @layer utilities 或 Plugin .text-balance
动态主题切换 CSS 变量 + theme.extend var(--color-primary)
可复用插件 Plugin 包 addUtilities / addComponents
覆盖第三方样式 important! 前缀 !text-red-500

核心原则

  1. Arbitrary Values 用于一次性 — 出现 2 次以上就应提取到配置
  2. extend 优先于覆盖 — 保留 Tailwind 默认值
  3. CSS 变量实现动态主题 — 配合 theme.extend 双向联动
  4. @layer 控制优先级 — base < components < utilities
  5. Plugin 用于跨项目复用 — 单项目用 @layer 即可
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐