Nuxt3.js移动端Pc端自适应解决方案:使用flexible.js和postcss-pxtorem实现傻瓜式Px转Rem

需求场景

Nuxt 3 项目,设计稿移动端是 750 像素宽,Pc 端是 1920 像素宽,要在一个项目里都跑 —— 移动端写 32px 字号自动按比例缩放,Pc 端原样显示。

核心思路:flexible.js 根据设备宽度动态设置根字号 html.style.fontSize,然后用 postcss-pxtorem 在构建期把代码里的 px 自动转 rem。这样写代码时永远写 px,运行时自动适配。

Nuxt3 移动端 Pc 端自适应方案

方案核心:flexible.js + postcss-pxtorem

  • flexible.js —— 阿里 lib-flexible,运行时根据屏幕宽度调整 htmlfont-size,这样 1rem 等于 (屏幕宽 / 10) px
  • postcss-pxtorem —— PostCSS 插件,把所有 px 在 CSS 编译时除以一个值,转成 rem

结果就是你写 font-size: 32px;,实际跑出来根据屏幕宽度自动调整。傻瓜式,不用思考。

移动端自适应

项目依赖

{
  "name": "nuxt-app",
  "private": true,
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "devDependencies": {
    "@types/node": "^18",
    "nuxt": "^3.5.0",
    "postcss": "^8.4.23",
    "postcss-pxtorem": "^6.0.0"
  },
  "dependencies": {
    "less": "^4.1.3"
  }
}

nuxt.config.ts 配置 postcss

// nuxt.config.ts
export default defineNuxtConfig({
    postcss: {
        plugins: {
            'postcss-pxtorem': {
                rootValue: 75,           // 设计稿宽度 / 10 (750 设计稿就 75)
                propList: ['*'],         // 所有属性都转
                selectorBlackList: [/^.pc-/],   // 类名以 .pc- 开头的不转(Pc 专用)
                minPixelValue: 2,        // 小于 2px 不转
                exclude: /node_modules/i
            }
        }
    }
})

核心两个参数:

  • rootValue: 75 —— 设计稿 750px,转换基准是 75。配合 flexible.js 把屏幕分成 10 份的逻辑。
  • selectorBlackList —— 黑名单,匹配的选择器不转 px。这是关键,后面 PC 适配靠它。

引入 flexible.js

Nuxt 3 客户端插件:

// plugins/flexible.client.ts
import 'amfe-flexible'
export default defineNuxtPlugin(() => {})

amfe-flexible 是 lib-flexible 的官方继任者(amfe = 阿里移动前端组),包名变了但功能一样。装一下:

npm install amfe-flexible

文件名结尾 .client.ts 关键:Nuxt 3 约定只在客户端执行这个插件,SSR 阶段不跑(因为服务端没 window,flexible.js 会报错)。

PC 端怎么不被转

核心技巧:Pc 端用专属 class 前缀(pc-desktop-),postcss 黑名单跳过这些选择器。

实际例子:

<template>
    <!-- 移动端布局 — 写的 px 会被转 rem,自动适配 -->
    <div v-if="isMobile" class="m-page">
        <h1 class="m-title">标题</h1>
    </div>

    <!-- Pc 端布局 — class 名 pc- 开头,px 不转 -->
    <div v-else class="pc-page">
        <h1 class="pc-title">Title</h1>
    </div>
</template>

<style lang="less" scoped>
.m-page {
    padding: 30px;
    .m-title { font-size: 36px; }   /* → rem,屏幕宽度自动缩放 */
}
.pc-page {
    padding: 60px;
    .pc-title { font-size: 48px; }  /* → 保留 px,固定大小 */
}
</style>

判断当前是 PC 还是移动端

客户端的 composable:

// composables/useDevice.ts
export const useDevice = () => {
    const isMobile = ref(false)
    if (process.client) {
        const check = () => {
            isMobile.value = window.innerWidth < 768
        }
        check()
        window.addEventListener('resize', check)
        onBeforeUnmount(() => window.removeEventListener('resize', check))
    }
    return { isMobile }
}

更稳的方式是用 VueUseuseMediaQuery:

import { useMediaQuery } from '@vueuse/core'

const isMobile = useMediaQuery('(max-width: 767px)')

SSR 阶段的坑

Nuxt 是 SSR,服务器渲染时没有 window,useDevice 第一次拿到 isMobile 一定是 false。客户端水合后才更新。这会导致首屏闪烁(Pc 布局闪一下变成移动端)。

解决:用 User-Agent 在服务端判断:

// composables/useDevice.ts
export const useDevice = () => {
    const headers = useRequestHeaders(['user-agent'])
    const ua = headers['user-agent'] || ''
    const isMobile = ref(/Mobile|Android|iPhone|iPad/i.test(ua))

    // 客户端校正(防止 UA 误判)
    onMounted(() => {
        isMobile.value = window.innerWidth < 768
    })

    return { isMobile }
}

这样 SSR 时已经按 UA 判断好了,客户端水合时再用屏幕宽度做精确校正,首屏不闪。

下载示例项目

把完整代码打包了两份,直接 clone 看 / 跑:

替代方案对比

方案 原理 优点 缺点
flexible + pxtorem 动态根字号 + 自动转 rem 最傻瓜,代码里只写 px 需要黑名单分 Pc/移动
vw 单位 postcss-px-to-viewport 转 vw 不依赖 JS,纯 CSS 超大屏(平板横屏)字会过大
UnoCSS / TailwindCSS 原子化 class + 响应式断点 最现代,可控性最强 学习成本,改设计稿对应难

新项目我个人更倾向 UnoCSS / Tailwind,旧项目转 rem 的成本最低,看场景挑。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

前端解决无法创建Nuxt3项目!

2023-5-17 15:08:10

技术教程

Vue2移动端使用felxbilejs自适应

2023-5-19 15:30:41

2 条回复 A文章作者 M管理员
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索