JSFiddle - React, Tailwind, and code Playground

by Oski Krawczyk

HTML

<div id="progress">
    <div id="bar"></div>
    <div id="breakpoints"></div>
</div>
<div id="bp" data-pages="5">
    <div class="test">
        <span class="badge"></span>
        <div class="outercont">
            <div class="cont">
                <div class="innercont">
                    <div class="slide">1</div>
                    <div class="slide">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur aliquid id commodi asperiores quas voluptatum quaerat non excepturi facere beatae maxime vitae? Laudantium nesciunt ipsum amet aliquam placeat expedita excepturi.</div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="breakpoint"></div>

SCSS

body {
    background: #F6F6F6;
    font-size: 13px;
    font-family: BentonSans-Medium;
}

#progress {
    height: 1px;
    background: #ccc;
    width: 300px;
    position: fixed;
    top: 10px;
}

#bar {
    height: 5px;
    background: #ccc;
    width: 0;
    position: absolute;
    top: -2px
}

#breakpoints {
    .dot {
        display: block;
        height: 5px;
        width: 5px;
        border-radius: 5px;
        background: red;
        position: absolute;
        top: -2px;
    }
}

.breakpoint {
    height: 2000px;
}

#bp {
    position: fixed;
    top: 0;
    
    .test {
        position: absolute;
        top: 20px;
        left: 50px;
        height: 300px;
        width: 300px;
        transition: all 0.3s;
        
        .badge {
            position: absolute;
            top: 0;
            left: 0;
            height: 20px;
            width: 20px;
            background: #CD4B5B;
            border-radius: 100%;
            opacity: 0;
            text-align: center;
            line-height: 20px;
            color: #fff;
            transition: all 0.3s;
            transform: scale(0.3);
        }
        
        .outercont {
            position: absolute;
            top: 40px;
            left: -20px;
            height: 200px;
            width: 300px;
            background: #fff;
            box-shadow: 0px 10px 60px 0px rgba(#000, 0.3);
            border-radius: 4px;
            opacity: 0;
            transition: all 0.3s;
            transform: scale(1) translate(0, 40px);
            
            
            &:after {
                content: "";
                position: absolute;
                top: -12px;
                left: 20px;
                display: block;
                width: 0;
                height: 0;
                border-left: 12px solid transparent;
                border-right: 12px solid transparent;
                border-bottom: 12px solid #fff;
            }
                
               ...

CoffeeScript

bp         = document.querySelector "#bp"
contHeight = document.querySelector ".breakpoint"
badge      = document.querySelector ".badge"
bar        = document.querySelector "#bar"
breakpoints = document.querySelector "#breakpoints"
pages      = parseInt bp.getAttribute "data-pages"
breakpoint = (contHeight.scrollHeight-window.innerHeight) / pages
page       = 1
animate    = ->

    # be sure to update the breakpoint
    breakpoint = (contHeight.scrollHeight-window.innerHeight) / pages
    
    top   = document.body.scrollTop
    page += 1 if top >= page * breakpoint
    page -= 1 if top <= page * breakpoint
    
    bp.setAttribute "class", "bp_#{page}" unless page >= pages
    badge.innerHTML = page unless page >= pages
        
    windowHeight = window.innerHeight
    bar.style.width = "#{top/(contHeight.scrollHeight-windowHeight)*100}%";
    
    dots = document.querySelectorAll ".dot"
    dots[page].setAttribute "class", "dot up"

document.addEventListener "scroll", animate, false

# create the breakpoint dots in the timeline
dots = []

for dot in [1..pages-1]
    dots.push """
        <div class="dot" style="left: #{dot*(100/pages)}%"></div>
    """
breakpoints.innerHTML = dots.join ""