Fixing Layout Shift Caused by Display Ads
Ads are one of the biggest causes of content jumping on news sites, blogs and recipe pages. The ad is chosen and delivered after the page has started to render, so the box it lands in often starts empty and then opens up, shoving the article down mid-sentence. Readers lose their place and tap the wrong thing.
This guide explains why ad slots shift, how to size each one before the ad arrives, what to do with slots that come back empty, and how to handle sticky, refreshing and automatically placed ads without giving up the revenue they bring.
Why ads shift the page
An ordinary image comes from your own server and its size is known in advance. An ad is different. The page asks an ad server what to show, an auction or selection takes place, the winning creative is fetched, and only then is it drawn. That can take well over a second on a phone, by which time the reader has started scrolling through the text around the slot.
If the container is a plain <div> with no height, it takes up no space until the
creative arrives. When a 250-pixel-tall unit is written into it, everything below drops by 250 pixels.
That is one layout shift, often a large one, because it moves most of the visible screen.
Several things make ads harder than other late content:
- Unknown size. Many slots accept several sizes, such as 300 by 250 or 300 by 600, and you do not know which will win until it arrives.
- No fill. Sometimes no ad is returned. If the empty slot then collapses, content moves back up, which is another shift.
- Refresh. Some setups swap in a new creative every so often. If the new one is a different height, the page moves again, long after load.
- Automatic placement. Some networks decide where to insert ads themselves, adding new containers into the article as the script runs.
- Resizing creatives. Rich media and native units can change their own height after they render.
Tracing a shift back to an ad
The CLS Debugger names the elements that moved. With ads, those are usually your own paragraphs, headings or sidebar blocks, not the ad itself, because the ad is what appeared and pushed them. Look for a slot container directly above the moved element.
- Compare with ads blocked. In Chrome DevTools, open the Network panel, find the requests to your ad provider's domains and block them, then reload. If most of the CLS disappears, ads are the main source. Remember to unblock them afterwards.
- Record a throttled load. In the Performance panel with network and CPU throttling on, record a reload and scroll through the article. The Layout shifts track shows each shift; select one and the highlighted nodes show what moved and by how far.
- Check the served sizes. Right-click each filled slot and inspect it. Note the width and height of the creative's iframe. Do this several times across different page loads, because the size can change from one visit to the next.
- Look at the empty cases. Reload a few times on a low-traffic page or use a test ad unit with no campaigns. If the slot container shrinks to zero, you have a no-fill shift as well.
If you use Google Ad Manager, its publisher console, opened from the browser console or with a URL parameter, lists each slot, the sizes requested and the size delivered, which saves a lot of manual inspecting.
Choosing how much space to reserve
Reserving space means giving the slot container a min-height (and usually a min-width)
before any ad code runs, so the box is already the right size when the creative lands. The hard part
is picking the number when the slot can take several sizes.
| Slot set-up | What to reserve | Trade-off |
|---|---|---|
| One fixed size, such as 300 x 250 | Exactly that height | None; this is the ideal case |
| Several sizes, one usually wins | The height of the size that wins most often, from your reporting | A taller creative still shifts, but rarely |
| Several sizes, no clear winner | The tallest size | Smaller creatives leave a gap; no shift |
| Different sizes on mobile and desktop | A separate height per breakpoint | More CSS to maintain |
| Fluid or native units with variable height | A realistic minimum, and place the slot below the first screen | Some movement may remain |
A simple, readable pattern is a class per slot type, sized with media queries that mirror your ad server's size mapping:
<div class="ad ad--in-article" id="ad-article-1"></div>
.ad { display: flex; align-items: center; justify-content: center;
margin: 24px auto; background: #f3f3f3; }
.ad--in-article { min-width: 300px; min-height: 250px; }
.ad--leaderboard { min-height: 50px; }
@media (min-width: 768px) {
.ad--leaderboard { min-height: 90px; }
}
@media (min-width: 1024px) {
.ad--in-article { min-height: 280px; }
}
A light background and a small "Advertisement" label make the reserved box look intentional while it waits, and tell readers what is coming. Keep the label outside the ad container if your network does not allow extra content inside it.
Slots that come back empty
When there is no ad to show, many set-ups hide the slot. That feels tidy but it moves content twice: down if something briefly appeared, or up when the reserved box disappears.
In Google Publisher Tag the behaviour depends on how you call collapseEmptyDivs:
- Not called. The container stays at whatever size your CSS gives it. With a reserved height, nothing moves. This is the most stable choice.
googletag.pubads().collapseEmptyDivs()collapses a slot after the ad server says there is nothing to show. Your reserved space disappears and the content below jumps up.googletag.pubads().collapseEmptyDivs(true)keeps slots collapsed until an ad is returned, then expands them. That turns every filled slot into a downward shift.
Keeping the space is better for CLS. To avoid a blank rectangle, fill it with a house advert for your own newsletter or products, or a neutral placeholder. Other networks have similar settings; look for options named along the lines of "collapse empty" or "hide unfilled".
Where slots sit matters as much as their size
A shift is scored by how much of the screen moved and how far. A leaderboard at the very top of the page, above the headline, moves the entire visible page when it opens. The same unit halfway down an article, loaded before the reader reaches it, may move nothing they can see.
- Above the first screen: reserve exact space or remove the slot. Every visitor sees these shifts.
- In the article body: reserve space and load the ad a little before it scrolls into view. GPT's lazy loading setting can fetch slots a set distance ahead of the viewport.
- Sidebars: a slot in its own column pushes only the sidebar, which is a smaller area, but a sticky sidebar can still move. Reserve its height too.
- Sticky and anchor units: these should use
position: fixedorstickyand sit on top of the content. If a "sticky" unit is actually inserted at the top of the page and pushes everything down, it is not implemented as an overlay.
Automatically placed ads
Features that choose ad positions for you, such as automatic placement in some ad networks, insert new containers wherever the script decides. You cannot reserve space for a slot you do not know about. If they cause heavy shifting, reduce the formats they may use, exclude areas of the page where your network allows it, or replace in-page automatic units with fixed, manually placed slots that you can size.
Refreshing and expanding units
If slots refresh while visible, request only sizes that fit the reserved box so a refresh cannot change the height. Expanding creatives should expand over the content rather than pushing it, which most ad policies already require.
The fix, step by step
Step 1
Map every ad slot and its sizes
List each ad position on your main templates: article, category, home page and any others that carry ads. For each one record the container's id or class, where it sits on mobile and desktop, every size it is allowed to serve at each breakpoint, and whether it is placed by you or inserted automatically. Your ad server or network dashboard holds the size settings; the page template tells you where the containers are.
Step 2
Find which slots cause the biggest shifts
Run the CLS Debugger on each template and note the largest shifts and the elements that moved. For each, find the ad container directly above the moved content. Confirm by blocking the ad provider's domains in Chrome DevTools and reloading: the shift should vanish. Rank the slots by the size of the shift they cause, and start with anything above the first screen or at the top of the article.
Step 3
Reserve a minimum height per breakpoint
Give
each slot container a class with a min-height and min-width set in your main
stylesheet, not by the ad script, so the space exists from the first paint. Use the single size if the
slot has one, otherwise the most common winning size or the tallest. Add media queries so mobile and
desktop heights match your ad server's size mapping, and give the box a light background and label.
Step 4
Stop empty slots collapsing
Check
whether your ad code collapses slots that receive no ad. In Google Publisher Tag, remove calls to collapseEmptyDivs,
especially collapseEmptyDivs(true), which keeps slots shut until filled. For other networks,
turn off any setting that hides unfilled units. Then decide what to show in an unfilled box, such as
a house advert or a neutral placeholder, so readers do not see an unexplained gap in the page.
Step 5
Move or restrict the worst slots
For slots that still shift because their creatives vary widely in height, either limit them to sizes that fit the reserved box or move them lower in the page, below the first screen, where fewer readers see any movement. Consider removing a leaderboard that sits above the headline on mobile. Compare earnings for the changed slots over a few weeks, and agree larger changes with your ad partner before making them.
Step 6
Control auto-placed, sticky and refreshed ads
If your network inserts in-page ads automatically, limit the formats it uses or
switch to fixed slots you can size. Inspect sticky and anchor units and confirm they use position: fixed
over the content rather than being inserted into it. For refreshing slots, allow only sizes that fit
the reserved height, so a new creative never changes the size of the box while someone is reading.
Step 7
Verify with ads on and off
Run the CLS Debugger again on each template, then record throttled loads in DevTools several times, because each load may serve a different creative. Repeat with the ad domains blocked to make sure the reserved boxes do not cause problems of their own. Scroll through long articles while recording. Finally, watch the mobile Core Web Vitals report in Search Console, which reflects the real mix of ads visitors get.
Notes for common set-ups
- WordPress ad plugins. Plugins that insert ads between paragraphs usually let you
add a wrapper class or custom CSS for each placement. Put the
min-heightthere. Check whether the plugin hides empty placements and turn that off. The WordPress CLS guide covers the other plugin-related shifts. - Managed ad partners. If a partner manages your ad code, ask them for their layout-stability options. Many can add reserved heights per slot on request.
- Single-page apps. When routes change without a full page load, destroy old slots and define new ones in containers that are already sized, otherwise every navigation repeats the shift.
- Consent. Where ads wait for a consent choice, reserve the space anyway. The box should not depend on whether personalised ads are allowed.
Keeping ad shifts under control
- Make reserved space a rule for new slots. No slot goes live without a sized container in the stylesheet.
- Review size mappings with the CSS. When someone adds a size in the ad server, the
matching
min-heightneeds checking too. - Test more than once. Because creatives vary, one clean test proves little. Check a handful of loads per template after any ad change.
- Keep an eye on field data. Ad campaigns change constantly, so a sudden rise in mobile CLS in Search Console with no site release is often a new creative or format.
1. Do ads count towards my Cumulative Layout Shift score?
Yes. Google measures layout shifts on the page as the visitor experiences it, and it does not matter whether the content that caused the movement came from your server or an ad network. An ad container that opens up after the text has been drawn pushes that text down, and the movement is counted like any other shift. Ads in overlays that do not move your content, such as properly built anchor units, do not add to the score.
2. How much height should I reserve for an ad slot with several sizes?
Look at your ad reporting to see which size wins most often in that slot. If one size clearly dominates, reserve its height and accept an occasional shift when a taller one wins. If sizes are evenly split, reserve the tallest, so nothing ever moves, and accept a gap around smaller creatives. Set different heights for mobile and desktop to match the sizes each breakpoint is allowed to serve, and review them when sizes change.
3. Should I collapse ad slots that do not fill?
For layout stability, no. Collapsing an unfilled slot removes space that the reader has already seen, so the content below jumps up, which counts as a shift. Collapsing slots until they fill is worse, because every filled slot then pushes content down. Keeping the reserved box and filling it with a house advert or a subtle placeholder avoids both. If you must collapse, do it only for slots well below the first screen.
4. Will reserving ad space reduce my ad revenue?
It might change it, in either direction, and the effect depends on your site, audience and ad partner. Reserving space itself does not stop ads serving, but limiting a slot to fewer sizes can reduce competition for it, and moving slots lower can change viewability. Measure earnings for each changed slot for a few weeks and compare with the previous period. Some publishers also find readers stay longer when the page stops jumping.
5. Do sticky ads cause layout shift?
Not if they are built as overlays. An anchor ad fixed to the bottom or top of the screen with position fixed sits above the content and does not move it. Problems arise when a so-called sticky unit is actually inserted at the top of the page and pushes the article down, or when a sticky sidebar changes height as its ad loads. Inspect the element and check its position style to see which you have.
6. Can lazy loading ads reduce layout shift?
Lazy loading reduces the work done at page load and means fewer ads load that nobody sees, but it does not stop shifts by itself. A lazy slot that opens up just as the reader scrolls to it still pushes content. It helps when combined with reserved space: the box is already the right size, and the ad simply appears inside it. Fetch lazy slots a little before they enter the screen so they are ready in time.
The CLS Debugger records the layout shifts that happen while your page loads, names the elements involved, totals the cumulative score and ranks every shift by how much it contributes, so the ad slots doing the most damage stand out.
Open CLS Debugger Fixes โ