Colors & Styles
A deep dive into color theory, gradients, patterns, transparency, compositing, line styles, and shadows on the Canvas.
How Computers Represent Color
Before we paint anything, let’s understand how color works on screens. Your monitor has millions of tiny lights, each made of three sub-pixels: one red, one green, and one blue. By mixing these three colors of light at different intensities, your screen can create virtually any color you can see.
This is called the RGB color model. Each channel (Red, Green, Blue) ranges from 0 (off) to 255 (full brightness). That gives us 256 x 256 x 256 = over 16 million possible colors.
Think of it like stage lighting. Imagine three spotlights in a dark theater: one red, one green, one blue. Point them all at the same spot on the wall:
Red only Green only Blue only Red + Green All three
+------+ +------+ +------+ +------+ +------+
| R | | G | | | | R G | | R G |
| ** | | ** | | ** | | ** | | ** |
| RED | | GRN | | B | | YLW | | B |
+------+ +------+ +------+ +------+ +------+
(255,0,0) (0,255,0) (0,0,255) (255,255,0) (255,255,255)
= Yellow = White!Key insight: mixing light is additive. Adding more light makes things brighter. This is the opposite of mixing paint, where adding more paint makes things darker.
The demos below use beginPath() and arc() from Lesson 2 to draw circles. Here, we focus on color rather than shape.
Try this: Change the globalAlpha values from 0.6 to 0.3 for subtle blending, or 0.9 for near-solid layers. Watch how the overlap colors shift.
Color Formats Canvas Understands
Canvas accepts any color format that CSS understands. Let’s explore each one so you know your options.
Named Colors: CSS has 140+ built-in color names like crimson, cornflowerblue, salmon. Easy to read, but limited palette.
Hex (#rrggbb): Each pair of hex digits represents a channel: #ff0000 = red 255, green 0, blue 0. Compact, widely used.
RGB (r, g, b): rgb(255, 0, 0), same as hex but easier to read. Values 0-255 per channel.
RGBA (r, g, b, a): Like RGB but with an alpha (opacity) channel from 0.0 (invisible) to 1.0 (solid).
HSL (h, s%, l%): Hue (0-360 degrees on a color wheel), Saturation (0-100%), Lightness (0-100%). Often more intuitive; we’ll explore this next.
The HSL Color Model: Your Secret Weapon
RGB makes you juggle three numbers to get a color. HSL (Hue, Saturation, Lightness) lets you think about color the way you already do: pick a color, decide how bold it should be, then choose how light or dark.
Hue: “What color?” Pick a spot on the rainbow. It is a number from 0 to 360, like degrees on a circle. 0 is red, 120 is green, 240 is blue, and 360 wraps back to red.
Saturation: “How vivid?” At 100% the color is pure and vibrant. At 0% all the color drains out and you get gray.
Lightness: “How light or dark?” 0% is always black, 100% is always white, and 50% gives you the true color.
The Hue Color Wheel (degrees)
0/360 = Red
|
330 | 30
Magenta \ | / Orange
\ | /
300 ------+-------+----- 60
Violet | * | Yellow
/ | \
270 / | \ 90
Blue-Violet | Yellow-Green
|
180 = Cyan
(turquoise)
Saturation: center (gray) ────> edge (vivid)
Lightness: separate axis: 0% black, 100% white HSL is incredibly useful in code because you can generate harmonious color schemes just by shifting the hue angle, and you can create tints and shades by adjusting lightness.
fillStyle and strokeStyle
Every shape you draw on Canvas uses two style properties. Think of them like choosing your art supplies:
fillStyle: the paint color that fills the inside of shapes. Like choosing which paint to pour into a bucket.
strokeStyle: the pen color for outlines. Like choosing which marker to trace edges with.
Both accept any color format. Once set, they stay set until you change them, like picking up a new paintbrush.
Transparency and Opacity
Transparency lets you see through shapes to whatever is behind them. Canvas gives you two ways to control this.
Analogy: Glass Windows. Imagine stacking colored glass windows:
alpha = 1.0 alpha = 0.5 alpha = 0.0 (fully opaque) (semi-transparent) (invisible) +──────────+ +──────────+ +──────────+ │##########│ │# # # # # │ │ │ │##########│ │ # # # # │ │ │ │## SOLID ##│ │# SEMI # │ │ NOTHING │ │##########│ │ # # # # │ │ │ +──────────+ +──────────+ +──────────+ Like a wall. Like tinted Like clear Blocks everything glass. Lets some glass. Fully behind it. light through. transparent.
Method 1: ctx.globalAlpha = 0.5 affects ALL subsequent draws. Remember to reset it to 1.0!
Method 2: rgba(r, g, b, alpha) or hsla(h, s%, l%, alpha) for per-color transparency. More precise control.
Linear Gradients
A gradient smoothly transitions between two or more colors. A linear gradient transitions along a straight line. Think of it like a paint roller that starts with one color and gradually shifts to another.
createLinearGradient(x0, y0, x1, y1) defines the line along which colors change:
Horizontal: (0, 100) ─────────> (500, 100)
start end
Left to right, same y
Vertical: (100, 0)
│
│ Top to bottom, same x
v
(100, 400)
Diagonal: (0, 0)
\
\ Corner to corner
v
(500, 400)After creating the gradient, add color stops: gradient.addColorStop(position, color)
position is 0.0 (start) to 1.0 (end). You can add as many stops as you want!
Radial Gradients
A radial gradient transitions colors outward from a center point, like ripples in a pond. It’s defined by two circles: an inner circle (where the gradient starts) and an outer circle (where it ends).
createRadialGradient(x0, y0, r0, x1, y1, r1)
(x0, y0, r0) = inner circle center + radius (gradient START) (x1, y1, r1) = outer circle center + radius (gradient END) Centered (same center): Off-center (spotlight): +───────────────────+ +───────────────────+ │ │ │ │ │ .-"""-. │ │ .-"""-. │ │ / inner \ │ │ / inner \ outer │ │ │ (r0) │ │ │ │ (r0) \ (r1) │ │ \ / │ │ \ / ---' │ │ '-...-' │ │ '-...-' │ │ outer (r1) │ │ │ +───────────────────+ +───────────────────+ Colors radiate evenly Light source is offset from center outward creating a spotlight
Patterns with createPattern()
Besides solid colors and gradients, you can fill shapes with a repeating pattern. A pattern is like digital wallpaper: you create a small tile, and Canvas repeats it to fill any shape.
createPattern(image, repetition) where:
image = any image source (Image, Canvas, Video)
repetition = “repeat” (tile both ways), “repeat-x” (horizontal only), “repeat-y” (vertical only), “no-repeat” (once)
The easiest way to make patterns is to draw a tile on an offscreen canvas, then use that canvas as the pattern source.
Composite Operations (Blending Modes)
globalCompositeOperation controls how new shapes interact with existing content on the canvas. The default is “source-over”, where new shapes paint on top. But there are 26 different modes that let you multiply, screen, subtract, and more.
Analogy: Photo editing layers. If you’ve used Photoshop or GIMP, composite operations are like blend modes. They control how a new layer combines with layers below it.
”source” = the new shape you’re drawing
”destination” = what’s already on the canvas
source-over source-atop destination-over xor +------+ +------+ +------+ +------+ | BB | | .B | | AA | | BA | | AABB | | AABB | | AABB | | AA.BB| | AA | | AA | | AABB | | AA | +------+ +------+ +------+ +------+ New on top New only where Old on top Overlap of old old exists of new becomes clear A = existing (destination) B = new shape (source)
Line Styles
Lines in Canvas aren’t just “draw a line.” You can control their thickness, how their ends look, how corners connect, and whether they’re dashed.
lineWidth: thickness in pixels. The line is centered on the path, so half the width extends to each side.
lineCap: how line endpoints are drawn:
"butt" "round" "square"
---|--- ---O--- --[|]--
Ends at Adds a Adds a
the exact semicircle rectangle
endpoint beyond beyond the
the end endpointlineJoin: how corners between line segments connect:
"miter" "round" "bevel" /\ /\ /\ / \ ( ) /--\ Sharp Rounded Flat corner corner corner
Dashed Lines and Marching Ants
setLineDash([segments]) creates dashed lines. The array alternates between dash length and gap length. lineDashOffset shifts the pattern; animate it for a “marching ants” selection effect.
Shadows
Canvas can add shadows to anything you draw: shapes, text, and images. There are four shadow properties that work together.
shadowColor: the shadow’s color (use rgba for translucent shadows).
shadowBlur: how fuzzy the shadow is (0 = sharp, higher = softer).
shadowOffsetX / shadowOffsetY: where the shadow falls relative to the shape.
shadowBlur = 0 shadowBlur = 10 shadowBlur = 30 +───+ +───+ +───+ │ │x │ │ │ │ +───+x +───+ +───+ xxxx . soft . ......... Sharp shadow Moderate blur Extremely soft offsetX = 5, offsetY = 5 (shadow cast down-right) offsetX = 0, offsetY = 0 (glow effect: shadow all around)
Always reset shadows when done! Otherwise every subsequent draw gets shadows too.
Putting It All Together: Night City Scene
Let’s combine gradients, patterns, transparency, shadows, and compositing into one scene. Study this example to see how all the techniques work together.
Lesson 3 Recap: What you learned.
Colors: RGB (how screens work), HSL (how humans think), and all CSS formats. fillStyle for fills, strokeStyle for outlines.
Transparency: globalAlpha (affects everything, so always reset!) vs rgba()/hsla() (per-color control).
Gradients: createLinearGradient for straight-line transitions, createRadialGradient for circular transitions. Both use addColorStop().
Patterns: createPattern repeats a tile image to fill shapes.
Compositing: globalCompositeOperation controls how new shapes blend with existing content (26 modes!).
Lines: lineWidth, lineCap, lineJoin, setLineDash, and animated lineDashOffset.
Shadows: shadowColor, shadowBlur, shadowOffsetX/Y, used for glow, depth, and drop shadows.