Skip to content

Technique C43:Using CSS margin and scroll-margin to un-obscure content

Applicability

All technologies that support CSS.

This technique is not referenced from any Understanding document.

Description

The objective of this technique is to ensure that user interface components (for example: links, buttons, and form fields) that are initially completely obscured by a fixed-position component can still be accessed by users. In this example, this is achieved using the CSS margin and scroll-margin properties to create space underneath the site footer and allow the link in the footer to scroll into view when it is focused with a keyboard.

Examples

Example 1: Using CSS margin and scroll-margin to un-obscure content

This example shows a situation where there is a fixed-position banner at the bottom of the screen that is covering up the site footer, which contains a link. This type of fixed-position banner is a common design for cookie-consent banners.

Working example: Using CSS margin and scroll-margin to un-obscure content.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Using CSS margin and scroll-margin to un-obscure content</title>
  <style>
    ...

    .wrapper {
      display:grid;
      gap:1rem;
      grid-template-columns:repeat(9, 1fr);
      grid-template-rows:8rem auto minmax(10rem, max-content);
      height:100vh;
    }

    .wrapper > * {
      border:1px solid var(--black);
      padding:1rem;
    }

    header {
      grid-column:1 / -1;
      grid-row:1;
    }

    main {
      grid-column:1 / 8;
    }

    aside {
      grid-column:8 / 10;
    }

    footer {
      grid-column:1 / -1;
    }

    @media (max-width:70rem) {
      main {
       grid-column:1 / -1;
      }

      aside {
        grid-column:1 / -1;
      }
    }

    .fixed-position-banner {
      background:var(--banner-background);
      border:3px solid var(--banner-border);
      height:12rem;
      inset-block-end:0;      
      margin-block-end:1rem;
      padding:1rem;
      position:relative;
      width:calc(100vw - 1rem);
    }

    @media (min-width:70rem), (min-height:60rem) {
      .fixed-position-banner {
        margin-block-end:0;
        position:fixed; 
      }

      .banner-open {
        margin-block-end:14rem;
      }

      .banner-open footer a {
        scroll-margin-block-end:15.5rem;
      }
    }
  </style>
</head>
<body>
  <dialog class="fixed-position-banner">
    <h2 tabindex="-1">Fixed-Position Banner</h2>
    <button aria-label="close fixed-position banner" class="close-banner" type="button">
      ...
    </button>
  </dialog>
  <div class="wrapper">
    <header>
      <p>Header Content</p>
    </header>
    <main>
      <h1>Main Content</h1>
    </main>
    <aside>
      <h2>Sidebar Content</h2>
    </aside>
    <footer>
      <h2>Footer Content</h2>
      <p><a href="https://example.com">Here's an example link in the footer</a>.</p>
    </footer>
  </div>
  <script>
    document.addEventListener("DOMContentLoaded", function(e){
      const cookieBanner = document.querySelector(".fixed-position-banner");
      const closeBannerBtn = document.querySelector(".close-banner");
      const pageBody = document.querySelector("body");

      cookieBanner.show();

      if(cookieBanner.hasAttribute("open")){
        pageBody.classList.add("banner-open");
      }

      closeBannerBtn.addEventListener("click", function(e){
        cookieBanner.close();
        pageBody.classList.remove("banner-open");
      }, false);
    });
  </script>	
</body>
</html>

Other sources

No endorsement implied.

  1. W3C - CSS margins.
  2. W3C - CSS the scroll-margin property.
  3. MDN - :has() property.

Tests

Procedure

For each user interface component that can receive keyboard focus:

  1. Check that the user interface component is not entirely hidden when it receives keyboard focus.

Expected Results

  • Check 1 is true.
Back to Top