Cookie Banners and Web Vitals

Is your cookie banner punching you in the Web Vitals? πŸ₯Š Then stop treating it like critical content.


The bane of users and development teams alike, cookie banners negatively impact the user experience and can ruin page loading performance.

If a cookie banner is inserted directly into the flow of the page layout, nasty layout shift will occur, which adds up as Cumulative Layout Shift (CLS).

If you insert a cookie banner directly in the page layout, you'll have to deal with layout shift.

If a cookie banner contains a large headline or a paragraph of legalese, it may register as the Largest Contentful Paint (LCP) on a page.

Performance trace from DevTools
If loaded incorrectly, a large cookie banner will kill your LCP. In the performance trace above, we see LCP marked at the time when a large cookie banner paragraph is visible. Logging LCP candidates to console, we see the first candidate for the main page content – and the second costly one for the banner.

Often, 3P cookie banners are added via a tag manager, making it easier for marketing teams to independently add and remove trackers. But loading a cookie banner at the end of a long request chain means it will render very late in the game.

One strategy for improving LCP in this case is to make sure the cookie banner loads sooner and use a placeholder in the layout until it’s there. The downside of this approach is that you still have JavaScript meddling in the critical rendering path.

From a user perspective, a cookie banner is definitely not critical content. It’s arguably more important to know if the page you just landed on is the one you were looking for than how important privacy is to the website owner.

Thus, I think a better approach to implementing a 3P banner is to treat it as non-critical.

How to avoid seriously bad LCP and CLS from a cookie banner

I’ve been able to dramatically reduce LCP and avoid adding to CLS on productive websites with the following approach:

Assuming you’re adding an external cookie banner via JavaScript, you’ll probably plop a script into your document or use a tag manager to do it.

<script defer src=β€œhttps://cdn.cookie-banner-vendor.com/bundle.js”></script>

Use animation to slide the cookie banner up into the viewport after its initial paint

Now assuming you have some level of control over cookie banner styling, you add some custom styles for the banner to initially paint outside of the viewport and declare an animation for moving it into the viewport.

@keyframes slide-up {
0% {
transform: translateY(110vh);
}
100% {
transform: translateY(0vh);
}
}

.cookie-banner {
/* Important: Position the cookie
banner so it initially paints
outside of the viewport */

transform: translateY(110vh);
animation: slide-up 1s forwards;
}

When animating just the cookie banner itself, you can declare an animation for it to move into view after initially rendering (open demo in new tab).
Performance trace from DevTools
LCP is registered for the main page and not the cookie banner which contains a physically larger element. In the demo, I set a timeout on loading the banner to mimic typical loading delays.

When using multiple animations, add in classes using JS

Now if you also want to animate in a background overlay to darken the page behind the cookie banner, you’ll have

@keyframes fade-in {
0% {opacity(0);}
100% {opacity(1);}
}
@keyframes slide-up {
0% {transform: translateY(110vh);}
100% {transform: translateY(0vh);}
}

/* Add this class to the cookie
banner later via JS */

.slide-up {
animation: slide-up 1s forwards;
}

.cookie-banner-overlay {
animation: fade-in 1s forwards;
}

.cookie-banner {
/* Important: Position the cookie
banner so it initially paints
outside of the viewport
and add the animation later
via JS */

transform: translateY(110vh);
}
cookieBanner.classList.add(β€œslide-up”);

When animating multiple elements, adding a class to a potential LCP candidate via JS will help it avoid being registered as LCP (open demo in new tab).

The performance trace shows LCP register way prior to cookie banner render and no layout shift.

Performance trace from DevTools
LCP is registered for the main page and not the cookie banner which contains a physically larger element. In the demo, I set a timeout on loading the banner to mimic typical loading delays.

Of course, this approach depends upon your ability to add custom code. If you cannot, I suggest working with your cookie banner vendor to have them optimize for performance.

Other approaches that don’t improve LCP

If you declare a CSS animation for the cookie banner to slide up, the banner will register as LCP. You don’t want that to happen.

.cookie-banner {
animation: slide-up 1s forwards;
}

Also, if you animate in the cookie banner background, don’t add animate the cookie banner into position in the same function like this:

setTimeout(() => {
bannerOverlay.classList.add("fade-in");
banner.classList.add("slide-up");
}, 1000);

Otherwise the cookie banner could end up registering as LCP.

Keep in mind the critical rendering path and where the banner paints to the screen to avoid β€œtossing cookies” πŸ˜‰ when you check your Web Vitals.


Published: Mar 29, 2021

More from my blog

All Blog Articles β†’