DEV Community

GIRIDHAR DEV
GIRIDHAR DEV

Posted on

Modern CSS & Rendering Performance in Shopify

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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()
  • offsetWidth
  • scrollHeight

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.offsetWidth
  • element.offsetHeight
  • element.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;
}
Enter fullscreen mode Exit fullscreen mode

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(...)
Enter fullscreen mode Exit fullscreen mode

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 {}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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)