October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Chart.js

How to Create a Bar Graph in HTML: HTML/CSS, SVG, and Chart.js

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The fastest answer: HTML provides the structure, while CSS, SVG, or JavaScript draws the bars. Use HTML and CSS for a small, static graphic; inline SVG when you need scalable, individually addressable shapes; and Chart.js when values, responsiveness, orientation, or interaction are data-driven. Whichever method you choose, define categories, numeric values, one shared scale, and a clear baseline before writing the markup.

Choose the right bar-graph method

Approach Best for Strengths Trade-offs
HTML and CSS A few fixed values No dependency; values remain ordinary document content; easy to style You must calculate bar sizes and build responsiveness yourself
Inline SVG Static or moderately dynamic graphics that must scale cleanly Vector output; each rectangle and label can be addressed; supports <title> and <desc> Coordinates and scaling require more geometry than CSS bars
Canvas with Chart.js Data-driven, responsive, configurable or interactive charts Ready-made axes, tooltips, orientation, spacing and responsive behavior External dependency; canvas is not semantic HTML and needs an accessible alternative

A bar graph compares discrete categories. Keep every bar on the same baseline and scale. Do not use a truncated axis for ordinary comparisons unless the break is made unmistakable; starting at zero is the safest default.

Build a simple bar graph with HTML and CSS

This version uses a list, so category names and values are present in the document even if CSS is disabled. The percentage is the value divided by the chart’s declared maximum. Here, the maximum is 100.

<div class="bar-chart" role="img" aria-label="Monthly sign-ups: January 42, February 68, March 55, April 87">
  <div class="bar-row">
    <span class="bar-label">January</span>
    <div class="bar-track"><span class="bar-fill" style="--value: 42%"></span></div>
    <span class="bar-value">42</span>
  </div>
  <div class="bar-row">
    <span class="bar-label">February</span>
    <div class="bar-track"><span class="bar-fill" style="--value: 68%"></span></div>
    <span class="bar-value">68</span>
  </div>
  <div class="bar-row">
    <span class="bar-label">March</span>
    <div class="bar-track"><span class="bar-fill" style="--value: 55%"></span></div>
    <span class="bar-value">55</span>
  </div>
  <div class="bar-row">
    <span class="bar-label">April</span>
    <div class="bar-track"><span class="bar-fill" style="--value: 87%"></span></div>
    <span class="bar-value">87</span>
  </div>
</div>

<style>
.bar-chart { max-width: 42rem; font: 1rem system-ui, sans-serif; }
.bar-row { display: grid; grid-template-columns: 7rem 1fr 2.5rem; gap: .75rem; align-items: center; margin: .6rem 0; }
.bar-label { text-align: right; }
.bar-track { height: 1.4rem; background: #e5e7eb; border-radius: .25rem; overflow: hidden; }
.bar-fill { display: block; width: var(--value); height: 100%; background: #2563eb; }
.bar-value { font-variant-numeric: tabular-nums; }
@media (max-width:  thirtyrem) {
  .bar-row { grid-template-columns: 5rem 1fr 2rem; gap: .4rem; }
}
</style>

Replace the values and the maximum consistently. If your data ranges from 0 to 2,000, a value of 1,000 is 50%, not 1,000%. For negative numbers, use a centered zero axis instead of a one-sided fill; the CSS pattern above is intended for non-negative values.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Create a scalable bar graph with inline SVG

SVG lets you draw each bar as a <rect>. The viewBox makes the drawing scale with its container. A title and description give assistive technology a text introduction; a data table remains the most dependable way to expose every value.

<svg viewBox="0 0 500 300" role="img" aria-labelledby="chart-title chart-desc" style="max-width:100%;height:auto">
  <title id="chart-title">Monthly sign-ups</title>
  <desc id="chart-desc">January 42, February 68, March 55, April 87.</desc>
  <line x1="55" y1="250" x2="480" y2="250" stroke="currentColor" />
  <rect x="80" y="145" width="55" height="105" fill="#2563eb" />
  <rect x="180" y="80" width="55" height="170" fill="#2563eb" />
  <rect x="280" y="112.5" width="55" height="137.5" fill="#2563eb" />
  <rect x="380" y="32.5" width="55" height="217.5" fill="#2563eb" />
  <text x="107" y="270" text-anchor="middle">Jan</text>
  <text x="207" y="270" text-anchor="middle">Feb</text>
  <text x="307" y="270" text-anchor="middle">Mar</text>
  <text x="407" y="270" text-anchor="middle">Apr</text>
</svg>

<table>
  <caption>Monthly sign-ups</caption>
  <tr><th scope="col">Month</th><th scope="col">Sign-ups</th></tr>
  <tr><td>January</td><td>42</td></tr>
  <tr><td>February</td><td>68</td></tr>
  <tr><td>March</td><td>55</td></tr>
  <tr><td>April</td><td>87</td></tr>
</table>

For a generated SVG, calculate each rectangle’s x position, width, and height from the same scale. Keep labels readable when categories are numerous; rotate or abbreviate them only when the full names are also available as text.

Create a data-driven chart with Chart.js

Complete browser example

Chart.js documents a canvas-based bar chart. Put the canvas in a dedicated container, load the library, then provide labels, values, and options. The CDN URL below is an example; for an application build, install Chart.js through your package manager and pin the dependency according to your deployment policy.

<div class="chart-container" style="position:relative;height:22rem;width:100%">
  <canvas id="signups-chart" role="img"
    aria-label="Monthly sign-ups: January 42, February 68, March 55, April 87">
    Monthly sign-ups: January 42; February 68; March 55; April 87.
  </canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  const canvas = document.getElementById('signups-chart');
  new Chart(canvas, {
    type: 'bar',
    data: {
      labels: ['January', 'February', 'March', 'April'],
      datasets: [{
        label: 'Sign-ups',
        data: [42, 68, 55, 87],
        backgroundColor: '#2563eb',
        borderColor: '#1d4ed8',
        borderWidth: 1
      }]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      scales: {
        y: { beginAtZero: true, title: { display: true, text: 'Sign-ups' } }
      },
      plugins: { legend: { display: true } }
    }
  });
</script>

The documented beginAtZero: true setting gives the vertical axis a zero baseline. To make horizontal bars, add indexAxis: 'y' in options. This is useful for long category labels. Chart.js also exposes controls for bar thickness and category spacing; adjust those when many categories become crowded rather than shrinking labels until they are unreadable.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make the chart accessible

  • Provide a visible heading and units, such as “Orders (per month)” rather than an unexplained number.
  • For canvas, add an accessible name with role="img" and aria-label, or fallback text inside the canvas. Canvas content is not exposed as semantic HTML to screen readers, as documented by Chart.js accessibility guidance and the MDN canvas reference.
  • For substantial data, include an equivalent HTML table or concise textual summary so users can retrieve every category/value pair.
  • SVG can include <title> and <desc>; connect them with aria-labelledby and keep the underlying text meaningful.
  • Do not rely on color alone. Add labels, patterns, or direct values and maintain readable contrast.
  • Interactive behavior needs real keyboard and assistive-technology testing. The W3C Graphics-ARIA guidance notes that static checks alone cannot confirm interactive accessibility.

Responsive sizing and visual accuracy

Let the chart container control responsive width. With canvas, changing only CSS display dimensions scales the bitmap and can distort it; set intrinsic width and height appropriately or follow the chart library’s responsive-container guidance. On small screens, horizontal bars often preserve category labels better than vertical bars. Keep units, tick intervals, and decimal precision consistent, and avoid mixing percentages and raw counts on one axis.

Common problems and fixes

Bars have the wrong length

Check that every percentage uses the same maximum and that the axis starts at the intended baseline. A mixture of maxima makes visual comparison invalid.

The chart is blank

Open the browser console. A missing Chart.js script, a misspelled canvas ID, invalid JavaScript, or a blocked CDN request prevents construction. Confirm the script loads before the initialization code and that the data arrays have equal lengths.

Labels overlap

Use indexAxis: 'y', increase the container height, shorten displayed labels while retaining full accessible text, or reduce category count. Do not rotate labels without checking touch and screen-reader usability.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The canvas looks blurry

Do not stretch a small intrinsic canvas with CSS alone. Set its intrinsic dimensions or let Chart.js manage responsive sizing through a positioned container.

Screen-reader users hear nothing useful

Add an accessible name and a fallback summary, then provide a data table when individual values matter. A color legend by itself is not a text alternative.

Negative values disappear

The CSS fill example assumes values are zero or greater. Use a zero-centered SVG, a diverging layout, or Chart.js scales that include both negative and positive ranges.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

For automated page images rather than a data visualization, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. Its cleanup steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

See the ScreenshotNeo API documentation for options such as full-page or element capture, device presets, retina scale, custom CSS/JavaScript, waits, blocked resources, authentication headers, caching, signed links, asynchronous webhooks, bulk capture, and usage reporting.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan. Create a free ScreenshotNeo account.

When each approach is the practical choice

  • Choose HTML/CSS when the dataset is short, fixed, and best represented as normal page content.
  • Choose SVG when crisp scaling, print output, or individual graphical elements matters.
  • Choose Chart.js when data changes regularly or you need built-in axes, tooltips, orientation and spacing controls.
  • Whichever you choose, expose the values as text and verify the result at narrow widths and with keyboard and screen-reader workflows.

Frequently Asked Questions

Can I create a bar graph using only HTML?

HTML alone supplies structure, not bar geometry. Combine it with CSS for static bars, or embed SVG markup; JavaScript is needed for data-driven drawing and interaction.

Should a bar graph always start at zero?

For ordinary magnitude comparisons, yes. A zero baseline makes bar lengths honest. If you use another baseline, label the break clearly and explain it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Is SVG or Canvas better for accessibility?

SVG can expose titled and described vector content, while canvas requires an accessible name and text alternative because its pixels are not semantic HTML. A data table is useful with either approach.

The Bottom Line

Use CSS for a few fixed bars, SVG for scalable addressable graphics, and Chart.js for configurable data-driven charts. In every case, keep one scale and baseline, label the values in text, and test the responsive and accessible result.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.