htmlcsssticky

How to show a sticky button after scrolling 200px without JavaScript?


my goal is to set the sticky div initially to visibility: hidden. After scrolling more than 200px, the button should appear with visibility: visible. Is there a workaround to achieve this only with CSS, without JavaScript? In pure CSS, there doesn’t seem to be a way to detect exact scroll distances like 200px. Any suggestions?

This is my example:

body {
  margin: 0;
  padding: 0;
}

header {
  height: 150px;
  background-color: black;
}

.container {
  height: 1500px;
  background-color: azure;
}

footer {
  height: 500px;
  background-color: grey;
}

.sticky {
  display: flex;
  justify-content: flex-end;
  position: sticky;
  bottom: 10px;
  margin: 10px;
}

.sticky a {
  background-color: black;
  color: #fff;
  padding: 5px;
}
<!DOCTYPE html>
<html>

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
</head>

<body>
  <header></header>
  <div class="container"></div>
  <div class="sticky">
    <a href="#top">ScrollToTop</a>
  </div>
  <footer></footer>
</body>

</html>

I tried many things like a sticky spacer, semi-sticky with multiple elements, and so on. Unfortunately, nothing worked.


Solution

  • You can also use a grid-layout, container query (to toggle an hide/show) and float/clear-both to show & push down a sticky link if needed only: example from my earlier comment with your HTML:

    body {
      margin: 0;
      padding: 0;
    }
    header {
      height: 100px;
      background-color: black;
      color: white;
    }
    .container {
      background-color: azure;
    }
    footer {
      height: 100px;
      background-color: grey;
    }
    html {
      scroll-behavior: smooth;
    }
    
    body {
      --d: 4rem;
      --m: 1rem;
      --showScrollTopAt: calc(100vh + 150px); /* valeur a reporter en dur le container querie, la variable ne passe pas */
      display: grid;
      grid-template-columns:  1fr ;
      overflow: auto;
      max-height: 100vh;
      margin: 0;
      padding: 0;
    }
    header ,
    .container,
    footer {
      grid-column:1;
    }
    header,footer {
     display:grid;
     place-content:center;
     font-size:5vw
    }
    .container:has(p #show:checked) {
      height:1500px;
    }
    /* container cell to query */
    .sticky {
      container-type: size;
      container-name: divTopLink;
      grid-column: 2;
      grid-row:1/4;
      overflow: visible;
    }
    /* pushing floatting pseudo  */
    .sticky::before {
      content: "";
      float: left;
      height: var(--showScrollTopAt);
      max-height: 100cqh;
    }
    .sticky a {
      clear: both;
      position: sticky;
      top: calc(100vh - var(--d) - 1rem);
      margin: 0 1rem 0 auto;
      display: flex;
      justify-content: center;
      align-items: center;
      height: var(--d);
      width: var(--d);
      border-radius: 50%;
      background-color: #0007;
      color: #fff;
      text-shadow:1px 1px 1px black;
      margin-left: calc(var(--d) * -1 - 1rem);
      z-index: 1;
    }
    /* ************* container Querie ****************** 
    max-height must be equal to var(--showScrollTopAt) !!
    */
    
    @container divTopLink (max-height : calc(100vh + 150px)) {
      .sticky::before,
      .sticky a {
        display: none;
      }
    }
    /* ***************** fin container Querie ********************* */
    <header id="top">header</header>
    <div class="container">container
      <p><label>Check to make me 1500px tall <input type="checkbox" id="show"> to reveal the top link</label></p>    
      </div>
    <div class="sticky">
      <a href="#top">ScrollToTop</a>
    </div>
    <footer>footer</footer>