SVG
WebF provides comprehensive support for Scalable Vector Graphics (SVG), allowing you to create resolution-independent graphics that scale perfectly on any device. SVG can be used in multiple ways: inline elements, images, and backgrounds.
Using Inline SVG Elements
Inline SVG gives you full control and interactivity through the DOM.
Basic SVG Example
function Logo() {
return (
<svg width="100" height="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#4F46E5" />
<text x="50" y="55" textAnchor="middle" fill="white" fontSize="20">
SVG
</text>
</svg>
);
}Common SVG Shapes
function Shapes() {
return (
<svg width="400" height="200" viewBox="0 0 400 200">
{/* Rectangle */}
<rect x="10" y="10" width="80" height="60" fill="#EF4444" rx="5" />
{/* Circle */}
<circle cx="150" cy="40" r="30" fill="#10B981" />
{/* Ellipse */}
<ellipse cx="250" cy="40" rx="40" ry="25" fill="#F59E0B" />
{/* Line */}
<line x1="320" y1="10" x2="380" y2="70" stroke="#8B5CF6" strokeWidth="3" />
{/* Polygon (Triangle) */}
<polygon points="50,120 80,180 20,180" fill="#EC4899" />
{/* Polyline */}
<polyline
points="120,120 140,160 160,140 180,180"
fill="none"
stroke="#06B6D4"
strokeWidth="3"
/>
{/* Path */}
<path
d="M 250 120 Q 280 140 250 180 Q 220 140 250 120"
fill="#A855F7"
/>
</svg>
);
}Using SVG with <img /> Tag
Load SVG files as images for simple, non-interactive graphics:
function SVGImage() {
return (
<div>
{/* Local SVG file */}
<img
src="/icons/logo.svg"
alt="Logo"
width="100"
height="100"
/>
{/* Remote SVG file */}
<img
src="https://example.com/icon.svg"
alt="Icon"
width="50"
height="50"
/>
{/* With lazy loading */}
<img
src="/images/illustration.svg"
alt="Illustration"
loading="lazy"
width="400"
height="300"
/>
</div>
);
}Benefits of SVG as <img />
- Simple to use
- Cacheable like other images
- No DOM overhead
- Supports lazy loading
- Works with responsive images
Limitations
- No JavaScript interaction with SVG content
- Cannot style internal SVG elements with CSS
- Cannot animate internal SVG elements
Using SVG as CSS Background
SVG can be used in CSS backgrounds for patterns, icons, and decorative elements:
Background Image
/* External SVG file */
.icon {
width: 50px;
height: 50px;
background-image: url('/icons/star.svg');
background-size: contain;
background-repeat: no-repeat;
}
/* With positioning */
.decorated {
background-image: url('/patterns/dots.svg');
background-position: center;
background-size: cover;
}Inline SVG in CSS (Data URI)
.checkmark {
width: 24px;
height: 24px;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%234F46E5" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>');
background-size: contain;
}Tailwind CSS with SVG Backgrounds
function BackgroundExample() {
return (
<div
className="w-full h-64 bg-cover bg-center"
style={{ backgroundImage: "url('/patterns/waves.svg')" }}
>
<div className="p-6 text-white">
Content over SVG background
</div>
</div>
);
}SVG Gradients and Filters
Linear Gradients
function GradientExample() {
return (
<svg width="300" height="200" viewBox="0 0 300 200">
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#4F46E5" />
<stop offset="100%" stopColor="#EC4899" />
</linearGradient>
</defs>
<rect
x="10"
y="10"
width="280"
height="180"
fill="url(#gradient1)"
rx="10"
/>
</svg>
);
}Radial Gradients
function RadialGradientExample() {
return (
<svg width="200" height="200" viewBox="0 0 200 200">
<defs>
<radialGradient id="radial1">
<stop offset="0%" stopColor="#FBBF24" />
<stop offset="100%" stopColor="#F59E0B" />
</radialGradient>
</defs>
<circle cx="100" cy="100" r="80" fill="url(#radial1)" />
</svg>
);
}Filters and Effects
function FilterExample() {
return (
<svg width="300" height="200" viewBox="0 0 300 200">
<defs>
{/* Drop shadow */}
<filter id="shadow">
<feDropShadow dx="2" dy="2" stdDeviation="3" floodOpacity="0.3" />
</filter>
{/* Blur effect */}
<filter id="blur">
<feGaussianBlur stdDeviation="2" />
</filter>
</defs>
<circle
cx="80"
cy="100"
r="40"
fill="#4F46E5"
filter="url(#shadow)"
/>
<circle
cx="220"
cy="100"
r="40"
fill="#EF4444"
filter="url(#blur)"
/>
</svg>
);
}SVG Icons
Icon Component System
// Icon component
function Icon({ name, size = 24, color = 'currentColor', ...props }) {
const icons = {
heart: (
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
),
star: (
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
),
menu: (
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" />
),
};
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill={color}
{...props}
>
{icons[name]}
</svg>
);
}
// Usage
function App() {
return (
<div>
<Icon name="heart" size={32} color="#EF4444" />
<Icon name="star" size={24} color="#FBBF24" />
<Icon name="menu" size={28} />
</div>
);
}SVG Animations
CSS Animations on SVG
function AnimatedSVG() {
return (
<svg width="200" height="200" viewBox="0 0 200 200">
<style>{`
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.spinner {
transform-origin: center;
animation: rotate 2s linear infinite;
}
`}</style>
<circle
className="spinner"
cx="100"
cy="100"
r="40"
fill="none"
stroke="#4F46E5"
strokeWidth="8"
strokeDasharray="60 200"
/>
</svg>
);
}React-Controlled Animations
import { useState, useEffect } from 'react';
function ProgressCircle({ progress = 0 }) {
const radius = 40;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (progress / 100) * circumference;
return (
<svg width="100" height="100" viewBox="0 0 100 100">
{/* Background circle */}
<circle
cx="50"
cy="50"
r={radius}
fill="none"
stroke="#E5E7EB"
strokeWidth="8"
/>
{/* Progress circle */}
<circle
cx="50"
cy="50"
r={radius}
fill="none"
stroke="#4F46E5"
strokeWidth="8"
strokeDasharray={circumference}
strokeDashoffset={offset}
transform="rotate(-90 50 50)"
style={{ transition: 'stroke-dashoffset 0.3s ease' }}
/>
{/* Text */}
<text x="50" y="55" textAnchor="middle" fontSize="16" fill="#111">
{progress}%
</text>
</svg>
);
}SVG Patterns
Creating Reusable Patterns
function PatternExample() {
return (
<svg width="400" height="300" viewBox="0 0 400 300">
<defs>
{/* Dot pattern */}
<pattern id="dots" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="2" fill="#94A3B8" />
</pattern>
{/* Stripe pattern */}
<pattern id="stripes" x="0" y="0" width="10" height="10" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="5" height="10" fill="#E0E7FF" />
<rect x="5" y="0" width="5" height="10" fill="#C7D2FE" />
</pattern>
</defs>
<rect x="10" y="10" width="180" height="280" fill="url(#dots)" />
<rect x="210" y="10" width="180" height="280" fill="url(#stripes)" />
</svg>
);
}Responsive SVG
Using viewBox for Scalability
function ResponsiveSVG() {
return (
<div className="w-full max-w-md">
{/* SVG scales to container width while maintaining aspect ratio */}
<svg
viewBox="0 0 400 300"
className="w-full h-auto"
>
<rect x="10" y="10" width="380" height="280" fill="#4F46E5" rx="10" />
<text x="200" y="160" textAnchor="middle" fill="white" fontSize="32">
Responsive SVG
</text>
</svg>
</div>
);
}Preserving Aspect Ratio
function AspectRatioSVG() {
return (
<svg
viewBox="0 0 100 100"
preserveAspectRatio="xMidYMid meet"
className="w-32 h-32"
>
<circle cx="50" cy="50" r="40" fill="#EF4444" />
</svg>
);
}SVG vs Canvas
Choose the right tool for your use case:
Use SVG when:
- You need scalable, resolution-independent graphics
- You want DOM-based interactivity (hover, click on individual elements)
- You need accessibility features (screen readers can access SVG content)
- You have a moderate number of elements (up to hundreds)
- You need styling with CSS
- You want to animate individual elements
Use Canvas when:
- You need to render many elements (thousands of objects)
- You’re creating pixel-based graphics or effects
- You need high-performance real-time rendering
- You’re building games or complex data visualizations
- You need to manipulate pixels directly
Best Practices
1. Optimize SVG Files
# Use SVGO to optimize SVG files
npm install -g svgo
svgo input.svg -o output.svg2. Use Semantic Naming
// ✅ Good - clear naming
<svg aria-labelledby="chart-title">
<title id="chart-title">Monthly Sales Chart</title>
<rect ... />
</svg>
// ❌ Bad - no context
<svg>
<rect ... />
</svg>3. Keep ViewBox Simple
// ✅ Good - simple viewBox
<svg viewBox="0 0 100 100">
// ❌ Avoid - complex viewBox makes scaling harder
<svg viewBox="47.3 83.2 234.8 156.4">4. Use CSS for Styling
// ✅ Good - CSS for reusable styles
<svg className="icon-primary">
<circle className="fill-current" />
</svg>
// ❌ Less flexible - inline styles
<svg>
<circle fill="#4F46E5" />
</svg>Accessibility
Make SVG accessible for all users:
function AccessibleSVG() {
return (
<svg
role="img"
aria-labelledby="logo-title logo-desc"
viewBox="0 0 100 100"
>
<title id="logo-title">Company Logo</title>
<desc id="logo-desc">A blue circle with white text</desc>
<circle cx="50" cy="50" r="40" fill="#4F46E5" />
<text x="50" y="55" textAnchor="middle" fill="white">Logo</text>
</svg>
);
}
// For decorative SVG
function DecorativeSVG() {
return (
<svg aria-hidden="true" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#E5E7EB" />
</svg>
);
}Next Steps
- Learn about Canvas for pixel-based graphics
- Explore Animations for CSS animations
- Check out Accessibility best practices