SVG Fundamentals and Implementation

Creating Scalable Vector Graphics for Modern Web Applications

Introduction to SVG

Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics. Unlike raster image formats (like JPEG, PNG, and GIF) that store image data as a grid of pixels, SVG defines images using mathematical descriptions of geometric shapes.

Think of the difference between vector and raster graphics this way: a raster image is like a mosaic made of tiny tiles (pixels), while a vector image is like a set of instructions for drawing shapes. When you zoom in on a mosaic, you eventually see the individual tiles. But with vector graphics, the shapes are redrawn at any size using the same mathematical instructions, always maintaining crisp edges.

flowchart LR A[SVG Format] -->|Defined by| B[XML Markup] A -->|Renders as| C[Vector Graphics] C -->|Maintains quality at| D[Any Scale] C -->|Supported by| E[All Modern Browsers] A -->|Can be| F[Static or Dynamic] F -->|Dynamic via| G[JavaScript/CSS]

The key advantages of SVG include:

SVG vs. Raster Graphics

To understand the value of SVG, it's important to compare it with raster-based alternatives:

Feature SVG (Vector) PNG/JPEG/GIF (Raster)
Scaling Perfect at any size Becomes pixelated when enlarged
File Size Often smaller for logos, icons, diagrams Often smaller for photographs, complex textures
Complexity Better for geometric shapes and illustrations Better for photographs and complex images
Animation Native support via CSS/JS Requires multiple frames (GIF) or video formats
Transparency Full alpha channel support Varies (PNG: yes, JPEG: no, GIF: binary)
Interactivity Individual elements can have events Only the entire image can have events
Accessibility Can include semantic information Requires alt text only
Browser Support All modern browsers Universal
SVG (Vector) PNG (Raster) Always Sharp Becomes Pixelated

When selecting between SVG and raster formats, consider your specific needs:

A common approach is to combine both: use SVG for UI elements and icons, while using raster formats for content images and photos.

Basic SVG Structure

An SVG document is an XML file that defines vector-based graphics. Here's the simplest possible SVG containing a single circle:

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <circle cx="50" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>

Let's break down the essential structure:

The coordinate system in SVG starts from the top-left corner (0,0) and increases right and down. This is similar to the coordinate system used in HTML elements, but different from the Cartesian coordinate system you might remember from math class.

X Y (0,0) (150,100) Width = 300 Height = 200

Basic SVG Shapes

SVG provides several basic shape elements that can be combined to create complex graphics:

classDiagram class SVGElement { +attributes +styles +event handlers } class GeometricShapes { } class UtilityElements { } SVGElement <|-- GeometricShapes SVGElement <|-- UtilityElements GeometricShapes <|-- circle GeometricShapes <|-- rect GeometricShapes <|-- line GeometricShapes <|-- polyline GeometricShapes <|-- polygon GeometricShapes <|-- ellipse GeometricShapes <|-- path UtilityElements <|-- g UtilityElements <|-- defs UtilityElements <|-- text UtilityElements <|-- use
Shape Element Key Attributes Example
Rectangle <rect> x, y, width, height, rx, ry <rect x="10" y="10" width="80" height="60" rx="5" ry="5" />
Circle <circle> cx, cy, r <circle cx="50" cy="50" r="40" />
Ellipse <ellipse> cx, cy, rx, ry <ellipse cx="100" cy="50" rx="80" ry="30" />
Line <line> x1, y1, x2, y2 <line x1="10" y1="10" x2="90" y2="90" />
Polyline <polyline> points <polyline points="10,10 30,30 10,50 70,50" />
Polygon <polygon> points <polygon points="50,10 90,90 10,90" />
Path <path> d <path d="M10,30 L90,30 L50,90 Z" />

Let's visualize these shapes with a practical example:

Rectangle Circle Ellipse Line Polyline Polygon Path

The Path Element

The <path> element is the most powerful and flexible shape in SVG. It can create any shape using a series of commands in the d (data) attribute:

Command Description Parameters Example
M/m Move to x y M10,10 (absolute) or m5,5 (relative)
L/l Line to x y L50,50 (absolute) or l10,10 (relative)
H/h Horizontal line x H50 (absolute) or h10 (relative)
V/v Vertical line y V50 (absolute) or v10 (relative)
C/c Cubic Bézier curve x1 y1 x2 y2 x y C10,10 20,20 30,30
S/s Smooth cubic Bézier x2 y2 x y S20,20 30,30
Q/q Quadratic Bézier curve x1 y1 x y Q10,10 20,20
T/t Smooth quadratic Bézier x y T20,20
A/a Elliptical arc rx ry angle large-arc sweep x y A30,50 0 0 1 100,100
Z/z Close path none Z (connect to start point)

Path commands use uppercase letters for absolute coordinates and lowercase for relative coordinates. Think of absolute coordinates as GPS coordinates (go to a specific location), while relative coordinates are like directions (move forward 10 steps).

Here's a heart shape created with a path:

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <path d="M100,30 
             C60,10 10,50 10,90 
             C10,130 50,150 100,180 
             C150,150 190,130 190,90 
             C190,50 140,10 100,30 Z" 
          fill="red" />
</svg>
Start: M100,30 C60,10 10,50 10,90 Path Command Components: M = Move to starting point C = Cubic Bézier curve with control points Z = Close path (connect to start) Tips for Path Creation: • Use a drawing program to generate paths • Break complex shapes into segments • Use relative commands for repeated patterns

The path syntax takes practice to master, but it offers incredible flexibility. For complex shapes, you'll typically use a graphic design tool like Adobe Illustrator, Inkscape, or Figma to create them, then export the SVG code.

Styling SVG Elements

SVG elements can be styled using attributes directly in the elements or with CSS. This dual approach provides flexibility and separation of concerns.

<!-- Styling with attributes (inline) -->
<circle cx="50" cy="50" r="40" fill="blue" stroke="black" stroke-width="2" opacity="0.7" />

<!-- Styling with CSS -->
<style>
  .styled-circle {
    fill: blue;
    stroke: black;
    stroke-width: 2;
    opacity: 0.7;
  }
</style>
<circle class="styled-circle" cx="50" cy="50" r="40" />

Common styling properties include:

Property Description Example
fill Interior color of the shape fill="red" or fill="rgba(255,0,0,0.5)"
fill-opacity Transparency of the fill fill-opacity="0.5"
stroke Outline color of the shape stroke="blue"
stroke-width Thickness of the outline stroke-width="2"
stroke-opacity Transparency of the stroke stroke-opacity="0.8"
stroke-linecap End style of lines (butt, round, square) stroke-linecap="round"
stroke-linejoin Join style of lines (miter, round, bevel) stroke-linejoin="round"
stroke-dasharray Pattern of dashes and gaps stroke-dasharray="5,5"
opacity Overall transparency of the element opacity="0.7"
Basic fill fill-opacity stroke only fill + stroke dasharray

Using CSS to style SVG offers several advantages:

<style>
  /* Target SVG elements with CSS */
  circle:hover {
    fill: red;
    transition: fill 0.3s ease;
  }
  
  /* Use classes for grouped styling */
  .chart-bar {
    fill: #2196f3;
  }
  
  .chart-bar:nth-child(odd) {
    fill: #1565c0;
  }
</style>

SVG Organization and Reuse

SVG provides several elements for organizing and reusing content, making complex graphics more manageable:

The <g> Element (Group)

The group element allows you to combine related shapes and apply transformations or styles to them collectively:

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <g fill="blue" transform="translate(20, 20)">
        <rect x="0" y="0" width="60" height="60" />
        <circle cx="100" cy="30" r="30" />
    </g>
</svg>

The <defs> and <use> Elements

These elements enable you to define shapes once and reuse them multiple times:

<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <g id="shape">
            <rect x="0" y="0" width="50" height="50" />
            <circle cx="25" cy="25" r="20" fill="red" />
        </g>
    </defs>
    
    <use href="#shape" x="10" y="10" />
    <use href="#shape" x="100" y="10" />
    <use href="#shape" x="190" y="10" />
</svg>

The <symbol> Element

Similar to <defs> but better for creating reusable icon libraries as it supports viewBox:

<svg xmlns="http://www.w3.org/2000/svg">
    <symbol id="icon-star" viewBox="0 0 100 100">
        <polygon points="50,10 61,35 90,40 70,60 75,90 50,75 25,90 30,60 10,40 39,35" />
    </symbol>
    
    <use href="#icon-star" x="10" y="10" width="50" height="50" fill="gold" />
    <use href="#icon-star" x="70" y="10" width="30" height="30" fill="silver" />
</svg>
Reusing SVG Elements with <symbol> and <use> Override fill color Apply transformation Different size

This approach is conceptually similar to creating reusable components in modern web development frameworks. It promotes efficiency and consistency across your graphics.

Integrating SVG in Web Pages

There are multiple ways to include SVG in web pages, each with different characteristics:

Method Code Example Advantages Limitations
Inline SVG <svg>...</svg> directly in HTML
  • Full DOM access
  • CSS styling
  • JavaScript interaction
  • No extra HTTP requests
  • Increases HTML size
  • Not cacheable separately
  • Can be verbose
IMG tag <img src="image.svg" alt="Description" />
  • Simple implementation
  • Browser caching
  • Works with lazy loading
  • No DOM access
  • No JavaScript interaction
  • Limited CSS control
CSS Background background-image: url('image.svg');
  • Good for decorative elements
  • Works with CSS sprites
  • Browser caching
  • No DOM access
  • No JavaScript interaction
  • Less accessible
Object tag <object data="image.svg" type="image/svg+xml"></object>
  • DOM access via scripts
  • Browser caching
  • Fallback content support
  • More complex to style
  • Cross-domain limitations
  • Additional HTTP request
Iframe <iframe src="image.svg"></iframe>
  • Complete isolation
  • Good for third-party SVGs
  • Browser caching
  • Limited interaction with page
  • Cross-domain restrictions
  • Extra markup overhead

For most interactive applications, inline SVG is the recommended approach:

<!-- Inline SVG Example -->
<div class="chart-container">
    <h2>Monthly Sales</h2>
    <svg width="500" height="300" viewBox="0 0 500 300">
        <rect class="bar" x="50" y="50" width="50" height="200" />
        <rect class="bar" x="120" y="100" width="50" height="150" />
        <rect class="bar" x="190" y="80" width="50" height="170" />
        <rect class="bar" x="260" y="30" width="50" height="220" />
        <rect class="bar" x="330" y="70" width="50" height="180" />
        
        <!-- X-axis labels -->
        <text x="75" y="270" text-anchor="middle">Jan</text>
        <text x="145" y="270" text-anchor="middle">Feb</text>
        <text x="215" y="270" text-anchor="middle">Mar</text>
        <text x="285" y="270" text-anchor="middle">Apr</text>
        <text x="355" y="270" text-anchor="middle">May</text>
    </svg>
</div>

<style>
    .bar {
        fill: #2196f3;
        transition: fill 0.3s;
    }
    .bar:hover {
        fill: #ff9800;
    }
</style>

SVG Transformations

SVG elements can be transformed in various ways using the transform attribute:

Transformation Syntax Description
translate transform="translate(x, y)" Moves an element by x units horizontally and y units vertically
rotate transform="rotate(angle [cx cy])" Rotates an element by angle degrees, optionally around point (cx, cy)
scale transform="scale(x [y])" Resizes an element by x horizontally and y vertically (if y is omitted, it equals x)
skewX transform="skewX(angle)" Skews an element along the x-axis by angle degrees
skewY transform="skewY(angle)" Skews an element along the y-axis by angle degrees
matrix transform="matrix(a b c d e f)" Applies a custom transformation matrix for advanced transformations

Multiple transformations can be combined in a single attribute:

transform="translate(100, 50) rotate(45) scale(1.5)"

The order of transformations matters! Each transformation is applied to the result of the previous one.

Original translate(0, -50) rotate(45) scale(1.5) skewX(30) translate(300, 250) rotate(30) scale(1.2) Combined transformations

Transformations are essential for creating complex graphics, animations, and interactive elements. They're conceptually similar to CSS transforms but operate within the SVG coordinate system.

Text in SVG

SVG allows for precise control over text positioning and appearance:

<svg width="400" height="100" xmlns="http://www.w3.org/2000/svg">
    <text x="20" y="50" font-family="Arial" font-size="24" fill="blue">
        Basic SVG Text
    </text>
    
    <text x="20" y="80" font-family="Arial" font-size="16">
        Text with <tspan fill="red" font-weight="bold">styled</tspan> segments
    </text>
</svg>

Key text-related elements and attributes include:

SVG Text Examples Basic text at (20,70) Centered text with text-anchor="middle" Right-aligned with text-anchor="end" Text with styled segments using tspan Text flowing along a curved path

Text in SVG is particularly useful for:

Practical Example: Creating an Interactive Chart

Let's combine what we've learned to create a simple interactive bar chart:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SVG Interactive Chart Example</title>
    <style>
        .chart-container {
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            font-family: Arial, sans-serif;
        }
        
        .bar {
            fill: #2196f3;
            transition: all 0.3s ease;
        }
        
        .bar:hover {
            fill: #ff9800;
            cursor: pointer;
        }
        
        .bar-label {
            font-size: 12px;
            text-anchor: middle;
            fill: #333;
        }
        
        .axis {
            stroke: #ccc;
            stroke-width: 1;
        }
        
        .axis-label {
            font-size: 14px;
            fill: #666;
        }
        
        .chart-title {
            font-size: 18px;
            font-weight: bold;
            text-anchor: middle;
            fill: #333;
        }
        
        .tooltip {
            position: absolute;
            padding: 8px;
            background: #333;
            color: white;
            border-radius: 4px;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s;
        }
    </style>
</head>
<body>
    <div class="chart-container">
        <svg width="600" height="350" viewBox="0 0 600 350">
            <!-- Chart title -->
            <text x="300" y="30" class="chart-title">Monthly Sales Data (2025)</text>
            
            <!-- X and Y axes -->
            <line x1="50" y1="300" x2="550" y2="300" class="axis" />
            <line x1="50" y1="50" x2="50" y2="300" class="axis" />
            
            <!-- Y-axis labels -->
            <text x="45" y="300" text-anchor="end" class="axis-label">0</text>
            <text x="45" y="225" text-anchor="end" class="axis-label">25K</text>
            <text x="45" y="150" text-anchor="end" class="axis-label">50K</text>
            <text x="45" y="75" text-anchor="end" class="axis-label">75K</text>
            
            <!-- Horizontal grid lines -->
            <line x1="50" y1="225" x2="550" y2="225" stroke="#eee" />
            <line x1="50" y1="150" x2="550" y2="150" stroke="#eee" />
            <line x1="50" y1="75" x2="550" y2="75" stroke="#eee" />
            
            <!-- Bars -->
            <g id="bars">
                <rect class="bar" x="80" y="200" width="40" height="100" data-value="25000" data-month="January" />
                <rect class="bar" x="140" y="160" width="40" height="140" data-value="35000" data-month="February" />
                <rect class="bar" x="200" y="120" width="40" height="180" data-value="45000" data-month="March" />
                <rect class="bar" x="260" y="80" width="40" height="220" data-value="55000" data-month="April" />
                <rect class="bar" x="320" y="100" width="40" height="200" data-value="50000" data-month="May" />
                <rect class="bar" x="380" y="140" width="40" height="160" data-value="40000" data-month="June" />
                <rect class="bar" x="440" y="180" width="40" height="120" data-value="30000" data-month="July" />
                <rect class="bar" x="500" y="220" width="40" height="80" data-value="20000" data-month="August" />
            </g>
            
            <!-- X-axis labels -->
            <text x="100" y="320" text-anchor="middle" class="axis-label">Jan</text>
            <text x="160" y="320" text-anchor="middle" class="axis-label">Feb</text>
            <text x="220" y="320" text-anchor="middle" class="axis-label">Mar</text>
            <text x="280" y="320" text-anchor="middle" class="axis-label">Apr</text>
            <text x="340" y="320" text-anchor="middle" class="axis-label">May</text>
            <text x="400" y="320" text-anchor="middle" class="axis-label">Jun</text>
            <text x="460" y="320" text-anchor="middle" class="axis-label">Jul</text>
            <text x="520" y="320" text-anchor="middle" class="axis-label">Aug</text>
        </svg>
        
        <div id="tooltip" class="tooltip"></div>
    </div>
    
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const bars = document.querySelectorAll('.bar');
            const tooltip = document.getElementById('tooltip');
            
            bars.forEach(bar => {
                bar.addEventListener('mouseover', function(e) {
                    // Get data values from attributes
                    const value = this.getAttribute('data-value');
                    const month = this.getAttribute('data-month');
                    
                    // Format value with comma separators
                    const formattedValue = parseInt(value).toLocaleString();
                    
                    // Update and position tooltip
                    tooltip.innerHTML = `${month}: $${formattedValue}`;
                    tooltip.style.left = (e.pageX + 10) + 'px';
                    tooltip.style.top = (e.pageY - 40) + 'px';
                    tooltip.style.opacity = 1;
                });
                
                bar.addEventListener('mousemove', function(e) {
                    // Update tooltip position as mouse moves
                    tooltip.style.left = (e.pageX + 10) + 'px';
                    tooltip.style.top = (e.pageY - 40) + 'px';
                });
                
                bar.addEventListener('mouseout', function() {
                    // Hide tooltip
                    tooltip.style.opacity = 0;
                });
                
                bar.addEventListener('click', function() {
                    // Example of responding to clicks
                    alert(`${this.getAttribute('data-month')} sales: $${parseInt(this.getAttribute('data-value')).toLocaleString()}`);
                });
            });
        });
    </script>
</body>
</html>

This example demonstrates several key SVG concepts:

The result is a professional-looking, interactive chart that scales perfectly at any size and provides rich user interaction.

SVG Optimization

Before deploying SVG in production, consider optimizing for performance:

graph TD A[Unoptimized SVG] --> B[Remove unnecessary metadata] B --> C[Round decimal values] C --> D[Simplify paths] D --> E[Minify attributes] E --> F[Remove comments] F --> G[Clean up groups] G --> H[Use compression] H --> I[Optimized SVG]

Manual Optimization Tips:

Automated Optimization Tools:

Example of optimization results:

/* Before optimization */
              
/* Before optimization */
                <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0 0 100 100" version="1.1" id="svg8">
                  <defs id="defs2">
                    <linearGradient id="linearGradient1">
                      <stop style="stop-color:#0000ff;stop-opacity:1;" offset="0" id="stop1"/>
                      <stop style="stop-color:#00ffff;stop-opacity:1.0000000" offset="1.0000000" id="stop2"/>
                    </linearGradient>
                  </defs>
                  <!-- This is a blue circle -->
                  <circle style="fill:url(#linearGradient1);fill-opacity:1.0;stroke:#000000;stroke-width:2.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000" id="path10" cx="50.000000" cy="50.000000" r="40.000000"/>
                </svg>
                
                /* After optimization */
                <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
                  <defs>
                    <linearGradient id="a">
                      <stop offset="0" stop-color="#00f"/>
                      <stop offset="1" stop-color="#0ff"/>
                    </linearGradient>
                  </defs>
                  <circle cx="50" cy="50" r="40" fill="url(#a)" stroke="#000" stroke-width="2"/>
                </svg>

The optimized version is about 65% smaller but renders identically in the browser. For large, complex SVGs, optimization can make a significant difference in loading times and performance.

SVG Accessibility

Making SVG accessible ensures that your graphics are usable by everyone, including people using assistive technologies:

  • Title and Description: Add <title> and <desc> elements
  • ARIA attributes: Use role and aria-* attributes
  • Focus management: Make interactive elements focusable
  • Keyboard navigation: Support keyboard interaction
  • Text alternatives: Include fallback content for complex graphics
<svg role="img" aria-labelledby="chartTitle chartDesc" viewBox="0 0 100 100">
                    <title id="chartTitle">Annual Sales Growth</title>
                    <desc id="chartDesc">Bar chart showing 15% growth in sales from 2024 to 2025</desc>
                    
                    <!-- Chart content... -->
                    
                    <g role="button" tabindex="0" aria-label="View sales details" 
                       onkeydown="if(event.key==='Enter')showDetails();"
                       onclick="showDetails();">
                        <!-- Interactive element content... -->
                    </g>
                </svg>

Following these practices makes SVG content perceivable and operable for users with disabilities, similar to how proper signage and ramps make physical buildings accessible to everyone.

Practice Activities

Basic Exercise: Create a Logo

Design a simple logo using basic SVG shapes. Include at least three different shape types and use gradients or solid colors. Make sure the SVG is properly structured with appropriate viewBox settings.

Intermediate Exercise: Interactive Icon Set

Create a set of 4-6 related icons (e.g., social media icons, weather symbols, or UI controls) using the <symbol> and <use> elements. Add hover effects with CSS and basic click interactions with JavaScript.

Advanced Exercise: Data Visualization

Build a data visualization (pie chart, line graph, or bar chart) using SVG. Use real or sample data, implement proper labeling, and add interactive features like tooltips on hover.

Challenge Project: Animated Infographic

Create an animated infographic that tells a story with data. Use multiple SVG techniques, including paths, text, and groups. Implement animations with CSS or JavaScript and ensure the infographic is accessible with appropriate ARIA attributes and text alternatives.

Exploration Activity: SVG Filters

Research and experiment with SVG filters (not covered in this lecture). Try implementing effects like drop shadows, blurs, or color transformations on SVG elements. Document your findings and share examples of the effects.

Additional Resources