Home

Awesome

postcss-mobile-forever

<img src="https://postcss.github.io/postcss/logo.svg" alt="PostCSS" width="90" height="90" align="right">

<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" align="right"></a>

⚠️ Warning

使用本插件转换的 vw,或是其它使用动态根元素 font-size 结合 rem,这两种方法生成的伸缩视图,不能触发浏览器的缩放功能(可以通过快捷键同时按下 <kbd>Cmd/Ctrl</kbd><kbd>+/-</kbd> 触发),不能满足针对缩放的可访问性标准,因此存在可访问性问题。查看一个关于 vw 伸缩视图的可访问性实验

不同设备上的界面一致,不等于用户体验一致,使用 vw(或 rem)做移动端适配,是一种粗暴的、技术先于设计的适配方法,是一条技术捷径,请考虑站在用户的角度、利用专业知识,使用响应式设计开发页面,使得用户在大尺寸设备上看到更丰富的内容,在小尺寸设备上看到更简洁的内容。

一款 PostCSS 插件,用于将基于特定宽度的固定尺寸的视图,转为可跟随宽度变化而等比例伸缩的视图,并提供超出某一宽度后停止放大视图的方法,这种视图常见于移动端页面的适配。postcss-mobile-forever 可以配合 scale-view 使用,前者用于编译阶段,后者用于运行阶段。postcss-mobile-forever 具备以下特性:

<details> <summary> 使用媒体查询限制最大宽度的方法,能够为桌面端与横屏各自设置最大宽度。 </summary>

您可以查看一个在线范例,通过旋转屏幕、改变窗口大小、在不同屏幕查看展示效果。范例顶部的文字会提示您,当前的视图是移动端竖屏(Portrait)、移动端横屏(Landscape)还是桌面端(Desktop)。

下面的三张图是使用本插件生成媒体查询,移动端、移动端横屏和桌面端的展示效果:

<table> <tr> <td><img src="./images/portrait.png" alt="移动端的展示效果" /></td> <td><img src="./images/landscape.png" alt="移动端横屏的展示效果" /></td> </tr> <tr> <td colspan="2"><img src="./images/desktop.png" alt="桌面端的展示效果" /></td> </tr> </table>

在“范例”一节查看,源码中提供了范例,用于在本地运行后验证演示效果,或者您也可以查看文档开头的在线范例。

您也可以通过配合 px2vw,把转换视口单位(适配移动端竖屏)的任务交给 px2vw 完成,然后打开本插件的 disableMobile,关闭本插件的视口单位转换功能。这样做只适用于上面的第二种方法,生成媒体查询的方法。

</details>

使用 postcss-px-to-viewport 实现伸缩界面的时候,如果不希望界面在大屏设备上撑满整个屏幕而难以浏览,希望界面在达到某一个合适的宽度后停止伸缩(限制最大宽度),您可以使用本插件。

移动端模版和范例

下面是一个宽屏展示良好的移动端模版列表,每一条都包含了演示链接和代码,打开演示,查看模版在使用 postcss-mobile-forever 之后在不同宽度屏幕下的展示效果,打开代码,查看配置方法。

<details> <summary> 文件夹 “example/” 内提供了在诸如 React、Svelte、Vue、Next.js、Nuxt 和原生 JavaScript 中使用 postcss-mobile-forever 的范例,范例中也包含部分上面的移动端模板,克隆本仓库后,通过命令行进入对应的范例文件夹中,即可运行。 </summary>
cd example/react/
npm install
npm run start
</details>

安装和迁移

npm 安装最新版本(基于 postcss@^8.0.0)(yarn 则是 yarn add -D postcss postcss-mobile-forever):

npm install --save-dev postcss postcss-mobile-forever

npm 安装最新的兼容版本(基于 postcss@^6.0.0)(yarn 则是 yarn add -D postcss-mobile-forever@legacy):

npm install postcss-mobile-forever@legacy --save-dev

查看兼容版本的 mobile-forever 文档,目前兼容版本不支持逻辑属性的处理。

<details> <summary> 安装之后在 postcss.config.js 配置文件中引入,或者其它框架配置文件中引入。 </summary>

postcss.config.js 有好几种配置格式,下面是其中一种配置方法:

import mobile from 'postcss-mobile-forever' // <---- 这里
import autoprefixer from 'autoprefixer'
// 省略……
{
	postcss: {
		plugins: [
			autoprefixer(),
			mobile({ // <---- 这里
				appSelector: '#app',
				viewportWidth: 375,
				maxDisplayWidth: 580,
			}),
		]
	}
}
// 省略……

https://github.com/webpack-contrib/postcss-loader/issues/172

</details>

如果你的项目是基于 rem 做的移动端适配,可以参考文档“迁移”,迁移到 vw 移动端适配。

配置参数

<details> <summary> 查看使用 postcss-mobile-forever 适配移动端视图的流程图(白色图片),以理解配置的过程和一些关键的配置选项。 </summary> <img src="images/flow-chart.png" alt="一张展示使用 postcss-mobile-forever 适配移动端的流程图" /> </details>

一大波配置参数正在靠近,不必焦虑,尽在掌握,在这之前可以先尝试最基础的配置参数。下方是一个基础配置,表示了应用正在基于 750px 的宽度开发,经过 mobile-forever 转换后,浏览器中,应用视图将被限制在 600px 宽度以内进行等比例伸缩,当宽度大于 600px,视图将不改变,并且根元素 #app 的应用视图是居中于浏览器窗口的:

{
  "viewportWidth": 750,
  "appSelector": "#app",
  "maxDisplayWidth": 600
}

下面的每一项都是可选的。

NameTypeDefaultDesc
viewportWidthnumber|(file: string, selector: string) => number750应用基于该宽度进行开发,转换后的伸缩视图将会以该宽度的视图作为标准进行比例伸缩;可以传递函数动态生成宽度,例如 file => file.includes("vant") ? 375 : 750 表示在名称包含“vant”的文件内使用 375px 的宽度,而其他文件使用 750px 的宽度
mobileUnitstring"vw"移动端竖屏视口视图,转换成什么视口单位?
maxDisplayWidthnumber/限制视口单位的最大宽度
enableMediaQuerybooleanfalse打开媒体查询模式,打开后将自动关闭 maxDisplayWidth
desktopWidthnumber600适配到桌面端时,展示的视图宽度
landscapeWidthnumber425适配到移动端横屏时,展示的视图宽度
appSelectorstring/页面最外层选择器,例如“#app”,用于设置在桌面端和移动端横屏时的居中样式
appContainingBlock"calc"|"manual"|"auto""calc"该属性和矫正 fixed 定位元素有关,manual 将不矫正;calc 将通过插件主动计算的方式矫正元素尺寸;auto 将通过 transform: translateZ(0) 强制设置根包含块appSelector,从而自动矫正元素,并且此时需要设置属性 necessarySelectorWhenAuto
necessarySelectorWhenAutostring/appContainingBlock 设为 auto 时,需要指定该属性,该属性指定了 appSelector 往内一层的元素选择器,查看一个关于指定元素作为包含块的实验以了解如何使用该属性,您也可以查看使用这个属性的示例项目以了解如何使用这个属性
borderboolean|stringfalse在页面外层展示边框吗,用于分辨居中的小版心布局和背景,可以设置颜色字符串
disableDesktopbooleanfalse打开则不做桌面端适配,使用该参数前需要打开 enableMediaQuery
disableLandscapebooleanfalse打开则不做移动端横屏适配,使用该参数前需要打开 enableMediaQuery
disableMobilebooleanfalse打开则不做移动端竖屏适配,把 px 转换为视口单位,如 vw
excludeRegExp|RegExp[]/排除文件或文件夹
includeRegExp|RegExp[]/包括文件或文件夹
unitPrecisionnumber3单位精确到小数点后几位?
propListstring[]['*']哪些属性要替换,哪些属性忽略?用法参考 postcss-px-to-viewport 文档
selectorBlackList(string|RegExp)[][]选择器黑名单,名单上的不转换
propertyBlackListpropertyBlackList[]属性黑名单,名单上的不转换,如果要指定选择器内的属性,用对象的键表示选择器名称,具体用法见 vant 的范例代码
valueBlackList(string|RegExp)[][]属性值黑名单,名单上的值不转换
rootContainingBlockSelectorList(string|RegExp)[][]包含块是根元素的选择器列表,效果和标注注释 /* root-containing-block */ 相同
verticalWritingSelectorList(string|RegExp)[][]纵向书写模式的选择器列表,效果和在选择器顶部标注注释 /* vertical-writing-mode */ 相同
minDesktopDisplayWidthnumber/宽度断点,如果不提供这个值,默认使用 desktopWidth 的值,视图大于这个宽度,则页面宽度是桌面端宽度 desktopWidth,“原理和输入输出范例”一节具体介绍了该值的触发情况
maxLandscapeDisplayHeightnumber640高度断点,视图小于这个高度,并满足一定条件,则页面使用移动端横屏宽度,“原理和输入输出范例”一节具体介绍了该值的触发情况
sideany/侧边配置,在桌面端媒体查询中生效,用于利用宽屏的空间,后文将介绍它的若干子属性
commentany/自定义注释,改变注释的名称,后文将介绍它的若干子属性
customLengthPropertyany/用于指定需要添加到桌面端或横屏的自定义变量(css 变量,var(...)),如果不指定,默认所有和长度有关的属性,如果使用了自定义变量,都会被添加入桌面端和横屏,后文将介绍它的若干子属性
experimental.extractbooleanfalse提取桌面端与横屏样式代码,用于生产环境,用于代码分割优化产包,具体查看“注意事项”一节
experimental.minDisplayWidthnumber/限制最小宽度,和 maxDisplayWidth 搭配使用

下面是属性 customLengthProperty 的子属性,用于自定义变量,并且每一个属性都是可选的。customLengthProperty 有两个作用,一个是指定转换方式,例如基于根包含块的 leftright,则需要 customLengthProperty.rootContainingBlockList_LR 进行指定,来得到正确的转换结果,另一个作用是,在媒体查询模式下,避免所有和长度有关的使用 CSS 变量的属性,都被添加到媒体查询中,用于指定真正需要添加到桌面端或横屏的自定义变量:

NameTypeDefaultDesc
rootContainingBlockList_LRstring[][]用于根包含块的,left、right 的自定义属性,例如设置 ["--len-a", "--len-b"] 后,--len-a--len-b 的值会转换为用于 leftright 属性,并且包含块是根包含块的值,并添加到桌面端和横屏中
rootContainingBlockList_NOT_LRstring[][]用于根包含块的,非 left、right 的自定义属性
ancestorContainingBlockListstring[][]用于非根包含块的自定义属性,这些属性值不会被转换,但是会添加到桌面端和横屏,用于避免优先级问题
disableAutoApplybooleanfalse关闭自定义属性自动添加到桌面端和横屏,设置上面的三个选项后,这个选项自动为 true
<details> <summary> 还有一些属性可以把页面上某个部分在宽屏设备上转移到侧边,例如可以把在移动端底部的二维码转移到桌面端的侧边栏区域以利用空白区域,这些属性不常用,您可以展开查看具体属性情况。 </summary>

下面是属性 side 的子属性,每一个属性都是可选的,side 用于配制侧边内容,只有当打开媒体查询模式、disableDesktop 为 false 的时候,side 将生效:

NameTypeDefaultDesc
widthnumber/侧边宽度,如果指定的选择器下有 width 属性,则无需设置
gapnumber18侧边布局的上下左右间隔
selector1string/左上侧边元素选择器
selector2string/右上侧边元素选择器
selector3string/右下侧边元素选择器
selector4string/左下侧边元素选择器
width1number/左上侧边宽度,优先级大于 width
width2number/右上侧边宽度
width3number/右下侧边宽度
width4number/左下侧边宽度
</details>

也可以通过在样式文件中添加注释,来标记局部的尺寸该如何转换,下面是一些标记注释:

<details> <summary>标记注释的名称可以通过属性自定义,这些属性不常用,您可以展开查看属性的具体说明。</summary>

下面是属性 comment 的子属性,每一个属性都是可选的,comment 用于自定义注释:

NameTypeDefaultDesc
applyWithoutConvertstring"apply-without-convert"直接添加进屏幕媒体查询,不转换
rootContainingBlockstring"root-containing-block"包含块注释
notRootContainingBlockstring"not-root-containing-block"非包含块注释
ignoreNextstring"mobile-ignore-next"忽略选择器内的转换
ignoreLinestring"mobile-ignore"忽略本行转换
verticalWritingModestring"vertical-writing-mode"纵向书写模式
</details> <details> <summary> 虽然配置选项的数量看起来很多,但是只需要指定选项 viewportWidth 后,就可以输出伸缩视图的结果,通常我们还需要让伸缩视图具有最大宽度,只要再添加 appSelector 和 maxDisplayWidth,即可完成。开发中,如果在浏览器看到了宽屏的视图有和在移动端视图不一样的地方,再考虑配置其它选项也不迟。 </summary>

下面的配置会激活第一种方法,使用 CSS 函数限制视口单位的最大值,当屏幕宽度超过 600px 后,视图不会再变化:

{
  "viewportWidth": 750,
  "appSelector": "#app",
  "maxDisplayWidth": 600
}

下面的配置会激活第二种方法,生成媒体查询,适配桌面端和横屏,桌面端视图的宽度是 600px,横屏的宽度是 425px:

{
  "viewportWidth": 750,
  "appSelector": "#app",
  "enableMediaQuery": true
}

如果暂时不希望优化视图在大屏的可访问性,不做最大宽度的限制,可以像下面这样配置:

{
  "viewportWidth": 750
}
</details> <details> <summary> 展开查看默认的配置参数。 </summary>
{
  "viewportWidth": 750,
  "maxDisplayWidth": null,
  "enableMediaQuery": false,
  "desktopWidth": 600,
  "landscapeWidth": 425,
  "minDesktopDisplayWidth": null,
  "maxLandscapeDisplayHeight": 640,
  "appSelector": "#app",
  "appContainingBlock": "calc",
  "necessarySelectorWhenAuto": null,
  "border": false,
  "disableDesktop": false,
  "disableLandscape": false,
  "disableMobile": false,
  "exclude": null,
  "include": null,
  "unitPrecision": 3,
  "selectorBlackList": [],
  "valueBlackList": [],
  "rootContainingBlockSelectorList": [],
  "verticalWritingSelectorList": [],
  "propList": ["*"],
  "mobileUnit": "vw",
  "side": {
    "width": null,
    "gap": 18,
    "selector1": null,
    "selector2": null,
    "selector3": null,
    "selector4": null,
    "width1": null,
    "width2": null,
    "width3": null,
    "width4": null
  },
  "comment": {
    "applyWithoutConvert": "apply-without-convert",
    "rootContainingBlock": "root-containing-block",
    "notRootContainingBlock": "not-root-containing-block",
    "ignoreNext": "mobile-ignore-next",
    "ignoreLine": "mobile-ignore",
    "verticalWritingMode": "vertical-writing-mode"
  },
  "customLengthProperty": {
    "rootContainingBlockList_LR": [],
    "rootContainingBlockList_NOT_LR": [],
    "ancestorContainingBlockList": [],
    "disableAutoApply": false
  },
  "experimental": {
    "extract": false,
    "minDisplayWidth": null
  }
}
</details>

单元测试与参与开发

npm install
npm run test

修改源码后,编写单元测试,验证是否输出了预期的结果。另外,在文件夹 example/ 内提供了一些范例,可以用来模拟生产环境使用插件的场景,这些范例项目中依赖的 postcss-mobile-forever 来自源码,因此当修改源码后,可以通过在范例里 npm i 安装依赖,然后本地运行,通过浏览器验证自己的修改是否符合预期。

如果您是移动端模版的开发者,成功引入 postcss-mobile-forever 之后,您可以按照“移动端模版和范例”一节的格式,提交 PR,将您的模版仓库以及在线演示地址添加到后续的列表中,这样可以为您的模版提供更多的曝光,也能够表示您的移动端模版具有良好的桌面端体验。

一起开发,让程序的变量命名更合适、性能和功能更好。

输入输出范例和原理

插件配置:

{
  "viewportWidth": 750,
  "maxDisplayWidth": 560,
  "appSelector": "#app"
}

输入范例:

#app {
  width: 100%;
}

.nav {
  position: fixed;
  width   : 100%;
  height  : 72px;
  left    : 0;
  top     : 0;
}

输出范例:

#app {
  width       : 100%;
  max-width   : 560px !important;
  margin-left : auto !important;
  margin-right: auto !important;
}

.nav {
  position: fixed;
  width   : min(100%, 560px);
  height  : min(9.6vw, 53.76px);
  left    : calc(50% - min(50%, 280px));
  top     : 0;
}
<details> <summary>查看打开选项 enableMediaQuery,媒体查询模式下的输出范例。</summary>

插件配置:

{
  "appSelector": "#app",
  "enableMediaQuery": true
}

输出范例:

#app {
  width: 100%;
}

.nav {
  position: fixed;
  width   : 100%;
  height  : 9.6vw;
  left    : 0;
  top     : 0;
}

/* 桌面端媒体查询 */
@media (min-width: 600px) and (min-height: 640px) { /* 这里的 600 是默认值,可以自定义 */
  #app {
    max-width: 600px !important;
  }

  .nav {
    height: 57.6px;
    top   : 0;
    left  : calc(50% - 300px); /* calc(50% - (600 / 2 - 0 * 600 / 750)px) */
    width : 600px; /* 100% -> 600px */
  }
}

/* 移动端媒体查询 */
@media (min-width: 600px) and (max-height: 640px),
(max-width: 600px) and (min-width: 425px) and (orientation: landscape) { /* 这里的 640 和 425 是默认值,可自定义 */
  #app {
    max-width: 425px !important;
  }

  .nav {
    height: 40.8px;
    top   : 0;
    left  : calc(50% - 212.5px); /* calc(50% - (425 / 2 - 0 * 425 / 750)px) */
    width : 425px; /* 100% -> 425px */
  }
}

/* 桌面端和移动端公共的媒体查询 */
@media (min-width: 600px),
(orientation: landscape) and (max-width: 600px) and (min-width: 425px) {
  #app {
    margin-left : auto !important;
    margin-right: auto !important;
  }
}

相比使用 CSS 函数,使用媒体查询限制宽度,生成的代码量更大。

</details>

查看原理

注意事项

插件提供了两个方法限制伸缩视图的最大宽度。使用媒体查询的方法会生成较多代码量,但是可以分别设置桌面端与横屏的不同最大宽度(在线范例配置);使用 CSS 函数的方法生成代码量较少,只能设置单个最大宽度(在线范例配置)。

appSelector 所在元素的居中属性会被占用,包括 margin-leftmargin-rightmax-width,如果开启了 border,box-shadow 会被占用。

默认情况,插件会把所有 fixed 定位的元素的包含块当成根元素,如果希望跳过处理非根元素的包含块,请在选择器上方添加注释,/* not-root-containing-block */,这样设置后,插件会知道这个选择器内的计算方式统一使用非根包含块的计算方式:

/* not-root-containing-block */
.class {
  position: fixed;
  left: 50%;
}

对于 fixed 定位元素的包含块是祖先元素,而不是根元素(浏览器窗口,visual viewport)的条件,请查看“其它”一节。

<details> <summary> 对于包含块,如果“position: fixed;”和“left: 0;”不在同一选择器,可以在需要重新计算的选择器上标记注释“/* root-containing-block */”(另一个方法是设置“rootContainingBlockSelectorList”参数)。 </summary>
.position {
	position: fixed;
}
/* root-containing-block */
.top-box {
	right: 0;
	bottom: 0;
	width: 66px;
	height: 66px;
	border-radius: 9px;
}
</details>

插件转换的是选择器中的属性的值,At 规则中,除了用于定义动画的 @keyframes 中的属性会转换,其它的 At 规则不转换。

<details> <summary> 展开查看关于“experimental.extract”选项的一些说明。 </summary> <details> <summary>展开查看使用“experimental.extract”的一份范例配置。</summary>
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { defaultGetLocalIdent } = require("css-loader");
const { remakeExtractedGetLocalIdent } = require("postcss-mobile-forever");

const isProdMode = process.env.NODE_ENV === "production";

module.exports = {
  mode: isProdMode ? "production" : "development",
  entry: "./src/index.js",
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "build"),
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [isProdMode ? MiniCssExtractPlugin.loader : "style-loader", {
          loader: "css-loader",
          options: {
            modules: {
              localIdentName: isProdMode ? "[hash:base64]" : "[path][name]__[local]",
              getLocalIdent: isProdMode ? remakeExtractedGetLocalIdent({ defaultGetLocalIdent }) : undefined, // 开发环境不分割,因此设置为 undefined
            },
          }
        }, {
          loader: "postcss-loader",
          options: {
            postcssOptions: [
              ["postcss-mobile-forever", {
                appSelector: ".root-class",
                experimental: {
                  extract: isProdMode, // 生产环境打开文件的提取
                },
              }]
            ]
          }
        }],
      }
    ],
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        desktop: {
          chunks: "all",
          enforce: true,
          test: /desktop[^\\/]*?\.css$/, // 分割桌面端样式
          name: "desktop",
          priority: 101, // 第三位被加载
        },
        landscape: {
          chunks: "all",
          enforce: true,
          test: /landscape[^\\/]*?\.css$/, // 分割横屏样式
          name: "landscape",
          priority: 102, // 第二位被加载
        },
        mobile: {
          chunks: "all",
          enforce: true,
          test: /mobile[^\\/]*?\.css$/, // 分割移动端样式
          name: "mobile",
          priority: 103, // 第一位被加载
        },
      }
    }
  },
};

前往范例查看可运行的配置。

</details> </details> <details> <summary> 关于 CSS 自定义属性,默认情况下,所有和长度相关的属性,如果使用了自定义属性,都会被添加入桌面端和横屏,这可能会带来一些冗余的添加,也可能会有一些转换的错误,转换的错误和包含块相关。 </summary>

下面的例子,默认的情况,--len-a 的值在桌面端会被转为 60px,横屏会被转为 42.5px,但是可以看到实际的应用场景中,定位是 fixed,因此包含块是根包含块,所以默认的转换是错误的,正确的转换应该是,桌面端会被转为 calc(50% - 240px),横屏会被转为 calc(50% - 170px)

:root {
  --len-a: 75px;
}
.rule {
  left: var(--len-a);
  position: fixed;
}

上面的例子中,如果要正确的转换,需要在配置中明确指定,--len-a 用于根包含块,并且被用于 left 属性:

{
  // ...其它配置
  customLengthProperty: {
    rootContainingBlockList_LR: ["--len-a"]
  }
}
</details>

本插件媒体查询模式的目标是在不同尺寸的屏幕上展示合适的视图,在宽一点的屏幕上展示大一点的视图,在扁一点的屏幕上展示小一点的视图,在窄一些的屏幕展示移动端竖屏视图,而非准确地识别具体的设备或平台来应用对应视图。

使用插件转换后的浏览器兼容性情况:媒体查询模式下会利用 CSS 函数 calc(),因此兼容性略有降低,Opera Mini 完全不可用,max-display-width 模式利用了 CSS 函数 max()min() 以及 calc(),会有兼容性问题,IE、Opera Mini、QQ 浏览器 13.1 完全不可用,具体可以查看 caniuse min(), max()caniuse calc()

期望效果

在不同设备上,duozhuayu.com(多抓鱼)公用一套 UI,访问无障碍,没有巨大字体和全宽的问题。

<details> <summary> 查看“多抓鱼“在移动端、移动端横屏和桌面端的展示效果。 </summary> <table> <tr> <td><img src="./images/dzy-portrait.png" alt="移动端的展示效果" /></td> <td><img src="./images/dzy-landscape.png" alt="移动端横屏的展示效果" /></td> </tr> <tr> <td colspan="2"><img src="./images/dzy-desktop.png" alt="桌面端的展示效果" /></td> </tr> </table> </details>

多抓鱼官网用百分比单位做适配,最大宽度是 600px,小于这个宽度则向内挤压,大于这个宽度则居中移动端竖屏视图,这种小版心布局在不同尺寸屏幕的设备上,展示效果很好。这样的适配方法舍弃了对设计稿的“完美”还原,相应的,代码没有了预处理,更轻量了,没有了“完美”的限制,开发的过程也变得灵活,对于一种布局,有很多方式实现适配,而且,这样适配也能很好地触发浏览器的缩放功能,满足了针对缩放的可访问性标准

CHANGELOG

查看更新日志

版本规则

查看语义化版本 2.0.0

协议

查看 MIT License

支持与赞助

请随意 Issue、PR 和 Star,您也可以支付该项目,支付金额由您从该项目中获得的收益自行决定。

<details> <summary>展开查看用于微信支付和支付宝支付的二维码。</summary> <table> <tr align="center"> <td>微信支付</td> <td>支付宝支付</td> </tr> <tr> <td><img src="./images/wechat-pay.png" alt="Pay through WeChat" /></td> <td><img src="./images/ali-pay.jpg" alt="Pay through AliPay" /></td> </tr> </table> </details>

其它

<details> <summary> 如果仅使用 postcss-px-to-viewport,并且项目无路由,可以通过 iframe 嵌套 vw 伸缩界面(<a href="https://github.com/evrone/postcss-px-to-viewport/issues/130#issuecomment-1641725322">来源链接</a>),来达到限制最大宽度的目的。 </summary>
<style>
  body {
    margin: 0;
  }
  #iframe {
    max-width: 520px;
    width: 100%;
    height: 100%;
    margin: 0 auto;
    display: block;
  }
</style>
<body>
  <!-- vw-index.html 为 postcss-px-to-viewport 转换后的伸缩界面 -->
  <iframe id="iframe" src="./vw-index.html" frameborder="0"></iframe>
<body>
</details>

与本项目有关或者可以配合使用的项目:

对于包含块,插件默认的处理方式不能处理下面的情况,如果某个情况设置在祖先元素上,那么当前定位为 fixed 元素的包含块就是那个祖先元素,而插件默认所有的 fixed 元素的包含块是浏览器窗口(visual viewport):

相关链接: