Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                
<div class="MouseScroll">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" version="1.1">
            <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                <g fill="rgba(160, 187, 189, 0.8)">
                    <path d="M40,41.0074017 L40,41.0074017 L40,58.9925983 C40,64.5218355 44.4762336,69 50,69 C55.5234877,69 60,64.5203508 60,58.9925983 L60,41.0074017 C60,35.4781645 55.5237664,31 50,31 C44.4765123,31 40,35.4796492 40,41.0074017 L40,41.0074017 Z M38,41.0074017 C38,34.3758969 43.3711258,29 50,29 C56.627417,29 62,34.3726755 62,41.0074017 L62,58.9925983 C62,65.6241031 56.6288742,71 50,71 C43.372583,71 38,65.6273245 38,58.9925983 L38,41.0074017 L38,41.0074017 Z"></path>
                    <path d="M49,36 L49,40 C49,40.5522847 49.4477153,41 50,41 C50.5522847,41 51,40.5522847 51,40 L51,36 C51,35.4477153 50.5522847,35 50,35 C49.4477153,35 49,35.4477153 49,36 L49,36 Z"></path>
                    <path d="M50,81.9929939 L55.4998372,76.4931567 C55.8903615,76.1026324 56.5235265,76.1026324 56.9140508,76.4931567 C57.3045751,76.883681 57.3045751,77.516846 56.9140508,77.9073703 L50.7071068,84.1143143 C50.5118446,84.3095764 50.2559223,84.4072075 50,84.4072075 C49.7440777,84.4072075 49.4881554,84.3095764 49.2928932,84.1143143 L43.038379,77.8598002 C42.6478547,77.4692759 42.6478547,76.8361109 43.038379,76.4455866 C43.4289033,76.0550623 44.0620683,76.0550623 44.4525926,76.4455866 L50,81.9929939 Z" class="MouseScroll--chevron"></path>
                </g>
            </g>
        </svg>
    </div>

<section class="Intro CenterAlign">
    <div class="Wrapper">
        <h1>ScrollTrigger</h1>
        <h2>Let your page react to scroll changes</h2>
    </div>
</section>
<section class="About">
    <div class="Wrapper">
        <h3 data-slideInLeft>
            Trigger classes based on scroll position
        </h3>
        <p data-slideInRight>
            The most basic usage of ScrollTrigger is to trigger classes based on the current scroll position. E.g. when an element enters the viewport, fade it in. You can add custom offsets per element, or set offsets on the viewport (e.g. always trigger after the
            element reaches 20% of the viewport)
        </p>

        <h3 data-slideInLeft>
            Execute callbacks on entering / leaving the viewport
        </h3>
        <p data-slideInRight>
            When using the callbacks ScrollTrigger becomes really powerfull. You can run custom code when an element enters / becomes visible, and even return Promises to halt the trigger if the callback fails. This makes lazy loading images very easy.
        </p>
        <p></p>
        <div data-callback data-slideInBottom class="CenterAlign">
            You've scrolled passed this block <span>0</span> times.
        </div>
    </div>
</section>
<section class="Examples">
    <div class="Wrapper">
        <h3 data-slideInBottom>Show me some code!</h3>
        <p data-slideInBottom>
            The easiest way to start is to create a new instance and add some triggers to it, with all default values. This will toggle the 'visible' class when the element comes into the viewport, and toggles the 'invisible' class when it scrolls out of the viewport.
        </p>

        <code data-slideInBottom>
                <span>// Create a new ScrollTrigger instance with default options</span><br />
                const trigger = new ScrollTrigger()<br />
                <span>// Add all html elements with attribute data-trigger</span><br />
                trigger.add('[data-trigger]')<br />
                <br />
                <span>// Now in your CSS add the following classes, this
                    fades the [data-trigger] elements in and out</span><br />

                .visible, .invisible {<br />
                    &nbsp;&nbsp;opacity: 0.0;<br />
                    &nbsp;&nbsp;transition: opacity 0.5s ease;<br />
                }<br />

                .visible {<br />
                    &nbsp;&nbsp;opacity: 1.0;<br />
                }
            </code>

        <h3 data-slideInBottom>Now let's add some callbacks and custom classes</h3>
        <p data-slideInBottom>
            Adding callbacks / different classes can be done globally, this becomes the default for all triggers you add, or you can specify custom configuration when adding a trigger.
        </p>

        <code data-slideInBottom>
                <span>// Create a new ScrollTrigger instance with some custom options</span><br />
                const trigger = new ScrollTrigger({<br />
                &nbsp;&nbsp;trigger: {<br />
                &nbsp;&nbsp;&nbsp;&nbsp;once: true<br />
                &nbsp;&nbsp;}<br />
                })<br />
                <span>// Add all html elements with attribute data-trigger, these elements will only be triggered once</span><br />
                trigger.add('[data-trigger]')<br />

                <span>// Add all html elements with attribute data-triggerAlways, these elements will always be triggered</span><br />
                trigger.add('[data-triggerAlways]', { once: false })<br />
            </code>

        <p></p>

        <p data-slideInBottom>
            For more examples, checkout the <span>/demo</span> directory on
            <a href="https://github.com/terwanerik/ScrollTrigger/tree/master/demo">GitHub</a>.
        </p>
    </div>
</section>
<section class="MoreInformation CenterAlign">
    <div class="Wrapper">
        <h2>More information?</h2>
        <h3><a href="https://github.com/terwanerik/ScrollTrigger">Visit GitHub!</a></h3>
    </div>
</section>
              
            
!

CSS

              
                /* .visible, .invisible {
  opacity: 0.0;
  transition: opacity 0.5s ease;
}
.visible {
  opacity: 1.0;
} */

html, body {
	margin: 0;
	padding: 0;
}

body {
	background: #021517;
    color: #a0bbbd;

	font-family: 'Montserrat', Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
	font-weight: 400;
    font-size: 21px;
	-webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, p {
    margin: 0;
    padding: 0.25em 0;
}

h1 {
    font-size: 2.5em;
}

h2 {
    font-size: 1.875em;
    font-weight: normal;
}

h3 {
    font-size: 1.5em;
}

a {
    text-decoration: none;
    font-weight: 500;
    color: #689396;
}

section {
    display: table;
    position: relative;
    box-sizing: border-box;
    width: 100%;
    min-height: 100vh;

    padding: 75px 15px;
}

section div.Wrapper {
    display: table-cell;
    vertical-align: middle;
}

canvas {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;

    z-index: 0;
}

section h3,
section p,
section code {
    display: block;
    width: 98%;
    max-width: 680px;
    margin: 0 auto;
    padding: 0 0 25px 0;

    line-height: 1.4em;
    color: inherit;
}

section h3 {
    margin: 45px auto 0 auto;
}

section p span {
    display: inline-block;
    position: relative;
    top: -2px;
    padding: 0 5px;

    background: #689396;

    font-family: monospace;
    font-size: 14px;
    color: #fff;
}

section code {
    padding: 15px;

    background: #689396;
    color: #fff;
    font-size: 14px;
}

section code span {
    opacity: 0.6;
}

section.Intro {
    color: #a0bbbd;
}

section.Intro h2 {
    color: rgba(160, 187, 189, 0.8);
}

section.About {
    color: #497275;
    background: #a0bbbd;
}

section.Examples {
    background: #fff;
    color: #689396;
}

.CenterAlign {
    text-align: center;
}

div.Wrapper {
    position: relative;
    width: 96%;
    max-width: 680px;
    margin: 0 auto;

    z-index: 1;
}

div.MouseScroll {
    position: absolute;
    left: 50%;
    bottom: 25px;
    width: 100px;
    height: 100px;
    margin: 0 0 0 -50px;

    z-index: 2;
}

path.MouseScroll--chevron {
	animation: ChevronAnimation 3s ease infinite;
	transform: translateY(3px)
}

[data-slideInLeft].visible, [data-slideInLeft].invisible,
[data-slideInRight].visible, [data-slideInRight].invisible ,
[data-slideInBottom].visible, [data-slideInBottom].invisible {
    opacity: 1.0;
    transform: translate(0, 0);
    transition: transform 0.8s ease, opacity 0.8s ease;
}

[data-slideInLeft].invisible {
    opacity: 0.0;
    transform: translate(10px, 0);
}

[data-slideInRight].invisible {
    opacity: 0.0;
    transform: translate(-10px, 0);
}

[data-slideInBottom].invisible {
    opacity: 0.0;
    transform: translate(0, 10px);
}

@keyframes ChevronAnimation {
	0% {
		transform: translateY(3px);
		opacity: 1
	}
	50% {
		transform: translateY(8px);
		opacity: 0
	}
	60% {
		transform: translateY(3px);
		opacity: 0
	}
}
              
            
!

JS

              
                import ScrollTrigger from "https://esm.sh/@terwanerik/scrolltrigger"

((document, window) => {
    // This is where the magic happens, start by initializing a ScrollTrigger
    // instance. We can set default options for all triggers in the constructor.
    //
    // We set some default 'trigger' options, and add a custom callback for
    // the didScroll method. Also we set the scroll sustain to 800ms.
    const trigger = new ScrollTrigger({
        // Set custom (default) options for the triggers, these can be overwritten
        // when adding new triggers to the ScrollTrigger instance. If you pass
        // options when adding new triggers, you'll only need to pass the object
        // `trigger`, e.g. { once: false }
        trigger: {
            // If the trigger should just work one time
            once: false,
            offset: {
                // Set an offset based on the elements position, returning an
                // integer = offset in px, float = offset in percentage of either
                // width (when setting the x offset) or height (when setting y)
                //
                // So setting an yOffset of 0.2 means 20% of the elements height,
                // the callback / class will be toggled when the element is 20%
                // in the viewport.
                element: {
                    x: 0,
                    y: (trigger, rect, direction) => {
                        // You can add custom offsets according to callbacks, you
                        // get passed the trigger, rect (DOMRect) and the scroll
                        // direction, a string of either top, left, right or
                        // bottom.
                        return 0.2
                    }
                },
                // Setting an offset of 0.2 on the viewport means the trigger
                // will be called when the element is 20% in the viewport. So if
                // your screen is 1200x600px, the trigger will be called when the
                // user has scrolled for 120px.
                viewport: {
                    x: 0,
                    y: (trigger, frame, direction) => {
                        // We check if the trigger is visible, if so, the offset
                        // on the viewport is 0, otherwise it's 20% of the height
                        // of the viewport. This causes the triggers to animate
                        // 'on screen' when the element is in the viewport, but
                        // don't trigger the 'out' class until the element is out
                        // of the viewport.

                        // This is the same as returning Math.ceil(0.2 * frame.h)
                        return trigger.visible ? 0 : 0.2
                    }
                }
            },
            toggle: {
                // The class(es) that should be toggled
                class: {
                    in: 'visible', // Either a string, or an array of strings
                    out: ['invisible', 'extraClassToToggleWhenHidden']
                },
                callback: {
                    // A callback when the element is going in the viewport, you can
                    // return a Promise here, the trigger will not be called until
                    // the promise resolves.
                    in: null,
                    // A callback when the element is visible on screen, keeps
                    // on triggering for as long as 'sustain' is set
                    visible: null,
                    // A callback when the element is going out of the viewport.
                    // You can also return a promise here, like in the 'in' callback.
                    //
                    // Here an example where all triggers take 10ms to trigger
                    // the 'out' class.
                    out: (trigger) => {
                        // `trigger` contains the Trigger object that goes out
                        // of the viewport
                        return new Promise((resolve, reject) => {
                            setTimeout(resolve, 10)
                        })
                    }
                }
            },
        },
        // Set custom options and callbacks for the ScrollAnimationLoop
        scroll: {
            // The amount of ms the scroll loop should keep triggering after the
            // scrolling has stopped. This is sometimes nice for canvas
            // animations.
            sustain: 200,
            // Window|HTMLDocument|HTMLElement to check for scroll events
            element: window,
      
            // Callback when the user started scrolling
            start: () => {},
            // Callback when the user stopped scrolling
            stop: () => {},
            // Callback when the user changes direction in scrolling
            directionChange: () => {}
        }
    })




    function setup() {
        // Add the triggers
        addTriggers()

    
    }

    function addTriggers() {
        // Adding triggers can be done in multiple ways, the easiest is to pass
        // a querySelector.
        trigger.add('[data-slideInLeft]')
               .add('[data-slideInRight]')
               .add('[data-slideInBottom]')

        // Add the trigger for the callback example, also add a custom callback
        // when the trigger becomes visible. As an example we pass an HTMLElement
        // instead of a querySelector.
        const element = document.querySelector('[data-callback]')
        trigger.add(element, {
            toggle: {
                callback: {
                    in: counterCallback
                }
            }
        })
    }

    function counterCallback(trigger) {
        // In the callback we get passed the Trigger object, from here we have
        // access to the responding HTMLElement among other things. You could,
        // for instance, change the class it toggles, or attach another callback.
        // Check the console for more info.
        console.info(trigger)

        // For now, we just append the counter
        const counterElement = trigger.element.querySelector('span')
        const counter = parseInt(counterElement.innerText)

        counterElement.innerText = counter + 1
    }


    setup()
})(document, window)
              
            
!
999px

Console