【更新日 : 】
【脱Jquery】javascriptでフェード系アニメーション(fadeIn、fadeOut、fadeToggle)を実装する
- Category:
- JavaScript
Vanilla JSでフェード系アニメーション(fadeIn、fadeOut、fadeToggle)を実装したサンプルです。
イージング編集と、コールバック関数に対応させました。
後から作成したWeb Animations API 版の方がより最適化してあります。
Web Animations API 版
See the Pen fadeIn fadeOut fadeToggle Vanilla JS (Web Animations API) by web_nak (@web_walking_nak) on CodePen.
JavaScript
/**
* Web Animations APIによるfadeIn・fadeOut・fadeToggleアニメーション処理関数
* @type {Object}
* @param {HTMLElement} target ターゲット設定(必須)
* @param {string} animeType アニメーションの種類 'fadeIn' or 'fadeOut' or 'fadeToggle'(任意 デフォルト:'fadeToggle')
* @param {number} duration アニメーション時間 ミリ秒(任意 デフォルト:400)
* @param {string} easing 'Web Animations API'で設定できるイージング(任意 デフォルト:ease)
* @param {string} displayStyle 'fadeIn'表示後に付与されるcss displayの値(任意 デフォルト:block)
* @param {function} callBack アニメーション後に呼び出すコールバック関数(任意 デフォルト:null)
*/
const fadeAnime = async setOptions => {
'use strict';
const typeFadeToggle = 'fadeToggle';
const typeFadeIn = 'fadeIn';
const typeFadeOut = 'fadeOut';
//デフォルト設定
const defaultOptions = {
target: false,
animeType: typeFadeToggle,
duration: 400,
easing: 'ease',
displayStyle: 'block',
callBack: null,
}
//設定をマージ
const options = Object.assign({}, defaultOptions, setOptions);
//要素が存在しない場合は処理を終了
const target = options.target;
if(!target) {
return;
}
//fadeToggle分岐
let animeType = options.animeType;
const styles = getComputedStyle(target);
const textNone = 'none';
const isDisplayNone = styles.display === textNone;
if (animeType === typeFadeToggle) {
animeType = isDisplayNone ? typeFadeIn : typeFadeOut;
}
const busyClass = 'is-fade-busy';
const targetClassList = target.classList;
//既に表示されている or 実行中だった場合は処理しない
const isFadeIn = animeType === typeFadeIn;
const isFadeOut = animeType === typeFadeOut;
const isBusy = targetClassList.contains(busyClass);
if (
//fadeIn 既に表示されている or 実行中だった場合は処理しない
(isFadeIn && (!isDisplayNone || isBusy))
//fadeOut 既に非表示 or 実行中だった場合は処理しない
|| (isFadeOut && (isDisplayNone || isBusy))
//有効なキーワードではない場合も処理しない
|| (!isFadeIn && !isFadeOut)
) {
return false;
}
//重複処理対策class追加
targetClassList.add(busyClass);
//フェードアニメーション
const targetStyle = target.style;
const displayStyle = options.displayStyle;
let opacityAnimeValue;
if(isFadeOut) {
//opacity 1 → 0 へアニメーション
targetStyle.opacity = 1;
opacityAnimeValue = 0;
} else {
//opacity 0 → 1 へアニメーション
targetStyle.display = displayStyle;
targetStyle.opacity = 0;
opacityAnimeValue = 1;
}
await target.animate(
{
opacity: opacityAnimeValue
},
{
duration: options.duration,
easing: options.easing
}
).finished;
//アニメーション終了処理
//opacity削除
targetStyle.opacity = '';
//実行中class削除
targetClassList.remove(busyClass);
if(isFadeOut) {
//要素を非表示
targetStyle.display = textNone;
}
//コールバック関数が設定されていたら呼び出す
const callBack = options.callBack;
if(typeof callBack === 'function') {
callBack();
}
}
関数の呼び出し
任意の場所で以下を実行し関数を呼び出してください。
ターゲット以外は任意設定です。
fadeAnime({
//ターゲット設定(必須)
target: target,
//↓は任意設定
//アニメーションの種類 'fadeIn' or 'fadeOut' or 'fadeToggle'(任意 デフォルト:'fadeToggle')
animeType: 'fadeToggle',
//アニメーション時間 ミリ秒(任意 デフォルト:400)
duration: 400,
//Web Animations APIで設定できるイージング(任意 デフォルト:ease)
easing: 'ease',
//fadeIn表示後に付与されるcss displayの値(任意 デフォルト:block)
displayStyle: 'block',
//アニメーション後に呼び出すコールバック関数(任意 デフォルト:null)
callBack: () => {
console.log('fadeアニメ終了');
}
});
requestAnimationFrame() 版
See the Pen fadeIn fadeOut fadeToggle Vanilla JS (Easing support) by web_nak (@web_walking_nak) on CodePen.
JavaScript
/**
* requestAnimationFrame()によるfadeIn・fadeOut・fadeToggleアニメーション処理関数
* @type {Object}
* @param {HTMLElement} target ターゲット設定(必須)
* @param {string} animeType アニメーションの種類 'fadeIn' or 'fadeOut' or 'fadeToggle'(任意 デフォルト:'fadeToggle')
* @param {number} duration アニメーション時間 ミリ秒(任意 デフォルト:400)
* @param {string} easing 'Web Animations API'で設定できるイージング(任意 デフォルト:ease)
* @param {string} displayStyle 'fadeIn'表示後に付与されるcss displayの値(任意 デフォルト:block)
* @param {function} callBack アニメーション後に呼び出すコールバック関数(任意 デフォルト:null)
*/
function fadeAnime(animeType, elm, duration, callBack) {
'use strict';
//fadeToggle分岐
if (animeType === 'fadeToggle') {
animeType = getComputedStyle(elm).display === 'none' ? 'fadeIn' : 'fadeOut';
}
//既に表示されている or 実行中だった場合は処理しない
if (
//fadeIn 既に表示されている or 実行中だった場合は処理しない
(animeType === 'fadeIn' && (getComputedStyle(elm).display !== 'none' || elm.classList.contains('is-fade-busy')))
//fadeOut 既に非表示 or 実行中だった場合は処理しない
|| (animeType === 'fadeOut' && (getComputedStyle(elm).display === 'none' || elm.classList.contains('is-fade-busy')))
//有効なキーワードではない場合も処理しない
|| (animeType !== 'fadeIn' && animeType !== 'fadeOut')
) {
return false;
}
//重複処理対策class追加
elm.classList.add('is-fade-busy');
/*
イージング設定
・参考サイト
https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
【JavaScript】スムーススクロールをjQueryを使わずにシンプルに実装する【Vanilla JS】
「t:アニメーションの経過時間」「b:始点」「c:変化量」「d:変化にかける時間」
*/
function easing(t, b, c, d) {
return c * (0.5 - Math.cos((t / d) * Math.PI) / 2) + b;
}
//アニメーション分岐
let fadeFunc = null;
if(animeType === 'fadeOut') {
//初期設定
elm.style.opacity = 1;
//アニメーション関数設定
fadeFunc = function(elapsedTime,duration) {
//easing(「アニメーションの経過時間」,「始点」,「変化量」,「変化にかける時間」)
return 1 - easing(elapsedTime, 0, 1, duration);
}
} else if(animeType === 'fadeIn') {
//初期設定
elm.style.display = 'block';
elm.style.opacity = 0;
//アニメーション関数設定
fadeFunc = function(elapsedTime,duration) {
//easing(「アニメーションの経過時間」,「始点」,「変化量」,「変化にかける時間」)
return easing(elapsedTime, 0, 1, duration);
}
}
//アニメーション開始時間
const start = new Date();
function mainAnime() {
//イベント発生後の経過時間
let elapsedTime = new Date() - start;
//アニメーション終了処理
if (elapsedTime > duration) {
//opacity削除
elm.style.removeProperty('opacity');
//実行中class削除
elm.classList.remove('is-fade-busy');
if(animeType === 'fadeOut') {
//要素を非表示
elm.style.display = 'none';
}
//コールバック関数が設定されていたら呼び出す
if(typeof callBack === 'function') {
callBack();
}
//処理を終了
return false;
}
//アニメーション実行処理
elm.style.opacity = fadeFunc(elapsedTime,duration);
requestAnimationFrame(mainAnime);
}
//アニメーション初回呼び出し
requestAnimationFrame(mainAnime, callBack);
}
関数の呼び出し
任意の場所で以下を実行し関数を呼び出してください。
//フェードイン
fadeAnime('fadeIn', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
//フェードアウト
fadeAnime('fadeOut', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
//フェードイン・アウトテスト
fadeAnime('fadeToggle', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
動作サンプル
HTML
<button id="js-fade-in">fadeIn</button>
<div class="js-fade-in-elm">fadeIn要素</div>
<button id="js-fade-out">fadeOut</button>
<div class="js-fade-out-elm">fadeOut要素</div>
<button id="js-fade-toggle">fadeToggle</button>
<div class="js-fade-toggle-elm">fadeToggle要素</div>
CSS
/* fadeIn用設定 */
.js-fade-in-elm {
display: none;
}
JavaScript
イージング設定や処理速度、コールバック関数(任意)はサイトに合わせて編集してください。
//【Web Animations API 版】
//フェードインテスト
const fadeInElm = document.querySelector('.js-fade-in-elm');
document.getElementById('js-fade-in').addEventListener('click', ()=> {
//フェードイン呼び出し
fadeAnime({
target: fadeInElm,
animeType: 'fadeIn',
duration: 400,
easing: 'ease',
displayStyle: 'block',
callBack: () => {
console.log('fadeIn終了');
}
});
});
//フェードアウトテスト
const fadeOutElm = document.querySelector('.js-fade-out-elm');
document.getElementById('js-fade-out').addEventListener('click', ()=> {
//フェードアウト呼び出し
fadeAnime({
target: fadeOutElm,
animeType: 'fadeOut',
callBack: () => {
console.log('fadeOut終了');
}
});
});
//フェードイン・アウトテスト
const fadeToggleElm = document.querySelector('.js-fade-toggle-elm');
document.getElementById('js-fade-toggle').addEventListener('click', ()=> {
//フェードイン・アウト呼び出し
fadeAnime({
target: fadeToggleElm,
animeType: 'fadeToggle'
});
});
//【requestAnimationFrame() 版】
//フェードインテスト
const fadeInElm = document.querySelector('.js-fade-in-elm');
document.getElementById('js-fade-in').addEventListener('click', function() {
/*
・フェードイン呼び出し
fadeAnime('fadeIn', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
*/
fadeAnime('fadeIn', fadeInElm, 400, function() {
console.log('fadeIn終了');
});
});
//フェードアウトテスト
const fadeOutElm = document.querySelector('.js-fade-out-elm');
document.getElementById('js-fade-out').addEventListener('click', function() {
/*
・フェードアウト呼び出し
fadeAnime('fadeOut', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
*/
fadeAnime('fadeOut', fadeOutElm, 400, function() {
console.log('fadeOut終了');
});
});
//フェードイン・アウトテスト
const fadeToggleElm = document.querySelector('.js-fade-toggle-elm');
document.getElementById('js-fade-toggle').addEventListener('click', function() {
/*
・フェードイン・アウト呼び出し
fadeAnime('fadeToggle', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
*/
fadeAnime('fadeToggle', fadeToggleElm, 400, function() {
console.log('fadeToggle終了');
});
});