LoginSignup
8
3

【React】Qiita アドカレみたいな雪が降るアニメーションを作る

Last updated at Posted at 2021-12-01

はじめに

Qiita Advent Calendar 2021の2日目は、
Qiita 株式会社 プロダクト開発G デザインTMの出口(@degudegu2510)が担当します!
業務では、QiitaQiita TeamQiita JobsのUI/UX、フロントエンド、各イベント等のクリエイティブを担当しています。

今年から大きくリニューアルされたQiita Advent Calendar 2021のデザインを担当したのが僕です。
リニューアルした内容や、どうしてこのようなデザインにしたのかををまとめた記事も投稿しています。
ぜひご覧ください。

この記事では、リニューアルされたQiita Advent Calendar 2021 のTOPページの雪が降るアニメーションについての記事です。

  • Qiita Advent Calendar みたいな雪を降るアニメーションをつくってみたい。
  • particles.jsについて知りたい。

という人におすすめです。

particles.js

particles.jsは、雪っぽいアニメーションや宇宙っぽいアニメーション、幾何学図形をアニメーションさせたりできるJSのライブラリーになります。

宇宙 幾何学図形
スクリーンショット 2021-11-22 19.58.47.png スクリーンショット 2021-11-22 19.59.52.png スクリーンショット 2021-11-22 20.00.25.png

パラメーターが豊富で、マウスのホバーに合わせてアニメーションさせたり、
クリックに合わせてアニメーションさせたり、色々なカスタマイズが可能です。

公式デモサイトで、パラメーターをいじりながらアニメーションを試すことができます。
(公式デモサイトをいじってるだけで楽しいです。)

インストール

react-particles-jsをインストールします。
※ npmを使用する場合は、以下のコマンドでインストールできます。

npm i react-particles-js

実装

コーディングは簡単です。最小で実装するとこれだけ。

import css from '@emotion/css'
import React from 'react'
import Particles from 'react-particles-js'

export const AdventCalendarHeroAnimation = () => {
    return (
        <Particles
            params={{
                {/* ここでアニメーションのパラメータを設定しています */}
                particles: {
                    number: {
                        value: 20,
                        density: {
                            enable: true,
                            value_area: 2000,
                        },
                    },
                   ... {/* パラメーターの設定が続く */}
                },
            }}
        />
    )
}

各パラメーターについて

こちらのURLでパラメーターの値を変えることでどんなアニメーションになるか確認できます。
ここでは、各パラメーターが何が変わるかを説明します。

particles

number
value 画面内のシェイプの数 number
density.enable valueの数を表示するareaを決めるか bool
density.value_area valueの数を表示するをareaの大きさ number
color
value シェイプの色 string
shape
type shapeの形 circle、edge、triangle
polygon、star、image
stroke.width 枠線の太さ number
stroke.color 枠線の色 srting
polygon.nb_sides typeがpolygonの時の頂点の数 number
image.src typeがimageの時の画像 string
image.width typeがimageの時の画像の横幅 number
image.height typeがimageの時の画像の縦幅 number
size
value シェイプの大きさ number
random 大きさをランダムにするか bool
anim.enable 大きさをアニメーションさせるか bool
anim.speed アニメーションのスピード number
anim.size_min アニメーション時のシェイプの最小の大きさ number
anim.sync 全てのシェイプのアニメーションを合わせるか bool
opacity
value シェイプの不透明度 number
random 不透明度をランダムにするか bool
anim.enable 不透明度をアニメーションさせるか bool
anim.speed アニメーションのスピード number
anim.size_min アニメーション時のシェイプの最小の不透明度 number
anim.sync 全てのシェイプのアニメーションを合わせるか bool
line_linked
enable_auto シェイプ間の線を引くか bool
distance シェイプ間の線を引く時のシェイプ間の距離 number
color シェイプ間の線の色 string
opacity シェイプ間の線の不透明度
(シェイプの不透明度に影響されます)
number
width シェイプ間の線の幅 number
move
enable シェイプをアニメーションさせるか bool
direction シェイプのアニメーション方向 none、top、top-right、right、bottom-right、bottom、bottom-left、left、top-left
random シェイプのアニメーションスピードをランダムにするか bool
speed シェイプのアニメーションスピード string
straight シェイプのアニメーションを真っ直ぐにするか bool
out_mode 画面端に当たった時にどうするか out、bounce
attract.enable 画面外に出たら消すか bool
attract.rotateX 何が変わってるのかわからない number
attract.rotateY 何が変わってるのかわからない number

interactivity

onhover
enable マウスホバーでアニメーションするか bool
mode マウスホバーアニメーションのモード repuse、grab、bubble
onClick
enable クリックでアニメーションするか bool
mode クリックアニメーションのモード push、remove、repuse、bubble
modes
grab.distance grabモードでシェイプ間の線を引く時のシェイプ間の距離 number
grab.line_linked.opacity grabモードのシェイプ間の線の不透明度 number
bubble.distance bubbleモードで変化させる距離 number
bubble.size bubbleモードで変化させる大きさ number
bubble.opacity bubbleモードで変化させる不透明度 number
bubble.duration (sec) bubbleモードで変化させる時間 number
bubble.repulse repulseモードで変化させる距離 number

page background

page background
background-color 背景色 string
background-image 背景画像 string
background-position 背景画像の場所 string
background-repeat 背景画像のrepeat設定 string

Qiita Advent Calendar Topページの実装

Qiita Advent CalendarのTopページでは、このように実装しています。

完成形

スクリーンショット 2021-11-30 9.57.29.png
動いている様子はこちらからご確認ください

コード

マークアップ部分

import css from '@emotion/css'
import React from 'react'
import Particles from 'react-particles-js'

export const AdventCalendarHeroAnimation = () => {
  {/*表示領域を取得するライブラリを使用しています。直接値を入れても使えます。*/}
  const { currentWidth, currentHeight } = useWindowSize()

  return (
    <div css={heroStyle(heroBackgroundImage)}>
        {/* Qiita Advent Calendar の ロゴを入れます */}
        <img src={'./logo-advent_calendar.svg'} css={heroAnimationLogoStyle} />
        {/* react-particles-jsで雪を表現しています */}
        <Particles
            width={`${currentWidth}px`}
            height={`${currentHeight}px`} 
            style={{ display: 'block' }}
            params={{
                particles: {
                    number: {
                        value: 20,
                        density: {
                            enable: true,
                            value_area: 2000,
                        },
                    },
                    size: {
                        value: 8,
                        random: true,
                    },
                    opacity: {
                        anim: {
                            enable: false,
                        },
                        value: 1,
                        random: false,
                    },
                    move: {
                        direction: 'bottom',
                        out_mode: 'out',
                        speed: 6,
                        random: false,
                    },
                    line_linked: {
                        enable: false,
                    },
                },
            }}
        />
        {/* 画面下にある丘の画像を入れます */}
        <img src={'./image-back_hill.svg'} css={heroHillStyle} />
        <img src={'./image-front_hill.svg'} css={heroHillStyle} /> 
    </div>
  )
}

スタイリング部分

const heroStyle = (heroBackgroundImage: string) =>
  css({
    backgroundImage: `url(${heroBackgroundImage: string})`, // 背景画像を設定しています。
    backgroundSize: 'contain',
    position: 'relative',
    width: '100%',
  })

const logoAnimation = keyframes({
  '0%': {
    opacity: 0,
    transform: 'translate(-50%, -100%) scale(1.5)',
    ...viewportXS({
      transform: 'translate(0, 0) scale(1.5)',
    }),
  },
  '100%': {
    opacity: 1,
    transform: 'translate(-50%, -100%) scale(1)',
    ...viewportXS({
      transform: 'translate(0, 0) scale(1)',
    }),
  },
})

const heroAnimationLogoStyle = css({
  animationDelay: '0s',
  animationDuration: '3s',
  animationName: logoAnimation,
  left: '50%',
  maxWidth: 752,
  padding: `0 ${getSpace(2)}px`,
  position: 'absolute',
  top: '50%',
  transform: 'translate(-50%, -100%)',
  width: '100%',
  zIndex: 10,
})


const heroHillStyle = css({
  bottom: 0,
  left: '50%',
  minWidth: 1280,
  position: 'absolute',
  transform: 'translateX(-50%)',
  width: '100%',
  zIndex: 10,
  filter: 'drop-shadow(0px 4px 16px rgba(0, 0, 0, 0.5))',
})

まとめ

この記事では、リニューアルされたQiita Advent Calendar 2021 のTOPページの雪が降るアニメーションについてとparticles.jsについて説明しました。

particles.jsは、導入するのも実装するのも簡単でした。
特に、↓このサイトでパラメーターの設定を確認してから、実装できるので、
実装しながらパラメーターを調整することがほとんどなく、スムーズに実装できました。

雪のアニメーションだけではなく、
シェイプを桜の花びらにして、花びらが舞っているみたいなアニメーションも面白そうだなと思います。


最後まで読んでくださってありがとうございます!

Qiita Advent Calendar 2021の3日目も、
Qiita 株式会社 プロダクト開発G デザインTMの出口(@degudegu2510)が担当します!

ぜひQiita Advent Calendar 2021を購読設定して、
明日の記事もご覧いただけると嬉しいです。

また、デザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3