I’m currently working on an color-picker component using HTML, CSS and Javascript, one major question is how I should implement a color palette like this one:

Ignoring browser compatibility issues introduced by IE8 or earlier, I have 3 methods to implement this:
-
The
<img>way:This is simple and is used by many color-picker components for years, we simply include an image exactly the same as the above one using
<img src="palette.png" />.The problem is
<img>would introduce extra network roundtrip, although we can prevent it using dataURI, but an image data is a little too large for me. -
The
<div>way:In this way we should use 2
<div>elements, one of them provides a left-to-right linear gradient and the other provides a top-to-bottom alpha gradient, the style should be:<style> #map { width: 400px; height: 400px; background: -webkit-gradient( linear, left top, right top, color-stop(0%,#ff0000), color-stop(16.67%,#ffff00), color-stop(33.33%,#00ff00), color-stop(50%,#00ffff), color-stop(66.67%,#0000ff), color-stop(83.33%,#ff00ff), color-stop(100%,#ff0000) ); } #overlay { width: 400px; height: 400px; background: -webkit-gradient( linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 1)) ); } </style> <div id="palette"><div id="overlay"></div></div>It works perfectly, but the problem is, this method introduces 2 elements for styling only, the 2
<div>elements don’t have any semantic meanings and don’t act as a generic container or block, this is a violation to semantic HTML. -
The
<canvas>way:<canvas>provides very flexible graphic API to implement such a color palette, I use these code to draw it:var context = canvas.getContext('2d'); var palette = context.createLinearGradient(0, 0, 360, 0); palette.addColorStop(0 / 6, '#ff0000'); palette.addColorStop(1 / 6, '#ffff00'); palette.addColorStop(2 / 6, '#00ff00'); palette.addColorStop(3 / 6, '#00ffff'); palette.addColorStop(4 / 6, '#0000ff'); palette.addColorStop(5 / 6, '#ff00ff'); palette.addColorStop(6 / 6, '#ff0000'); context.fillStyle = palette; context.fillRect(0, 0, 360, 360); var overlay = context.createLinearGradient(0, 0, 0, 360); overlay.addColorStop(0, 'rgba(0, 0, 0, 0)'); overlay.addColorStop(1, 'rgba(0, 0, 0, 1)'); context.fillStyle = overlay; context.fillRect(0, 0, 360, 360);It works as well as the above 2 approaches, but I wonder whether I should use canvas to draw such a static image, shouldn’t canvas be used in more dynamic and complex enviroment?
So which way should I go to implement a simple color palette, or is there a better approach?
If you wanted to use an image, but don’t want the extra request, you could use a data URI:
Demo