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

推荐订阅源

K
Kaspersky official blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V
Visual Studio Blog
F
Full Disclosure
B
Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
L
Lohrmann on Cybersecurity
月光博客
月光博客
I
Intezer
博客园 - 三生石上(FineUI控件)
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园_首页
P
Proofpoint News Feed
C
Check Point Blog
N
News | PayPal Newsroom
H
Heimdal Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
G
GRAHAM CLULEY
WordPress大学
WordPress大学
C
CERT Recently Published Vulnerability Notes
Y
Y Combinator Blog
Recorded Future
Recorded Future
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tailwind CSS Blog
W
WeLiveSecurity
L
LINUX DO - 热门话题
Microsoft Azure Blog
Microsoft Azure Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Schneier on Security
Schneier on Security
爱范儿
爱范儿
Martin Fowler
Martin Fowler
U
Unit 42
T
Troy Hunt's Blog
S
Securelist
V
V2EX
V2EX - 技术
V2EX - 技术
MongoDB | Blog
MongoDB | Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
M
MIT News - Artificial intelligence
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
罗磊的独立博客
小众软件
小众软件
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News

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
shame.css
Harry Roberts · 2013-04-18 · via CSS Wizardry

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. The problem
  2. The solution
    1. Featured case study: NHS
  3. Not a blame game
  4. The rules
    1. Example
  5. Implementation
  6. Keep track of your hacks!

Update: I did a short interview about shame.css with .net magazine.

Something Chris Coyier, Dave Rupert and I joked about recently was the idea of a stylesheet dedicated to housing your nasty, hacky, quick-fix CSS. I’ve been thinking a lot more about it lately and I reckon it’s actually a pretty good idea; here’s why…

The problem

We all know that, no matter how hard we may try, sometimes we do need to use quick fixes, hacks and questionable techniques in our code. It happens, whether we like to admit it or not.

From using a quick overflow: hidden; instead of working out what’s actually broken our layout, to the odd !important to override some poor CSS, there are often times where we need to use less than ideal CSS in order to meet deadlines, to get something working, or to fix pressing—or even live—bugs.

Whilst this isn’t ideal, we have to do it from time to time; all of us.

The real problem, though, is that we rarely go back and tidy these things up. They slip through the cracks, get ignored, go unnoticed, and stay for good. This we do not have to do.

The problem with leaving hacks and nasty code is obvious; it’s hacky and nasty. However, other problems with leaving this code can arise… I think the most important and severe is the fact that, as soon as another developer sees that someone used !important, they feel less bad about doing the same; the next developer who comes along and sees that someone bodged something doesn’t feel too guilty about hacking something else. The first bits of bad code set a precedent and make subsequent developers feel less bad about using poor code themselves. It was like that when I got here! Give developers a clean slate and they’ll really think twice about messing it all up.

What is needed is a way of allowing these hacks when necessary, but making sure that they don’t go unnoticed and unresolved. Enter shame.css.

The solution

The idea of shame.css is that you have a totally new stylesheet reserved just for your hacky code. The code you have to write to get the release out on time, but the code that makes you ashamed.

Featured case study: NHS

How I helped the NHS rapidly build a brand new product.

Read case study…

By putting your bodges, hacks and quick-fixes in their own file you do a few things:

  1. You make them stick out like a sore thumb.
  2. You keep your ‘main’ codebase clean.
  3. You make developers aware that their hacks are made very visible.
  4. You make them easier to isolate and fix.
  5. $ git blame shame.css.

If anyone has to add a quick hack, they add it to shame.css, this means that they’re putting their hacks out there in the open; it means that they are aware that what they’re doing is hacky, it forces them to document what the problem was, how the hack fixes it, and how they might fix it for real given more time.

It means that other developers can see what hacks are being introduced, and why; it means that all the hacky bits of CSS are self contained, and it creates a self-fulfilling todo list.

It also means that you can run a $ git blame shame.css to see what was added when, and by who.

Not a blame game

You’d be forgiven for thinking the point of this whole exercise is to shame the developers (you can always pick a name other than shame.css) but it’s really not. I am well aware of (and responsible for) hacks and quick fixes; your product owner doesn’t care if you used an !important, they just want the new feature out of the door. Hacks happen, fact.

shame.css is jokingly titled to make it a little light-hearted whilst also indicating that anything in there is a bit of a shame; a shame to have to have done, a shame to pollute the codebase with and so on…

By isolating all your hacks and bodge-jobs in their own file you can really easily keep tabs on them; isolating them isn’t to shame the developers, not at all, it’s merely to make the team aware of them and make them painfully, unmissably obvious.

The rules

Obviously you need some kind of rules and criteria:

  1. If it’s a hack, it goes in shame.css.
  2. Document all hacks fully:
    1. What part of the codebase does it relate to?
    2. Why was this needed?
    3. How does this fix it?
    4. How might you fix it properly, given more time?
  3. Do not blame the developer; if they explained why they had to do it then their reasons are probably (hopefully) valid.
  4. Try and clean shame.css up when you have some down time.
    1. Even better, get a tech-debt story in which you can dedicate actual sprint time to it.

Example

/**
 * Nav specificity fix.
 *
 * Someone used an ID in the header code (`#header a {}`) which trumps the
 * nav selectors (`.site-nav a {}`). Use !important to override it until I
 * have time to refactor the header stuff.
 */
.site-nav a {
    color: #BADA55 !important;
}

Implementation

Obviously, the simplest way to implement shame.css is with a preprocessor that would simply import that file. If you aren’t using a preprocessor then you’ll need to have a build process which concatenates all your stylesheets for you. The idea isn’t to make shame.css publicly viewable, so you definitely don’t want two <link /> elements for two stylesheets; shame.css simply needs incorporating into your concatenated and minified stylesheet.

Keep track of your hacks!

I really think I’m going to implement this; if not on my current project then definitely on my next one. I’d love to know if anyone else uses it, or what you think to the idea.