Each vertex carries a color attribute, and the fragment shader receives interpolated colors across the triangle.

Program

Attributes are per-vertex input streams. Varyings carry those values from the vertex shader to the fragment shader.

attribute_colors.html
<canvas id="stage" width="360" height="210"></canvas>
<script>
  const vertices = new Float32Array([
    0.0,  0.62,  0.94, 0.35, 0.28,
   -0.62, -0.52,  0.22, 0.82, 0.55,
    0.62, -0.52,  0.29, 0.55, 0.96
  ]);
  gl.enableVertexAttribArray(aPos);
  gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 20, 0);
  gl.enableVertexAttribArray(aColor);
  gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, 20, 8);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
attribute An attribute is a per-vertex input read by the vertex shader.
varying A varying carries interpolated values from the vertex shader to the fragment shader.
stride Stride is the byte distance from one vertex record to the next.