skip to Main Content

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:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      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;
      }
    </style>
  </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.

2

Answers


  1. CSS Scroll animation

    It can be implemented similarly, but adjust it yourself.

    body {
      margin: 0;
      padding: 0;
      position: relative;
    }
    
    header {
      height: 150px;
      background-color: black;
    }
    
    .container {
      height: 200vh;
      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;
      bottom: 10px;
    
      /* scroll animation */
      view-timeline-name: --subjectReveal;
      animation-timeline: --subjectReveal;
      animation-name: appear;
      animation-fill-mode: both;
      animation-duration: 1ms;
    }
    
    /* scroll animation */
    @keyframes appear {
      39% {
        opacity: 0;
        transform: scaleX(0);
      }
    
      40% {
        opacity: 1;
        transform: scaleX(1);
      }
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <link rel="stylesheet" href="test.css">
    </head>
    
    <body>
      <header></header>
      <div class="container"></div>
        <div class="sticky">
          <a href="#top">ScrollToTop</a>
        </div>
      <footer></footer>
    </body>
    
    </html>

    Using JS

    It becomes simple and accurate.

    const scrollToTopBtn = document.querySelector('.sticky a');
    
    window.addEventListener('scroll', () => {
      if (window.scrollY > 200) {
        scrollToTopBtn.classList.add('visible');
      } else {
        scrollToTopBtn.classList.remove('visible');
      }
    });
    body {
      margin: 0;
      padding: 0;
    }
    
    header {
      height: 150px;
      background-color: black;
    }
    
    .container {
      height: 200vh;
      background-color: azure;
    }
    
    footer {
      height: 500px;
      background-color: grey;
    }
    
    .sticky {
      display: flex;
      justify-content: flex-end;
      position: sticky;
      bottom: 10px;
      margin: 10px;
    }
    
    .sticky a {
      opacity: 0;
      visibility: hidden;
      background-color: black;
      color: #fff;
      padding: 5px;
      transition: .3s;
    }
    
    .sticky a.visible {
      opacity: 1;
      visibility: visible;
    }
    <!DOCTYPE html>
    <html lang="ko">
    
    <head>
      <meta charset="UTF-8">
      <title>Scroll to Top 버튼</title>
    </head>
    
    <body>
      <header></header>
      <div class="container"></div>
      <div class="sticky">
        <a href="#top">ScrollToTop</a>
      </div>
      <footer></footer>
    </body>
    
    </html>
    Login or Signup to reply.
  2. 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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search