程序员开发实例大全宝库

网站首页 > 编程文章 正文

让PC页面自动伸缩,以适应所有设备

zazugpt 2024-08-16 06:49:21 编程文章 20 ℃ 0 评论

让PC页面自动伸缩,以适应所有设备

在切页面的过程中,我们不得不将页面写的死死的,精确到每一个px,但带来的弊端也是很明显,甚至可以说是致命的。

为了让PC页面能够真正自适应缩放,即使是用户用手机浏览,也能保证其铺满整个屏幕,我们需要提出一个针对该问题的解决方案,这也是本文需要讲的事情。

@-v-@


1. 为什么要让页面自动伸缩

上面这张图片来自百度统计,从中我们可以看到:

近3个月以来,PC上,1920x1080分辨率的显示器使用率最多,其次就是1366x768的分辨率了。

1366x768分辨率的显示器,应当是装在比较老的笔记本或特别旧的台式机上的,主要还是笔记本占多数。这些显示器的主要用户群,应该是学生。

1920x1080分辨率的显示器,应当是装在比较新的笔记本或一般的台式机上的。其中,台式机应当占多数。它们的主要用户群,应该是那些比较新潮的年轻人、网咖、社会工作人员等。

从这儿分析啊,我们就可以知道,1920x1080绝对是我们值得参考的一个屏幕尺寸。这个尺寸,在以后也会是主流。

为什么呢?

我们这样来分析一下:

用于影院的大显示器和家用的电视机的分辨率,肯定是越大越好,但并不是所有人都愿用money来买这种东西。最最主要的是,这种设备,追求的就是两个大字,一是分辨率要大,二是尺寸要大。但很可惜,影院的大显示器和家用的电视机是不太可能成为网页中访问量较高的那一部分的,至少当前不行。

你可能会想,尺寸小一点,分辨率高一点,岂不更好?

其实不是这样的。如果有一个23.8英寸的显示器,它的分辨率达到了4k,那么,我们是无法直接“正视”它的。至少对于我们这些普通人来说,是不能承受的。上面的字会小到让你无法直视的地步。想一想,16px的字体,在一个4k分辨率,但仅23.8英寸的屏幕上呈现时的情况,你就知道了。

若要说具体点,就是当你用手机去访问Github页面时,不要进行缩放,直接观看上面的文字,所产生的感受。(不建议你尝试这样做,幸好现在的手机屏幕一般都还不错,否则你真的会瞎眼的o-v-^,如果非要试一试,先滴几滴眼药水吧!)

现在很多网站为了兼容这两个用户量最多的PC设备屏幕以及分辨率在它们之间的那些PC设备屏幕,将设计稿定成总宽1600px,内容区域宽1200px的大小,就是为了保证绝大部分PC屏幕设备可以在不需要伸缩的情况下浏览,但这对于1920x1080分辨率设备的用户来说,就不太友好了,因为这样会留下很多的空白,视觉上体验很不好。

为了解决这个问题,有些网站会使用多个媒体查询来做不同分辨率的显示器样式匹配,就如同下面这样:

/* 为适配手机尺寸而引入 */ @media only screen and (max-width: 240px) { ... } @media only screen and (min-width: 241px) and (max-width: 360px) { ... } @media only screen and (min-width: 361px) and (max-width: 480px) { ... } @media only screen and (min-width: 481px) and (max-width: 799px) { ... } @media only screen and (min-width: 800px) and (max-width: 1199px) { ... } /* 为适配PC尺寸而引入 */ @media only screen and (min-width: 1200px) and (max-width: 1600px) { ... } @media only screen and (min-width: 1601px) and (max-width: 2048px) { ... } @media only screen and (min-width: 2049px) and (max-width: 5000px) { ... } /** * 还可以增加一个媒体查询项,即设备的横竖屏状态 * 该状态在下面会用到,而且是大有用处 * * (orientation : landscape) 代表设备竖屏时,书写方式为: * @media only screen and (orientation : landscape) { ... } * * (orientation : portrait) 代表设备横屏时,书写方式为 * @media only screen and (orientation : portrait) { ... } */
<!-- 为适配手机尺寸而引入 --> <link rel="stylesheet" media="only screen and (max-width: 240px)" href="style-0-240.css"> <link rel="stylesheet" media="only screen and (min-width: 241px) and (max-width: 360px)" href="style-241-360.css"> <link rel="stylesheet" media="only screen and (min-width: 361px) and (max-width: 480px)" href="style-361-480.css"> <link rel="stylesheet" media="only screen and (min-width: 481px) and (max-width: 799px)" href="style-481-799.css"> <link rel="stylesheet" media="only screen and (min-width: 800px) and (max-width: 1199px)" href="style-800-1199.css"> <!-- 为适配PC尺寸而引入 --> <link rel="stylesheet" media="only screen and (min-width: 1200px) and (max-width: 1600px)" href="style-1200-1600.css"> <link rel="stylesheet" media="only screen and (min-width: 1601px) and (max-width: 2048px)" href="style-1601-2048.css"> <link rel="stylesheet" media="only screen and (min-width: 2049px) and (max-width: 5000px)" href="style-2049-5000.css">

当你看到这么大一长串媒体查询的时候,是不是感觉挺烦的?

而且,你以为将页面定死了之后,应用媒体查询加载不同的css文件,或在同一文件中使用多个媒体查询,页面就一定可以适应所有的屏幕,但很可惜的是,事情并没有你想的那么简单。看下图:

这是在1920x1080屏幕下浏览百度的页面

这是在1366x768屏幕下浏览百度的页面

百度使用的就是典型的1200px设计方式,像素是直接写死了的。这种方式,其实也是现在大家普遍使用的方式,好处就是切图方便直接,而且也利于更改,可以进行组件化开发,是多少px就绝对不会偏差。但坏处是,对大屏幕不友好,会存在很多留白。


2. 一次切图,到处运行的方案

我苦思冥想,怎样才能使得“ 一次切图,到处运行”?即使是碰到手机端访问这个本属于PC的页面,我也不惧。

这真的是一个值得思考的问题。

我想到了两种方式来解决这个问题,但都比较痛苦,因为它们都需要浏览器支持js脚本,如果用户关闭了浏览器端js的渲染,就会出问题。

幸好,大部分用户还是挺“讲道理”的,不会无缘无故关闭这个功能。

接下来,我就来说说我想到的这两个方案。

2.1 加载后,动态修改px

我们可以写一个函数,这个函数需要一个参考像素大小,还需要接受一个dom,用于指定对谁进行动态修改。

其次,我们在页面加载完成后,运行一次这个函数,并把这个函数添加到,当页面大小更改时触发的事件回调上。

接下来,最重要的就是,编写这个函数了。它的运行过程是:

遍历dom下的所有CssStyle中的属性,以及dom下其它后代结点的中的CssStyle属性,只要是那些有px长度值的属性,统统都根据参考像素的大小,来更新。

这应该算是一种很笨,而且实现起来很难的方法。

2.2 用rem和em替换px值

这种方式应该算是最好的一种方式了,不用什么其他复杂的实现过程,只需要一段小小的js就能搞定一切。

不过呢,也会有问题的,那就是写css的时候,需要弄清楚,什么时候该用rem,什么时候该用em。

一般来说,对一个组件的内部,应该主要使用em,并且应当给组件容器的font-size,显式指定一下对应于html标签的font-size的大小。其他那些布局容器都使用rem或百分比作为单位。

可能我说的有点复杂,再简单点说吧:

  • 组件内部使用em作为主要单位,尽可能少地使用px

  • 组件容器的font-size使用rem作为单位,以指定组件的实际大小

  • 布局容器的宽、高等布局属性,全部使用rem作为单位

2.3 将来的布局新方式—-vw

如果没办法使用js,那么,我们可能就只能使用vw这个绝招了。

在网页设计过程中,我发现,其实所有的页面布局容器,都跟一个量有关,那就是视宽。

这儿的视宽并不是设备的宽度,而是指浏览器的视窗宽度。万幸,有一个尺寸单位,可以来衡量浏览器的视窗宽度,这就是vw。

vw、vh、vmin、vmax都是视口相对长度单位(Viewport-relative Length Units),其中最有用处的是vw。

vw是一个相对于视口宽度的单位。浏览器视窗被分成100份,1vw就代表其中的一份,再简单点说,就是 (1vw === 1% * 浏览器视窗宽度)

我们可以在开发过程中,使用vw替代掉rem,这样,不需要js就可以让页面自适应缩放。

这时,我们就可以这样做:

  • 组件内部使用em作为主要单位,尽可能少地使用px

  • 组件容器的font-size使用vw作为单位,以指定组件的实际大小

  • 布局容器的宽、高等布局属性,全部使用vw作为单位

但是呢,最最让人绝望的是…看下图:

IE7和IE8暂时是消除不了的,这也就阻碍了我们使用vw单位,而且更重要的是,vw在安卓4.3以下都不行,如果我们一意孤行,使用它的话,带来的灾难就是,很大一部分手机会被网页“淘汰”掉。

这一张图,来自css88的vw兼容性信息截图

天呐,vw是不是很“危险”?

没错,我们可以这样认为: vw === 暂时性的禁区,为了避免后期修改代码,我们还是只能选择使用rem,这个vw倒是将来切图的一个利器,可以先备着。


3. 将第二种方案实现一下

废话说了一大堆,情怀也聊的差不多了,接下来,我们来做一个使用 rem + auto flexible 搞定的html页面吧。

这一次,我选择使用我自己的首页来说明一下它的切图流程。

你可以去我的首页地址试一下效果, 链接 => freeedit.cn

亲请用不是Chrome的浏览器,打开这个链接,(如果是IE,请确保浏览器在IE10以上的模式下运行),然后把窗口大小进行缩放,看页面是否有问题。如果存在问题,请给我在我的个人网站仓库下留个issue,谢谢 ^-^。

3.1 准备作品的目录

  • 新建一个文件夹,取名叫pc-auto-flexible

  • 在该文件夹中,新建以下文件及文件夹

  • index.html

  • css\

  • js\

  • lib\

  • img\

  • 在css文件夹下新建一个名叫style.css的文件

  • 在js文件夹下新建一个名叫script.es5.js的文件

  • 在lib文件夹下新建一个名叫auto-flexible.js的文件

然后,我们就来直接动手撸吧

3.2 准备好auto-flexible.js的内容

首先,我们肯定需要添加事件,所以需要一个门面来包装一下这个添加事件的功能,保证在任何浏览器上都能添加事件。

其实这些代码,相信大家都已经写过很多遍了,这儿就直接给代码了,没有什么好说的,真正重要的,是接下来的代码。

function addEvent(el, type, fn, isBubble) { if (el) { if (window.addEventListener) el.addEventListener(type, fn, isBubble); else if (window.attachEvent) el.attachEvent('on' + type, fn, isBubble); else { var onEv = 'on' + type; var onFn = onEv + 'Fn'; var onBu = onEv + 'Bu'; el[onBu] = isBubble; if (!el[onFn]) { el[onFn] = []; el[onFn].push(fn); el[onEv] = function (e) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = el[onFn][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { ev = _step.value; ev(e); if (!isBubble) stopEvent(e); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } }; } else { el[onFn].push(fn); } } } }

接下来的这个代码是auto-flexible实现的关键,它并非是我写的,我只是给它润了润色,原始的实现代码是来自网络上的一篇文章,具体在哪里,我已经找不到了(作者,请原谅我 -。o-)。

(function (doc, win) { var docEl = doc.documentElement; var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'; var recalc = function () { var clientWidth = docEl.clientWidth; if (!clientWidth) return; docEl.style.fontSize = 100 * (clientWidth / 1366) + 'px'; }; docEl.style.textSizeAdjust = 'auto'; addEvent(win, resizeEvt, recalc, false); addEvent(doc, 'DOMContentLoaded', recalc, false); })(document, window);

在阅读上面这段代码的时候,我们先来看看DOM文档的加载步骤:

  1. 首先解析HTML结构

  2. 然后加载外部脚本和样式表文件

  3. 接着解析并执行脚本代码

  4. DOM树构建完成 => DOMContentLoaded

  5. 加载图片等外部文件

  6. 页面加载完毕 => load

document.documentElementDOMContentLoaded事件在第4步发生,即等DOM树加载完成后,立即更新其style.fontSize属性。

其实document.documentElement对应的就是html标签元素,在XML中就是文档根节点。

window上面添加orientationchangeresize事件,是为了当屏幕方向更改,或者浏览器宽度被更改时,html标签的style.fontSize属性就会被recalc函数计算后的值替换掉。

docEl.style.textSizeAdjust = 'auto';是用来保证在老版本的Chrome浏览器下,字体能够被缩放。

为什么在上面,我会专门说明,不用Chrome浏览器打开,就是因为在新版本的Chrome浏览器下,文字是不能小于12px的,即使是将html标签的style.textSizeAdjust样式属性设为auto,也一点用都没有。

这是为什么呢?一直对我们开发人员很有好的Chrome浏览器,为什么会搞这么一手呢?

还记得最上面提到的那个小尺寸高分辨率屏幕的问题么?

Chrome浏览器毕竟需要考虑用户的感受,它设置字体不能小于12px,就是因为字体一般是16px-16px的矩阵,设置字体为12px、14px、16px这种偶数型的,能更利于字体的渲染速度和渲染效果。而且12px的的确确算是比较小的字体了,再小的话,就会影响到用户的阅读了,为了避免瞎眼,Chrome就直接给我们丢来了一个根本无法解决的题。

docEl.style.fontSize = 100 * (clientWidth / 1366) + 'px';是这段代码中,最最主要的功能实现。

1366代表使用1366x768的屏幕作为设计参考,来进行页面的切图工作。

100代笔在1366x768的屏幕下,html的font-size为100px,这样方便于我们在切图过程中进行计算。

当我们拿着一张标准的1600px-1200px的设计稿时,我们就可以直接用1200px === 12rem来表示主体内容的容器宽度。

其实本来可以这样的: docEl.style.fontSize = clientWidth / 100 + 'px';

简单粗暴,直接将页面的宽度分成100分,rem就有了和vw一样的能力。

但是这并不方便于计算,所以我将其改成了在1366x768的屏幕下100px === 1rem的形式。

为什么没有使用1920x1080分辨率来作为设计参考呢?这是为了设计的美观性和便捷性。

在1920x1080分辨率下设计网站样式,不利于我们掌控文字的大小。1366x768分辨率下,我们可以直接使用16px的字体,这个字体不会显得太大,也不会显得太小,正好合适。

上面的两段代码,都应放在auto-flexible.js文件下。

如果复制存在问题,可以去https://github.com/freeedit/lib-mini-libs-collection/blob/master/auto-flexible.js上面复制一下代码

3.3 准备好其它文件的内容

刚才建了一堆的文件,其实只是为了让你了解一下这个例子的结构,和auto-flexible的实现方法。

我们现在就去https://github.com/freeedit/learn-pc-auto-flexible上面,将这个库克隆至本地,然后从中取出new-project文件夹下的所有文件和文件夹,放置在pc-auto-flexible文件夹中,最后选择“是”,将其全部覆盖。

3.4 编写HTML代码

建议在书写的过程中,使用browser-over打开浏览器来实时预览该效果

打开index.html文件,编写页面整体的结构

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="./lib/auto-flexible.js"></script> <!-- <link rel="apple-touch-icon" href="./img/favicon.png"> --> <link rel="Shortcut Icon" href="./img/favicon.ico" type="image/x-icon"> <title>易杭网 | 首页</title> <!-- <link rel="stylesheet" href="./lib/normalize.css"> --> <link rel="stylesheet" href="./css/style.css"> <!-- <script src="./lib/prefixfree.min.js"></script> --> </head> <body> <div class="yh-container no-scroll"> <!-- 页面最上面的浮动层所在地 --> </div> <script src="./js/script.es5.js"></script> </body> </html>

编写页面最上面的浮动层

 <div class="yh-over__icon-container"> <img src="./img/yh-icon.svg" alt="" class="yh-over__icon"> </div> <div class="yh-over posa-full"> <img src="./img/yh-name.svg" alt="" class="yh-over__bg posa-center"> </div> <!-- 页面的主体容器所在地 -->

编写页面的主体容器

 <div class="yh-page no-scroll" oncontextmenu="return false;" ondragstart="return false" onselectstart="return false" onselect="document.selection.empty();"> <div class="yh-page__bd posa-center clearfix"> <!-- 页面的主体所在地 --> </div> <div class="yh-page__over-layer posa-center"></div> <img src="./img/1366x768-1.jpg" alt="" class="yh-page__bg posa-center"> </div>

编写页面的主体

 <!-- 最左侧的展示区域 --> <div class="yh-display no-scroll flex-cont-center"> <img src="./img/24x24-1.png" alt="" class="yh-display__animation-controller"> <img src="./img/35x25-1.png" alt="" class="yh-display__seal"> <img src="./img/100x240-1.png" alt="" class="yh-display__art-font posa-center"> <div class="yh-display__over-layer posa-full"></div> <img src="./img/240x400-1.jpg" alt="" class="yh-display__animation"> </div> <!-- 中间的个人链接区域 --> <div class="yh-about"> <a href="http://www.freeedit.cn/about/who-am-i.html" class="yh-about__who-am-i no-scroll flex-cont-center"> <span class="yh-about__desc">WHO AM I</span> </a> <a href="javascript:;" class="yh-about__what-i-do no-scroll flex-cont-center"> <span class="yh-about__desc">WHAT I DO</span> </a> <a href="javascript:;" class="yh-about__what-i-use no-scroll flex-cont-center"> <span class="yh-about__desc">WHAT I USE</span> </a> <a href="javascript:;" class="yh-about__other no-scroll flex-cont-center"> <span class="yh-about__desc">OTHER INFO</span> </a> </div> <!-- 右边的四大区块 --> <div class="yh-domains"> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">0</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭博客</div> <a href="http://blog.freeedit.cn" class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭博客</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 地震高岗,<br/>一派溪山千古秀。<br/> 门朝大海,<br/>三河合水万年流。 </strong> <img src="./img/40x40-1.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-1.jpg" alt="" class="yh-domain__bg"> </div> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">3</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭仓库</div> <a href="https://github.com/freeedit" class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭仓库</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 竹杖芒鞋轻胜马,<br/> 谁怕?<br/> 一蓑烟雨任平生。 </strong> <img src="./img/40x40-2.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-2.jpg" alt="" class="yh-domain__bg"> </div> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">3</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭动态</div> <a href="javascript:;" class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭动态</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 人生若只如初见,<br/> 何事秋风悲画扇。 </strong> <img src="./img/40x40-3.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-3.jpg" alt="" class="yh-domain__bg"> </div> <div class="yh-domain no-scroll flex-cont-center"> <a href="javascript:;" class="yh-domain__badge">3</a> <div class="yh-domain__title-below posa-horizontal-center ellipsis">易杭导航</div> <a href="javascript:;" class="yh-domain__over-info posa-full"> <h1 class="yh-domain__title posa-horizontal-center ellipsis">易杭导航</h1> <strong class="yh-domain__desc posa-horizontal-center ellipsis"> 俏也不争春,<br/> 只把春来报。<br/> 待到山花烂漫时,<br/> 她在丛中笑。 </strong> <img src="./img/40x40-4.png" alt="" class="yh-domain__icon posa-horizontal-center"> </a> <div class="yh-domain__over-layer posa-full"></div> <img src="./img/180x400-4.jpg" alt="" class="yh-domain__bg"> </div> </div> <!-- 最下面的备案信息 --> <div class="yh-beian-info posa-horizontal-center"> <a href="http://www.beianbeian.com/beianxinxi/a4dc4ee5-7b5d-4c9c-a2f0-0b0654e7fa51.html">蜀ICP备16016576号-1 <strong>[易杭网]</strong></a> <a href="http://www.beianbeian.com/search/freeedit.cn">http://www.beianbeian.com/search/<strong>freeedit.cn</strong></a> </div>

当你书写完成该html代码的时候,就可以试一试会不会出现和www.freeedit.cn首页一样的效果。

3.5 使用px2rem搞定css中的px

在style.css文件中,我们可以看到,里面使用的全是以px为单位的布局方式,我们需要将其转换为rem。

在命令提示符中,使用npm安装一个名叫px2rem的包,它可以帮助我们用命令行的方式生成新文件。

在命令提示符中,切换到css文件夹下,使用以下命令生成新文件

$ px2rem -u 100 *.css -o ./

最后改一下<link rel="stylesheet" href="./css/style.css">中的href值为./css/style.debug.css

运行一下index.html文件 看看是否可以自动伸缩了。


4 总结

最好的方式是自己约束自己,一开始就以rem和em为主进行切图,遵循的规则是:

  • 组件内部使用em作为主要单位,尽可能少地使用px

  • 组件容器的font-size使用rem作为单位,以指定组件的实际大小

  • 布局容器的宽、高等布局属性,全部使用rem作为单位

在最开始切图的时候,也可以使用px来搞定页面,然后再用px2rem转一下文件。

这种方式会存在问题,比如较窄的边框和较小的阴影效果等,都可能因为长度值出现小数点,而使线条变得模糊,尽管肉眼可能看不到。

以上就是本文的全部内容,不知道这个技能,对于你而言,是不是有用的。

如果你认同本文的某些观点,并且挺喜欢我滴~,请给我的仓库点个赞好么 (o_o)

本文使用的代码: https://github.com/freeedit/learn-pc-auto-flexible

如果你能follow我一下,就更好了。 a li ga do ^&-&^

我的Github

最后的最后,我想和大家一起来写ES的知识总结,不知道你能否给我个膝盖。

详情传送地 => -^-^-

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表