简体   繁体   中英

Fill a circle on scroll in CSS

I'm trying to make a stem filling with a color and with circles for steps along the stem.

This is an example of what I'm currently aiming for: https://codepen.io/nicklassandell/pen/ztGac

This is currently what I have: https://codepen.io/TheOshika/full/xxRRVNb (the design is similar to the above code but I wrote the code from scratch) I'm using a scrollspy script in order to trigger a filling animation in the circles. However I'm not satisfied with it because the offset for the trigger is too difficult to set for a responsive design. I'm now thinking about removing the javascript part and instead having a stem filling the circles with the scrolling, but no animation.

This is what I'm looking for, except I don't know how to make the background color in the stem fill the circles:

 .header { position: relative; height: 800px; background: blueviolet; z-index: 3; } html, body { margin: 0; padding: 0; } body { background: #4c63b6; }.container { margin: 0px auto; position: relative; } /* stem */.filling-stem { position: sticky; z-index: 1; float: left; top: 0; left: 50%; transform: translate(-50%, 0); height: 50vh; width: 5px; background-color: #bed0f7; }.stem-background { position: absolute; z-index: 0; left: 50%; transform: translate(-50%, 0); height: 100%; width: 5px; background-color: #1f2933; }.stem-nav { position: absolute; z-index: 2; left: 50%; transform: translate(-50%, 0); height: 100%; } #my-awesome-nav { display: flex; height: 100%; justify-content: space-around; flex-direction: column; list-style: none; margin-left: 0; padding-left: 0; } #my-awesome-nav li a { border: solid 3px black; border-radius: 50%; display: inline-block; background-color: #1f2933; } #my-awesome-nav li a.color-change { height: 40px; width: 40px; background-color: #1f2933; border-radius: 50%; } /* timeline */.timeline-container { position: relative; }.step-container { margin: 0 25% 0 25%; display: flex; align-items: center; height: 1500px; } /* footer */ footer { display: flex; justify-content: center; align-items: center; height: 1000px; width: 100%; background-color: black; color: white; }
 <div class="container"> <div class="container-inner"> <div class="filling-stem"></div> <div class="header"></div> <div class="timeline-container"> <div class="timeline-container-inner"> <div class="stem-background"></div> <div class="stem-nav"> <ul id="my-awesome-nav"> <li data-index="0"><a href="#step-one"> <div class="color-change one"></div> </a></li> <li data-index="1"><a href="#step-two"> <div class="color-change two"></div> </a></li> <li data-index="2"><a href="#step-three"> <div class="color-change three"></div> </a></li> <li data-index="3"><a href="#step-four"> <div class="color-change four"></div> </a></li> <li data-index="4"><a href="#step-five"> <div class="color-change five"></div> </a></li> </ul> </div> <div class="step-container"> <div class="step-container-inner"> </div> </div> </div> </div> </div> </div> <footer> <p>End of the page</p> </footer>

It should be possible to get the required 'filling' effect using just CSS.

We add a pseudo before and a pseudo after element to each of the li elements. These have a radial-gradient background which has a transparent 'bite' out at the position of the circles containing the a (anchor) element. Behind the whole thing we put a fixed element which has the 'fill' color in the top half and the darker (non-filled) color in the bottom half. This is done by giving it a background image which is a linear gradient.

The inner divs (inside the anchor elements) are not now needed.

Here is a snippet to show the idea. CSS variables have been introduced to make it easier to change dimensions if required. (Note: there is redundant CSS in here which could do with tidying up.)

 * { margin: 0; padding: 0; --stemw: 5px; /* the width of the stem */ --circled: 40px; /* the diameter of the circles */ --lih: 300px; /* the height of each list item */ --nolis: 5; /* the number of items in the list */ --halfstemw: calc(var(--stemw) / 2); --circler: calc(var(--circled) / 2); /* the circle radius */ --halflih: calc(var(--lih) / 2); } div.bg { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-image: linear-gradient(to top, #1f2933 0%, #1f2933 50%, #bed0f7 50%, #bed0f7 100%); overflow: hidden; } #my-awesome-nav li { position: relative; } #my-awesome-nav li::before, #my-awesome-nav li::after { position: absolute; transform: translateX(calc(-100% + var(--circler))); width: calc(50vw - var(--halfstemw)); height: var(--lih); top: calc(var(--halflih) * -1); content: ''; z-index: -1; } #my-awesome-nav li::before { left: 0; background: radial-gradient(circle at calc(100% + var(--halfstemw)) calc(50% + var(--circler)), transparent 0%, transparent 3%, #4c63b6 3%, #4c63b6 100%); } #my-awesome-nav li::after{ left: calc(50vw + var(--halfstemw)); background: radial-gradient(circle at calc(var(--halfstemw) * -1) calc(50% + var(--circler)), transparent 0%, transparent 3%, #4c63b6 3%, #4c63b6 100%); }.header { position: relative; height: 800px; background: blueviolet; z-index: 3; } html, body { margin: 0; padding: 0; } body { background: #4c63b6; }.container { margin: 0px auto; position: relative; } /* stem */.filling-stem { position: sticky; z-index: 1; float: left; top: 0; left: 50%; transform: translate(-50%, 0); height: 50vh; width: 5px; background-color: #bed0f7; }.stem-background { position: absolute; z-index: 0; left: 50%; transform: translate(-50%, 0); height: 100%; width: 5px; background-color: #1f2933; }.stem-nav { position: absolute; z-index: 2; left: 50%; transform: translate(-50%, 0); height: 100%; } #my-awesome-nav { display: flex; height: 100%; justify-content: space-around; flex-direction: column; list-style: none; margin-left: 0; padding-left: 0; } #my-awesome-nav li a { width: 40px; height: 40px; border: solid 3px black; border-style: none; border-radius: 50%; display: inline-block; background-color: #1f2933; background-color: transparent; } /* #my-awesome-nav li a.color-change { height: 40px; width: 40px; background-color: #1f2933; border-radius: 50%; background-color: transparent; } */ /* timeline */.timeline-container { position: relative; }.step-container { margin: 0 25% 0 25%; display: flex; align-items: center; height: 1500px; } /* footer */ footer { display: flex; justify-content: center; align-items: center; height: 1000px; width: 100%; background-color: black; color: white; }
 <div class="bg"></div> <div class="container"> <div class="container-inner"> <div class="filling-stem"></div> <div class="header"></div> <div class="timeline-container"> <div class="timeline-container-inner"> <div class="stem-background"></div> <div class="stem-nav"> <ul id="my-awesome-nav"> <li data-index="0"><a href="#step-one"> </a></li> <li data-index="1"><a href="#step-two"> </a></li> <li data-index="2"><a href="#step-three"> </a></li> <li data-index="3"><a href="#step-four"> </a></li> <li data-index="4"><a href="#step-five"> </a></li> </ul> </div> <div class="step-container"> <div class="step-container-inner"> </div> </div> </div> </div> </div> </div> <footer> <p>End of the page</p> </footer>

Footnote: on retina screens I've occasionally seen a faint line between the pseudo elements - I think it's where the positioning calculations come at part of a CSS pixel (which on a high res screen may mean a screen pixel is 'left behind'). It's probably necessary to make the pseudo elements 1 CSS pixel higher to overlap the next one to give a continuous effect to the background.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM