PageSourceSearch

https://soulbeauty.jp/app/wp-content/themes/drop_tcd087/js/parallax.js?ver=2.0.1

js soulbeauty.jp collected 2026-09-24 15:05:09 UTC 19,603 bytes, 552 lines download raw bytes

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

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.