惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
雷峰网
雷峰网
The Register - Security
The Register - Security
The Cloudflare Blog
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
I
InfoQ
博客园 - 三生石上(FineUI控件)
H
Help Net Security
博客园 - 司徒正美
Vercel News
Vercel News
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
B
Blog
Google DeepMind News
Google DeepMind News
B
Blog RSS Feed
L
LangChain Blog
人人都是产品经理
人人都是产品经理
GbyAI
GbyAI
T
The Blog of Author Tim Ferriss
T
Tailwind CSS Blog
aimingoo的专栏
aimingoo的专栏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recorded Future
Recorded Future
小众软件
小众软件
Martin Fowler
Martin Fowler
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Apple Machine Learning Research
Apple Machine Learning Research
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - Franky
Hugging Face - Blog
Hugging Face - Blog
Y
Y Combinator Blog
V
Visual Studio Blog
F
Fortinet All Blogs
Microsoft Azure Blog
Microsoft Azure Blog
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
V
V2EX
Blog — PlanetScale
Blog — PlanetScale

CSS Wizardry

Front-End’s Missing Metric: The TBT Window Meet Your Users Where They Are with Obs.js Better Browser Caching with No-Vary-Search font-family Doesn’t Fall Back the Way You Think What Is CSS Containment and How Can I Use It? When All You Can Do Is All or Nothing, Do Nothing Obs.js: Context-Aware Web Performance for Everyone Low- and Mid-Tier Mobile for the Real World (2025) The Fastest Site in the Tour de France Making Sense of the Performance Extensibility API Why Do We Have a Cache-Control Request Header? HTML Is Not a Programming Language… Build for the Web, Build on the Web, Build with the Web Licensing Code on CSS Wizardry A Layered Approach to Speculation Rules Designing (and Evolving) a New Web Performance Score Core Web Vitals Colours The Ultimate Contract Templates for Tech Consultants: Protect Your Business and Get Paid Optimising for High Latency Environments Cache Grab: How Much Are You Leaving on the Table? blocking=render: Why would you do that?! Correctly Configure (Pre) Connections The Three Cs: 🤝 Concatenate, 🗜️ Compress, 🗳️ Cache What Is the Maximum max-age? How to Clear Cache and Cookies on a Customer’s Device The Ultimate Low-Quality Image Placeholder Technique Core Web Vitals for Search Engine Optimisation: What Do We Need to Know? The HTTP/1-liness of HTTP/2 In Defence of DOM­Content­Loaded Site-Speed Topography Remapped Why Not document.write()? Speeding Up Async Snippets Critical CSS? Not So Fast! Measure What You Impact, Not What You Influence Optimising Largest Contentful Paint Measuring Web Performance in Mobile Safari Site-Speed Topography Speed Up Google Fonts Real-World Effectiveness of Brotli Performance Budgets, Pragmatically Lazy Pre-Browsing with Prefetch Making Cloud.typography Fast(er) Time to First Byte: What It Is and How to Improve It Self-Host Your Static Assets Tips for Technical Interviews Cache-Control for Civilians Bandwidth or Latency: When to Optimise for Which ITCSS × Skillshare What If? CSS and Network Performance The Three Types of Performance Testing Getting to Know a Legacy Codebase Image Inconsistencies: How and When Browsers Download Images Identifying, Auditing, and Discussing Third Parties My Digital Music Setup Measuring the Hard-to-Measure Finding Dead CSS The Fallacies of Distributed Computing (Applied to Front-End Performance) Ten Years Old Relative Requirements Airplanes and Ashtrays Performance and Resilience: Stress-Testing Third Parties Refactoring Tunnels Little Things I Like to Do with Git Writing Tidy Code Configuring Git and Vim Base64 Encoding & Performance, Part 2: Gathering Data Base64 Encoding & Performance, Part 1: What’s Up with Base64? Code Smells in CSS Revisited Typography for Developers Moving CSS Wizardry onto HTTPS and HTTP/2 Ack for CSS Developers A New Year, a New Focus Preparing Vim for Apple’s Touch Bar Choosing the Correct Average CSS Shorthand Syntax Considered an Anti-Pattern CSS Wizardry Newsletter Nesting Your BEM? Improving Perceived Performance with Multiple Background Images Continue Normalising Your CSS Pure CSS Content Filter Pragmatic, Practical, and Progressive Theming with Custom Properties Refactoring CSS: The Three I’s Speaker’s Checklist: Before and After Your Talk Improving Your CSS with Parker The Importance of !important: Forcing Immutability in CSS Mixins Better for Performance Managing Typography on Large Apps White October Events Workshop Partnership BEMIT: Taking the BEM Naming Convention a Step Further Travelling Like You Want to, When You Have To Contextual Styling: UI Components, Nesting, and Implementation Detail Subtleties with Self-Chained Classes Cyclomatic Complexity: Logic in CSS Immutable CSS Can CSS Be Too Modular? More Transparent UI Code with Namespaces When to use @extend; when to use a mixin The Specificity Graph CSS Wizardry Ltd.: Year 1 in review
CSS bar charts—styling data with CSS3 and progressive enhancement
Harry Roberts · 2010-02-03 · via CSS Wizardry

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. View demo
  2. Progressive enhancement
    1. Isn’t this just graceful degradation?
    2. Internet Explorer
    3. Firefox
    4. Safari/Chrome
  3. The code
    1. The markup
    2. The CSS, CSS3 and progressive enhancement
  4. Closing word

Bar charts in CSS are neither very new, or very difficult. Using some pretty basic styling you can force lists etc into resembling graphs and charts fairly easily. Such charts, in their most basic form, work perfectly well in displaying and presenting the data they represent. However, using some rich CSS3 and progressive enhancement, you can really start pushing the display and presentation of these normally boring documents to the next level. They are also an ideal way in which to demonstrate the power and ability of progressive enhancement.

View demo

Look at the site in IE8, then Firefox, then Safari/Chrome. Keep refreshing.

I have created a demo page which simply represents three items of data expressed as percentages. It is not the data itself or the numbers we are concerned with here–it is the proof of concept. The fact that this can be done on my made up data shows that you can do it too, on real life information.

Progressive enhancement

At Venturelab, we decided to use progressive enhancement as a matter of course. CSS3 and designing in the browser all the way!

Progressive enhancement is, in my opinion, one of the most exciting schools of thought web development has seen in years (though I have only been in the web for three…). It is the idea whereby any non-essential features (i.e. anything whose absence will have no adverse effect on the usability or accessibility of a website) are added to the website in a progressive manner–often through CSS3.

The benchmark example is rounded corners; to apply these through old means, for example with images, would have taken a developer a substantial amount of time–time the client is paying for. It seems silly now to think that way-back-when, putting rounded corners on a div might have taken upward of 30 minutes, when we can apply it in about 5 seconds using -moz-border-radius:5px;.

It really is a no brainer–anyone visiting the site in a browser with no CSS3 support will see square corners. Does this matter? Of course it doesn’t. No one visits a site to look solely at the design–they visit for content. Does it matter to them what shape the corners of your RSS button are? No again. Progressive enhancement saves you time, and your client money.

Isn’t this just graceful degradation?

Graceful degradation = building for the best and getting worse; progressive enhancement = building to cater the worst and getting better…

The line between progressive enhancement and graceful degradation is fine but significant. Graceful degradation is the idea that you’d build a site for, say, Firefox, then selectively break and downgrade it in the likes of IE(6). Progressive enhancement takes a much more positive attitude in that you build for IE(6) and then selectively upgrade it in browsers like Firefox and Safari. It’s no longer starting great and getting worse, it’s now starting great and getting better.

Internet Explorer

N.B. Only tested in IE8 as this is not a final solution, rather a proof-of-concept.

Internet Explorer(8)’s take on my bar charts is as you’d expect from any browser, it renders it perfectly well, providing clear, accessible content, with a flawless UX and perfectly usable. This is not bad! We don’t need to downgrade anything, this is our starting point. It looks good and it functions perfectly. If you did as above and visited in IE8 first, you wouldn’t know that there were round corners missing–because that doesn’t matter.

A screenshot of the CSS bar chart in Internet Explorer 8

Firefox

Next up is Firefox, where we add some round corners to the blue bars, and also a very subtle drop shadow (text-shadow:;) on the text. This is no more usable than before, the content is no more accessible than in IE, but it does look a tad nicer.

A screenshot of the CSS bar chart in Firefox

Safari/Chrome

It is in Webkit based browsers such as Safari and Chrome that the real magic happens. Webkit’s proprietary CSS is above and beyond that of any other rendering engine…

A screenshot of the CSS bar chart in Safari

What if I couldn’t be bothered opening Photoshop to make a subtle gradient .gif for the bars? No worries, use Webkit’s gradient CSS. A little reflection might look nice on the bars too, but I don’t fancy any superfluous markup or .pngs to fiddle with. Ah great, Webkit has a bit of reflection CSS too.

However, for the real show-piece, the Webkit animation. I’m not using any Javascript libraries anywhere else in the page so I don’t fancy pulling a whole one in for something that won’t really be missed if it’s not there. I hear Webkit has animations… magic!

The code

Now that’s the theory covered, let’s look at what does all this stuff… Please note, I have used some PHP to randomise the values used by the bars of the chart. As a result, some CSS appears in the source code of the PHP file, and the rest in the page’s CSS file. The code shown in the examples below is condensed into one large chunk.

The markup

The markup simply comprises of one uncluttered dl. The reasoning behind a definition list is that each item is a title, followed by some information about that title. Not only is this semantically correct, it’s a nice set of elements to be working with to achieve the layout we’ve got.

<code><dl id="chart">
  <dt>Sales increase this week</dt>
  <dd><span id="data-one">47%</span></dd>
  <dt>Revenue increase this week</dt>
  <dd><span id="data-two">59%</span></dd>
  <dt>Profit increase this week</dt>
  <dd><span id="data-three">26%</span></dd>
</dl></code>

That’s all there is to it.

The CSS, CSS3 and progressive enhancement

<code><span class="code-comment">/*------------------------------------*\
  CHART
\*------------------------------------*/</span>
#chart{
  width:520px;
}
#chart dt{
  width:160px;
  float:left;
  margin:0 20px 5px 0;
  padding:2px 0;
  display:inline;
  font-weight:bold;
  text-align:right;
}
#chart dd{
  width:339px;
  border-right:1px solid #ddd;
  float:left;
  margin-bottom:5px;
  display:inline;
}
#chart dd span{
  color:#fff;
  background:#09f;
  text-align:center;
  padding:2px 0;
  display:block;
  
  text-shadow:1px 1px 1px rgba(0,0,0,0.2);
  -moz-border-radius:2px;
  -webkit-border-radius:2px;
  border-radius:2px;
  background:-webkit-gradient(linear, left top, ->
  left bottom, from(#09f), to(#077fd0));
  -webkit-box-reflect:below 0 ->
  -webkit-gradient(linear, left top, ->
  left bottom, from(rgba(0,0,0,0)), to(rgba(0,0,0,0.25)));
}
#data-one{
  width:47%;
}
#data-two{
  width:59%;
}
#data-three{
  width:26%;
}
#data-one{
  -webkit-animation-name:bar-one; <span class="code-comment">/* Give the bar an animation with a
    unique name */</span>
}
#data-two{
  -webkit-animation-name:bar-two; <span class="code-comment">/* Give the bar an animation with a
    unique name */</span>
}
#data-three{
  -webkit-animation-name:bar-three; <span class="code-comment">/* Give the bar an animation with a
    unique name */</span>
}
#data-one,#data-two,#data-three{ <span class="code-comment">/* Define animation styles for all three
    bars at once */</span>
  -webkit-animation-duration:0.5s; <span class="code-comment">/* Animation duration in seconds */</span>
  -webkit-animation-iteration-count:1; <span class="code-comment">/* Amount of times to loop */</span>
  -webkit-animation-timing-function:ease-out; <span class="code-comment">/* Ease in, out etc. */</span>
}
@-webkit-keyframes bar-one{
  0%{ <span class="code-comment">/* Define bar-one styles at 0% (0 seconds) */</span>
    width:0%;
  }
  100%{ <span class="code-comment">/* Define bar-one styles at 100% (0.5 seconds) */</span>
    width:47%;
  }
}
@-webkit-keyframes bar-two{
  0%{ <span class="code-comment">/* Define bar-two styles at 0% (0 seconds) */</span>
    width:0%;
  }
  100%{ <span class="code-comment">/* Define bar-two styles at 100% (0.5 seconds) */</span>
    width:59%;
  }
}
@-webkit-keyframes bar-three{
  0%{ <span class="code-comment">/* Define bar-three styles at 0% (0 seconds) */</span>
    width:0%;
  }
  100%{ <span class="code-comment">/* Define bar-three styles at 100% (0.5 seconds) */</span>
    width:26%;
  }
}</code>

In detail

There may well be some bits in there that you’re not familiar with, particularly CSS animations. Basically, to animate an element you need to do a few things:

  1. Assign the element an animation name. This name is the ‘hook’ to link an animation, defined later, to an element.
<code>#data-one{
  -webkit-animation-name:bar-one;
}</code>
  1. Assign the element animation properties. Here you set things like duration, repetition and ease-in/out.
<code>#data-one,#data-two,#data-three{
  -webkit-animation-duration:0.5s;
  -webkit-animation-iteration-count:1;
  -webkit-animation-timing-function:ease-out;
}</code>
  1. Set up the keyframes of the animation. Here you set the various points. Here we have one thing to animate through two states, so we simply set a beginning at 0% and and end at 100%. We could set at any percentage in between but as we just have a beginning and an end, we don’t need to–Webkit sees to that.
<code>@-webkit-keyframes bar-one{
  0%{
    width:0%;
  }
  100%{
    width:47%;
  }
}</code>

With regards the Webkit reflections, it may be a better idea to consult the Surfin’ Safari page on that, as anything I’d say would most likely be a poorly pulled off rehash.

Closing word

So there you have it, a real life, justifiable and wholly appropriate application of CSS3 and progressive enhancement coupled with data visualisation. Don’t be held back by the limitations of older browsers–relish in the opportunities new ones bring.

And as a final bonus, @VIPickering requested this (view in Safari/Chrome)… enjoy.