屏幕比例与分辨率 & 响应式大屏实现的几种方式

一、屏幕比例:

屏幕比例即屏幕宽度和高度的比例,又名纵横比或者长宽比,常见的屏幕比例主要是 16:9 和 4:3 和 16:10

其中,16:9是目前最为常见的屏幕比例,适用于电视、电脑显示器等。

(1).4:3【1.33:1】比例是最早的电视时代标准,‌常见于早期的电视和计算机显示器。‌这种比例的显示器在显示4:3画幅的内容时,‌能够保持内容的原始比例,‌不会出现图像变形。‌

VGA (640x480)    SVGA (800x600)    XGA (1024x768)  SXGA+ (1400x1050)  UXGA (1600x1200)  QXGA (2048x1536)

目前除了在特定的行业,比如:工控、安防、仪器仪表等行业,个人已经不会再购买这种比例的显示器了

(2)16:9【1.77:1】比例逐渐成为高清电视和电影的标准比例,‌也广泛应用于现代计算机显示器。‌这种比例的显示器能够提供更广阔的视野

720p (1280x720)    Full HD【1080p】 (1920x1080) ‌  

(3).16:10【1.6:1】比例介于4:3和16:9之间,‌提供了一种平衡视野和内容显示区域的选择。‌这种比例的显示器可以提供比4:3更多的垂直空间,‌适合需要同时显示多个窗口或文档的用户。‌

这个也是一度非常热门的屏幕比例,在2005到2008年之间,16:10取代4:3成为最畅销的液晶显示器比例,也是当时最普遍的笔记本电脑的屏幕比例,然而到2010年后,16:9被制定为现代电视标准,对于显示器制造来说,肯定是生产统一尺寸的面板成本更为划算,16:10屏幕比例很快被16:9比例取代

常见的分辨率有1600x1000和1920x1200等。‌

额外: 21:9就是我们经常听到的带鱼屏,虽然兼容性没有最主流的16:9更好,但是对于大部分电影资源来讲全屏播放更有沉浸感和冲击力,玩游戏类似荒野大镖客,一边玩一边旅游的游戏以及很多单机类游戏,以及赛车类游戏等会有更好的沉浸感

4K分辨率可能会有以下3种:

1:3840×2160【16:9】 这是最常见,最多的一种4K分辨率,市面上的4K电视、4K显示器99%都是这种分辨率。这就是标准4K分辨率。

2:4096×2160【16:10】 这种分辨率并不多见,跟第一种不同的是在比例格式上。举个栗子3840×2160会应用在16:9的屏幕上,而4096×2160应用在16:10的屏幕上。

3:3840×1632 这种常见在4K电影上,因尚未加上上下黑边,所以会有一个这样的分辨率。当然最佳的欣赏还是全屏无黑边。

二、大屏自适应

由于大屏数据可视化项目通常用于放在电视或广告屏上展示用,而不允许出现滚动条。

设计稿一般按照1920*1080的分辨率,16:9的比例设计, 实际开发中,document窗口是不足16:9(高度减掉顶部tab及导航栏,地址栏等)

最佳做法是保持【16:9】等比缩放来实现自适应,避免被挤压或拉伸变形:

实现效果为:

当屏幕的尺寸比例刚好是16:9时,页面能刚好全屏展示,内容占满显示器

当屏幕的尺寸比例小于16:9时,页面上下留白,左右占满并上下居中,显示比例保持16:9

当屏幕尺寸比例大于16:9时,页面左右留白,上下占满并居中,显示比例保持16:9

(一)、scale方案

概述:是目前效果最好的一个方案. 计算scale缩放比率,然后在根组件上设置transform缩放. 比如: style.transform =`scaleX(${this.scaleX}) scaleY(${this.scaleY})`

transform-origin属性表示在对元素进行变换的时候,设置围绕哪个点进行变化的。默认情况,变换的原点在元素的中心点,即是元素X轴和Y轴的50%处

用法:transform-origin: x-axis y-axis z-axis;

优点:代码量少,适配简单 、一次处理后不需要在各个图表中再去单独适配.

缺点:留白,据说有事件热区偏移,但是我目前没有发现有这个问题

相关API介绍:

translate(-50%): 单个值x轴平移  俩个值 x y平移  三个值 x y z平移

translate(1): 单个值 同时作用于 X 轴和 Y 轴缩放。 俩个值:指定x y缩放  三个值:指定x y z缩放

一般情况下transform复合写法先执行后面的操作,比如 tranform: `scale(${scale}) translate(-50%)`;

先执行translate再执行scale,导致实际的tranlate平移过程中translate的值也会乘上你的scale中的参数。

1.scale缩放自适应自行实现

1-1.我们直接对body进行scale缩放,会将弹窗也缩放处理。 如果使用element,需要处理el-select、overflow-tooltip等错位问题。

(1).自适应缩放实现代码如下,放到main.js最后执行即可:

//如果实际宽高比 > 设计宽高比,则按高度进行整体缩小(不能按宽度整体放大,否则会有部分内容缺失),横向有留白,进行居中。
//如果实际宽高比 < 设计宽高比,则按宽度进行整体缩小(不能按高度整体放大,否则会有部分内容缺失),纵向有留白,进行居中。
import { debounce } from 'lodash';
(function setZoom() {
  const initScale = () => {
    const [designWidth, designHeight] = [1920, 1080]; //设计宽高比,按16:9的比例
    const bodyStyle = document.body.style;//获取body

    const { clientWidth, clientHeight } = document.documentElement;
    const designRatio = designWidth  / designHeight;
    const actualRatio = clientWidth / clientHeight;
    const widthScaleRatio = clientWidth / designWidth;
    const heightScaleRatio = clientHeight / designHeight;
    if( actualRatio <  designRatio){
      bodyStyle.transform = `scale(${widthScaleRatio}) translate(0 , -50%)`;
      bodyStyle.top= '50%';
      bodyStyle.left= '0';
    }else{
      bodyStyle.transform = `scale(${heightScaleRatio}) translate(-50%)`;
      bodyStyle.left= '50%';
      bodyStyle.top= '0';
    }
    //整体拉伸保证占满屏幕无任何留白, 但会出现挤压和拉伸变形, 不建议。
    //bodyStyle.transform = `scaleX(${widthScaleRatio}) scaleY(${heightScaleRatio}) `;
    bodyStyle.width = `${designWidth}px`;
    bodyStyle.height = `${designHeight}px`;
    bodyStyle.position = 'absolute';
  };
  initScale();
  window.addEventListener("resize", debounce(() => { initScale(); }, 300));
})();

(2).然后设置填充留白为背景图片或背景色,适应整体样式,避免太突兀,index.html中:

html{
    height: 100vh;
    width: 100vw;
    background-image: url(/static/img/backgroud.be22ef4e.png);
    box-sizing: border-box;
}

(3).然后在开发者工具-响应式设计模式中测试,调整分辨率,测试16:9比例的: 720p (1280x720)  1080p (1920x1080) ‌  4K (3840×2160)    再测试宽高比 小于16:9  和 大于16:9 的分辨率,符合正常预期即可。

浏览器打开 非全屏时(存在顶部tab和导航栏高度占用一部分高度) 实际宽高比(2.089) 会有留白  计宽高比16:9(1.777)

全屏时 实际宽高比 16:9(1.777)  设计宽高比16:9(1.777) 缩放比例1。

给客户部署到16:9的大屏显示器上时,全屏即可。

(4).下拉框错位解决: el-select的下拉框默认是添加到body中的。

添加属性,不让其放到body中 <el-select :popper-append-to-body="false">

然后调整下拉框样式即可:

::v-deep .el-select-dropdown{ 
  position: absolute !important;
  min-width: 100% !important;
  top: auto !important;  
  left: auto !important;
}

ps: 如果使用了pagination 并设置了sizes分页下拉框,配置layout slot嵌入一个自定义下拉框代替并修改配置即可。

<el-pagination layout="total, slot, prev, pager, next, jumper" > <el-select></el-select> </el-pagination>

(5).另外我这边还遇到了下拉框打开后,点击空白位置未自动收缩问题。报错:Uncaught TypeError: this.triggerElm is null

解决办法如下:

1).main.js注册全局指令v-clickOutside,判断click在el-select外面,则触发vnode中的clickOutSide方法

Vue.directive('clickOutside',{ 
  bind: function (el, binding, vnode) {
    el.clickOutsideEvent = function (event) { 
      if (!(el === event.target || el.contains(event.target))) { //检查click是否在el和他的children外面
        vnode.context[binding.expression](event,binding.arg)
      }
    }
    document.body.addEventListener('click', el.clickOutsideEvent)
  },
  unbind: function (el) {
    document.body.removeEventListener('click', el.clickOutsideEvent)
  }
})

2).在组件methos中增加clickOutSide方法: 触发blur()失焦:

clickOutSide (event, arg) {   this.$refs[`select-${arg}`].blur();  }        

3). el-select中增加ref 和 v-clickOutside属性即可,如下

<el-select ref="select-3" v-clickOutside:[3]="clickOutSide" v-model="form.f" placeholder="请选择普氏系数">

(6).解决el-table中show-overflow-tooltip 错位问题:

overflow-tooltip 默认也是添加到body中的,  el-tooltip虽然源码中有:append-to-body="false"属性,但加上会无法显示tooltip。

故这里采用的是css 省略,然后显示的浏览器原生悬浮框:

<template slot-scope="scope" >
    <div :title="scope.row.name" style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis"> {{  scope.row.name }}</div>
</template>
1-2.对根div缩放,由于和弹窗等在同一级,缩放不会影响到他们,也不会影响到他们的定位。然后只需单独处理弹窗等缩放即可:

(1).单独处理弹窗、popper等的scale收缩。

:root {
    --app-scale: 1;
}
body .el-message-box__wrapper .el-message-box, /**confirm确认框 删除按钮 */
body .el-dropdown-menu,/**下拉菜单 */
body .el-popover, /** Popover 弹出框 */
body .el-dialog, /**Dialog对话框*/
body .el-tooltip__popper /**表格中overflow-tooltip提示条*/{
  transform: var(--app-scale);
  transform-origin: 0 0;
}
/** 由于大部分下拉框都加了:popper-append-to-body="false",不会放到body中,会受到根div和el-dialog的scale收缩影响
    故这里只对没有添加此属性,会放到body下面的下拉框进行scale处理,比如pagination中的size下拉框等 */
body > .el-select-dropdown { /**  */
  transform: var(--app-scale) !important;
  transform-origin: 0 0;
}

(2).处理根div缩放,并设置--app-scale css变量

import { debounce } from 'lodash';
(function setZoom() {
  const initScale = () => {
    const [designWidth, designHeight] = [1920, 1080]; //设计宽高比,按16:9的比例
    const bodyStyle =  document.querySelector("#app").style; //获取根节点

    const { clientWidth, clientHeight } = document.documentElement;
    const designRatio = designWidth  / designHeight;
    const actualRatio = clientWidth / clientHeight;
    const widthScaleRatio = clientWidth / designWidth;
    const heightScaleRatio = clientHeight / designHeight;
    if( actualRatio <  designRatio){
      bodyStyle.transform = `scale(${widthScaleRatio}) translate(0 , -50%)`;
      document.documentElement.style.setProperty('--app-scale', `scale(${widthScaleRatio})`);
      bodyStyle.top= '50%';
      bodyStyle.left= '0';
    }else{
      bodyStyle.transform = `scale(${heightScaleRatio}) translate(-50%)`;
      document.documentElement.style.setProperty('--app-scale', `scale(${heightScaleRatio})`);
      bodyStyle.left= '50%';
      bodyStyle.top= '0';
    }
    //整体拉伸保证占满屏幕无任何留白, 但会出现挤压和拉伸变形, 不建议。
    //bodyStyle.transform = `scaleX(${widthScaleRatio}) scaleY(${heightScaleRatio}) `;
    bodyStyle.width = `${designWidth}px`;
    bodyStyle.height = `${designHeight}px`;
    bodyStyle.position = 'absolute';
    bodyStyle['transform-origin'] = '0 0';
  };
  initScale();
  window.addEventListener("resize", debounce(() => { initScale(); }, 300));
})();

(3).然后设置填充留白为背景图片或背景色,适应整体样式,避免太突兀,index.html中:

html{
    height: 100vh;
    width: 100vw;
    background-image: url(/static/img/backgroud.be22ef4e.png);
    box-sizing: border-box;
}

(4)然后在开发者工具-响应式设计模式中测试,调整分辨率,测试16:9比例的: 720p (1280x720)  1080p (1920x1080) ‌  4K (3840×2160)    再测试宽高比 小于16:9  和 大于16:9 的分辨率,符合正常预期即可。

浏览器打开 非全屏时(存在顶部tab和导航栏高度占用一部分高度) 会有留白  

给客户部署到16:9的大屏显示器上时,全屏即可。

若缩放后存在宽度溢出或者高度溢出问题,则多半时子元素中部分元素的width、height设置的问题,用开发者工具排查并修复即可。

我遇到的有: min-height: calc(100vh - 50px); 去掉min-height等让其自适应即可。

还有height:100%;使用父div全部高度导致溢出。需要减去头部高度:height: calc(100% - 50px);

2.可以直接使用插件v-scale-screen(根div缩放)

v-scale-screen   也是对根div进行缩放,是没有对弹窗进行缩放处理,需自己对弹窗进行vw/vh 百分比处理或缩放处理。

宽高设计1920*1080会有留白,因为存在浏览器顶部tab和导航栏高度,全屏即可(这个插件是给设置了个黑色背景,上下或左右平分了留白)。

npm install v-scale-screen
main.js注册插件:
import VScaleScreen from 'v-scale-screen'
Vue.use(VScaleScreen)
在根div中添加<v-scale-screen>标签即可:
 <v-scale-screen width="1920" height="1080">
<...其他子组件>
 </v-scale-screen>

3.还可以使用autofit.js插件来实现(默认设置到document.body 根节点上)

不会出现留白,移动屏也无留白,但会导致内容挤压或拉伸变形。因为设在根节点上,所以弹窗也会进行缩放。

另外还有个问题是el-select等选择定位会不准。作者说解决不了,需要去floating-ui/popper.js进行适配。

npm install autofit.js
import autofit from 'autofit.js'
  mounted(){
    autofit.init();//init()默认是按照1920 1080来处理的,可以在init中传参调整。 { dw = 1920, dh = 1080,el = typeof options === "string" ? options : "body", resize = true,ignore = [], transition = "none",delay = 0, limit = 0.1 }
  }

(二)、%百分比布局

比如,当浏览器的宽度或者高度发生变化时,通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果。

height、width 属性的%百分比依托于父标签的宽高但是 padding、border、margin 等属性的情况又不一样

1、子元素的 top 和 bottom 如果设置百分比,则相对于直接非 static 定位(默认定位)的父元素的高度,同样,子元素的 left 和 right 如果设置百分比,则相对于直接非 static 定位(默认定位的)父元素的宽度。

2、子元素的 padding 和 margin 如果设置百分比,不论是垂直方向或者是水平方向都相对于直接父亲元素的 width,而与父元素的 height 无关。

3.border-radius 为百分比,则是相对于自身的宽度

缺点:计算困难,如果我们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。

(三)、vw/vh方案(px -> vw/vh)

按照设计稿的尺寸,将px按比例计算转为vw和vh

(1).vw 和 vh 分别相对的是视图窗口的宽度和视口窗的高度 100vw = 视图窗宽度 ,100vh = 视图窗高度

在不同尺寸下1vw代表的值不同,比如在视图窗口为1920情况下1vw代表:1920px -> 19.2px

(3).我们在实际开发时,只需要按其中的某一个尺寸来的 px 单位的设计稿来开发就好(一般是以1920px 的大小为主)

代码全部开发好后,利用postcss-px-to-viewport来实现单位的自动转换即可。

例如:在宽为 1920px 的设计稿下,把 px 转换为 vw,是用 px/19.2 得到对应的 vw 单位值。转换好后,vw 是自动应视口宽的,所以就达到了响应式开发的效果。

npm install -D postcss-loader postcss-px-to-viewport

配置 vue.config.js即可:

module.exports = {
    css: {
        loaderOptions: {
            postcss: {
                plugins: [
                  require('postcss-px-to-viewport')({
                    viewportWidth: 1920, // 设计稿的视口宽度,可以根据实际情况调整
                    viewportHeight: 1080, // 设计稿的视口高度,可以根据实际情况调整
                    unitPrecision: 3, // 转换后的精度,即小数点位数
                    viewportUnit: 'vw', // 要转换成的视口单位
                    selectorBlackList: ['.ignore', '.hairlines'], // 不转换的类名
                    minPixelValue: 1, // 小于或等于1px不转换为视口单位
                    mediaQuery: false // 允许在媒体查询中转换px
                  })
                ]
              }
        },
},
}

postcss-px-to-viewport使用较为简单,只需要通过安装插件和配置即可快速实现 px 转换为 vw 或 vh 单位

缺点:

vw 和 vh 单位不适用于字体大小,因此需要单独设置字体大小的转换方式。

无法把行内样式中的 px 转换成视口单位(vw, vh, vmin, vmax)。

由于浏览器的视口宽度和高度不同,转换后的样式可能会有一定的误差,无法精确控制样式。

额外:vw/vh/% 均是css的响应式单位。如果外层使用%等响应式单位, 内部元素使用px, 在不同分辨率下还是会有问题(外层自适应了,但内部px会溢出), 故使用vw/vh 或百分比, 内部也需要用vw/vh 

(四)、rem方案(px -> rem)

(1).rem 是相对于 html 根元素的字体大小的单位。我们通过修改 html 中 font-size 的字体大小来控制 rem 的大小。

比如: html { font-size: 10px; }  .box { width: 10rem; height: 20rem;  }

当 html 中 font-size: 10px; 时,此时 1rem = 10px, box 盒子的宽高分别为:100px 和 200px;

当 html 中 font-size: 20px; 时,此时 1rem = 20px,  box 盒子的宽高就为 200px 和 400px;

(2).在实际的开发中,通常以 1920px 的设计稿来开发。我们在代码写完后,统一会把所有 px 单位全部转成 rem

如果我们把总宽 1920px 分成 10rem,些时 1rem = 192px; ,转成对应的 rem 单位,就是用对应的 px/192px

代码全部开发好后,再利用 postcss-px2rem插件 来自动转换即可。

(3).适配不同的浏览器,实现等比例的缩放比如有3个尺寸的屏幕 (3840 1920 1280),所有屏幕整体宽分成10rem,html根元素的font-size大小就是(384 192 128)

可以通过 js 来动态修改不同屏幕尺寸下的 font-size 大小就可以实现等比例放大和缩小

initPage();
function initPage() {
    var clientWidth =document.documentElement.clientWidth || document.body / clientWidth; //获取屏幕可视区宽
    var html = document.getElementsByTagName("html")[0]; //获取html根元素
    html.style.fontSize = clientWidth / 10 + "px"; //动态设置font-size大小
} 
window.onresize = initPage;

ps: 也可以直接使用以用 flexible.js 插件,flexible 原理就是根据不同的屏幕宽度动态的设置网页中 html 根节点的 font-size

然后将所有的 px 用 rem 来代替,这样就实现了不同大小的屏幕都适应相同的样式了。

(五)、@media 媒体查询布局:

通过@media 媒体查询,可以通过给不同屏幕的大小编写不同的样式来实现响应式的布局。

响应式缺点:如果浏览器大小改变时,需要改变的样式太多,那么多套样式代码会很繁琐。

@media (max-width: 768px) {  /* 在小于等于768px的宽度下应用的样式 */}

@media (min-width: 1201px) {  /* 在大于等于1201px的宽度下应用的样式 */ }

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李庆政370

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值