evrone / postcss-px-to-viewport

A plugin for PostCSS that generates viewport units (vw, vh, vmin, vmax) from pixel units. The best choice to create a scalable interface on different displays by one design size.
https://evrone.com/postcss-px-viewport
MIT License
2.98k stars 401 forks source link

行内样式自动转换vw vh 不生效 #147

Open MaDeLu opened 1 year ago

MaDeLu commented 1 year ago

发现一个问题。用 这个插件,无法自动转换,写在标签上的行内样式

LuoRiWuSheng commented 1 year ago

是的, 得自己写方法转换

/** px 转 vw, 375 是设置的屏幕宽度 */
export const px2vw = (px: number): string => `${(window.screen.width / 375) * px}vw`
MaDeLu commented 1 year ago

你写的这个,我感觉好怪啊 window.screen.width 不就是375 嘛?

wswmsword commented 1 year ago

每个设备的 window.screen.width 的值不一样,iPhone SE 是 375,iPhone XR 是 414

yozojo commented 1 year ago

如果是vite脚手架的react框架可以使用https://github.com/yozojo/inline-px-to-viewport,处理内联style的px,如果对你有帮助,可以给star吗

vaynevayne commented 1 year ago

是的, 得自己写方法转换

/** px 转 vw, 375 是设置的屏幕宽度 */
export const px2vw = (px: number): string => `${(window.screen.width / 375) * px}vw`

@LuoRiWuSheng luo 大佬, 请教下, 设计图是1920x1080(宽x高), 量的设计图上一个元素左侧100px,宽200px,高100px,字体大小20px,

公式是这样吗?


export const px2vw = (px: number): string => `${(window.screen.width / 1920) * px}vw`

.box{
margin-left: px2vw(100); // 19.53125vw
width:px2vw(200); // 39.0625vw
height:100px; //高度不用转对吧? px2vierport 好像也没转
font-size:px2vw(20); // 3.90625vw
}

// 假设用户使用iphone se(375x667),浏览器显示的是

{
margin-left: 73.2421875px; // 375/ 100 * 19.53125
width:146.484375px; // 375/ 100 * 39.0625
height:100px;
font-size:14.6484375px // 375/ 100 * 3.90625
}

是这样理解吗?

vaynevayne commented 1 year ago

不对啊, window.screen.width 是一个运行时变量, 怎么可能在插件编译时使用呢

wswmsword commented 1 year ago

@vaynevayne 你说的函数 px2vw 就是在运行时使用,不是在编译时使用的,vw 这个单位就相当于百分比,只不过百分比的基准是基于屏幕的宽度,也就是 window.screen.width

vaynevayne commented 1 year ago

哦哦。那么这个插件的原理是什么啊,大哥@wswmsword

wswmsword commented 1 year ago

哦哦。那么这个插件的原理是什么啊,大哥

就是编译的时候做 px 转换的,插件依赖 postcss,postcss 又会在打包工具 webpack 或者 vite 上用,用的时候都是根据文件类型来决定是不是做编译转换,所以基本上都是在独立的 css 文件用这个插件。如果你能用某个工具找到所有行内样式,那也能用这个插件,不然不好做。

vaynevayne commented 1 year ago

我问的是他用不了运行时变量,那他的转换公式又是什么? 我看了下首页的demo 貌似公式得到的vw是 100 / designAllwidth * designElementWidth ,问题来了,假设1920,font-size是20px 那么经过这个公式,得到 100/1920×20=1.041666667vw, 用户在414宽度的手机上使用时,414/100×1.041666667=4.312500001px ,可以看到20px的字体变成了4px,这是正确的吗?然后浏览器最小字体大小是12px,最终显示的是12px,这是因为字体有浏览器兜底,但是其他元素 没有浏览器兜底的,会不会出现错误啊?

wswmsword commented 1 year ago

@vaynevayne 不好意思,我重新看了 @LuoRiWuSheng 的公式,是有问题的,计算 vw 不需要运行时的 window.screen.width。如果你的设计图宽度是 375,px 转 vw 的公式应该是 100/375*value,这个 value 是行内样式的 px 值。

你说的设计图尺寸是 1920,字体 20px,那转换之后就是 100/1920*20=1.04167,也就是 1.04167vw,在任何宽度都是这个值。1.04167vw 在宽度是 414 的设备上经过浏览器计算最终是 4px,我测了火狐和 Safari 可以正常显示,Chrome 和 edge 会卡最小字体大小 12px,不过这个问题和视口单位转换无关,任何字体单位都会被卡最小值。

px 转换成 vw 的公式(设计图宽度 375):

export const px2vw = (px: number): string => `${(100 / 375) * px}vw`;
vaynevayne commented 1 year ago

嗯,谢谢, 我也搞懂了, css里的%单位是相对于父元素或其他规则 ,其实vw就是运行时会帮你把分母换成设备宽度的%单位, 这样的话理解vw就简单了:

在设计阶段, 我们要得到一个百分比值, 在渲染阶段使用这个百分比结合屏幕宽度,计算出最终的px单位

设计阶段:

在浏览器渲染时,比如在414px(window.screen.width)的屏幕上, 1vw就是 414/100 = 4.14 px, 10.416666666666668 * 4.14 = 43.125px

绕这半天,其实就是

200 / 1920 === 43.125 / 414  // true

不过有个需要注意的点:

ys3322 commented 10 months ago
africa1207 commented 3 months ago

如果是vite脚手架的react框架可以使用https://github.com/yozojo/inline-px-to-viewport,处理内联style的px,如果对你有帮助,可以给star吗

如果能增加排除目录就好了,有些UI库样式写在style上,也被转换了

yozojo commented 3 months ago

把px大写就不会被转换了在 2024年4月2日,12:00,africa1207 @.***> 写道:

如果是vite脚手架的react框架可以使用https://github.com/yozojo/inline-px-to-viewport,处理内联style的px,如果对你有帮助,可以给star吗

如果能增加排除目录就好了,有些UI库样式写在style上,也被转换了

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.***>

africa1207 commented 3 months ago

把px大写就不会被转换了在 2024年4月2日,12:00,africa1207 @.> 写道: 如果是vite脚手架的react框架可以使用https://github.com/yozojo/inline-px-to-viewport,处理内联style的px,如果对你有帮助,可以给star吗 如果能增加排除目录就好了,有些UI库样式写在style上,也被转换了 —Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.>

我知道大写PX或者不写可以不转换,但是UI库不听我指挥。。我使用import { createFilter } from '@rollup/pluginutils';将node_modules过滤掉直接返回code没效果,仍然被转换了

import { createFilter } from '@rollup/pluginutils';

function InlinePx2Vw(customOptions = defaultsProp) {

    const { exclude,include } = customOptions;

    const filter = createFilter(include , exclude);

    return {
        name: 'inline-px-to-viewport',
        transform(code, id) {
            if (!filter(id))  return { code };

            if (fileGlobalReg.test(id)) {
                if (pxGlobalReg.test(code)) {
                    const $_source = code.replace(
                        pxGlobalReg,
                        createPxReplace(
                            customOptions.viewportWidth,
                            customOptions.minPixelValue,
                            customOptions.unitPrecision,
                            customOptions.viewportUnit,
                        ),
                    );
                    code = code.replace(code, $_source);
                }
            }
            return { code };
        },
    };
}
const viteConfig = {
    plugins: [
        ConfigInlinePxToVwPlugin({
            exclude: ['node_modules'],
        }),
    ],
};