实现移动端响应式布局

更新日期: 2019-07-16阅读: 3.1k标签: 响应式

单位选择: vw 还是 rem ?

我们选择了 rem 作为像素单位。因为本次开发的项目包含 ipad 与手机端,使用 rem 单位应对的根元素字体可以根据设备动态设置。因此 ipad 端与手机端公共的样式只需要写一套代码就能实现,而使用vw作为单位在无论什么情况下都需要写2套样式,见下面的例子:

假设现在2倍视觉稿上有一个显示 500*300 的按钮,而这个按钮在ipad端和手机端的样式相同。下面是两种写法的对比:

使用vw作为单位,视觉稿上手机宽度为 750,ipad宽度为 2048

.button.phone {
    width: 100 * 500 / 750vw;
    height: 100 * 300/ 750vw;
}
.button.ipad {
    width: 100 * 500 / 2048vw;
    height: 100 * 300/ 2048vw;
}

使用rem作为像素单位,根据屏幕的宽度(1024px作为分界点)大于这个像素按ipad的样式做适配,否则按手机设备做适配。设置基数为20,即视觉稿上的html根元素字体大小20px。

let wWidth = document.body.offsetWidth;  
let html = document.documentElement;  
let remNum = wWidth < 1024 ? (wWidth / 750) * 20 : (wWidth / 2048) * 20;  
 html.style.fontSize = `${remNum}px`;

因此对于公共的样式只需要写一套代码就行。

.button {
    width: 500 / 20rem;
    height: 300 / 20rem;
}

当然上述的都是伪代码,less是不支持这种写法 因此最终的代码要这么写:

.button {
    width: 25rem;
    height: 15rem;
}


手动计算不恶心吗?

每次写样式都要在心里计算一遍单位,如果碰到不能被20整除的单位,只能使用计算器,非常恶心。

好在 less 提供了一套单位转换函数 unit(@px, rem) 将px转化为rem,且它支持四则运算。

因此上述的样式可以这么写:

.button {
    width: unit(500/20, rem);
    height: unit(300/20, rem);
}


结束了?

这样就结束了?远远不够,每次都要写重复的代码,非常麻烦,可以再节约些吗?

使用less 提供的mixin 封装公共的样式方法:

.button {
    .w(500);
    .h(300);
}

// mixin
.w(@px) {
    width: unit(@px / @baseUnit, rem);
}
.h(@px) {
    height: unit(@px / @baseUnit, rem);
}


真的结束了吗?

看似解决了重复的问题,但是有引入了新的问题: 设置margin的值,不能连着写, 必须写四个样式,虽然说mixin 支持...arguments 实现动态参数,但别忘记了还需要对参数做单位转化呢,因此不能满足我们的需求。

.button {
    .mt(10);
    .mr(10);
    .mb(10);
    .ml(10);
}

遇到 translate, background-size 等这些不常用的样式,推荐用原始的方式去写。对这种不常用的样式封装意义不大,而且还会增加mixin函数的记忆成本。

.button {
    translate: (unit(300/20, rem), unit(300/20, rem));
    background-size: (unit(300/20, rem), unit(300/20, rem));
}


切换成 sass 去避坑

sass自带了自定义函数的功能,可以解决上述问题的痛点。

// px to rem
@function x2r($px) {
  @return $px * $baseUnit * 1rem;
}
.button{
  width: x2r(500);
  height: x2r(300);
  margin: x2r(10) x2r(10);
  transform: translate(x2r(500), x2r(300));
}

唯一的缺点是语法不够优雅:joy:


有最终的解决方案吗?

感觉这样用起来还是很不方便,还达不到完美的境界,有更好的解决办法吗? 最终解决方案:采用 webpack 的 loader 直接完成单位的转换。

.button {
  width: 500pxr;
  height: 300pxr;
  margin: 10pxr 10pxr;
  transform: translate(500pxr, 300pxr);
}
// loader 转化后
.button {
  width: 250rem;
  height: 150rem;
  margin: 0.5rem 0.5rem;
  translate: (150rem, 150rem);
}

具体思路:对.vue文件与.less 文件中的less代码做一次替换,把pxr单位转换成rem单位。在vue-loader与less-loader之前插入这个单位转化的 loader 完成单位的转化。

// unit-convert-loader.js
const loaderUtils = require('loader-utils');

exports.default = function(source) {  
    const { remBase = 16, isVueFile = false } = loaderUtils.getOptions(this);
    function replaceStyle(styleStr) {
        return styleStr.replace(/\d*\.?\d+pxr(?=;|\)|,| )/g, $1 => {
            const pixels = parseInt($1);
            return `${pixels / remBase}rem`;
        });
    }
    // .vue 文件中从 style 标签中获取样式规则进行替换
    if (isVueFile) {
        source = source.replace(
            /(<style.+>)([\s\S]*)(<\/style>)/g,
            (_, $1, style, $2) => {
                return `${$1}${replaceStyle(style)}${$2}`;
            }
        );
        return `export default ${source}`;
    } else {
        // 其他的样式文件,直接进行替换
        return replaceStyle(source);
    }
};

不用手动计算单位,不用去记mixin的函数,不用每次写重复的的代码,书写规则更接近于原始,是不是很方便:smile:。


VS postcss-pxtorem

与postcss-pxtorem 做比较,不敢说比它更优秀,但是应该比它更能满足我们目前的业务需求。一旦将来切换到其他项目,单位换成vw,这个工具只需稍微做个拓展,改变下loader中传入的参数也依旧可以支持将单位转换为vw。


结束了

仅仅只是是文章结束了。这种方法还有一些局限性,不支持vue模板中的style语法中的单位转换。不是不能实现,一旦支持但是上面的“replaceStyle” 函数就没法复用,替换的正则表达式会更加复杂,而且即时支持了收益也不大,完全有代替的方案。杀鸡不用牛刀,所以我选择放弃。


最后再附上vue-cli3 自定义loader的配置

chainWebpack: config => {
        config.module
            .rule('less')
            .test(/\.less$/)
            .oneOf('normal')
            .use('unit-convert-loader')
            .loader(path.resolve('unit-convert-loader.js'))
            .options({
                remBase: 20
            });
        config.module
            .rule('vue')
            .test(/\.vue$/)
            .use('unit-convert-loader')
            .loader(path.resolve('unit-convert-loader.js'))
            .options({
                remBase: 20,
                isVueFile: true
            });


原文:https://blog.souche.com/untitled-26/

链接: https://fly63.com/article/detial/4230

移动端web app要使用rem实现自适应布局:font-size的响应式

rem是相对于根元素html,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算出元素的宽高。

使用现代CSS的响应式版面

通过模块化缩放,使用传统属性和calc()来动态缩放你的字体大小.为字体大小使用百分比.给文本内容和媒体查询使用em,针对不同视口尺寸使用不同缩放值.视口越小,缩放比例越小,使用媒体查询或者media()函数基于视口来改变比例和基础字号

web响应式图片的5种实现

在目前的前端开发中,我们经常需要进行响应式的网站开发。本文着重介绍一下弹性图片,也就是响应式图片的解决方案:js或服务端、srcset 、sizes 、picture标签、svg图片

HTML5+CSS3响应式垂直时间轴,高端,大气

HTML5+CSS3响应式垂直时间轴,使用了HTML5标签<section>,时间轴中所有的内容包括标题、简介、时间和图像都放在.cd-timeline-block的DIV中,多个DIV形成一个序列,并把这些DIV放在<section>中。

实现响应式_CSS变量

CSS 变量是 CSS 引入的一个新特性,目前绝大多数浏览器已经支持了,它可以帮助我们用更少的代码写出同样多的样式,大大提高了工作效率,本篇文章将教你如何使用 CSS 变量(css variable)。CSS中原生的变量定义语法是:--*,变量使用语法是:var(--*),其中*表示变量名称

vue响应式原理及依赖收集

Vue通过设定对象属性的setter/getter方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

vue响应式系统--observe、watcher、dep

Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的JavaScript 对象,而当你修改它们时,视图会进行更新,这使得状态管理非常简单直接,我们可以只关注数据本身

Responsive Web Design 响应式网页设计

常见的布局方案:固定布局:以像素作为页面的基本单位,不管设备屏幕及浏览器宽度,只设计一套尺寸;可切换的固定布局:同样以像素作为页面单位,参考主流设备尺寸

响应式布局的实现

响应式布局,即 Responsive design,在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。响应式布局的关键不仅仅在于布局

深入响应式原理

说到响应式原理其实就是双向绑定的实现,说到 双向绑定 其实有两个操作,数据变化修改dom,input等文本框修改值的时候修改数据1. 数据变化 -> 修改dom;2. 通过表单修改value -> 修改数据

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!