What Actually Improves Rendering (and What Doesn’t)
This article is part of my Shopify Performance Engineering Series.
In previous articles, I covered:
In this post, I’ll focus on something deeper:
👉 Rendering performance — what the browser actually does after loading resources
Why Rendering Performance Matters?
Even if:
- images are optimized
- JavaScript is deferred
your site can still feel slow because of:
- layout calculations
- style recalculations
- paint work
Browsers don’t just “load” pages — they:
- parse HTML
- build DOM
- calculate styles
- calculate layout
- paint pixels
👉 Performance issues often come from steps 3–5, not just network.
Ever wondered if we could improve page performance using CSS?
The Biggest Misconception
Most developers think:
“If content is below the fold, it doesn’t affect performance”
❌ This is wrong.
By default, browsers still:
- calculate layout
- compute styles
- sometimes paint
So, for off-screen content use:
content-visibility — What It Actually Does?
.section {
content-visibility: auto;
}
This tells the browser:
“Skip rendering work for this subtree until it is needed”
Specifically, the browser can skip:
- layout
- style calculation
- painting
Real Impact (Accurate)
When used correctly:
- reduces initial rendering work
- improves interaction readiness
- improves metrics like INP and sometimes LCP
In some cases, rendering work can drop significantly (even multiple times faster)
When content-visibility Works Well
Use it when:
- content is below-the-fold
- sections are independent (no layout dependency)
- large DOM trees exist
Avoid when:
- content affects layout above
- you rely heavily on DOM measurements (important!)
- The Hidden Problem: Layout Shift (CLS)
When you apply:
content-visibility: auto;
The browser may treat the element as:
👉 having no intrinsic size initially
This can cause layout jumps.
Correct Fix: contain-intrinsic-size
.section {
content-visibility: auto;
contain-intrinsic-size: auto 500px;
}
This:
- provides a placeholder size
- prevents layout shifts
- stabilizes rendering
👉 Without this, CLS issues are very likely
Important Correction: content-visibility is NOT free
If you use APIs like:
getBoundingClientRect()offsetWidthscrollHeight
on those elements:
👉 browser is forced to render them anyway
So you lose the benefit.
This is explicitly warned in browser docs.
Forced Reflow — What Actually Happens
Forced reflow happens when JS asks:
“Give me layout info NOW”
Examples:
element.offsetWidthelement.offsetHeightelement.getBoundingClientRect()
👉 All of these can trigger layout calculation
So what should you do?
- ❌ Don’t avoid APIs blindly
- ✅ Avoid calling them frequently
Better Strategy (Real Answer)
Instead of:
for (let i = 0; i < 100; i++) {
element.offsetWidth;
}
Do:
- batch DOM reads
- batch DOM writes
- avoid interleaving them
ResizeObserver — Is it better?
✅ Yes, but with context.
ResizeObserver:
- reacts to size changes asynchronously
- avoids manual polling
- reduces forced synchronous layout reads
BUT:
- ⚠️ It still depends on layout updates happening
- ⚠️ Overusing observers can also hurt performance
IntersectionObserver — When it helps?
const observer = new IntersectionObserver(...)
This is genuinely useful for:
- lazy loading
- triggering work only when visible
👉 Works very well with content-visibility
CSS Optimization — What Actually Matters?
1) Deep selectors (real impact)
Bad:
.container .wrapper .item .text span {}
Why bad:
- increases selector matching cost
- harder for browser to resolve
2) DOM depth (real impact)
Deep DOM:
<div><div><div><span>Text</span></div></div></div>
This increases:
- layout complexity
- style recalculation cost
3) CSS modularization (real benefit)
Separating:
- layout styles
- animation styles
helps:
- reduce layout recalculation
- improve maintainability
What Actually Improves Rendering Performance?
Based on real browser behavior:
✅ High impact:
- reducing DOM size
- using content-visibility correctly
- avoiding unnecessary layout calculations
- deferring off-screen rendering
⚠️ Medium impact:
- CSS selector optimization
- modular CSS
❌ Low / misunderstood impact:
- blindly replacing offsetWidth
- assuming one API is “faster” than another
Key Insight
Rendering performance is not about:
❌ using specific APIs
❌ micro-optimizing CSS
It is about:
- reducing how much work the browser needs to do
Final Thought
The biggest performance gains come from skipping work — not optimizing it.
Question for Developers
- Have you used content-visibility in production?
- Did you face issues with layout shifts or unexpected rendering?
What’s Next?
In the next article, I’ll share:
👉 Performance-first Shopify development rules I follow while building themes
Top comments (0)