问题描述:
有个插件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('');
}, []);