From harness-claude
Optimizes SVGs with SVGO minification, compares inline/external delivery and sprite sheets, improves accessibility attributes, and enhances rendering performance for icon systems and complex graphics.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Master SVG optimization — automated minification with SVGO, inline versus external delivery trade-offs, SVG sprite sheet systems, accessibility patterns, rendering performance for complex vector graphics, and icon system architecture.
Generates and edits SVG logos, icons, and graphics. Covers path commands, shape primitives, styling, accessibility, gradients, masks, sprites, optimization, and animation techniques like CSS keyframes and SVG-specific methods.
Optimizes web images using compression for JPEG/PNG/WebP/SVG, modern formats, and responsive techniques to reduce file size and improve loading speed.
Generates SVG icons and configurations for visual content tasks like diagrams and charts. Provides step-by-step guidance, best practices, and production-ready code. Auto-activates on 'svg icon generator' or 'svg' phrases.
Share bugs, ideas, or general feedback.
Master SVG optimization — automated minification with SVGO, inline versus external delivery trade-offs, SVG sprite sheet systems, accessibility patterns, rendering performance for complex vector graphics, and icon system architecture.
Optimize SVGs with SVGO. SVGO removes editor metadata, simplifies paths, and reduces file size by 30-80%:
# Install and run SVGO
npx svgo icon.svg -o icon.min.svg
# Batch optimize a directory
npx svgo -f src/icons/ -o dist/icons/
# Show detailed savings
npx svgo icon.svg --pretty --indent=2
// svgo.config.js — recommended configuration
module.exports = {
multipass: true,
plugins: [
'preset-default',
'removeDimensions', // use viewBox instead of width/height
'sortAttrs',
{
name: 'removeAttrs',
params: { attrs: ['data-name', 'class'] }, // remove editor cruft
},
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false, // keep viewBox for scalability
cleanupIds: {
minify: true,
remove: false, // keep IDs for sprite references
},
},
},
},
],
};
Choose the right delivery method. Each approach has specific trade-offs:
Method | Cacheable | Styleable | HTTP Requests | HTML Size
-----------------|-----------|-----------|---------------|----------
Inline SVG | No | Full CSS | 0 | Increases
External <img> | Yes | None | 1 per icon | Minimal
SVG sprite <use> | Yes | Limited | 1 total | Minimal
CSS background | Yes | None | 1 per icon | Minimal
Data URI | No | None | 0 | Increases
Inline SVG for icons that need CSS styling (color, hover states) and appear above the fold. SVG sprites for icon systems with many icons across the site. External <img> for complex illustrations that benefit from caching.
Build an SVG sprite sheet. Combine icons into a single file referenced via <use>:
# Generate sprite with svg-sprite
npx svg-sprite --symbol --symbol-dest=dist --symbol-sprite=icons.svg src/icons/*.svg
<!-- icons.svg sprite file -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-search" viewBox="0 0 24 24">
<path d="M15.5 14h-.79l-.28-.27A6.47..." />
</symbol>
<symbol id="icon-close" viewBox="0 0 24 24">
<path d="M19 6.41L17.59 5 12 10.59..." />
</symbol>
</svg>
<!-- Reference icons anywhere in the page -->
<svg width="24" height="24" aria-hidden="true">
<use href="/icons.svg#icon-search"></use>
</svg>
Make SVGs accessible. Icons need proper ARIA attributes depending on their role:
<!-- Decorative icon (next to text label): hide from screen readers -->
<button>
<svg width="20" height="20" aria-hidden="true" focusable="false">
<use href="#icon-search"></use>
</svg>
Search
</button>
<!-- Informational icon (no visible label): provide accessible name -->
<button aria-label="Search">
<svg width="20" height="20" role="img" aria-label="Search" focusable="false">
<use href="#icon-search"></use>
</svg>
</button>
<!-- Complex illustration: use title and desc -->
<svg role="img" aria-labelledby="chart-title chart-desc">
<title id="chart-title">Revenue Growth 2024</title>
<desc id="chart-desc">Bar chart showing 23% year-over-year revenue growth</desc>
<!-- chart paths -->
</svg>
Optimize complex SVGs for rendering performance. SVGs with thousands of paths cause layout and paint cost:
<!-- Contain rendering cost of complex SVGs -->
<div style="contain: layout paint; will-change: transform;">
<svg viewBox="0 0 1000 1000">
<!-- complex illustration with many paths -->
</svg>
</div>
<!-- Simplify paths: reduce control points -->
<!-- Before: <path d="M 10.123456 20.789012 C 30.111111..."> -->
<!-- After: <path d="M 10.1 20.8 C 30.1..."> -->
// SVGO: reduce path precision
module.exports = {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
cleanupNumericValues: { floatPrecision: 1 },
convertPathData: { floatPrecision: 1 },
},
},
},
],
};
Implement an icon component for consistent delivery. Abstract the sprite reference into a reusable component:
interface IconProps {
name: string;
size?: number;
className?: string;
title?: string;
}
function Icon({ name, size = 24, className, title }: IconProps) {
const hasTitle = Boolean(title);
return (
<svg
width={size}
height={size}
className={className}
role={hasTitle ? 'img' : undefined}
aria-label={hasTitle ? title : undefined}
aria-hidden={hasTitle ? undefined : true}
focusable="false"
>
{hasTitle && <title>{title}</title>}
<use href={`/icons.svg#icon-${name}`} />
</svg>
);
}
// Usage
<Icon name="search" />
<Icon name="close" title="Close dialog" />
Remove embedded raster images and fonts. Design tools sometimes embed base64-encoded PNGs or font subsets inside SVGs:
# Find SVGs with embedded images
grep -rl 'image.*base64' src/icons/
grep -rl '<font' src/icons/
# These need to be re-exported from the design tool
# without "include images" or "outline fonts" options
Icon fonts (Font Awesome, Material Icons) were the standard icon delivery method before SVG systems matured. SVGs are superior in every dimension: per-icon loading (icon fonts are all-or-nothing), multi-color support, CSS animation control, accessibility (icon fonts use pseudo-elements that screen readers handle inconsistently), and rendering precision (icon fonts suffer from anti-aliasing artifacts at certain sizes). The only advantage of icon fonts is simpler setup — a single CSS include.
GitHub's Octicons icon system uses inline SVGs for above-the-fold icons (navigation, status indicators) and an SVG sprite for the full icon set. Each icon is optimized with SVGO to under 500 bytes. The sprite file (~15KB for 250+ icons) is loaded once and cached with a content-hashed filename. Icons use aria-hidden="true" when adjacent to text labels and aria-label when standalone. The Icon React component enforces these accessibility patterns, making incorrect usage a lint error. Total icon overhead per page: ~2KB inline + 15KB sprite (cached).
Figma exports SVGs with editor metadata (data-name, Figma-specific attributes) that double file size. A production pipeline runs: (1) Export from Figma via API, (2) SVGO with custom config that strips Figma metadata and reduces precision to 1 decimal, (3) Generate sprite sheet with svg-sprite, (4) Generate TypeScript icon name union type from the sprite for type safety. This automated pipeline runs in CI when designers push to the Figma file, ensuring icons are always optimized and type-safe.
Inlining large SVGs in every page. A 20KB inline SVG illustration on every page adds 20KB to every HTML response and is never cached. Use <img> or <object> for illustrations larger than 2KB so the browser can cache them.
Using SVGs with embedded raster images. An SVG containing a base64-encoded PNG is worse than serving the PNG directly: larger file, no responsive image benefits, and the SVG wrapper adds parse overhead.
Animating SVG properties that trigger layout. Animating width, height, x, y, or path d attributes causes layout recalculation on every frame. Use transform (translate, scale, rotate) and opacity for smooth 60fps animations.
Not setting viewBox on SVG elements. Without viewBox, SVGs cannot scale proportionally. Always include viewBox and remove fixed width/height attributes (set dimensions via CSS or the parent element instead).