devlog
Hey guys, how’s going? I’m pretty well, I have loads of things to do, but there’s always time for my biggest passion, coding.
Yesterday I turned on a strinct CSP (content security policy) for this project, so today the pricing section looked like the one in the first screen.
The Popular badge had no pill behind it, it was just the word, with the card’s border running straight through it.
The higlighted card’s border was white, instead of indigo.
Also the Get Pro was the same flat grey as the two buttons next to it.
It looked like a CSS mistake, but actually it wasn’t.
“It worked on my machine”
ng serve rendered it correctly. Same commit, same browser. That is the part that cost me the
most time: I kept hunting for a rule that only existed in production.
So I stopped reading CSS and read the live page instead:
--color-primary → "" (empty)
badge background → rgba(0, 0, 0, 0) (transparent)
card border → rgb(255, 255, 255)
--color-primary wasn’t defined at all. And when a custom property is undefined,
background-color: var(--color-primary) computes to transparent, while
border-color: var(--color-primary) falls back to currentColor, which on that section is
white. One missing variable, and every symptom follows from it, including the ones that look
unrelated.
Where the variable went
Angular’s production build enables inlineCritical. It inlines the critical CSS and defers the
rest of the stylesheet like this:
<link rel="stylesheet" href="styles-XXXX.css" media="print" onload="this.media='all'">
That onload is an inline event handler, and script-src 'self' blocks inline handlers.
So the handler never ran, the stylesheet stayed at media="print", and it was never applied.
For a whole day the site had been running on nothing but the inlined critical CSS, and the
theme tokens live in the file that never loaded.
ng serve doesn’t run inlineCritical. That’s the entire reason it only happened in production.
The fix is one flag in angular.json:
"optimization": { "styles": { "minify": true, "inlineCritical": false } }
The stylesheet now ships as a plain blocking <link>. One render-blocking request, ~20 KB
gzipped, and the CSP stays exactly as strict as it was.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.