前端自适应布局之等比例缩放

问题描述:

有个插件Postcss-pxtorem能自动转换px做适配,但是某些插件不能转换,例如antd。

设计图只有一套1920*1080.要做到尽量1比1还原,又能适配大小屏幕,如果一个个转百分比会非常麻烦。

这时就可以选择用等比例缩放实现自适应布局。
运行环境 :react+umi(其他也可用,原理一样)

1.根据设计图1比1写px。

2.在layout写

复制代码
import React, { useEffect, useRef, useState } from 'react';
import { Outlet } from '@umijs/max';
import styles from './ScaleLayout.less';
import { LayoutProvider } from './context';

const ScaleLayout: React.FC = () => {
  const [bg, setBgState] = useState('');

  const scaleRootRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const setScale = () => {
      const scaleX = window.innerWidth / 1920;
      const scaleY = window.innerHeight / 1080;
      // Use Math.min to fit the screen while maintaining aspect ratio (letterboxing)
      const scale = Math.min(scaleX, scaleY);
      console.log('scale', scale);

      if (scaleRootRef.current) {
        scaleRootRef.current.style.transform = `scale(${scale})`;
      }
    };

    // Initial scale
    setScale();
    
    // Add event listener
    window.addEventListener('resize', setScale);
    
    // Cleanup
    return () => window.removeEventListener('resize', setScale);
  }, []);

  return (
    <LayoutProvider value={{ setBg: setBgState }}>
      <div className={styles.viewport}>
        <div className={styles.pageBg} style={{ backgroundImage: bg ? `url(${bg})` : 'none' }} />
        <div className={styles.scaleRoot} ref={scaleRootRef}>
          <Outlet />
        </div>
      </div>
    </LayoutProvider>
  );
};

export default ScaleLayout;

layout样式:

复制代码
.viewport {
  width: 100vw;
  height: 100vh;
  background: #050b16; // Match the app's dark theme
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* 页面背景层(不参与缩放) */
.pageBg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  z-index: 0;

}
.scaleRoot {
  width: 1920px;
  height: 1080px;
  transform-origin: center center;
  flex-shrink: 0;
  overflow: hidden;
}

背景有黑边?把背景提到缩放盒子外边。这样就能实现内容的1比1,又不会太难看。

context.tsx

复制代码
import React, { createContext, useContext, useState } from 'react';

interface LayoutContextType {
  setBg: (bg: string) => void;
}

const LayoutContext = createContext<LayoutContextType | undefined>(undefined);

export const useLayout = () => {
  const context = useContext(LayoutContext);
  if (!context) {
    throw new Error('useLayout must be used within a LayoutProvider');
  }
  return context;
};

export const LayoutProvider: React.FC<{ children: React.ReactNode; value: LayoutContextType }> = ({ children, value }) => {
  return <LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>;
};

页面设置背景

复制代码
import { useLayout } from '@/layouts/context';
import bg from '@/assets/imgs/training/zice/learn_sel_bg.png'
const { setBg } = useLayout();
  useEffect(() => {
    setBg(bg);
    return () => setBg('');
  }, []);
相关推荐
我是唐青枫13 分钟前
Kotlin Delegation 委托详解
开发语言·kotlin
qq_4069810317 分钟前
共享变量一 关于extern与const
开发语言·c++
FRing031 小时前
JavaScript入门到精通三十二(深拷贝、浅拷贝、递归函数)
开发语言·前端·javascript
excel1 小时前
双 Token 与前端使用 Crypto 公私钥鉴权换 Token,哪种方案更好?
前端·后端
外收内放1 小时前
Python基础语法练习题(73)
java·前端·python
风骏时光牛马2 小时前
面向复杂场景的大模型应用落地与能力优化实践
前端
小小善后师2 小时前
我做了个病历归档小程序,被 AI 识别的"最后一公里"狠狠上了一课
前端
小嘉丶学长2 小时前
Day14 · 字典与集合
java·开发语言·网络·python·学习·1024程序员节
H_Lisa2 小时前
我用 Express 写了个 MCP,Claude 直接调用我的 API 了
前端
IT_陈寒2 小时前
React的useEffect依赖数组把我坑惨了
前端·人工智能·后端