JSFiddle - React, Tailwind, and code Playground

by HDL52

HTML

<div class="container">
   <img src="https://raw.githubusercontent.com/Hongda-OSU/PicGo-2.3.1/master/imgfront_page_app.6d99061.png" alt="Flipping Image" id="flippingImage">
 </div>

CSS

body,
html {
  height: 200%;
  margin: 0;
  overflow-x: hidden;
  width: 100%;
}

.container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  height: 200vh;
  perspective: 1000px;
  padding-top: 300px;
}

img {
  width: 500px;
  height: auto;
  transform: translateY(-20px) rotateX(-15deg);
  /* 初始时稍微向上倾斜 */
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  box-shadow: 0px 22.5px 22.5px rgba(0, 0, 0, 0.5);
  /* 初始的阴影效果 */
}

JavaScript

document.addEventListener('DOMContentLoaded', () => {
  const image = document.getElementById('flippingImage');
  const initialRotation = -15;
  const shadowOffsetX = initialRotation * -1.5;
  const shadowOffsetY = Math.abs(initialRotation * 1.5);
  const shadowBlur = 30;
  const shadowOpacity = 0.5;

  image.style.boxShadow = `${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px rgba(0, 0, 0, ${shadowOpacity})`;
});

document.addEventListener('scroll', () => {
  const image = document.getElementById('flippingImage');
  const scrollPosition = window.scrollY;
  const screenHeight = window.innerHeight;

  // 初始角度是 -15 度,最大向下旋转角度为 30 度
  const initialRotation = -15;
  const maxRotation = 30;
  const rotationRange = maxRotation - initialRotation;

  let rotationAngle = initialRotation + (scrollPosition / screenHeight) * rotationRange;

  // 确保角度不会超过最大值
  if (rotationAngle > maxRotation) rotationAngle = maxRotation;
  if (rotationAngle < initialRotation) rotationAngle = initialRotation;

  // 动态调整阴影效果
  const shadowOffsetX = rotationAngle * -1.5;
  const shadowOffsetY = Math.abs(rotationAngle * 1.5);
  const shadowBlur = 30;
  const shadowOpacity = 0.5;

  image.style.transform = `translateY(-20px) rotateX(${rotationAngle}deg)`;
  image.style.boxShadow = `${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px rgba(0, 0, 0, ${shadowOpacity})`;
});