Zum Hauptinhalt springen
CSS-Optimierung Teil 5: Tooling & Metriken
#CSS #DevTools #Linting #Performance #Testing

CSS-Optimierung Teil 5: Tooling & Metriken


CSS-Profiling, DevTools, Stylelint und Performance-Metriken - Messen statt raten

6 Minuten Lesezeit

“Das fühlt sich langsam an” ist keine Metrik. Messen, nicht raten.

1. CSS-Profiling mit DevTools

Chrome DevTools Performance:

F12 → Performance Tab → Record → Interaktion → Stop

Was du suchst:

  • Recalculate Style < 10ms
  • Layout < 5ms
  • Paint < 10ms
  • Composite < 2ms

Rote Flags:

  • Lange gelbe Balken (Style Recalc)
  • Violette Balken (Layout/Reflow)
  • “Forced reflow” Warnungen

Coverage-Check:

DevTools → Coverage → Reload

Ziel: > 70% genutztes CSS (grün). Alles andere (rot) mit PurgeCSS eliminieren.

Rendering-Debugging:

DevTools → Rendering → Paint flashing

Viele grüne Flashes beim Scrollen? Du hast ein Repaint-Problem.

Performance Tab:

  • Bessere Waterfall-Ansicht
  • Genauere Timing-Daten

Inspector → Animations:

  • Zeigt alle laufenden Animationen
  • Timeline zum Scrubben
  • Performance-Warnungen

2. Linting & Stylelint für Performance

Stylelint Setup

npm install --save-dev stylelint stylelint-config-standard
// .stylelintrc.js
module.exports = {
  extends: 'stylelint-config-standard',
  rules: {
    // Performance-Regeln
    'no-descending-specificity': true,
    'no-duplicate-selectors': true,
    'selector-max-id': 0, // Keine IDs
    'selector-max-universal': 1, // Max 1x *
    'max-nesting-depth': 3,
    
    // Accessibility
    'color-contrast': true,
    'font-weight-notation': 'numeric',
    
    // Konsistenz
    'color-hex-length': 'short',
    'color-named': 'never',
    'length-zero-no-unit': true,
  }
};

Performance-Regeln

Verbiete teure Selektoren:

rules: {
  // ❌ Verhindert
  'selector-max-universal': 0, // Kein *
  'selector-max-type': 2, // Max 2 Type-Selektoren
  'selector-max-combinators': 3, // Max 3 Kombinatoren
}

Verbiete teure Properties:

rules: {
  'declaration-property-value-disallowed-list': {
    // Warnung bei teuren Filtern
    'filter': ['/blur/'],
    'backdrop-filter': ['/.*/'],
  }
}

Stylelint Plugins

stylelint-high-performance-animation:

npm install --save-dev stylelint-high-performance-animation
{
  plugins: ['stylelint-high-performance-animation'],
  rules: {
    'plugin/no-low-performance-animation-properties': [
      true,
      {
        // Nur transform und opacity erlauben
        ignoreProperties: ['transform', 'opacity']
      }
    ]
  }
}

stylelint-a11y:

npm install --save-dev stylelint-a11y
{
  plugins: ['stylelint-a11y'],
  rules: {
    'a11y/content-property-no-static-value': true,
    'a11y/font-size-is-readable': true,
    'a11y/line-height-is-vertical-rhythmed': true,
    'a11y/media-prefers-reduced-motion': true,
    'a11y/no-outline-none': true,
  }
}

Pre-commit Hooks

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.css": "stylelint --fix"
  }
}

3. Performance-Metriken

Core Web Vitals für CSS

LCP (Largest Contentful Paint):

  • Ziel: < 2.5s
  • CSS-Impact: Render-blocking CSS
<!-- ❌ Blockiert Rendering -->
<link rel="stylesheet" href="styles.css">

<!-- ✅ Kritisches CSS inline -->
<style>
  /* Critical CSS */
  body { margin: 0; font-family: sans-serif; }
  .hero { height: 100vh; }
</style>

<!-- Nicht-kritisches verzögert laden -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

CLS (Cumulative Layout Shift):

  • Ziel: < 0.1
  • CSS-Impact: Keine Größenangaben
/* ✅ Verhindert CLS */
img {
  aspect-ratio: 16 / 9;
}

.skeleton {
  min-height: 200px;
}

FID (First Input Delay):

  • Ziel: < 100ms
  • CSS-Impact: Schwere Selektoren

CSS-Size Budget

// budget.json
{
  "budgets": [{
    "resourceSizes": [{
      "resourceType": "stylesheet",
      "budget": 50 // 50KB
    }]
  }]
}

Webpack:

// webpack.config.js
module.exports = {
  performance: {
    maxAssetSize: 50000, // 50KB
    maxEntrypointSize: 50000,
    hints: 'error'
  }
}

Lighthouse CI

# .lighthouserc.yml
ci:
  collect:
    numberOfRuns: 3
  assert:
    assertions:
      'first-contentful-paint': ['error', {maxNumericValue: 2000}]
      'cumulative-layout-shift': ['error', {maxNumericValue: 0.1}]
      'total-blocking-time': ['error', {maxNumericValue: 300}]
npm install -g @lhci/cli
lhci autorun

Bundle Analyzer

# Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

Für CSS:

  • Zeigt CSS-Bundle-Größen
  • Identifiziert große Dependencies
  • Zeigt Duplikate

4. Automatisierte Performance-Tests

Jest + CSS Testing

// css-performance.test.js
describe('CSS Performance', () => {
  test('No universal selectors with !important', () => {
    const css = fs.readFileSync('styles.css', 'utf-8');
    expect(css).not.toMatch(/\*[^{]*!important/);
  });
  
  test('Max 3 levels of nesting', () => {
    // PostCSS parsing
    const root = postcss.parse(css);
    root.walkRules(rule => {
      const depth = getDepth(rule);
      expect(depth).toBeLessThanOrEqual(3);
    });
  });
});

Visual Regression Testing

// backstop.config.js
module.exports = {
  scenarios: [{
    label: "Homepage",
    url: "http://localhost:3000",
    delay: 500,
    misMatchThreshold: 0.1
  }],
  onBeforeScript: "puppet/onBefore.js",
  onReadyScript: "puppet/onReady.js"
};

CSS-Änderungen testen:

  1. Baseline erstellen
  2. CSS ändern
  3. Vergleich → Visual Diff

Automated Accessibility Testing

// a11y.test.js
import { axe } from 'jest-axe';

test('should not have a11y violations', async () => {
  const { container } = render(<App />);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

Performance-Budget Beispiel

{
  "css": {
    "critical": "< 14KB (inline)",
    "total": "< 50KB",
    "unused": "< 10%"
  },
  "metrics": {
    "lcp": "< 2.5s",
    "cls": "< 0.1",
    "fid": "< 100ms"
  },
  "rendering": {
    "styleRecalc": "< 10ms",
    "layout": "< 5ms",
    "paint": "< 10ms"
  }
}

  • Zugängliches CSS (WCAG AA+)
  • Messbares CSS (Metriken!)

Links: