PageSourceSearch

https://isidori.jp/wp-content/themes/muum_tcd085/js/parallax.js?ver=3.7.5

js isidori.jp collected 2026-10-02 19:25:47 UTC 17,239 bytes, 477 lines download raw bytes

1/*
2パララックス化する要素に下記属性を追加してください。
3data-parallax-image="PC用画像URL" ※必須 これをjsセレクタとして要素検索 空ならモバイル用画像を使用
4data-parallax-mobile-image="モバイル用画像URL" ※オプション 空ならPC用画像を使用
5data-parallax-speed="0~2" ※オプション パララックススクロール係数 0でパララックス効果なし。未指定時はデフォルト設定defaultSpeedを使用します。
6data-parallax-blur="0~" ※オプション 背景画像全体のぼかしサイズ 0でぼかしなし、未設定時はデフォルト設定defaultBlurを使用します。全体ぼかしを使用する場合はcssでposition: absoluteが指定されている必要があります。
7
8パララックス要素上のオーバーレイ要素にぼかし背景を入れる場合はぼかし要素に下記属性を追加してください。
9data-parallax-overlay-blur="1~" ※必須 パララックス要素の子要素もしくはパララックス要素のposition:relative要素の子要素にオーバーレイ要素が存在し、その子要素に指定する必要があります。この要素のposition系cssは基本的に不要です。
10
11オーバーレイぼかしのサンプル:
12<div class="parallax" style="position: relative; height: 600px;" data-parallax-image="01.jpg">
13	<div class="parallax-overlay" style="position: absolute; bottom: 50px; left: 50px; right: 50px; top: 50px; z-index: 2;">
14		<div class="parallax-overlay-contents">text...</div>
15		<div class="parallax-overlay-bg" data-parallax-overlay-blur="5"></div>
16	</div>
17</div>
18<div class="parallax" style="position: relative; height: 600px;">
19	<div class="parallax-overlay" style="position: absolute; bottom: 50px; left: 50px; right: 50px; top: 50px; z-index: 2;">
20		<div class="parallax-overlay-contents">text...</div>
21		<div class="parallax-overlay-bg" data-parallax-overlay-blur="5"></div>
22	</div>
23	<div class="parallax-image" data-parallax-image="01.jpg" style="position: absolute; bottom: 0; left: 0; right: 0; top: 0; z-index: 1;"></div>
24</div>
25*/
26jQuery(function($){
27
28	var $elems = $('[data-parallax-image]');
29	if (!$elems.length) return;
30
31	// モバイル画像に切り替えるブレイクポイント
32	var mobileBreakpoint = 650;
33
34	// デフォルトのパララックススクロール係数
35	// data-parallax-speedで上書きされます
36	// ここの乗数を0~2の間で変えることで視差調整が可能。0=通常表示、1=background-attachment: fixed;と同等表示、1以上で通常とは逆方向へ移動する感じになります。2以上も設定可能ですが拡大されすぎるので注意してください。
37	var defaultSpeed = 0.3;
38
39	// デフォルトの全体ぼかし
40	// data-parallax-blurで上書きされます
41	var defaultBlur = 0;
42
43	// 変数
44	var $window = $(window);
45	var $body = $('body');
46	var ua = window.navigator.userAgent.toLowerCase();
47	var elemSettings = [];
48	var images = [];
49	var mobileImages = [];
50	var resizeTimer = null;
51	var winWidth = window.innerWidth || $body.width();
52	var winHeight = window.innerHeight || $window.innerHeight();
53
54	// IE判別
55	var isIE = (ua.indexOf('msie') > -1 || ua.indexOf('trident') > -1);
56
57	// IE・Edgeの場合はsvgでぼかし
58	// Edgeはfilter: blur(Npx)だとフチ透過対策が効かないため。
59	// 2019/08時点 Chromium版EdgeはUAがEdgeではなくEdgのため対象外で問題なし。
60	var useSvgBlur = (isIE || ua.indexOf('edge') > -1);
61
62	// スマホ判別
63	var isSmartPhone = (ua.indexOf('iphone') > -1 || ua.indexOf('ipod') > -1 || ua.indexOf('android') > -1 && ua.indexOf('mobile') > -1);
64
65	// モバイル判別
66	var isMobile = (isSmartPhone || ua.indexOf('ipad') > -1 || ua.indexOf('android') > -1);
67
68	// ブレイクポイントによるモバイル判別
69	var checkParallaxMobile = function() {
70		var mql = window.matchMedia('(max-width: ' + mobileBreakpoint + 'px)');
71		return mql.matches;
72	};
73	var isParallaxMobile = checkParallaxMobile();
74
75	// SVGぼかし用SVG生成
76	var parallaxCreateSvg = function(src, blur) {
77		var svgid = Math.random().toString(36).substr(2, 9);
78		var $svg = $('<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg-' + svgid + '" class="parallax-blur" width="100%" height="100%" viewBox="0 0 100% 100%" preserveAspectRatio="none"><filter id="blur-' + svgid + '"><feGaussianBlur in="SourceGraphic" stdDeviation="' + blur + '"></feGaussianBlur></filter><image x="0" y="0" width="100%" height="100%" externalResourcesRequired="true" xlink:href="' + src + '" style="filter:url(#blur-' + svgid + ')" preserveAspectRatio="none"></image></svg>');
79		return $svg;
80	};
81
82	// パララックススクロール処理
83	var parallaxBgScroll = function() {
84		var winScrollTop = $window.scrollTop();
85
86		$elems.each(function(i){
87			// パララックスなしもしくはサイズ計算が終わっていない場合は終了
88			if (elemSettings[i].speed === 0 || elemSettings[i].imageOffsetY === undefined) return;
89
90			// 全体ぼかしあり
91			if (elemSettings[i].blur) {
92				var $elem = $(this);
93				var $box = $elem.offsetParent();
94				var boxOffsetTop = Math.ceil($box.offset().top);
95				var boxHeight = $box.innerHeight();
96
97				// この領域が画面内に表示されている場合
98				if ((winScrollTop + winHeight > boxOffsetTop - 10) && (boxOffsetTop + boxHeight > winScrollTop + 10)) {
99					var offsetY = Math.round(((winScrollTop - boxOffsetTop - boxHeight / 2 + winHeight / 2) * elemSettings[i].speed - elemSettings[i].imageOffsetY) * 2) / 2;
100					// translate3dだとchromeで表示領域にぼかしがかかる
101					$elem.css('transform', 'translateY(' + offsetY + 'px)');
102
103					// オーバーレイぼかしありの場合
104					if (elemSettings[i].$overlayBlurInner) {
105						elemSettings[i].$overlayBlurInner.css('transform', 'translateY(' + offsetY + 'px)');
106					}
107				}
108
109			// 全体ぼかしなし
110			} else {
111				var $elem = $(this);
112				var boxOffsetTop = Math.ceil($elem.offset().top);
113				var boxHeight = $elem.innerHeight();
114
115				// この領域が画面内に表示されている場合
116				if ((winScrollTop + winHeight > boxOffsetTop - 10) && (boxOffsetTop + boxHeight > winScrollTop + 10)) {
117					var offsetY = Math.round(((winScrollTop - boxOffsetTop - boxHeight / 2) * elemSettings[i].speed - elemSettings[i].imageOffsetY) * 2) / 2;
118					$elem.css('backgroundPositionY', offsetY);
119
120					// オーバーレイぼかしありの場合
121					if (elemSettings[i].$overlayBlurInner) {
122						var overlayOffsetY = Math.round(((winScrollTop - boxOffsetTop - boxHeight / 2 + winHeight / 2) * elemSettings[i].speed - elemSettings[i].imageOffsetY) * 2) / 2;
123						// translate3dだとchromeで表示領域にぼかしがかかる
124						elemSettings[i].$overlayBlurInner.css('transform', 'translateY(' + overlayOffsetY + 'px)');
125					}
126				}
127			}
128		});
129	};
130	$window.on('load scroll', parallaxBgScroll);
131
132	// 背景画像サイズ計算
133	var parallaxCalcBgImageSize = function(i){
134		var $elem = $elems.eq(i);
135		var img, $box, boxHeight, boxWidth, backgroundImageHeight, backgroundImageWidth;
136
137		if (isParallaxMobile && mobileImages[i].img.src) {
138			if (!mobileImages[i].img.complete) return;
139			img = mobileImages[i].img;
140		} else {
141			if (!images[i].img.complete) return;
142			img = images[i].img;
143		}
144
145		// 画像変更
146		if (elemSettings[i].currentImageSrc !== img.src) {
147			$elem.css('backgroundImage', 'url(' + img.src + ')');
148			elemSettings[i].currentImageSrc = img.src;
149
150			// SVGぼかしあり(全体ぼかし・オーバーレイぼかし兼用)
151			if (useSvgBlur) {
152				for (var j = 0; j < elemSettings[i].svgs.length; j++) {
153					elemSettings[i].svgs[j].find('image').attr('xlink:href', img.src);
154				}
155
156			// filter:blurのオーバーレイぼかしあり
157			} else if (elemSettings[i].$overlayBlurInner) {
158				elemSettings[i].$overlayBlurInner.css('backgroundImage', 'url(' + img.src + ')');
159			}
160		}
161
162		// 全体ぼかしあり
163		if (elemSettings[i].blur) {
164			$box = $elem.offsetParent();
165			boxHeight = $box.innerHeight();
166			boxWidth = $box.innerWidth();
167
168			// パララックス効果分込みで必要な画像の高さ
169			var parallaxHeight = Math.ceil(winHeight * elemSettings[i].speed + boxHeight);
170
171			// ぼかしのフチの透過領域込みのサイズ
172			var parallaxBlurHeight = parallaxHeight + elemSettings[i].blur * 2 * 2;
173			var parallaxBlurWidth = boxWidth + elemSettings[i].blur * 2 * 2;
174
175			var parallaxRatio, imgRatio;
176			parallaxRatio = parallaxBlurWidth / parallaxBlurWidth;
177			imgRatio = img.width / img.height;
178
179			// 画像の方が横長
180			if (parallaxRatio < imgRatio) {
181				backgroundImageWidth = Math.ceil(parallaxBlurHeight / img.height * img.width);
182				backgroundImageHeight = parallaxBlurHeight;
183				elemSettings[i].imageOffsetX = (backgroundImageWidth - parallaxBlurWidth) / 2 + elemSettings[i].blur * 2;
184				elemSettings[i].imageOffsetY = 0;
185			// 画像の方が縦長
186			} else {
187				backgroundImageHeight = Math.ceil(parallaxBlurWidth / img.width * img.height);
188				backgroundImageWidth = parallaxBlurWidth;
189				elemSettings[i].imageOffsetX = elemSettings[i].blur * 2;
190				elemSettings[i].imageOffsetY = 0;
191			}
192
193			$elem.css({
194				height: backgroundImageHeight,
195				width: backgroundImageWidth,
196				bottom: 'auto',
197				left: elemSettings[i].imageOffsetX * -1,
198				right: 'auto',
199				top: (backgroundImageHeight - boxHeight) / -2
200			});
201
202			// スクロール0時に画面内にある場合は天地位置調整
203			var boxOffsetTop = Math.ceil($box.offset().top);
204			if (boxOffsetTop + boxHeight < winHeight) {
205				elemSettings[i].imageOffsetY += Math.ceil((winHeight / 2 - boxOffsetTop - boxHeight / 2) * elemSettings[i].speed);
206			}
207
208		// ぼかしなし
209		} else {
210			$box = $elem;
211			boxHeight = $box.innerHeight();
212			boxWidth = $box.innerWidth();
213
214			// パララックス効果分込みで必要な画像の高さ
215			var parallaxHeight = Math.ceil(winHeight * elemSettings[i].speed + boxHeight);
216
217			var parallaxRatio, imgRatio;
218			parallaxRatio = boxWidth / parallaxHeight;
219			imgRatio = img.width / img.height;
220
221			// 画像の方が横長
222			if (parallaxRatio < imgRatio) {
223				backgroundImageHeight = parallaxHeight;
224				backgroundImageWidth = Math.ceil(parallaxHeight / img.height * img.width);
225				$elem.css('backgroundSize', backgroundImageWidth + 'px ' + parallaxHeight + 'px');
226				elemSettings[i].imageOffsetY = 0;
227			// 画像の方が縦長
228			} else {
229				$elem.css('backgroundSize', 'cover');
230				backgroundImageHeight = Math.ceil(boxWidth / img.width * img.height);
231				backgroundImageWidth = boxWidth;
232				elemSettings[i].imageOffsetY = (backgroundImageHeight - parallaxHeight) / 2;
233			}
234
235			// スクロール0時に画面内にある場合は天地位置調整
236			var boxOffsetTop = Math.ceil($elem.offset().top);
237			if (boxOffsetTop + boxHeight < winHeight) {
238				elemSettings[i].imageOffsetY += Math.ceil((winHeight / 2 - boxOffsetTop - boxHeight / 2) * elemSettings[i].speed);
239			}
240		}
241
242		// オーバーレイぼかしありの場合
243		if (elemSettings[i].$overlayBlur) {
244			var boxOffset = $box.offset();
245			elemSettings[i].$overlayBlur.each(function(){
246				var $this = $(this);
247				var offset = $this.offset();
248				var $inner = $this.find('.parallax-overlay-blur-inner');
249
250				$inner.css({
251					height: backgroundImageHeight,
252					width: backgroundImageWidth,
253					position: 'absolute',
254					bottom: 'auto',
255					right: 'auto',
256					left: (backgroundImageWidth - boxWidth) / -2 + boxOffset.left - offset.left,
257					top: (backgroundImageHeight - boxHeight) / -2 + boxOffset.top - offset.top,
258				});
259			});
260		}
261	};
262
263	// 初期化
264	$elems.each(function(i){
265		var $elem = $(this);
266		var src = $elem.attr('data-parallax-image');
267		var srcMobile = $elem.attr('data-parallax-mobile-image');
268
269		if (!src && srcMobile) {
270			src = srcMobile;
271			srcMobile = null;
272		}
273
274		var initialSrc = src;
275
276		// パララックススクロール係数
277		var speed = parseFloat($elem.attr('data-parallax-speed'));
278		if (isNaN(speed) || speed < 0 || speed > 1) {
279			speed = parseFloat(defaultSpeed) || 0;
280		}
281
282		// 全体ぼかし
283		var blur = parseFloat($elem.attr('data-parallax-blur'));
284		if (isNaN(blur) || blur < 0) {
285			blur = parseFloat(defaultBlur) || 0;
286		}
287		if (blur > 0) {
288			var pos = $elem.css('position');
289			if (pos !== 'absolute' && pos !== 'fixed') {
290				blur = 0;
291			}
292		}
293
294		elemSettings[i] = {
295			speed: speed,
296			blur: blur
297		};
298
299		// 画像オブジェクト初期化
300		images[i] = {};
301		images[i].img = new Image();
302		mobileImages[i] = {};
303		mobileImages[i].img = new Image();
304
305		// スマホの場合は1画像のみ
306		if (isSmartPhone && srcMobile) {
307			src = srcMobile;
308			initialSrc = srcMobile;
309			srcMobile = null;
310		}
311
312		// オーバーレイぼかし
313		var $closest, $overlayBlur;
314		var elemPosition = $elem.css('position');
315		if (elemPosition === 'relative') {
316			$closest = $elem;
317		} else if (elemPosition === 'absolute' || elemPosition === 'fixed') {
318			$closest = $elem.offsetParent();
319		}
320		if ($closest) {
321			$overlayBlur = $closest.find('[data-parallax-overlay-blur]').not('[data-parallax-overlay-blur=""], [data-parallax-overlay-blur="0"]');
322		}
323
324		// モバイルの場合でモバイル画像ありなら初期画像変更
325		if (isParallaxMobile && srcMobile) {
326			initialSrc = srcMobile;
327		}
328
329		// オーバーレイぼかしありの場合、子要素生成
330		if ($overlayBlur.length) {
331			$overlayBlur.each(function(){
332				var parallaxOverlayBlur= parseFloat(this.dataset.parallaxOverlayBlur);
333				if (isNaN(parallaxOverlayBlur) || parallaxOverlayBlur < 0) {
334					return;
335				}
336
337				var $inner = $('<div class="parallax-overlay-blur-inner"></div>');
338
339				// SVGでのぼかし
340				if (useSvgBlur) {
341					var $svg = parallaxCreateSvg(initialSrc, parallaxOverlayBlur);
342					$inner.html($svg);
343					if (!elemSettings[i].svgs) {
344						elemSettings[i].svgs = [];
345					}
346					elemSettings[i].svgs.push = $svg;
347
348				// filter:blurでのぼかし
349				} else {
350					$inner.css({
351						backgroundImage: 'url(' + initialSrc + ')',
352						backgroundPositionX: 'center',
353						backgroundPositionY: 'center',
354						backgroundRepeat: 'no-repeat',
355						backgroundSize: 'cover',
356						filter: 'blur(' + parallaxOverlayBlur + 'px)'
357					});
358				}
359
360				$(this).css({
361					overflow: 'hidden',
362					position: 'absolute',
363					bottom: 0,
364					right: 0,
365					left: 0,
366					top: 0,
367					zIndex: -1
368				}).html($inner);
369			});
370
371			elemSettings[i].$overlayBlur = $overlayBlur;
372			elemSettings[i].$overlayBlurInner = $closest.find('.parallax-overlay-blur-inner');
373		}
374
375		// 全体ぼかしあり
376		if (elemSettings[i].blur) {
377			// SVGでのぼかし
378			if (useSvgBlur) {
379				var $svg = parallaxCreateSvg(initialSrc, elemSettings[i].blur);
380				$elem.html($svg);
381				if (!elemSettings[i].svgs) {
382					elemSettings[i].svgs = [];
383				}
384				elemSettings[i].svgs.push = $svg;
385
386			// filter:blurでのぼかし
387			} else {
388				$elem.css({
389					backgroundImage: 'url(' + initialSrc + ')',
390					backgroundPositionX: 'center',
391					backgroundPositionY: 'center',
392					backgroundRepeat: 'no-repeat',
393					backgroundSize: 'cover',
394					filter: 'blur(' + elemSettings[i].blur + 'px)'
395				});
396			}
397
398		// 全体ぼかしなし
399		} else {
400			$elem.css({
401				backgroundImage: 'url(' + initialSrc + ')',
402				backgroundPositionX: 'center',
403				backgroundPositionY: 'center',
404				backgroundRepeat: 'no-repeat',
405				backgroundSize: 'cover'
406			});
407		}
408
409		// モバイルの場合でモバイル画像あり
410		if (isParallaxMobile && srcMobile) {
411			// 画像を読み込んでからサイズ計算
412			var img = mobileImages[i].img;
413			img.onload = function() {
414				parallaxCalcBgImageSize(i);
415			};
416			img.src = srcMobile;
417			if (img.complete) {
418				parallaxCalcBgImageSize(i);
419			}
420
421			elemSettings[i].currentImageSrc = srcMobile;
422			images[i].img.src = src;
423
424		// PCの場合
425		} else if (src) {
426			// 画像を読み込んでからサイズ計算
427			var img = images[i].img;
428			img.onload = function() {
429				parallaxCalcBgImageSize(i);
430			};
431			img.src = src;
432			if (img.complete) {
433				parallaxCalcBgImageSize(i);
434			}
435
436			elemSettings[i].currentImageSrc = src;
437
438			if (srcMobile) {
439				mobileImages[i].img.src = srcMobile;
440			}
441		}
442	});
443
444	parallaxBgScroll();
445
446	// リサイズ
447	$window.on('resize', function(){
448		clearTimeout(resizeTimer);
449		resizeTimer = setTimeout(function(){
450			var w = window.innerWidth || $body.width();
451			var h = window.innerHeight || $window.innerHeight();
452
453			// モバイルでスクロール時のアドレスバー表示トグルでresizeイベントが実行されるため横幅のみで判定
454			if (isMobile && winWidth !== w || (!isMobile && (winWidth !== w || winHeight !== h))) {
455				winWidth = w;
456				winHeight = h;
457				isParallaxMobile = checkParallaxMobile();
458
459				$elems.each(function(i){
460					parallaxCalcBgImageSize(i);
461				});
462				parallaxBgScroll();
463			}
464		}, isIE ? 100 : 16.6666);
465	});
466
467	// iOS系 ブラウザ戻る対策
468	var isIOS = (ua.indexOf('iphone') > -1 || ua.indexOf('ipad') > -1 || ua.indexOf('ipod') > -1 );
469	if (isIOS) {
470		window.addEventListener('pageshow', function(event) {
471			if (event.persisted) {
472				parallaxBgScroll();
473			}
474		});
475	}
476
477});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.