| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- /**
- * viewport 适配工具 - 移动端适配方案
- *
- * 支持两套设计稿(当前统一为 393 × 852):
- * - mvp:393 × 852(默认)
- * - v2:393 × 852(与 mvp 一致,便于旧页面显式传参)
- *
- * 适配策略:
- * - CSS 文件:使用 postcss-px-to-viewport 自动转换 px 为 vw
- * - 内联样式:使用工具函数手动转换,可按页面传入 design 指定设计稿
- *
- * 单位选择规则:
- * - 横向属性 → px2vw(px, design?)
- * - 纵向属性 → px2vh(px, design?)
- * - 宽高皆用 → px2vmin(px, design?) / px2vmax(px, design?)
- * - 字体 → px2fluidFontSize(px, options?)
- */
- /** 设计稿规格:mvp / v2 均为 393×852 */
- export type ViewportDesign = 'mvp' | 'v2';
- const DESIGN_SPECS: Record<ViewportDesign, { width: number; height: number }> = {
- mvp: { width: 393, height: 852 },
- v2: { width: 393, height: 852 },
- };
- /**
- * px 转 vw 辅助函数(用于内联样式)
- * - 视口宽度 > 500px 时按 500px 封顶
- * - 使用 --vw(visualViewport)解决曲面屏问题
- *
- * @param px 设计稿上的 px 值
- * @param design 设计稿规格,默认 'mvp'(393×852)
- */
- export const px2vw = (px: number, design: ViewportDesign = 'mvp'): string => {
- const baseWidth = DESIGN_SPECS[design].width;
- return `calc(${px} * min(var(--vw, 1vw) * 100, 500PX) / ${baseWidth})`;
- };
- /**
- * px 转 vh 辅助函数(用于内联样式中的高度)
- * 使用 --vh 避免移动端地址栏/工具栏影响
- *
- * @param px 设计稿上的 px 值
- * @param design 设计稿规格,默认 'mvp'(393×852)
- */
- export const px2vh = (px: number, design: ViewportDesign = 'mvp'): string => {
- const baseHeight = DESIGN_SPECS[design].height;
- const ratio = (px / baseHeight) * 100;
- return `calc(${ratio} * var(--vh, 1vh))`;
- };
- /**
- * px 转最小视口单位(min(vw, vh)),确保任意宽高比下不过度放大
- *
- * @param px 设计稿上的 px 值
- * @param design 设计稿规格,默认 'mvp'
- */
- export const px2vmin = (px: number, design: ViewportDesign = 'mvp'): string => {
- return `min(${px2vw(px, design)}, ${px2vh(px, design)})`;
- };
- /**
- * px 转最大视口单位(max(vw, vh)),确保能填满视口
- *
- * @param px 设计稿上的 px 值
- * @param design 设计稿规格,默认 'mvp'
- */
- export const px2vmax = (px: number, design: ViewportDesign = 'mvp'): string => {
- return `max(${px2vw(px, design)}, ${px2vh(px, design)})`;
- };
- /**
- * px 转流体字体大小(clamp + min(vw, vh))
- *
- * @param px 设计稿上的 px 值
- * @param options 可选:minRatio、maxRatio;design 指定设计稿(默认 'mvp')
- */
- export const px2fluidFontSize = (
- px: number,
- options?: { minRatio?: number; maxRatio?: number; design?: ViewportDesign }
- ): string => {
- const design = options?.design ?? 'mvp';
- const { width: baseWidth, height: baseHeight } = DESIGN_SPECS[design];
- const minRatio = options?.minRatio ?? 0.8;
- const maxRatio = options?.maxRatio ?? 1.2;
- const minSize = px * minRatio;
- const maxSize = px * maxRatio;
- const vwSize = (px / baseWidth) * 100;
- const vhSize = (px / baseHeight) * 100;
- return `clamp(${minSize}px, min(${vwSize}vw, ${vhSize}vh), ${maxSize}px)`;
- };
|