Why Does My Overlay Not Cover the Whole Page?

Overlay not covering whole page bugs happen when an overlay is sized to a parent, placed under a header, trapped in a scroll area, or mounted in the wrong layer.

CSS Overlay Fix

Why Does My Overlay Not Cover the Whole Page?

An overlay not cover whole page bug usually means the overlay is not actually sized or layered against the full viewport. It may be positioned inside a parent, limited by a grid column, trapped under a sticky header, clipped by a scroll container, or using height:100% when the page needs viewport-based sizing.

This is one of those bugs that looks simple but can destroy the feel of a page. A backdrop that only covers half the screen makes the modal feel broken. A menu overlay that stops under the header feels unfinished. A loading overlay that covers only one section can confuse users about what is actually disabled.

  • overlay
  • fixed inset
  • viewport coverage
  • z-index layers

Test viewport ownership first

Temporarily change the overlay to position:fixed; inset:0; and move it near the end of the body or into a root overlay layer. If it suddenly covers the whole page, the original overlay was attached to the wrong parent or layer.

Related: Try this in the FrontFixer Live Inspector.

Open Live Inspector

What the bug looks like

The backdrop, loading screen, menu layer, or dimmed area covers only part of the page.

Why it happens

The overlay is filling a parent, section, grid column, or scroll container instead of the viewport.

What usually fixes it

Use a fixed root overlay with inset:0 and a clear z-index layer.

Why overlays fail to cover the full viewport

An overlay is supposed to communicate control. When a modal opens, a menu slides out, or a loading state appears, users expect the affected area to be obvious. If the overlay only covers the component, the main column, or the area below the header, the interface sends mixed signals.

The overlay not cover whole page problem usually comes from mixing local layout rules with global UI intent. A card overlay can be local. A full-page modal backdrop should not be local. A section loading shimmer can belong inside one section. A global loading lock should belong to the viewport.

The clean fix is to decide the overlay’s job first. If it should cover the whole page, mount it in a root layer and size it to the viewport. If it should cover only one card, keep it inside that card intentionally.

Local overlayGood for cards, sections, and small loading states.
Global overlayNeeded for modals, drawers, menus, and page locks.
Viewport sizingfixed plus inset:0 is the safe baseline.
Better mindsetCoverage is a layout decision, not decoration.
Error 1

The overlay uses height:100% inside a short parent

height:100% does not automatically mean the full page. It means the height of the containing block. If the parent is only a card, section, or wrapper, the overlay will only cover that parent.

Broken code

Parent-sized overlay
.section {
  position: relative;
}

.overlay {
  position: absolute;
  width: 100%;
  height: 100%;
}

Broken visual result

Only covers parent
Page header
Overlay only fills section
The overlay is doing exactly what the CSS says: it fills the parent, not the viewport.

Correct code

Viewport overlay
.overlay {
  position: fixed;
  inset: 0;
  width: auto;
  height: auto;
  z-index: 1000;
}

Fixed visual result

Covers viewport
Page still exists below
Overlay covers the whole viewport area
Use fixed inset when the overlay is supposed to cover the page.
Error 2

The header stays above the overlay

Sometimes the overlay covers most of the page but the sticky header remains visible. That usually means the header has a higher z-index or the overlay is mounted below a layer system that the header already owns.

Broken code

Overlay below header
.header {
  position: sticky;
  z-index: 100;
}

.overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
}

Broken visual result

Header leaks through
Overlay behind header layer
Sticky header still clickable
The overlay covers the viewport but loses the stacking battle to the header.

Correct code

Overlay above page chrome
:root {
  --z-header: 100;
  --z-overlay: 1000;
}

.overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
}

Fixed visual result

Overlay owns top layer
Header below overlay
Overlay is above header and page content
Give overlay layers a clear z-index token above normal page chrome.
Error 3

The overlay is trapped inside a scroll container

A scrollable parent can make an overlay cover only the visible panel or scroll with the content. This is common in dashboards, drawers, sidebars, tables, and app layouts with internal scrolling.

Broken code

Overlay inside scroll panel
.panel {
  max-height: 500px;
  overflow: auto;
  position: relative;
}

.panel .overlay {
  position: absolute;
  inset: 0;
}

Broken visual result

Panel-sized overlay
Overlay trapped in scroll panel
The overlay belongs to the scroll panel, so it cannot behave like a page overlay.

Correct code

Root overlay outside scroll
.panel {
  max-height: 500px;
  overflow: auto;
}

.overlay-root {
  position: fixed;
  inset: 0;
  z-index: 1000;
}

Fixed visual result

Root overlay ignores scroll
Overlay root covers full panel and page
The scroll panel can remain scrollable while the overlay sits outside it.
Error 4

The overlay is mounted inside the main grid column

In two-column layouts, the overlay may be placed inside the main content column instead of a page-level root. It then covers only the article area while the sidebar, header, or other page regions remain uncovered.

Broken code

Overlay inside main column
.layout {
  display: grid;
  grid-template-columns: 1fr 280px;
}

.main .overlay {
  position: absolute;
  inset: 0;
}

Broken visual result

Sidebar uncovered
Sidebar still exposed
Overlay only covers main column
The overlay is mounted in the main column, so the sidebar remains outside the covered area.

Correct code

Overlay outside layout grid
.layout {
  display: grid;
  grid-template-columns: 1fr 280px;
}

.page-overlay {
  position: fixed;
  inset: 0;
}

Fixed visual result

Whole layout covered
Sidebar below overlay
Overlay root covers the full page layout
Mount global overlays beside the layout grid, not inside one grid column.
Premium patterns

Three production-minded overlay coverage patterns

Premium overlay systems define coverage, scroll behavior, and layer order on purpose. Below are three different visual patterns so the overlay architecture does not become a repeated template.

Premium code example 1

Full-page overlay stack
:root {
  --z-header: 100;
  --z-backdrop: 900;
  --z-dialog: 1000;
}

.overlay-root {
  position: fixed;
  inset: 0;
  z-index: var(--z-backdrop);
}

.dialog {
  position: fixed;
  z-index: var(--z-dialog);
}

Premium visual result 1

Layer order blueprint
premium
Overlay stack above page chrome

The header stays in the app layer while backdrop and dialog own the overlay layer.

dialog backdrop header page
No exposed page zones
Pattern 1 is ideal for modal backdrops, confirmation dialogs, and blocking page states.

Premium code example 2

Mobile viewport overlay
.mobile-overlay {
  position: fixed;
  inset: 0;
  min-height: 100dvh;
  overflow: auto;
}

.mobile-overlay__panel {
  width: min(420px, 100%);
  min-height: 100dvh;
}

Premium visual result 2

Mobile coverage map
premium
Mobile overlay respects dynamic viewport

The overlay uses viewport units and internal scrolling instead of depending on page height.

100dvh overlay
fixed inset mobile viewport internal scroll safe coverage
Pattern 2 is ideal for mobile menus, drawers, checkout steps, and full-screen filters.

Premium code example 3

Local vs global overlay tokens
.card-overlay {
  position: absolute;
  inset: 0;
}

.page-overlay {
  position: fixed;
  inset: 0;
}

.is-page-locked {
  overflow: hidden;
}

Premium visual result 3

Coverage decision system
premium
Choose coverage before styling

The component can use a local overlay, while the app can use a global overlay root.

Card stateabsolute inset
Page statefixed inset
Locked statebody scroll off
Pattern 3 is ideal for design systems that need both section overlays and full-page overlays.

Fast practical rule

If the overlay should cover the whole page, use position:fixed, inset:0, and a root overlay layer. Do not rely on height:100%, main-column placement, or a local parent unless the overlay is intentionally local.

Debug checklist

  • Check whether the overlay is absolute or fixed.
  • Replace width and height rules with inset:0 for full-page overlays.
  • Inspect whether the overlay is mounted inside a card, section, grid column, or scroll container.
  • Compare the overlay z-index against sticky headers, menus, drawers, and modals.
  • Look for parent overflow:hidden or overflow:auto.
  • Use a root overlay layer for modals, page locks, loading screens, and menus.
  • Use local overlays only for local card or section states.
  • Test mobile viewport height with address bars and long content.
Best first moveTry position:fixed; inset:0 and retest coverage.
Most common causeThe overlay is filling a parent instead of the viewport.
Most sneaky causeThe header has a higher z-index than the overlay.
Better mindsetChoose local or global coverage before styling the overlay.

When a partial overlay is correct

Partial overlays are not always wrong. A card loading state, image hover layer, table blocker, or local section skeleton can correctly cover only one component. The problem begins when the overlay is meant to block the page but is mounted like a local component.

Use local overlays for local states. Use global overlays for global states. That simple separation prevents most coverage bugs before they appear.

This also keeps the article intent clean: this fix is about coverage area, not a generic modal bug or a generic z-index bug. The main question is whether the overlay owns the viewport or only owns a component.

The authority move is not to make every overlay full-screen. The authority move is to make the coverage match the user’s expectation.

Why this bug feels so visible

Users do not need to understand CSS to feel when an overlay is wrong. They see uncovered areas, clickable headers, floating sidebars, or page content that should be disabled but still looks active. That visual mismatch creates distrust quickly.

A correct overlay makes the interface state obvious. It tells users whether the whole page is blocked, one section is loading, or a focused dialog needs attention.

Final takeaway

An overlay not cover whole page bug usually happens because the overlay is local while the design expects it to be global. The CSS may be filling a parent, grid column, scroll panel, or lower z-index layer instead of the viewport.

Use a root overlay layer, position:fixed, inset:0, and clear z-index tokens when the whole page must be covered. Keep partial overlays only when the component itself is the intended coverage area.

Want more fixes like this?

Browse more CSS overlay, z-index, fixed positioning, modal, dropdown, and responsive layout debugging guides in the FrontFixer library.

Why Is My Fixed Element Behind a Transformed Parent?

Fixed element behind transformed parent bugs happen when transform on an ancestor changes how fixed headers, drawers, modals, or toasts behave.

CSS Positioning Fix

Why Is My Fixed Element Behind a Transformed Parent?

A fixed element behind transformed parent usually means the element is not behaving like a true viewport-level fixed layer anymore. A parent with transform, translate, scale, rotate, or even transform:translateZ(0) can change the containing block and stacking behavior for fixed descendants.

This is different from a normal z-index problem. You can give the fixed child z-index:9999 and it may still appear behind a header, get clipped inside a card, move with a transformed wrapper, or behave like it belongs to the component instead of the viewport. The real problem is the ancestor. The transformed parent quietly changed the world the fixed element lives in.

  • position:fixed
  • transform
  • containing block
  • stacking context

Test the parent transform first

Temporarily remove transform from parent wrappers in DevTools. If the fixed element jumps to the correct viewport position or finally appears above the page, the ancestor transform is the cause.

Related: Try this in the FrontFixer Live Inspector.

Open Live Inspector

What the bug looks like

A fixed modal, drawer, toast, banner, or floating button behaves as if it belongs to a card or wrapper.

Why it happens

A transformed ancestor can create a containing block and stacking context for fixed children.

What usually fixes it

Move global fixed UI outside the transformed wrapper or remove transform from the ancestor.

Why fixed positioning can stop being viewport-level

Many developers expect position:fixed to always attach to the browser viewport. That is usually the mental model, but it can break when a transformed ancestor appears above the fixed element. The browser may treat that transformed ancestor as the fixed element’s containing block.

Once that happens, the fixed element is no longer truly global. It can move with the parent, stay under another page layer, obey the parent’s visual boundary, or appear in the wrong position. The code still says fixed, but the browser is resolving that fixed positioning inside a different context.

This post targets the fixed element behind transformed parent problem specifically. The broader transform z-index article explains stacking context conflicts; this fix focuses on fixed descendants that lose viewport behavior because an ancestor has transform.

Fixed can become localA transformed ancestor can become the reference boundary.
Transform can be invisibletranslateZ(0) may create the bug without a visible movement.
Global UI should be globalModals, toasts, and drawers should not live inside transformed shells.
Better mindsetSeparate animation wrappers from overlay roots.
Error 1

A modal is fixed inside a transformed card

A card may use transform for hover lift, animation, or performance. If a modal is nested inside that transformed card, the modal can stop behaving like a true viewport overlay and remain stuck in the card’s layer world.

Broken code

Fixed inside transformed card
.card {
  transform: translateY(-4px);
}

.card .modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
}

Broken visual result

Fixed trapped inside card world
Site header layer
Transformed card parent
Fixed modal stuck under header
The modal says fixed, but it is still inside the transformed card context.
A high z-index cannot make the modal global if it is mounted inside the transformed card.

Correct code

Modal root outside card
.card {
  transform: translateY(-4px);
}

.modal-root .modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
}

Fixed visual result

Modal escapes parent
Transformed card remains local
Site header layer
Modal root covers the viewport
The modal is mounted outside the transformed card, so fixed is viewport-level again.
Keep transformed cards local and render global modals from a root overlay layer.
Error 2

A fixed bottom bar lives inside an animated app shell

App shells often use transform for page transitions, drawer animations, or GPU acceleration. A fixed bottom bar inside that shell can become local to the shell instead of staying pinned to the viewport.

Broken code

Fixed bar inside transformed shell
.app-shell {
  transform: translateX(0);
}

.app-shell .bottom-bar {
  position: fixed;
  bottom: 0;
}

Broken visual result

Bottom bar becomes local
Transformed app shell
Fixed bar stuck inside shell
The fixed bar follows the transformed shell instead of the viewport.

Correct code

Fixed bar outside shell
.app-shell {
  transform: translateX(0);
}

.bottom-bar-root {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 50;
}

Fixed visual result

Bottom bar belongs to viewport
Animated shell
Viewport fixed bottom bar
Put fixed viewport UI beside the animated shell, not inside it.
Error 3

A mobile drawer is fixed inside a transformed page wrapper

Mobile menus and drawers often use fixed positioning. But if the drawer is inside a page wrapper that uses transform for transitions, it may not cover the screen correctly and can sit behind other interface layers.

Broken code

Drawer inside transformed page
.page {
  transform: translate3d(0, 0, 0);
}

.page .drawer {
  position: fixed;
  inset: 0 0 0 auto;
}

Broken visual result

Drawer cannot fully escape
Drawer attached to transformed page
The drawer is fixed, but it still behaves like part of the transformed page wrapper.

Correct code

Drawer portal outside page
.page {
  transform: translate3d(0, 0, 0);
}

.drawer-root .drawer {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 80;
}

Fixed visual result

Drawer uses viewport root
Drawer covers viewport layer
Mount mobile drawers in a root layer when the page wrapper is animated.
Error 4

A performance transform traps fixed notifications

Sometimes the transform was not added for design at all. It was added as a performance hack, such as translateZ(0) or will-change:transform. That invisible optimization can still change how fixed descendants behave.

Broken code

Performance hack on parent
.layout {
  transform: translateZ(0);
}

.layout .toast {
  position: fixed;
  top: 24px;
  right: 24px;
}

Broken visual result

Invisible transform trap
Transformed layout
toast local trapped

The toast appears inside the layout world, not above the entire page.

A transform added for performance can still change fixed positioning behavior.

Correct code

Toast root outside layout
.layout {
  transform: translateZ(0);
}

.toast-root {
  position: fixed;
  top: 24px;
  right: 24px;
  z-index: 90;
}

Fixed visual result

Toast root is global
Transformed layout
page clean

The toast root sits outside and above the layout.

Global toast
Keep notification roots outside performance-transformed layout containers.
Premium patterns

Two production-minded fixed layer patterns

Premium fixed positioning separates animated surfaces from viewport-owned overlays. Below are two different visual systems: one for a dashboard shell and one for a mobile drawer architecture.

Premium code example 1

Dashboard shell with overlay roots
.dashboard-shell {
  transform: translateX(var(--page-shift));
}

.overlay-root {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-overlay);
}

.overlay-root > * {
  pointer-events: auto;
}

Premium visual result 1

Dashboard layer map
premium
Dashboard shell architecture

The dashboard can animate while overlays stay in a viewport-owned root.

animated shell
content layer
overlay root
modal toast drawer
Pattern 1 is ideal for dashboards, admin panels, apps, and animated page transitions.

Premium code example 2

Mobile drawer outside transformed page
.page-transition {
  transform: translate3d(var(--x), 0, 0);
}

.mobile-drawer-root {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
}

.mobile-drawer {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(360px, 100%);
}

Premium visual result 2

Mobile root stack
premium
Mobile fixed drawer system

The page transition moves below while the drawer root remains viewport-owned.

page transition content
base page transformed transition drawer root fixed viewport safe
Pattern 2 is ideal for mobile menus, off-canvas navigation, app drawers, and page-slide transitions.

Fast practical rule

If a fixed element is behind a transformed parent, stop raising z-index first and inspect the ancestor chain. Remove the transform, move the fixed UI outside that parent, or create a dedicated viewport-level root for modals, drawers, toasts, and floating bars.

Debug checklist

  • Inspect the fixed element that appears behind the page or inside a component.
  • Check every ancestor for transform, translate, scale, or rotate.
  • Look for performance hacks such as translateZ(0).
  • Temporarily remove parent transforms in DevTools.
  • Move global fixed UI outside transformed wrappers.
  • Use a root overlay container for modals, drawers, toasts, and popovers.
  • Keep page transitions separate from overlay ownership.
  • Use z-index tokens only after the layer ownership is correct.
Best first moveRemove the ancestor transform and see if fixed behavior returns.
Most common causeA modal or drawer is mounted inside a transformed card or app shell.
Most sneaky causetransform:translateZ(0) was added as a performance fix.
Better mindsetAnimated surfaces and fixed overlay roots should be separate layers.

When transform is still the right choice

transform is not wrong. It is excellent for animation, hover movement, transitions, drawer motion, and smooth UI effects. The mistake is placing global fixed UI inside the element that is being transformed.

Keep transforms on the visual surface that needs movement. Keep fixed overlays in a stable root that is not part of that transformed surface. That gives you animation without turning fixed positioning into a local component behavior.

A good production rule is simple: if the element should cover the whole viewport or stay pinned to the browser window, mount it near the document root. If the element belongs visually to a card, drawer, or component, it can stay inside that component.

The authority move is not to avoid transform forever. The authority move is to avoid letting transform own the viewport layer.

Why this bug survives desktop review

This bug often survives because the fixed element may look almost correct on a wide desktop screen. The problem becomes obvious when a modal needs to cover the whole page, a mobile drawer opens, a toast should float above the app, or a bottom bar should stay attached to the viewport.

A serious review tests fixed UI inside every animated shell, transformed card, mobile page transition, and GPU-accelerated wrapper. If the element is meant to be global, it should not be mounted inside a transformed parent.

Final takeaway

A fixed element behind transformed parent is usually not fixed by a bigger z-index. The fixed element may be trapped because an ancestor with transform changed its containing block and stacking context.

Remove unnecessary parent transforms, avoid performance transforms on large layout wrappers, and mount global UI in viewport-level roots. That keeps modals, drawers, toasts, and fixed bars truly fixed.

When the bug appears only inside one animated section, do not rewrite every z-index value on the site. Find the transformed ancestor first.

Want more fixes like this?

Browse more CSS positioning, z-index, transform, modal, drawer, and responsive debugging guides in the FrontFixer library.

Why Is My Fixed Header Covering Content?

A fixed header covers content because position:fixed removes the header from normal document flow. The content below it does not automatically move down, so the first section, page title, or anchor target can slide underneath the header.

Fixed Header Layout Fix

Why Is My Fixed Header Covering Content?

A fixed header can look normal at first, but then the hero title sits behind it, anchor links land too high, or the top of the page feels hidden. The browser is not making a mistake. A fixed element is pinned to the viewport and no longer reserves layout space in the document.

  • Fixed header overlap
  • Anchor link offset
  • Sticky vs fixed layout

What the bug looks like

The page title hides behind the header, the hero looks cut off, or clicking a menu link lands with the heading covered.

Why it happens

Fixed elements do not reserve space in normal layout. The content starts at the top as if the header were not there.

What fixes it

Add a deliberate top offset, handle anchor scrolling, adjust mobile header height, or use position:sticky when it fits the layout better.

The simple rule behind fixed header overlap

A fixed header is removed from normal document flow. That means the browser paints the header on top of the viewport, but the next section still begins where it normally would: at the top of the page.

This is why the first heading can look like it disappeared. It is usually not missing. It is sitting underneath the header.

The fastest fix is to measure the real header height and create a matching offset for the content and scroll targets.

Error 1

The content has no top offset

This is the classic fixed header bug. The header is fixed to the top of the viewport, but the main content still begins at the top of the document.

Broken code

No offset
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 80px;
  z-index: 100;
}

main {
  /* no top offset */
}

Broken visual result

Content starts under the header
Fixed header
Hero title is partly hidden The content began at the top, underneath the fixed header.

Correct code

Add top offset
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 80px;
  z-index: 100;
}

main {
  padding-top: 80px;
}

Fixed visual result

Content starts below the header
Fixed header
Hero title is visible The main content now reserves space for the fixed header.
Error 2

The header height is duplicated in several places

Hard-coding the same header height in multiple rules works at first, but it becomes fragile. If the header height changes, one value is easy to forget.

Broken code

Repeated values
.site-header {
  height: 80px;
}

main {
  padding-top: 80px;
}

section {
  scroll-margin-top: 96px;
}

Broken visual result

Offsets can drift apart
Header 80px
Mixed spacing rules Different values make future changes risky.

Correct code

Single source of truth
:root {
  --header-height: 80px;
  --header-offset: calc(var(--header-height) + 16px);
}

.site-header {
  height: var(--header-height);
}

main {
  padding-top: var(--header-height);
}

section {
  scroll-margin-top: var(--header-offset);
}

Fixed visual result

One value controls the layout
Header variable
Offsets stay consistent Changing the header height becomes safer.
Error 3

Anchor links land behind the fixed header

You may fix the top of the page and still have broken in-page navigation. The browser scrolls the target to the top of the viewport, where the fixed header is waiting.

Broken code

No scroll offset
<a href="#features">Features</a>

<section id="features">
  <h2>Features</h2>
</section>

Broken visual result

Anchor target is covered
Fixed header
#features The target lands behind the fixed header.

Correct code

Scroll margin
section,
h2,
h3 {
  scroll-margin-top: 96px;
}

Fixed visual result

Anchor target has breathing room
Fixed header
#features The target lands below the header instead of behind it.
Error 4

The mobile header is taller than the desktop header

A header that is 72px on desktop may become 112px on mobile after nav items wrap or a second row appears. If the offset stays desktop-sized, mobile content gets covered.

Broken code

Desktop-only offset
:root {
  --header-height: 72px;
}

main {
  padding-top: var(--header-height);
}

Broken visual result

Mobile header is taller
Fixed header
DocsFixesCSSHTMLResponsive
Content is too high The mobile header grew, but the offset did not.

Correct code

Responsive offset
:root {
  --header-height: 72px;
}

@media (max-width: 768px) {
  :root {
    --header-height: 112px;
  }
}

main {
  padding-top: var(--header-height);
}

Fixed visual result

Mobile offset matches header
Fixed header
DocsFixesCSSHTMLResponsive
Content starts below The mobile offset now matches the taller header.
Error 5

Using fixed when sticky would be simpler

Many fixed header bugs happen because the header did not need to be fixed in the first place. If the header only needs to stick after reaching the top, position:sticky can be cleaner.

More fragile code

Fixed requires offset
.site-header {
  position: fixed;
  top: 0;
  height: 80px;
}

main {
  padding-top: 80px;
}

Fixed header behavior

Needs manual compensation
Fixed header
Works, but requires offset Fixed is valid, but you must manage the layout space.

Alternative code

Sticky header
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
}

Sticky visual result

Header keeps layout space
Sticky header
Content begins naturally The header still participates in normal document flow before sticking.

Fast practical rule

If a fixed header covers content, do not guess random margins. Measure the real header height, offset the content intentionally, and protect anchor links with a scroll offset.

Recommended baseline

Fixed header foundation

This baseline keeps the header height, page offset, and anchor offset connected through custom properties.

:root {
  --header-height: 80px;
  --anchor-offset: calc(var(--header-height) + 16px);
}

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-height);
  z-index: 100;
}

main {
  padding-top: var(--header-height);
}

section,
h2,
h3 {
  scroll-margin-top: var(--anchor-offset);
}

@media (max-width: 768px) {
  :root {
    --header-height: 104px;
  }
}

Why this baseline helps

It compensates for fixed positioning The main content gets space equal to the header height.
It protects anchor navigation scroll-margin-top keeps headings from landing behind the header.
It handles mobile height changes The same variable can change at mobile breakpoints.
It is easier to maintain You adjust one header value instead of chasing scattered magic numbers.

Debug checklist

  • Check whether the header uses position:fixed.
  • Measure the actual rendered header height in DevTools.
  • Add matching top padding to main, the content wrapper, or the first section.
  • Check whether the header height changes on mobile.
  • Test in-page anchor links like #features, #pricing, or #faq.
  • Use scroll-margin-top or scroll-padding-top for anchor navigation.
  • Check whether a fixed header is really needed or whether position:sticky is enough.
  • Avoid random margin guesses that only work at one screen size.
Best first move Measure the real header height and apply a deliberate top offset to the content.
Most common false fix Increasing z-index when the real problem is that the content starts under the header.
Most overlooked cause Anchor links can still hide headings behind the header even after the first page load looks fixed.
Better mindset Fixed headers are not wrong. They simply require layout compensation because they leave document flow.

When z-index is also involved

Sometimes the header covers content and also sits above dropdowns or modals. In that case, you may be dealing with a layering problem too.

If the issue involves elements appearing behind each other, read Why is my z-index not working?.

When responsive layout is the real problem

If the header only covers content on mobile, the layout may need a mobile-specific header height or responsive offset.

If multiple sections are breaking on mobile, read Why is my responsive design not working?.

When absolute elements are also misplaced

Fixed headers, dropdowns, badges, and menus often appear together. If an overlay is not only covered but also positioned in the wrong place, the parent positioning context may be wrong.

If that sounds familiar, read Why is my absolute positioned element in the wrong place?.

When overflow creates side effects

A fixed header can make layout issues more visible, but horizontal overflow usually comes from a wide element elsewhere on the page.

If the page also scrolls sideways, read Fix overflow causing horizontal scroll.

Final takeaway

A fixed header covers content because it is removed from normal document flow. The page content does not automatically reserve space for it.

Fix the layout by adding a top offset that matches the header height, using scroll offsets for anchor links, adjusting the value on mobile, and considering position:sticky when a fully fixed header is not necessary.

Once the content and scroll targets know the header exists, the overlap bug becomes predictable and easy to avoid.

Need more layout fixes?

Browse the responsive cluster or jump back to the full FrontFixer library to keep debugging faster.