CSS Optimization (Critical CSS, Purge Unused CSS)

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

CSS Optimization: critical CSS and purge unused styles

Unused CSS increases file size and slows FCP. Bootstrap with few components — 140 kB; after purge — 5–15 kB. Tailwind with full set — 3.5 MB; after purge — 5–50 kB.

Tailwind CSS: automatic purge

Tailwind 3+ removes unused classes at production build automatically based on content analysis:

// tailwind.config.ts
import type { Config } from 'tailwindcss';

export default {
    content: [
        './resources/views/**/*.blade.php',
        './resources/js/**/*.{ts,tsx}',
        // Important: include all files with classes
        './resources/js/**/*.json', // if classes generated dynamically
    ],
    theme: { extend: {} },
    plugins: [],
} satisfies Config;

Dynamic classes (string concatenation) — purge won't find them:

// Bad — purge won't see
const color = 'red';
<div className={`text-${color}-500`} /> // text-red-500 will be deleted

// Good — full class names
const colorMap = {
    red: 'text-red-500',
    blue: 'text-blue-500',
};
<div className={colorMap[color]} />

PurgeCSS for Bootstrap/custom CSS

// postcss.config.js
import purgecss from '@fullhuman/postcss-purgecss';

export default {
    plugins: [
        purgecss({
            content: [
                './resources/views/**/*.blade.php',
                './resources/js/**/*.tsx',
                './public/**/*.html',
            ],
            safelist: {
                // Classes added by JS/Livewire/Alpine
                standard: ['modal-open', 'show', 'active', 'fade'],
                deep: [/^modal/, /^alert/, /^toast/],
                greedy: [/swiper/],
            },
            defaultExtractor: content =>
                content.match(/[\w-/:]+(?<!:)/g) || [],
        }),
    ],
};

Critical CSS — inline styles for first screen

Idea: styles needed for above-the-fold rendering inline in <head>. Rest — load async.

Automatically via Vite (critters):

// vite.config.ts
import { defineConfig } from 'vite';
import { critters } from 'critters';

export default defineConfig({
    plugins: [
        critters({
            preload: 'media',     // async load for non-critical
            pruneSource: true,    // remove from external CSS what's already inline
            logLevel: 'silent',
        })
    ]
});

Manually for Laravel:

// Blade: inline critical CSS, async for rest
<style>{!! file_get_contents(public_path('css/critical.css')) !!}</style>

<link rel="preload" href="{{ mix('css/app.css') }}" as="style"
      onload="this.onload=null;this.rel='stylesheet'">
<noscript>
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
</noscript>

Critical CSS generation — critical npm package or penthouse:

npx critical https://example.ru/ --inline --minify > critical.css

CSS-in-JS — performance problems

Styled-components, Emotion generate CSS at runtime — additional JS load. For production prefer static CSS:

  • Tailwind CSS — utility classes, no runtime overhead
  • CSS Modules — local classes, compile to static CSS
  • Vanilla Extract — typed CSS, zero-runtime
// CSS Modules in React
import styles from './ProductCard.module.css';

function ProductCard({ product }) {
    return (
        <div className={styles.card}>
            <img className={styles.image} src={product.image} alt={product.name} />
            <h3 className={styles.title}>{product.name}</h3>
        </div>
    );
}

Minification and compression

// vite.config.ts — LightningCSS for fast minification
export default defineConfig({
    css: {
        transformer: 'lightningcss',
        lightningcss: {
            targets: browserslistToTargets(browserslist('>= 0.5%')),
            drafts: { customMedia: true },
        }
    },
    build: {
        cssMinify: 'lightningcss',
    }
});

LightningCSS also automatically adds vendor prefixes and polyfills for configured browserslist.

Metrics

Goals after optimization:

Metric Before Goal
CSS bundle (gzip) 50–140 kB < 20 kB
Tailwind after purge 3.5 MB 5–50 kB
Render-blocking CSS Yes No (critical inline)
CSS Coverage 10–30% > 80%

DevTools → Coverage → reload page → see % unused CSS.

Optimization time: 4–8 hours for purge + critical CSS setup in build.