You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React实现图片自适应所有设备屏幕及方向,无变形无滚动

React 全屏图片适配问题

我在React项目中有一个轮播组件,希望图片能在任意设备屏幕及横竖屏方向上实现最佳适配——图片保持原有宽高比缩放,直至触达屏幕上下或左右边界,且不会出现滚动条遮挡图片的情况。目前组件功能存在问题,尤其是移动端切换横竖屏及缩放时bug频发。为简化问题,我提供了一个具有相同样式逻辑的单图展示组件代码:

FullscreenImage.tsx

import React from "react";
import useWindowDimensions from "./hooks/useWindowDimensions";

interface IProps {
  imageUrl: string;
}

const FullscreenImage = (props: IProps) => {
  const { imageUrl } = props;
  const { height, width } = useWindowDimensions();

  return (
    <div style={{ width: width, height: height }}>
      <img
        style={{
          height: width <= height ? "auto" : height,
          width: height > width ? width : "auto",
          margin: "auto",
          display: "block"
        }}
        src={imageUrl}
        alt="picsumimage"
      />
    </div>
  );
};

export default FullscreenImage;

useWindowDimensions.tsx

import { useState, useEffect } from "react";

function getWindowDimensions() {
  const { innerWidth: width, innerHeight: height } = window;
  return {
    width,
    height
  };
}

const useWindowDimensions = () => {
  const [windowDimensions, setWindowDimensions] = useState(
    getWindowDimensions()
  );

  useEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }

    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return windowDimensions;
};

export default useWindowDimensions;

问题分析与修复方案

当前实现存在几个核心问题:

  1. 使用window.innerWidth/innerHeight会包含浏览器滚动条宽度,导致图片被遮挡
  2. 横竖屏切换时,部分设备的resize事件触发不及时或不准确
  3. 手动判断宽高比的逻辑容易出错,且未考虑图片自身的宽高比

修复后的实现

1. 优化窗口尺寸钩子(重命名为useViewportDimensions)

改用document.documentElement.clientWidth/clientHeight获取不含滚动条的视口尺寸,同时添加orientationchange事件监听横竖屏切换:

import { useState, useEffect } from "react";

function getViewportDimensions() {
  const { clientWidth: width, clientHeight: height } = document.documentElement;
  return { width, height };
}

const useViewportDimensions = () => {
  const [dimensions, setDimensions] = useState(getViewportDimensions());

  useEffect(() => {
    const handleResize = () => setDimensions(getViewportDimensions());
    
    window.addEventListener("resize", handleResize);
    window.addEventListener("orientationchange", handleResize);
    
    return () => {
      window.removeEventListener("resize", handleResize);
      window.removeEventListener("orientationchange", handleResize);
    };
  }, []);

  return dimensions;
};

export default useViewportDimensions;
2. 改用CSS object-fit实现自适应(推荐)

无需手动计算宽高比,利用CSS的object-fit: contain属性自动保持图片比例并适配容器,同时设置容器为全屏视口:

import React from "react";
import useViewportDimensions from "./hooks/useViewportDimensions";

interface IProps {
  imageUrl: string;
}

const FullscreenImage = (props: IProps) => {
  const { imageUrl } = props;
  const { width, height } = useViewportDimensions();

  return (
    <div 
      style={{
        width: width,
        height: height,
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        overflow: "hidden"
      }}
    >
      <img
        style={{
          maxWidth: "100%",
          maxHeight: "100%",
          objectFit: "contain"
        }}
        src={imageUrl}
        alt="picsumimage"
      />
    </div>
  );
};

export default FullscreenImage;
3. 进阶优化:基于图片宽高比精准适配

如果需要更精细的控制,可以预先获取图片宽高比,减少窗口resize时的重渲染次数:

import React, { useState, useEffect } from "react";
import useViewportDimensions from "./hooks/useViewportDimensions";

interface IProps {
  imageUrl: string;
}

const FullscreenImage = (props: IProps) => {
  const { imageUrl } = props;
  const { width, height } = useViewportDimensions();
  const [imageRatio, setImageRatio] = useState<number>(1);

  useEffect(() => {
    const img = new Image();
    img.src = imageUrl;
    img.onload = () => {
      setImageRatio(img.width / img.height);
    };
  }, [imageUrl]);

  const containerRatio = width / height;
  const imgStyle = containerRatio > imageRatio 
    ? { width: "auto", height: "100%" } 
    : { width: "100%", height: "auto" };

  return (
    <div 
      style={{
        width: width,
        height: height,
        display: "flex",
        justifyContent: "center",
        alignItems: "center"
      }}
    >
      <img
        style={{ ...imgStyle }}
        src={imageUrl}
        alt="picsumimage"
      />
    </div>
  );
};

export default FullscreenImage;

关键改进点

  • 使用document.documentElement.clientWidth/clientHeight获取准确的视口尺寸(不含滚动条)
  • 添加orientationchange事件监听横竖屏切换,确保移动端适配及时
  • 利用CSS object-fit: contain简化自适应逻辑,避免手动计算错误
  • 可选:预先获取图片宽高比,实现更精准的尺寸控制

内容的提问来源于stack exchange,提问作者Samuel Zrna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:06:25