<div class="scroll-anim-18-kv" id="js-scroll-anim-18">
    <div class="scroll-anim-18-kv__slider">
        <div class="scroll-anim-18-kv__slider-item">
            <div class="scroll-anim-18-kv__img-wrapper"><img class="scroll-anim-18-kv__img" src="https://picsum.photos/id/1000/800/400" alt="" /></div>
        </div>
        <div class="scroll-anim-18-kv__slider-item">
            <div class="scroll-anim-18-kv__img-wrapper"><img class="scroll-anim-18-kv__img" src="https://picsum.photos/id/1001/800/400" alt="" /></div>
        </div>
        <div class="scroll-anim-18-kv__slider-item">
            <div class="scroll-anim-18-kv__img-wrapper"><img class="scroll-anim-18-kv__img" src="https://picsum.photos/id/1002/800/400" alt="" /></div>
        </div>
    </div>
</div>
<div class="scroll-anim-18-header">
    <nav>
        <ul class="scroll-anim-18-header__nav">
            <li><a class="scroll-anim-18-header__nav-item" href="#">項目1</a></li>
            <li><a class="scroll-anim-18-header__nav-item" href="#">項目2</a></li>
            <li><a class="scroll-anim-18-header__nav-item" href="#">項目3</a></li>
        </ul>
    </nav><a class="scroll-anim-18-header__btn" href="#">ボタン</a>
</div>
<div style="height: 1000px; padding: 16px">
    <p>テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</p>
</div>
.scroll-anim-18-kv#js-scroll-anim-18
  .scroll-anim-18-kv__slider
    each item in sliderItems
      .scroll-anim-18-kv__slider-item
        .scroll-anim-18-kv__img-wrapper
          img.scroll-anim-18-kv__img(src=item.img, alt='')
.scroll-anim-18-header
  nav
    ul.scroll-anim-18-header__nav
      - for (var i = 1; i <= 3; i++)
        li
          a.scroll-anim-18-header__nav-item(href='#') 項目#{ i }
  a.scroll-anim-18-header__btn(href='#') ボタン
div(style='height: 1000px; padding: 16px')
  p テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。
{
  "sliderItems": [
    {
      "img": "https://picsum.photos/id/1000/800/400"
    },
    {
      "img": "https://picsum.photos/id/1001/800/400"
    },
    {
      "img": "https://picsum.photos/id/1002/800/400"
    }
  ]
}
  • Content:
    $BLOCK_KV_NAME: '.scroll-anim-18-kv';
    $BLOCK_HEADER_NAME: '.scroll-anim-18-header';
    
    // 変数
    $color_primary: #2c2929;
    $color_white: #fff;
    $height_header: 80px;
    $shadow_header: 0 5px 25px rgba(86, 49, 56, 0.15),
      0px 0px 8px rgba(86, 49, 56, 0.15);
    $ff_serif: 'Noto Serif JP', Garamond, 'Yu Mincho', 'YuMincho', 'Meiryo',
      sans-serif;
    $ff_sans_serif: 'Open Sans', 'Yu Gothic', '游ゴシック', 'YuGothic',
      '游ゴシック体', Hiragino Kaku Gothic ProN, 'Meiryo', sans-serif;
    
    #{ $BLOCK_KV_NAME } {
      position: relative;
      height: calc(100vh - #{$height_header});
      overflow: hidden;
      background: $color_white;
    
      &__slider {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        overflow: hidden;
      }
    
      &__slider-item {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 1;
        overflow: hidden;
        opacity: 0;
        animation: 6s ease-out forwards;
        &.is-active {
          z-index: 2;
          animation-name: anim18ShowImage;
        }
        &.is-leave {
          z-index: 2;
          animation-name: anim18HideImage;
        }
      }
    
      &__img-wrapper {
        position: absolute;
        top: 0;
        right: -50px;
        bottom: 0;
        left: -50px;
        background-repeat: no-repeat;
        background-position: center center;
        background-size: cover;
        animation: inherit;
        animation-timing-function: linear;
        @at-root #{ $BLOCK_KV_NAME }__slider-item.is-active & {
          animation-name: anim18SlideIn;
        }
        @at-root #{ $BLOCK_KV_NAME }__slider-item.is-leave & {
          animation-name: anim18SlideOut;
        }
      }
    
      &__img {
        display: none;
      }
    }
    
    #{ $BLOCK_HEADER_NAME } {
      position: sticky;
      top: 0;
      display: flex;
      justify-content: space-between;
      height: $height_header;
      font-family: $ff_serif;
      background: $color_white;
      box-shadow: $shadow_header;
    
      &__nav {
        display: flex;
        height: $height_header;
        font-size: 12.5px;
      }
    
      &__nav-item {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;
        padding: 20px 16px;
        &::before {
          position: absolute;
          right: 16px;
          bottom: 20px;
          left: 16px;
          height: 1px;
          content: '';
          background: $color_primary;
          transition: 0.2s ease-out;
          transform: scale(0);
          transform-origin: left;
        }
        &:hover::before {
          transform: scale(1);
        }
      }
    
      &__btn {
        display: flex;
        flex-shrink: 0;
        align-items: center;
        justify-content: center;
        width: 160px;
        height: $height_header;
        font-family: $ff_sans_serif;
        font-size: 13px;
        color: $color_white;
        text-align: center;
        background: $color_primary;
        &:hover {
          color: $color_white;
        }
      }
    }
    
    @keyframes anim18ShowImage {
      0% {
        opacity: 0;
      }
      50% {
        opacity: 1;
      }
      100% {
        opacity: 1;
      }
    }
    
    @keyframes anim18HideImage {
      0% {
        opacity: 1;
      }
      50% {
        opacity: 0;
      }
      100% {
        opacity: 0;
      }
    }
    
    @keyframes anim18SlideIn {
      0% {
        transform: translate3d(50px, 0, 0);
      }
      100% {
        transform: translate3d(0, 0, 0);
      }
    }
    
    @keyframes anim18SlideOut {
      0% {
        transform: translate3d(0, 0, 0);
      }
      100% {
        transform: translate3d(-50px, 0, 0);
      }
    }
    
  • URL: /components/raw/scroll-anim18/scroll-anim18.scss
  • Filesystem Path: src/components/scroll-anims/1_20/scroll-anim18/scroll-anim18.scss
  • Size: 3.4 KB
  • Content:
    'use strict';
    
    import { gsap } from 'gsap';
    import { ScrollTrigger } from 'gsap/ScrollTrigger';
    gsap.registerPlugin(ScrollTrigger);
    
    export const scrollAnim18 = () => {
      const anim = new Anim18('js-scroll-anim-18');
      anim.init();
    }
    
    class Anim18 {
      el: HTMLElement;
      sliderEl: HTMLElement;
      sliderItemEls: NodeListOf<HTMLElement>;
      imgLoadedNum: number;
      currentSliderIndex: number;
      duration: number;
      offsetParallax: number;
      constructor(elId: string) {
        this.el = document.getElementById(elId);
        if (!this.el) return;
        this.sliderEl = this.el.querySelector('.scroll-anim-18-kv__slider');
        this.sliderItemEls = this.sliderEl.querySelectorAll('.scroll-anim-18-kv__slider-item');
        this.imgLoadedNum = 0;
        this.currentSliderIndex = 0;
        this.duration = 6000;
        this.offsetParallax = 60;
      }
    
      init() {
        if (!this.el) return;
        this.parallax();
        this.onLoadHandler();
      }
    
      onLoadHandler() {
        this.sliderItemEls.forEach(el => {
          const imgWrapperEl = <HTMLElement>el.querySelector('.scroll-anim-18-kv__img-wrapper');
          const imgEl = imgWrapperEl.querySelector('img');
          imgEl.addEventListener('load', () => {
            const src = imgEl.getAttribute('src');
            imgWrapperEl.style.backgroundImage = `url(${ src })`;
            this.imgLoadedNum++;
            if (this.imgLoadedNum >= this.sliderItemEls.length) {
              this.startSlide();
            }
          });
        });
      }
    
      startSlide() {
        this.sliderItemEls[this.currentSliderIndex].classList.add('is-active');
        this.next();
      }
    
      next() {
        const self = this;
        setTimeout(() => {
          const prevIndex = self.currentSliderIndex === 0 ? self.sliderItemEls.length - 1 : self.currentSliderIndex - 1;
          const nextIndex = self.currentSliderIndex < self.sliderItemEls.length - 1 ? self.currentSliderIndex + 1 : 0;
          self.sliderItemEls[prevIndex].classList.remove('is-leave');
          self.sliderItemEls[self.currentSliderIndex].classList.remove('is-active');
          self.sliderItemEls[self.currentSliderIndex].classList.add('is-leave');
          self.sliderItemEls[nextIndex].classList.add('is-active');
          self.currentSliderIndex = nextIndex;
          self.next();
        }, this.duration);
      }
    
      parallax() {
        gsap.to(this.sliderEl, {
          scrollTrigger: {
            trigger: this.el,
            start: 'top top',
            end: 'bottom top',
            scrub: .3,
            // markers: true,
          },
          y: this.offsetParallax,
        });
      }
    }
    
  • URL: /components/raw/scroll-anim18/scroll-anim18.ts
  • Filesystem Path: src/components/scroll-anims/1_20/scroll-anim18/scroll-anim18.ts
  • Size: 2.5 KB