Steamer Lane Studio技術備忘録ユーティリティ

apple/Macサイトでみられるスクロール量によるオブジェクト拡大

utility apple/Macサイトでみられるスクロール量によるオブジェクト拡大
作成日: 2025年6月21日

表題の件、そのためのスクリプト他を作った。
落ちてるもんではなく、都合にあったもん。入れ子がビューポートに入ったら発火し、スクロール量に応じ拡大する。

サンプル

スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン
スクロールするためのマージン

apple/Macサイトでみられるスクロール量によるオブジェクト拡大

以下コード

<script>// Set minimum and maximum scale valuesconst MIN_SCALE = 0.5;let MAX_SCALE; // Max scale dynamically set based on devicefunction setMaxScaleBasedOnDevice() {const screenWidth = window.innerWidth;if (screenWidth < 768) { // Smartphone (e.g., less than 768px)MAX_SCALE = 1.0; // Smaller scale for smartphones} else { // PC (768px or more)MAX_SCALE = 1.0; // Standard scale for PCs}}setMaxScaleBasedOnDevice();window.addEventListener('resize', setMaxScaleBasedOnDevice);function updateImageScale(element, container) {const rect = container.getBoundingClientRect();const viewportHeight = window.innerHeight;const animationStartPoint = viewportHeight;const animationEndPoint = 0;const containerTop = rect.top;let progress = 1 - (containerTop - animationEndPoint) / (animationStartPoint - animationEndPoint);progress = Math.max(0, Math.min(1, progress));

const scale = MIN_SCALE + (MAX_SCALE - MIN_SCALE) * progress;element.style.setProperty('--current-scale', scale);}const observerOptions = {root: null,rootMargin: '0px',threshold: 0};

const observer = new IntersectionObserver((entries, observer) => {entries.forEach(entry => {const container = entry.target;const image = container.querySelector('img');if (!image) return; // Do nothing if no image is foundif (entry.isIntersecting) {const scrollHandler = () => updateImageScale(image, container);window.addEventListener('scroll', scrollHandler);container._scrollHandler = scrollHandler;updateImageScale(image, container);} else {if (container._scrollHandler) {window.removeEventListener('scroll', container._scrollHandler);container._scrollHandler = null;}const rect = container.getBoundingClientRect();const viewportHeight = window.innerHeight;

if (rect.bottom <= 0) {image.style.setProperty('--current-scale', MAX_SCALE);} else if (rect.top >= viewportHeight) {image.style.setProperty('--current-scale', MIN_SCALE);}}});}, observerOptions);

// Add all .scroll-effect elements to be observeddocument.querySelectorAll('.scroll-effect').forEach(element => {observer.observe(element);});</script>
<style><!--.scroll-effect {position:relative;display:inline-block;width:100%;max-width:1000px;text-align:center;}

.scroll-effect img {width: 100%;height: auto;transform: scale(var(--current-scale, 1));transform-origin: center bottom;transition: transform 0.05s linear;object-fit: cover;}--></style>

属性はscript css共に適宜変更。