Embedded Content
HTML5
The <canvas> element provides a drawable region in HTML where you can render graphics, animations, game graphics, data visualizations, photo manipulation, and real-time video processing using JavaScript. Unlike SVG which is vector-based, canvas uses a bitmap (raster) approach with immediate-mode rendering.
Interactive code playground requires JavaScript. Here's the code:
<canvas id="myCanvas" width="300" height="150">
Your browser does not support the canvas element.
</canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// Draw a blue rectangle
ctx.fillStyle = '#3b82f6';
ctx.fillRect(50, 50, 200, 50);
// Draw white text
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.fillText('Hello Canvas!', 90, 82);
</script>
< canvas id = " myCanvas " width = " 600 " height = " 400 " >
Fallback content for browsers that don't support canvas
Attribute Value Description widthNumber Canvas width in pixels (default: 300) heightNumber Canvas height in pixels (default: 150)
Caution
Important: Always set canvas dimensions using the width and height attributes, not CSS. CSS will scale the canvas bitmap, potentially causing distortion. The attributes set the actual coordinate space.
The <canvas> element supports all global attributes .
Before drawing, you must obtain a rendering context:
Interactive code playground requires JavaScript. Here's the code:
<canvas id="demo" width="300" height="150"></canvas>
<script>
const canvas = document.getElementById('demo');
const ctx = canvas.getContext('2d');
if (ctx) {
// Drawing code goes here
ctx.fillStyle = '#10b981';
ctx.fillRect(10, 10, 280, 130);
} else {
console.error('Canvas not supported');
}
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="rectangles" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById('rectangles').getContext('2d');
// Filled rectangle
ctx.fillStyle = '#ef4444';
ctx.fillRect(20, 20, 100, 60);
// Stroked rectangle
ctx.strokeStyle = '#3b82f6';
ctx.lineWidth = 3;
ctx.strokeRect(140, 20, 100, 60);
// Clear rectangle (erases area)
ctx.clearRect(50, 40, 40, 20);
</script> Interactive code playground requires JavaScript. Here's the code:
<canvas id="paths" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById('paths').getContext('2d');
// Triangle
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(100, 100);
ctx.lineTo(50, 100);
ctx.closePath();
ctx.fillStyle = '#8b5cf6';
ctx.fill();
// Circle
ctx.beginPath();
ctx.arc(200, 75, 40, 0, Math.PI * 2);
ctx.strokeStyle = '#ec4899';
ctx.lineWidth = 3;
ctx.stroke();
</script> Interactive code playground requires JavaScript. Here's the code:
<canvas id="text" width="300" height="150"></canvas>
<script>
const ctx = document.getElementById('text').getContext('2d');
// Filled text
ctx.font = 'bold 24px Arial';
ctx.fillStyle = '#1e40af';
ctx.fillText('Canvas Text', 50, 50);
// Stroked text
ctx.font = '20px Georgia';
ctx.strokeStyle = '#059669';
ctx.lineWidth = 1;
ctx.strokeText('Outlined Text', 50, 90);
// Text alignment
ctx.textAlign = 'center';
ctx.fillStyle = '#dc2626';
ctx.fillText('Centered', 150, 130);
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="gradients" width="300" height="150"></canvas>
<script>
const ctx = document.getElementById('gradients').getContext('2d');
// Linear gradient
const linearGrad = ctx.createLinearGradient(0, 0, 200, 0);
linearGrad.addColorStop(0, '#3b82f6');
linearGrad.addColorStop(1, '#8b5cf6');
ctx.fillStyle = linearGrad;
ctx.fillRect(10, 10, 130, 60);
// Radial gradient
const radialGrad = ctx.createRadialGradient(225, 45, 5, 225, 45, 40);
radialGrad.addColorStop(0, '#fbbf24');
radialGrad.addColorStop(1, '#ef4444');
ctx.fillStyle = radialGrad;
ctx.fillRect(160, 10, 130, 60);
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="imageCanvas" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById('imageCanvas').getContext('2d');
// Draw colored rectangles as a demo
const colors = ['#ef4444', '#3b82f6', '#10b981', '#f59e0b'];
colors.forEach((color, i) => {
ctx.fillStyle = color;
ctx.fillRect(i * 75, 0, 75, 100);
});
// Get image data
const imageData = ctx.getImageData(0, 0, 300, 100);
const data = imageData.data;
// Invert colors
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // Red
data[i + 1] = 255 - data[i + 1]; // Green
data[i + 2] = 255 - data[i + 2]; // Blue
}
// Put modified data back
ctx.putImageData(imageData, 0, 100);
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="animation" width="300" height="150"></canvas>
<script>
const canvas = document.getElementById('animation');
const ctx = canvas.getContext('2d');
let x = 0;
let direction = 1;
function animate() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw moving circle
ctx.beginPath();
ctx.arc(x, 75, 20, 0, Math.PI * 2);
ctx.fillStyle = '#3b82f6';
ctx.fill();
// Update position
x += 2 * direction;
// Bounce at edges
if (x > 280 || x < 20) {
direction *= -1;
}
// Request next frame
requestAnimationFrame(animate);
}
animate();
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="drawing" width="300" height="200" style="border: 2px solid #ddd; cursor: crosshair;"></canvas>
<button onclick="clearCanvas()">Clear</button>
<script>
const canvas = document.getElementById('drawing');
const ctx = canvas.getContext('2d');
let isDrawing = false;
ctx.strokeStyle = '#3b82f6';
ctx.lineWidth = 3;
ctx.lineCap = 'round';
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
const rect = canvas.getBoundingClientRect();
ctx.beginPath();
ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
});
canvas.addEventListener('mousemove', (e) => {
if (!isDrawing) return;
const rect = canvas.getBoundingClientRect();
ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
ctx.stroke();
});
canvas.addEventListener('mouseup', () => {
isDrawing = false;
});
window.clearCanvas = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
</script>
Canvas supports various transformations:
Interactive code playground requires JavaScript. Here's the code:
<canvas id="transforms" width="300" height="200"></canvas>
<script>
const ctx = document.getElementById('transforms').getContext('2d');
// Save original state
ctx.save();
// Translate (move origin)
ctx.translate(150, 100);
// Rotate (in radians)
ctx.rotate(Math.PI / 6);
// Scale
ctx.scale(1.5, 1);
// Draw transformed rectangle
ctx.fillStyle = '#8b5cf6';
ctx.fillRect(-40, -20, 80, 40);
// Restore original state
ctx.restore();
// Draw reference point
ctx.fillStyle = '#ef4444';
ctx.beginPath();
ctx.arc(150, 100, 3, 0, Math.PI * 2);
ctx.fill();
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="compositing" width="300" height="150"></canvas>
<script>
const ctx = document.getElementById('compositing').getContext('2d');
// Draw base circle
ctx.fillStyle = '#3b82f6';
ctx.beginPath();
ctx.arc(100, 75, 50, 0, Math.PI * 2);
ctx.fill();
// Set composite operation
ctx.globalCompositeOperation = 'multiply';
// Draw overlapping circle
ctx.fillStyle = '#f59e0b';
ctx.beginPath();
ctx.arc(140, 75, 50, 0, Math.PI * 2);
ctx.fill();
// Reset
ctx.globalCompositeOperation = 'source-over';
// Label
ctx.fillStyle = '#000';
ctx.font = '14px Arial';
ctx.fillText('multiply blend mode', 180, 75);
</script>
Interactive code playground requires JavaScript. Here's the code:
<canvas id="clipping" width="300" height="150"></canvas>
<script>
const ctx = document.getElementById('clipping').getContext('2d');
// Create circular clipping region
ctx.beginPath();
ctx.arc(150, 75, 60, 0, Math.PI * 2);
ctx.clip();
// Everything drawn now will be clipped to the circle
const gradient = ctx.createLinearGradient(0, 0, 300, 150);
gradient.addColorStop(0, '#3b82f6');
gradient.addColorStop(1, '#8b5cf6');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 300, 150);
// Draw text inside clipping region
ctx.fillStyle = 'white';
ctx.font = 'bold 20px Arial';
ctx.textAlign = 'center';
ctx.fillText('Clipped!', 150, 82);
</script>
Understanding when to use canvas versus SVG:
Use Canvas For
High-performance games
Pixel manipulation
Many objects (1000+)
Real-time data visualization
Photo editing
Particle effects
Use SVG For
Scalable graphics
Interactive UI elements
Accessibility requirements
SEO-friendly graphics
Print-quality output
Document illustrations
Canvas creates significant accessibility challenges because it renders to a bitmap:
Interactive code playground requires JavaScript. Here's the code:
<canvas id="chart" width="300" height="200"
role="img"
aria-label="Bar chart showing quarterly sales">
<table>
<caption>Quarterly Sales Data</caption>
<tr><th>Quarter</th><th>Sales</th></tr>
<tr><td>Q1</td><td>$50k</td></tr>
<tr><td>Q2</td><td>$75k</td></tr>
<tr><td>Q3</td><td>$60k</td></tr>
<tr><td>Q4</td><td>$90k</td></tr>
</table>
</canvas>
<script>
const ctx = document.getElementById('chart').getContext('2d');
const data = [50, 75, 60, 90];
const barWidth = 60;
const spacing = 15;
data.forEach((value, i) => {
const x = i * (barWidth + spacing) + 20;
const height = value * 1.5;
ctx.fillStyle = '#3b82f6';
ctx.fillRect(x, 200 - height, barWidth, height);
ctx.fillStyle = '#000';
ctx.font = '12px Arial';
ctx.fillText('Q' + (i + 1), x + 20, 195);
});
</script>
Provide text alternatives : Use ARIA labels or fallback content
Add keyboard navigation : For interactive canvases
Announce dynamic changes : Use ARIA live regions
Consider alternative formats : Provide data tables for charts
Test with screen readers : Ensure meaningful experience
Batch draw calls : Minimize state changes
Use layers : Multiple canvases for static/dynamic content
Optimize clearing : Clear only changed regions
Use offscreen canvas : Pre-render complex elements
Avoid unnecessary redraws : Track dirty regions
Reduce canvas size : Use CSS scaling when appropriate
Interactive code playground requires JavaScript. Here's the code:
<!-- Layered canvas example -->
<div style="position: relative; width: 300px; height: 200px;">
<!-- Background layer (static) -->
<canvas id="bgLayer" width="300" height="200"
style="position: absolute; left: 0; top: 0;"></canvas>
<!-- Foreground layer (animated) -->
<canvas id="fgLayer" width="300" height="200"
style="position: absolute; left: 0; top: 0;"></canvas>
</div>
<script>
// Draw static background once
const bgCtx = document.getElementById('bgLayer').getContext('2d');
const gradient = bgCtx.createLinearGradient(0, 0, 0, 200);
gradient.addColorStop(0, '#0ea5e9');
gradient.addColorStop(1, '#1e40af');
bgCtx.fillStyle = gradient;
bgCtx.fillRect(0, 0, 300, 200);
// Animate foreground only
const fgCtx = document.getElementById('fgLayer').getContext('2d');
let angle = 0;
function animateFg() {
fgCtx.clearRect(0, 0, 300, 200);
fgCtx.save();
fgCtx.translate(150, 100);
fgCtx.rotate(angle);
fgCtx.fillStyle = '#fbbf24';
fgCtx.fillRect(-30, -30, 60, 60);
fgCtx.restore();
angle += 0.02;
requestAnimationFrame(animateFg);
}
animateFg();
</script>
When you draw cross-origin images, the canvas becomes “tainted”:
const canvas = document . getElementById ( ' myCanvas ' );
const ctx = canvas . getContext ( ' 2d ' );
// This will taint the canvas if image is from another origin
img . src = ' https://example.com/image.jpg ' ;
ctx . drawImage ( img , 0 , 0 );
// This will throw a security error
// ctx.getImageData(0, 0, 100, 100); // Error!
// canvas.toDataURL(); // Error!
To avoid tainting, configure CORS properly:
img . crossOrigin = ' anonymous ' ;
img . src = ' https://example.com/image.jpg ' ;
Excellent Support
The <canvas> element is supported in all modern browsers:
Chrome : 4+ (2010)
Firefox : 2+ (2006)
Safari : 3.1+ (2008)
Edge : All versions
Opera : 9+ (2006)
Mobile : Full support
Fallback : Provide alternative content inside the <canvas> tags for older browsers.
<svg> - Vector graphics alternative
<img> - Static images
WebGL - 3D graphics context for canvas
OffscreenCanvas - Canvas in Web Workers
ImageBitmap - Optimized image rendering
Set dimensions correctly : Use width/height attributes, not CSS
Always provide fallback : Add meaningful content inside tags
Clear before redrawing : Prevent visual artifacts
Save/restore context state : When using transformations
Handle high DPI displays : Scale for retina screens
Optimize for performance : Use layers and batch operations
Make it accessible : Add ARIA labels and text alternatives
Test across devices : Performance varies significantly
Learn More: