css相关

265 阅读4分钟

核心问题是, 如何将设计图还原到不同屏幕宽度的设备上

github代码

需要解决如下问题:

    1. 配置样式预处理语言(scss)
    1. 将设计图还原到不同屏幕宽度的设备上
    1. 1px或者0.5px实现
    1. 图片展示模糊问题解决

配置样式预处理语言(scss)

使用vue-cli3配置

1. 安装依赖包

此处的sass-loader默认安装的是11以上的版本, 在vue3.0上会报错, 需要降级,尝试安装10.1.1后没问题了

npm install -D sass-loader sass

1. 配置自动化导入公共样式

(1) 使用了 style-resources-loader
npm install -D style-resources-loader
(2) 配置

在vue.config.js中, 配置chainWebpack属性; 这样全局会加入./src/styles/imports.scss下的公共样式, 省略了每个vue文件样式内手动引入.

const path = require('path');
module.exports = {
    chainWebpack: config => {
        const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
        types.forEach(type => addStyleResource(config.module.rule('scss').oneOf(type)))
    },
}

function addStyleResource (rule) {
    rule.use('style-resource')
        .loader('style-resources-loader')
        .options({
            patterns: [
                path.resolve(__dirname, './src/styles/imports.scss'),
            ],
        })
}

解决问题2,3,4

    1. 将设计图还原到不同屏幕宽度的设备上
    1. 1px或者0.5px实现
    1. 图片展示模糊问题解决

方案一: flexible方案

核心思想:

    1. 使用rem, 根据屏幕宽度动态设置根元素font-size
    1. 动态设置meta标签内的scale值, 根据dpr动态缩放屏幕,已达到理想效果 淘宝的讲解文章

方案二: viewport方案

使用vue-cli3配置, 不支持的设备实用Viewport Units Buggyfill兼容(现在不支持的很少了) 方案核心思想: 100vw等于页面的宽度, 任何设备,只要支持vw, 页面宽度就是100vw, 这样就能根据设计图转化为vw渲染页面, 从而保证设计图在不同设备的还原.

1. 安装包依赖
npm install -D postcss-px-to-viewport
2. 配置
  • 根目录下创建postcss.config.js
  • 根据设计图配置viewportWidth属性值, 一般设计图是以iphone6宽度设计的, 所以此处设计750.
  • 横屏宽度landscapeWidth为1334,也是iphone6的横屏宽度
  • selectorBlackList配置.如需部分选择器不转换单位,可以配置此属性([/^.ingore_/g]此正则会匹配所有以.ingore_开头的选择器, 比较实用)
module.exports = {
    plugins: {
        // 配置px to vw
        'postcss-px-to-viewport': {
            unitToConvert: 'px',    // 需要转换的单位
            viewportWidth: 750,     // 设计图视口宽度
            unitPrecision: 5,       // 小数保留位数
            propList: ['*'],        // 支持转换的css属性名称
            viewportUnit: 'vw',     // 转为为vw宽度单位
            fontViewportUnit: 'vw', // 字体单位
            selectorBlackList: [],  // 选择器黑名单,转换时不会转换符合此处的选择器
            minPixelValue: 1,       // 最小的转换数值
            mediaQuery: false,      // 媒体查询里面的是否转换
            replace: true,          // 是否直接替换属性值而不是添加备用属性
            exclude: undefined,     // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
            include: undefined,     // 设置此处值, 则只转换include内的文件
            landscape: false,       // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
            landscapeUnit: 'vw',    // 横屏时使用的单位
            landscapeWidth: 1334     // 横屏时使用的视口宽度
        }
    }
}
3. 1px问题解决

伪元素 + transform scale方案(sass版本)

@mixin border-1px($width: 1px, $color: #ccc, $radius: 0px, $direction: all) {
 position: relative;
 &::after {
   content: "";
   pointer-events: none;
   display: block;
   position: absolute;
   border-radius: $radius;
   box-sizing: border-box;
   width: 100%;
   height: 100%;
   left: 0;
   top: 0;
   transform-origin: 0 0;
   @if($direction == all) {
     border: $width solid $color;
   } @else {
     border-#{$direction}: $width solid $color;
   }
   @media only screen and (-webkit-min-device-pixel-ratio:2) {
     width: 200%;
     height: 200%;
     border-radius: $radius * 2;
     transform: scale(.5);
   }
   @media only screen and (-webkit-min-device-pixel-ratio:3) {
     width: 300%;
     height: 300%;
     border-radius: $radius * 3;
     transform: scale(.333);
   }
 }
}

使用

.box-1px {
 width: 200px;
 height: 200px;
 margin-top: 10px;
 @include border-1px(0.5px);
}
4. 图片展示模糊问题解决

图片模糊的根本原因是: 在高倍屏上, 1个css像素会被大于1个的物理像素渲染, 例如2倍屏上,图片一个像素点会被4个物理像素渲染,每个物理像素只能取临近的色值,所以就会模糊. 图片上一个像素对应于一个物理像素就不会产生模糊问题, 所以解决问题最终要朝这个方向努力.

以下也有几种方式解决:

(1)img标签推荐srcset,sizes的方式

作为原生的解决方案, 无疑是体验最好的, 也是最省力的.
srcset,sizes会根据屏幕宽度,设备像素比自动选择合适的图片渲染出来. image.png 如下例子:
在小于360px宽度的屏幕上,
dpr=1的屏幕上, 实际渲染宽度128 * 1 = 128, 所以会渲染mm-width-128px.jpg;
dpr=2的屏幕上, 实际渲染宽度 128 * 2 = 256, 所以会渲染mm-width-256px.jpg;
在大于360px宽度的屏幕上,
dpr=1的屏幕上, 实际渲染宽度256 * 1 = 256, 所以会渲染mm-width-256px.jpg;
dpr=2的屏幕上, 实际渲染宽度 256 * 2 = 512, 所以会渲染mm-width-512px.jpg;

<img class="ingore_img" src="https://www.zhangxinxu.com/study/201410/mm-width-128px.jpg"
         srcset="https://www.zhangxinxu.com/study/201410/mm-width-128px.jpg 128w, https://www.zhangxinxu.com/study/201410/mm-width-256px.jpg 256w, https://www.zhangxinxu.com/study/201410/mm-width-512px.jpg 512w"
         sizes="(max-width: 360px) 128px, 256px" alt="图片模糊解决">
(2)背景图片推荐image-set()

浏览器会根据dpr, 选择1倍图,或者2倍图展示, 单属性兼容性差

background-image: image-set( url(https://www.zhangxinxu.com/study/201410/mm-width-128px.jpg) 1x, url(https://www.zhangxinxu.com/study/201410/mm-width-256px.jpg) 2x, url(https://www.zhangxinxu.com/study/201410/mm-width-128px.jpg) 600dpi);
(3) 媒体查询方式
.avatar{
            background-image: url(conardLi_1x.png);
        }
        @media only screen and (-webkit-min-device-pixel-ratio:2){
            .avatar{
                background-image: url(conardLi_2x.png);
            }
        }
        @media only screen and (-webkit-min-device-pixel-ratio:3){
            .avatar{
                background-image: url(conardLi_3x.png);
            }
        }
(4) svg

svg无论放多大,都不会失真