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

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>

Applicability

All technologies that support CSS.

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