Skip to main content
skill CX Codex

postcss-best-practices — Claude Code skill: setup and usage

Skill providing PostCSS configuration patterns, CSS minification rules, and build tool setup for Vite, Webpack, and Next.js.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add Mindrally/skills --skill postcss-best-practices -a claude-code
Open on GitHub

What postcss-best-practices does

This skill equips coding assistants with guidelines for modern CSS processing pipelines. It details optimal setups for postcss.config.js, including vendor prefixing with autoprefixer and production minification using cssnano.

Inside, you find configuration templates for Vite, Webpack (postcss-loader), and Next.js alongside guidance on postcss-preset-env with Stage 2 specifications, native nesting, and custom media queries. It does not ship npm packages itself, so you must install postcss and plugin dependencies in your project beforehand.

What it helps with

  • configure a production-ready CSS build pipeline with minification
  • integrate PostCSS into Vite, Webpack, or Next.js projects
  • enable future CSS syntax with postcss-preset-env
  • set up automatic vendor prefixing via autoprefixer

Example prompts for the agent

  • Generate a postcss.config.js for Vite with cssnano production minification
  • Show how to configure postcss-preset-env with Stage 2 features and autoprefixer grid support
  • Set up postcss-loader rules inside webpack.config.js

How to install postcss-best-practices

1Skills CLI (Vercel)

npx skills add Mindrally/skills --skill postcss-best-practices -a claude-code

2Manually: put the files in place

~/.claude/skills/postcss-best-practices/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/postcss-best-practices/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about postcss-best-practices

How to install postcss-best-practices in Claude Code?

Run npx skills add Mindrally/skills --skill postcss-best-practices -a claude-code. The file will be placed in ~/.claude/skills/postcss-best-practices/SKILL.md.

What does postcss-best-practices do?

It guides the agent on structuring PostCSS configs, managing plugins like cssnano and autoprefixer, and writing modern CSS syntax.

Which build tools does this skill cover?

It includes integration snippets for Vite, Webpack via postcss-loader, and Next.js.

Source text

SKILL.md · Apache-2.0
---
name: postcss-best-practices
description: PostCSS best practices and configuration guidelines for modern CSS processing and optimization
metadata:
  maintainer: Mindrally
  source: https://github.com/Mindrally/skills
---

# PostCSS Best Practices

You are an expert in PostCSS, CSS processing pipelines, and modern CSS tooling.

## Key Principles

- Use PostCSS as a modular CSS processor with purpose-specific plugins
- Write future-proof CSS using modern syntax with appropriate transpilation
- Optimize CSS output for production with minification and autoprefixing
- Keep plugin configurations minimal and purposeful

## What is PostCSS

PostCSS is a tool for transforming CSS with JavaScript plugins. Unlike preprocessors (Sass/Less), PostCSS:
- Is modular - add only the features you need
- Can parse and transform standard CSS
- Enables future CSS syntax today
- Optimizes and minifies output
- Works with any build tool

## Project Setup

### Installation
```bash
# Core PostCSS
npm install postcss postcss-cli --save-dev

# Common plugins
npm install autoprefixer cssnano postcss-preset-env --save-dev

# Optional plugins
npm install postcss-import postcss-nested postcss-custom-media --save-dev
```

### Configuration File
```javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-preset-env')({
      stage: 2,
      features: {
        'nesting-rules': true,
        'custom-media-queries': true,
        'custom-properties': true,
      },
    }),
    require('autoprefixer'),
    require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true },
      }],
    }),
  ],
};
```

### Build Tool Integration

#### Webpack
```javascript
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
        ],
      },
    ],
  },
};
```

#### Vite
```javascript
// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  css: {
    postcss: './postcss.config.js',
  },
});
```

#### Next.js
```javascript
// postcss.config.js (auto-detected)
module.exports = {
  plugins: {
    'postcss-import': {},
    'tailwindcss/nesting': {},
    tailwindcss: {},
    autoprefixer: {},
  },
};
```

## Essential Plugins

### postcss-preset-env

Enables modern CSS features with polyfills:

```javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-preset-env')({
      stage: 2, // Stage 2 features are stable
      features: {
        'nesting-rules': true,
        'custom-media-queries': true,
        'custom-selectors': true,
        'gap-properties': true,
        'logical-properties-and-values': true,
      },
      autoprefixer: { grid: true },
      browsers: 'last 2 versions',
    }),
  ],
};
```

### autoprefixer

Adds vendor prefixes automatically:

```javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer')({
      grid: 'autoplace', // Enable grid prefixes
      flexbox: true,
    }),
  ],
};

// Input CSS
.element {
  display: flex;
  user-select: none;
}

// Output CSS
.element {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}
```

### cssnano

Minifies and optimizes CSS for production:

```javascript
// postcss.config.js
const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
  plugins: [
    require('autoprefixer'),
    isProduction && require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true },
        normalizeWhitespace: true,
        minifyFontValues: true,
        minifyGradients: true,
        reduceIdents: false, // Preserve animation names
        mergeRules: true,
        mergeLonghand: true,
      }],
    }),
  ].filter(Boolean),
};
```

### postcss-import

Inline @import statements:

```javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import')({
      path: ['src/styles'],
    }),
  ],
};
```

```css
/* main.css */
@import 'variables.css';
@import 'base.css';
@import 'components/buttons.css';
@import 'components/cards.css';
```

### postcss-nested

Enables Sass-like nesting:

```javascript
// postcss.config.js
module.exports = {
  plugins: [
    require('postcss-nested'),
  ],
};
```

```css
/* Input */
.card {
  background: white;

  &__header {
    padding: 16px;
  }

  &__body {
    padding: 16px;
  }

  &:hover {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  }

  @media (min-width: 768px) {
    display: flex;
  }
}

/* Output */
.card {
  background: white;
}
.card__header {
  padding: 16px;
}
.card__body {
  padding: 16px;
}
.card:hover {
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
@media (min-width: 768px) {
  .card {
    display: flex;
  }
}
```

## Modern CSS Features

### CSS Nesting (Native)
```css
/* Modern browsers support native nesting */
.card {
  background: white;
  border-radius: 8px;

  & .card-header {
    padding: 1rem;
    border-bottom: 1px solid #eee;
  }

  & .card-body {
    padding: 1rem;
  }

  &:hover {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  }

  @media (min-width: 768px) {
    display: flex;
  }
}
```

### Custom Properties (CSS Variables)
```css
:root {
  /* Colors */
  --color-primary: #3498db;
  --color-primary-light: color-mix(in srgb, var(--color-primary), white 20%);
  --color-primary-dark: color-mix(in srgb, var(--color-primary), black 20%);
  --color-text: #333333;
  --color-background: #ffffff;
  --color-border: #e0e0e0;

  /* Typography */
  --font-family-base: 'Helvetica Neue', Arial, sans-serif;
  --font-size-base: 1rem;
  --line-height-base: 1.5;

  /* Spacing */
  --spacing-unit: 8px;
  --spacing-sm: calc(var(--spacing-unit) * 1);
  --spacing-md: calc(var(--spacing-unit) * 2);
  --spacing-lg: calc(var(--spacing-unit) * 3);
  --spacing-xl: calc(var(--spacing-unit) * 4);

  /* Transitions */
  --transition-base: 0.3s ease;

  /* Shadows */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.button {
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-primary);
  color: white;
  transition: background var(--transition-base);
}

.button:hover {
  background: var(--color-primary-dark);
}
```

### Custom Media Queries
```css
/* Define custom media queries */
@custom-media --viewport-sm (min-width: 576px);
@custom-media --viewport-md (min-width: 768px);
@custom-media --viewport-lg (min-width: 992px);
@custom-media --viewport-xl (min-width: 1200px);

@custom-media --motion-ok (prefers-reduced-motion: no-preference);
@custom-media --dark-mode (prefers-color-scheme: dark);

/* Usage */
.element {
  width: 100%;
}

@media (--viewport-md) {
  .element {
    width: 50%;
  }
}

@media (--viewport-lg) {
  .element {
    width: 33.333%;
  }
}

@media (--motion-ok) {
  .element {
    transition: transform 0.3s ease;
  }
}
```

### Custom Selectors
```css
/* Define reusable selectors */
@custom-selector :--heading h1, h2, h3, h4, h5, h6;
@custom-selector :--button button, [type="button"], [type="submit"];
@custom-selector :--enter :hover, :focus;

/* Usage */
:--heading {
  font-family: var(--font-family-heading);
  line-height: 1.2;
  margin-bottom: 1rem;
}

:--button {
  cursor: pointer;
  font-family: inherit;
}

.link:--enter {
  color: var(--color-primary);
  text-decoration: underline;
}
```

### Logical Properties
```css
/* Use logical properties for internationalization */
.element {
  /* Instead of margin-left/right */
  margin-inline: auto;

  /* Instead of padding-top/bottom */
  padding-block: var(--spacing-md);

  /* Instead of width/height */
  inline-size: 100%;
  block-size: auto;

  /* Instead of border-left */
  border-inline-start: 2px solid var(--color-primary);

  /* Instead of text-align: left */
  text-align: start;
}
```

### Container Queries
```css
/* Modern container queries */
.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: block;
}

@container card (min-width: 400px) {
  .card {
    display: flex;
  }
}

@container card (min-width: 600px) {
  .card {
    gap: 2rem;
  }
}
```

## File Organization

### Structure
```
src/
├── styles/
│   ├── base/
│   │   ├── reset.css
│   │   ├── typography.css
│   │   └── base.css
│   ├── components/
│   │   ├── buttons.css
│   │   ├── cards.css
│   │   ├── forms.css
│   │   └── navigation.css
│   ├── layout/
│   │   ├── header.css
│   │   ├── footer.css
│   │   └── grid.css
│   ├── utilities/
│   │   ├── spacing.css
│   │   ├── colors.css
│   │   └── display.css
│   ├── variables.css
│   └── main.css
├── postcss.config.js
└── package.json
```

### Main Entry Point
```css
/* main.css */

/* Variables first */
@import 'variables.css';

/* Reset and base styles */
@import 'base/reset.css';
@import 'base/typography.css';
@import 'base/base.css';

/* Layout */
@import 'layout/grid.css';
@import 'layout/header.css';
@import 'layout/footer.css';

/* Components */
@import 'components/buttons.css';
@import 'components/cards.css';
@import 'components/forms.css';
@import 'components/navigation.css';

/* Utilities (last for specificity) */
@import 'utilities/spacing.css';
@import 'utilities/colors.css';
@import 'utilities/display.css';
```

## Production Configuration

### Environment-Based Config
```javascript
// postcss.config.js
const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
  plugins: [
    // Always run these
    require('postcss-import'),
    require('postcss-preset-env')({
      stage: 2,
      features: {
        'nesting-rules': true,
        'custom-media-queries': true,
      },
    }),
    require('autoprefixer'),

    // Production only
    isProduction && require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true },
        reduceIdents: false,
        zindex: false,
      }],
    }),

    isProduction && require('@fullhuman/postcss-purgecss')({
      content: [
        './src/**/*.html',
        './src/**/*.js',
        './src/**/*.jsx',
        './src/**/*.tsx',
      ],
      safelist: {
        standard: [/^is-/, /^has-/, /^js-/],
        deep: [/modal/, /tooltip/],
      },
    }),
  ].filter(Boolean),
};
```

### Browser Support
```javascript
// package.json
{
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie 11"
  ]
}

// Or .browserslistrc
> 1%
last 2 versions
not dead
not ie 11
```

## Useful Plugin Configurations

### postcss-custom-media
```javascript
require('postcss-custom-media')({
  importFrom: [
    {
      customMedia: {
        '--viewport-sm': '(min-width: 576px)',
        '--viewport-md': '(min-width: 768px)',
        '--viewport-lg': '(min-width: 992px)',
        '--viewport-xl': '(min-width: 1200px)',
      },
    },
  ],
});
```

### postcss-mixins
```javascript
require('postcss-mixins')({
  mixins: {
    'flex-center': {
      display: 'flex',
      'align-items': 'center',
      'justify-content': 'center',
    },
    'visually-hidden': {
      position: 'absolute',
      width: '1px',
      height: '1px',
      overflow: 'hidden',
      clip: 'rect(0, 0, 0, 0)',
    },
  },
});
```

### postcss-simple-vars
```javascript
require('postcss-simple-vars')({
  variables: {
    'color-primary': '#3498db',
    'spacing-unit': '8px',
  },
});
```

## Performance Tips

- Order plugins correctly: import, preset-env/nesting, autoprefixer, cssnano
- Use PurgeCSS to remove unused styles in production
- Enable source maps only in development
- Cache PostCSS results in build tools when possible
- Avoid unnecessary plugins - each adds processing time
- Use browserslist to target only necessary browsers

## Common Plugin Combinations

### Minimal Setup
```javascript
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('cssnano'),
  ],
};
```

### Modern CSS Features
```javascript
module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-preset-env')({ stage: 2 }),
    require('autoprefixer'),
    require('cssnano'),
  ],
};
```

### Sass-like Features
```javascript
module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-mixins'),
    require('postcss-simple-vars'),
    require('postcss-nested'),
    require('autoprefixer'),
    require('cssnano'),
  ],
};
```

### With Tailwind CSS
```javascript
module.exports = {
  plugins: {
    'postcss-import': {},
    'tailwindcss/nesting': {},
    tailwindcss: {},
    autoprefixer: {},
    ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
  },
};
```

## Debugging

### Enable Source Maps
```javascript
// postcss.config.js
module.exports = {
  map: process.env.NODE_ENV !== 'production'
    ? { inline: false }
    : false,
  plugins: [
    // ...plugins
  ],
};
```

### Verbose Output
```bash
# CLI with verbose output
postcss src/main.css -o dist/main.css --verbose
```

### Check Plugin Order
If styles aren't working as expected:
1. Check plugin order (import before others)
2. Verify preset-env stage settings
3. Check browserslist configuration
4. Review cssnano options (may be over-optimizing)

© Mindrally · Apache-2.0 · Mindrally/skills

Similar skills

Everything for Frontend and UI →

From the same set214

oauth-implementation Guides coding agents through OAuth 2.0 and 2.1 setup with PKCE, state checks, and token rotation. Built to prevent insecure grants like implicit flow. CX Codex +1 719installs figma-integration Guides AI agents through translating Figma designs into code. Covers design token extraction, layout conversion, and MCP server configuration. CX Codex +1 718installs vercel-development A rule set that steers your coding agent toward Next.js App Router, React Server Components and the Vercel AI SDK. Useful when the agent keeps reaching for client components by reflex. CX Codex +1 712installs rest-api-django A rule set that steers your coding agent through Django REST Framework work: project layout, serializers, JWT auth, N+1 queries. CX Codex +1 712installs kotlin-development Guides AI coding agents with strict Kotlin conventions for clean function design, data classes, immutability, and unit test structure. CX Codex +1 709installs rspec Gives the agent a working set of RSpec conventions for Ruby and Rails: spec organization, test data, isolation. Useful when specs drift and duplicate. CX Codex +1 707installs angular-development Tells the agent how to write Angular, SASS and TypeScript: strict typing, standalone components, signals. Useful once your project is already on Angular. CX Codex +1 705installs stripe Integration rules for Stripe in TypeScript, React and Next.js: server-side payments, subscriptions, webhooks. Useful when your agent writes checkout code. CX Codex +1 704installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor