diff --git a/Criterion/EmbeddedData.hs b/Criterion/EmbeddedData.hs
--- a/Criterion/EmbeddedData.hs
+++ b/Criterion/EmbeddedData.hs
@@ -12,7 +12,13 @@
 -- When the @embed-data-files@ @Cabal@ flag is enabled, this module exports
 -- the contents of various files (the @data-files@ from @criterion.cabal@, as
 -- well as minimized versions of jQuery and Flot) embedded as 'ByteString's.
-module Criterion.EmbeddedData (dataFiles, jQueryContents, flotContents) where
+module Criterion.EmbeddedData
+  ( dataFiles
+  , jQueryContents
+  , flotContents
+  , flotErrorbarsContents
+  , flotNavigateContents
+  ) where
 
 import Data.ByteString (ByteString)
 import Data.FileEmbed (embedDir, embedFile)
@@ -23,6 +29,9 @@
 dataFiles :: [(FilePath, ByteString)]
 dataFiles = $(embedDir "templates")
 
-jQueryContents, flotContents :: ByteString
-jQueryContents = $(embedFile =<< runIO JQuery.file)
-flotContents   = $(embedFile =<< runIO (Flot.file Flot.Flot))
+jQueryContents, flotContents,
+  flotErrorbarsContents, flotNavigateContents :: ByteString
+jQueryContents        = $(embedFile =<< runIO JQuery.file)
+flotContents          = $(embedFile =<< runIO (Flot.file Flot.Flot))
+flotErrorbarsContents = $(embedFile =<< runIO (Flot.file Flot.FlotErrorbars))
+flotNavigateContents  = $(embedFile =<< runIO (Flot.file Flot.FlotNavigate))
diff --git a/Criterion/Report.hs b/Criterion/Report.hs
--- a/Criterion/Report.hs
+++ b/Criterion/Report.hs
@@ -62,7 +62,8 @@
 import qualified Data.Vector.Unboxed as U
 
 #if defined(EMBED)
-import Criterion.EmbeddedData (dataFiles, flotContents, jQueryContents)
+import Criterion.EmbeddedData (dataFiles, jQueryContents, flotContents,
+                               flotErrorbarsContents, flotNavigateContents)
 import qualified Data.ByteString.Lazy as BL
 import qualified Data.Text.Encoding as TE
 #else
@@ -113,10 +114,12 @@
         Left err -> fail (show err) -- TODO: throw a template exception?
         Right x -> return x
 
-    jQuery <- jQueryFileContents
-    flot <- flotFileContents
+    jQuery            <- jQueryFileContents
+    flot              <- flotFileContents
+    flotErrorbars     <- flotErrorbarsFileContents
+    flotNavigate      <- flotNavigateFileContents
     jQueryCriterionJS <- readDataFile ("js" </> "jquery.criterion.js")
-    criterionCSS <- readDataFile "criterion.css"
+    criterionCSS      <- readDataFile "criterion.css"
 
     -- includes, only top level
     templates <- getTemplateDir
@@ -127,6 +130,8 @@
             , "report"              .= map inner reports
             , "js-jquery"           .= jQuery
             , "js-flot"             .= flot
+            , "js-flot-errorbars"   .= flotErrorbars
+            , "js-flot-navigate"    .= flotNavigate
             , "jquery-criterion-js" .= jQueryCriterionJS
             , "criterion-css"       .= criterionCSS
             ]
@@ -153,11 +158,15 @@
   where
     jQueryFileContents, flotFileContents :: IO T.Text
 #if defined(EMBED)
-    jQueryFileContents = pure $ TE.decodeUtf8 jQueryContents
-    flotFileContents   = pure $ TE.decodeUtf8 flotContents
+    jQueryFileContents        = pure $ TE.decodeUtf8 jQueryContents
+    flotFileContents          = pure $ TE.decodeUtf8 flotContents
+    flotErrorbarsFileContents = pure $ TE.decodeUtf8 flotErrorbarsContents
+    flotNavigateFileContents  = pure $ TE.decodeUtf8 flotNavigateContents
 #else
-    jQueryFileContents = T.readFile =<< JQuery.file
-    flotFileContents   = T.readFile =<< Flot.file Flot.Flot
+    jQueryFileContents        = T.readFile =<< JQuery.file
+    flotFileContents          = T.readFile =<< Flot.file Flot.Flot
+    flotErrorbarsFileContents = T.readFile =<< Flot.file Flot.FlotErrorbars
+    flotNavigateFileContents  = T.readFile =<< Flot.file Flot.FlotNavigate
 #endif
 
     readDataFile :: FilePath -> IO T.Text
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,16 @@
+1.2.6.0
+
+* Add error bars and zoomable navigation to generated HTML report graphs.
+
+  (Note that there have been reports that this feature can be somewhat unruly
+  when using macOS and Firefox simultaneously. See
+  https://github.com/flot/flot/issues/1554 for more details.)
+
+* Use a predetermined set of cycling colors for benchmark groups in HTML
+  reports. This avoids a bug in earlier versions of `criterion` where benchmark
+  group colors could be chosen that were almost completely white, which made
+  them impossible to distinguish from the background.
+
 1.2.5.0
 
 * Add an `-fembed-data-files` flag. Enabling this option will embed the
diff --git a/criterion.cabal b/criterion.cabal
--- a/criterion.cabal
+++ b/criterion.cabal
@@ -1,5 +1,5 @@
 name:           criterion
-version:        1.2.5.0
+version:        1.2.6.0
 synopsis:       Robust, reliable performance measurement and analysis
 license:        BSD3
 license-file:   LICENSE
diff --git a/templates/default.tpl b/templates/default.tpl
--- a/templates/default.tpl
+++ b/templates/default.tpl
@@ -10,6 +10,12 @@
       {{{js-flot}}}
     </script>
     <script language="javascript" type="text/javascript">
+      {{{js-flot-errorbars}}}
+    </script>
+    <script language="javascript" type="text/javascript">
+      {{{js-flot-navigate}}}
+    </script>
+    <script language="javascript" type="text/javascript">
       {{{jquery-criterion-js}}}
     </script>
     <style type="text/css">
@@ -283,26 +289,40 @@
   var benches = [{{#report}}"{{name}}",{{/report}}];
   var ylabels = [{{#report}}[-{{number}},'<a href="#b{{number}}">{{name}}</a>'],{{/report}}];
   var means = $.scaleTimes([{{#report}}{{anMean.estPoint}},{{/report}}]);
+  var stddevs = [{{#report}}{{anStdDev.estPoint}},{{/report}}];
+  stddevs = $.scaleBy(means[1], stddevs);
   var xs = [];
   var prev = null;
+  var colors = ["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"];
+  var max_time = 0;
   for (var i = 0; i < means[0].length; i++) {
     var name = benches[i].split(/\//);
     name.pop();
     name = name.join('/');
     if (name != prev) {
-      xs.push({ label: name, data: [[means[0][i], -i]]});
+      var color = colors[xs.length / 2 % colors.length];
+      xs.push({ data: [[means[0][i], -i]], label: name, color: color,
+                bars: { show: true, horizontal: true, barWidth: 0.75,
+                        align: "center" } });
+      xs.push({ data: [[means[0][i], -i, stddevs[i]]], color: color,
+                lines: { show: false },
+                points: { radius: 0, errorbars: "x",
+                          xerr: { show: true, radius: 5,
+                                  lowerCap: "-", upperCap: "-" } } });
       prev = name;
+    } else {
+      xs[xs.length - 2].data.push([means[0][i], -i]);
+      xs[xs.length - 1].data.push([means[0][i], -i, stddevs[i]]);
     }
-    else
-      xs[xs.length-1].data.push([means[0][i],-i]);
+    max_time = Math.max(max_time, means[0][i] + stddevs[i]);
   }
   var oq = $("#overview");
-  o = $.plot(oq, xs, { bars: { show: true, horizontal: true,
-                               barWidth: 0.75, align: "center" },
-                       grid: { borderColor: "#777", hoverable: true },
+  o = $.plot(oq, xs, { grid: { borderColor: "#777", hoverable: true },
                        legend: { show: xs.length > 1 },
-                       xaxis: { max: Math.max.apply(undefined,means[0]) * 1.02 },
-                       yaxis: { ticks: ylabels, tickColor: '#ffffff' } });
+                       xaxis: { max: max_time * 1.02 },
+                       yaxis: { ticks: ylabels, tickColor: '#ffffff' },
+                       zoom: { interactive: true, amount: 1.05 },
+                       pan: { interactive: true } });
   if (benches.length > 3)
     o.getPlaceholder().height(28*benches.length);
   o.resize();
