关于移动端适配,你必须要知道的,面试经典题型

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

我们可以通过调用document.documentElement.clientWidth / clientHeight来获取布局视口大小。

4.2 视觉视口

视觉视口(visual viewport):用户通过屏幕真实看到的区域。

视觉视口默认等于当前浏览器的窗口大小(包括滚动条宽度)。

当用户对浏览器进行缩放时,不会改变布局视口的大小,所以页面布局是不变的,但是缩放会改变视觉视口的大小。

例如:用户将浏览器窗口放大了200%,这时浏览器窗口中的CSS像素会随着视觉视口的放大而放大,这时一个CSS像素会跨越更多的物理像素。

所以,布局视口会限制你的CSS布局而视觉视口决定用户具体能看到什么。

我们可以通过调用window.innerWidth / innerHeight来获取视觉视口大小。

4.3 理想视口

布局视口在移动端展示的效果并不是一个理想的效果,所以理想视口(ideal viewport)就诞生了:网站页面在移动端展示的理想大小。

如上图,我们在描述设备独立像素时曾使用过这张图,在浏览器调试移动端时页面上给定的像素大小就是理想视口大小,它的单位正是设备独立像素。

上面在介绍CSS像素时曾经提到页面的缩放系数 = CSS像素 / 设备独立像素,实际上说页面的缩放系数 = 理想视口宽度 / 视觉视口宽度更为准确。

所以,当页面缩放比例为100%时,CSS像素 = 设备独立像素理想视口 = 视觉视口

我们可以通过调用screen.width / height来获取理想视口大小。

4.4 Meta viewport

<meta> 元素表示那些不能由其它HTML元相关元素之一表示的任何元数据信息,它可以告诉浏览器如何解析页面。

我们可以借助<meta>元素的viewport来帮助我们设置视口、缩放等,从而让移动端得到更好的展示效果。

上面是viewport的一个配置,我们来看看它们的具体含义:

Value| 可能值| 描述 -|-|- width| 正整数或device-width | 以pixels(像素)为单位, 定义布局视口的宽度。 height| 正整数或device-height | 以pixels(像素)为单位, 定义布局视口的高度。 initial-scale0.0 - 10.0|定义页面初始缩放比率。 minimum-scale0.0 - 10.0|定义缩放的最小值;必须小于或等于maximum-scale的值。 maximum-scale0.0 - 10.0|定义缩放的最大值;必须大于或等于minimum-scale的值。 user-scalable| 一个布尔值(yes或者no)| 如果设置为 no,用户将不能放大或缩小网页。默认值为 yes。

4.5 移动端适配

为了在移动端让页面获得更好的显示效果,我们必须让布局视口、视觉视口都尽可能等于理想视口。

device-width就等于理想视口的宽度,所以设置width=device-width就相当于让布局视口等于理想视口。

由于initial-scale = 理想视口宽度 / 视觉视口宽度,所以我们设置initial-scale=1;就相当于让视觉视口等于理想视口。

这时,1个CSS像素就等于1个设备独立像素,而且我们也是基于理想视口来进行布局的,所以呈现出来的页面布局在各种设备上都能大致相似。

4.6 缩放

上面提到width可以决定布局视口的宽度,实际上它并不是布局视口的唯一决定性因素,设置initial-scale也有肯能影响到布局视口,因为布局视口宽度取的是width和视觉视口宽度的最大值。

例如:若手机的理想视口宽度为400px,设置width=device-widthinitial-scale=2,此时视觉视口宽度 = 理想视口宽度 / initial-scale200px,布局视口取两者最大值即device-width 400px

若设置width=device-widthinitial-scale=0.5,此时视觉视口宽度 = 理想视口宽度 / initial-scale800px,布局视口取两者最大值即800px

4.7 获取浏览器大小

浏览器为我们提供的获取窗口大小的API有很多,下面我们再来对比一下:

  • window.innerHeight:获取浏览器视觉视口高度(包括垂直滚动条)。

  • window.outerHeight:获取浏览器窗口外部的高度。表示整个浏览器窗口的高度,包括侧边栏、窗口镶边和调正窗口大小的边框。

  • window.screen.Height:获取获屏幕取理想视口高度,这个数值是固定的,设备的分辨率/设备像素比

  • window.screen.availHeight:浏览器窗口可用的高度。

  • document.documentElement.clientHeight:获取浏览器布局视口高度,包括内边距,但不包括垂直滚动条、边框和外边距。

  • document.documentElement.offsetHeight:包括内边距、滚动条、边框和外边距。

  • document.documentElement.scrollHeight:在不使用滚动条的情况下适合视口中的所有内容所需的最小宽度。测量方式与clientHeight相同:它包含元素的内边距,但不包括边框,外边距或垂直滚动条。

五、1px问题


为了适配各种屏幕,我们写代码时一般使用设备独立像素来对页面进行布局。

而在设备像素比大于1的屏幕上,我们写的1px实际上是被多个物理像素渲染,这就会出现1px在有些屏幕上看起来很粗的现象。

5.1 border-image

基于media查询判断不同的设备像素比给定不同的border-image

.border_1px{

border-bottom: 1px solid #000;

}

@media only screen and (-webkit-min-device-pixel-ratio:2){

.border_1px{

border-bottom: none;

border-width: 0 0 1px 0;

border-image: url(…/img/1pxline.png) 0 0 2 0 stretch;

}

}

5.2 background-image

border-image类似,准备一张符合条件的边框背景图,模拟在背景上。

.border_1px{

border-bottom: 1px solid #000;

}

@media only screen and (-webkit-min-device-pixel-ratio:2){

.border_1px{

background: url(…/img/1pxline.png) repeat-x left bottom;

background-size: 100% 1px;

}

}

上面两种都需要单独准备图片,而且圆角不是很好处理,但是可以应对大部分场景。

5.3 伪类 + transform

基于media查询判断不同的设备像素比对线条进行缩放:

.border_1px:before{

content: ‘’;

position: absolute;

top: 0;

height: 1px;

width: 100%;

background-color: #000;

transform-origin: 50% 0%;

}

@media only screen and (-webkit-min-device-pixel-ratio:2){

.border_1px:before{

transform: scaleY(0.5);

}

}

@media only screen and (-webkit-min-device-pixel-ratio:3){

.border_1px:before{

transform: scaleY(0.33);

}

}

这种方式可以满足各种场景,如果需要满足圆角,只需要给伪类也加上border-radius即可。

5.4 svg

上面我们border-imagebackground-image都可以模拟1px边框,但是使用的都是位图,还需要外部引入。

借助PostCSSpostcss-write-svg我们能直接使用border-imagebackground-image创建svg1px边框:

@svg border_1px {

height: 2px;

@rect {

fill: var(–color, black);

width: 100%;

height: 50%;

}

}

.example { border: 1px solid transparent; border-image: svg(border_1px param(–color #00b1ff)) 2 2 stretch; }

编译后:

.example { border: 1px solid transparent; border-image: url(“data:image/svg+xml;charset=utf-8,%3Csvg xmlns=‘http://www.w3.org/2000/svg’ height=‘2px’%3E%3Crect fill=‘%2300b1ff’ width=‘100%25’ height=‘50%25’/%3E%3C/svg%3E”) 2 2 stretch; }

上面的方案是大漠在他的文章中推荐使用的,基本可以满足所有场景,而且不需要外部引入,这是我个人比较喜欢的一种方案。

5.5 设置viewport

通过设置缩放,让CSS像素等于真正的物理像素。

例如:当设备像素比为3时,我们将页面缩放1/3倍,这时1px等于一个真正的屏幕像素。

const scale = 1 / window.devicePixelRatio;

const viewport = document.querySelector(‘meta[name=“viewport”]’);

if (!viewport) {

viewport = document.createElement(‘meta’);

viewport.setAttribute(‘name’, ‘viewport’);

window.document.head.appendChild(viewport);

}

viewport.setAttribute(‘content’, ‘width=device-width,user-scalable=no,initial-scale=’ + scale + ‘,maximum-scale=’ + scale + ‘,minimum-scale=’ + scale);

实际上,上面这种方案是早先flexible采用的方案。

当然,这样做是要付出代价的,这意味着你页面上所有的布局都要按照物理像素来写。这显然是不现实的,这时,我们可以借助flexiblevw、vh来帮助我们进行适配。

六、移动端适配方案


尽管我们可以使用设备独立像素来保证各个设备在不同手机上显示的效果类似,但这并不能保证它们显示完全一致,我们需要一种方案来让设计稿得到更完美的适配。

6.1 flexible方案

flexible方案是阿里早期开源的一个移动端适配解决方案,引用flexible后,我们在页面上统一使用rem来布局。

它的核心代码非常简单:

// set 1rem = viewWidth / 10

function setRemUnit () {

var rem = docEl.clientWidth / 10

docEl.style.fontSize = rem + ‘px’

}

setRemUnit();

rem 是相对于html节点的font-size来做计算的。

我们通过设置document.documentElement.style.fontSize就可以统一整个页面的布局标准。

上面的代码中,将html节点的font-size设置为页面clientWidth(布局视口)的1/10,即1rem就等于页面布局视口的1/10,这就意味着我们后面使用的rem都是按照页面比例来计算的。

这时,我们只需要将UI出的图转换为rem即可。

iPhone6为例:布局视口为375px,则1rem = 37.5px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 37.5 = 2rem

当然,每个布局都要计算非常繁琐,我们可以借助PostCSSpx2rem插件来帮助我们完成这个过程。

下面的代码可以保证在页面大小变化时,布局可以自适应,当触发了windowresizepageShow事件之后自动调整htmlfontSize大小。

// reset rem unit on page resize

window.addEventListener(‘resize’, setRemUnit)window.addEventListener(‘pageshow’, function (e) {

if (e.persisted) {

setRemUnit()

}

})

由于viewport单位得到众多浏览器的兼容,上面这种方案现在已经被官方弃用:

lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方案。

下面我们来看看现在最流行的vh、vw方案。

6.2 vh、vw方案

vh、vw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight 等分为 100 份。

上面的flexible方案就是模仿这种方案,因为早些时候vw还没有得到很好的兼容。

  • vw(Viewport's width)1vw等于视觉视口的1%

  • vh(Viewport's height) :1vh 为视觉视口高度的1%

  • vmin : vw 和 vh 中的较小值

  • vmax : 选取 vw 和 vh 中的较大值

如果视觉视口为375px,那么1vw = 3.75px,这时UI给定一个元素的宽为75px(设备独立像素),我们只需要将它设置为75 / 3.75 = 20vw

这里的比例关系我们也不用自己换算,我们可以使用PostCSS的 postcss-px-to-viewport 插件帮我们完成这个过程。写代码时,我们只需要根据UI给的设计图写px单位即可。

当然,没有一种方案是十全十美的,vw同样有一定的缺陷:

  • px转换成vw不一定能完全整除,因此有一定的像素差。

  • 比如当容器使用vwmargin采用px时,很容易造成整体宽度超过100vw,从而影响布局效果。当然我们也是可以避免的,例如使用padding代替margin,结合calc()函数使用等等…

七、适配iPhoneX


iPhoneX的出现将手机的颜值带上了一个新的高度,它取消了物理按键,改成了底部的小黑条,但是这样的改动给开发者适配移动端又增加了难度。

7.1 安全区域

iPhoneX发布后,许多厂商相继推出了具有边缘屏幕的手机。

这些手机和普通手机在外观上无外乎做了三个改动:圆角(corners)、刘海(sensor housing)和小黑条(Home Indicator)。为了适配这些手机,安全区域这个概念变诞生了:安全区域就是一个不受上面三个效果的可视窗口范围。

为了保证页面的显示效果,我们必须把页面限制在安全范围内,但是不影响整体效果。

7.2 viewport-fit

viewport-fit是专门为了适配iPhoneX而诞生的一个属性,它用于限制网页如何在安全区域内进行展示。

contain: 可视窗口完全包含网页内容

cover:网页内容完全覆盖可视窗口

默认情况下或者设置为autocontain效果相同。

7.3 env、constant

我们需要将顶部和底部合理的摆放在安全区域内,iOS11新增了两个CSS函数env、constant,用于设定安全区域与边界的距离。

函数内部可以是四个常量:

  • safe-area-inset-left:安全区域距离左边边界距离

  • safe-area-inset-right:安全区域距离右边边界距离

  • safe-area-inset-top:安全区域距离顶部边界距离

  • safe-area-inset-bottom:安全区域距离底部边界距离

注意:我们必须指定viweport-fit后才能使用这两个函数:

constantiOS < 11.2的版本中生效,enviOS >= 11.2的版本中生效,这意味着我们往往要同时设置他们,将页面限制在安全区域内:

body {

padding-bottom: constant(safe-area-inset-bottom);

padding-bottom: env(safe-area-inset-bottom);

}

当使用底部固定导航栏时,我们要为他们设置padding值:

{

padding-bottom: constant(safe-area-inset-bottom);

padding-bottom: env(safe-area-inset-bottom);

}

八、横屏适配


很多视口我们要对横屏和竖屏显示不同的布局,所以我们需要检测在不同的场景下给定不同的样式:

8.1 JavaScript检测横屏

window.orientation:获取屏幕旋转方向

window.addEventListener(“resize”, ()=>{

if (window.orientation === 180 || window.orientation === 0) {

// 正常方向或屏幕旋转180度

console.log(‘竖屏’);

};

if (window.orientation === 90 || window.orientation === -90 ){

// 屏幕顺时钟旋转90度或屏幕逆时针旋转90度

console.log(‘横屏’);

}

});

8.2 CSS检测横屏

@media screen and (orientation: portrait) {

/竖屏…/

}

@media screen and (orientation: landscape) {

/横屏…/

}

九、图片模糊问题


9.1 产生原因

我们平时使用的图片大多数都属于位图(png、jpg...),位图由一个个像素点构成的,每个像素都具有特定的位置和颜色值:

理论上,位图的每个像素对应在屏幕上使用一个物理像素来渲染,才能达到最佳的显示效果。

而在dpr > 1的屏幕上,位图的一个像素可能由多个物理像素来渲染,然而这些物理像素点并不能被准确的分配上对应位图像素的颜色,只能取近似值,所以相同的图片在dpr > 1的屏幕上就会模糊:

9.2 解决方案

为了保证图片质量,我们应该尽可能让一个屏幕像素来渲染一个图片像素,所以,针对不同DPR的屏幕,我们需要展示不同分辨率的图片。

如:在dpr=2的屏幕上展示两倍图(@2x),在dpr=3的屏幕上展示三倍图(@3x)

9.3 media查询

使用media查询判断不同的设备像素比来显示不同精度的图片:

.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);

}

}

只适用于背景图

9.4 image-set

使用image-set

.avatar {

background-image: -webkit-image-set( “conardLi_1x.png” 1x, “conardLi_2x.png” 2x );

}

只适用于背景图

9.5 srcset

使用img标签的srcset属性,浏览器会自动根据像素密度匹配最佳显示图片:

<img src=“conardLi_1x.png”

srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">

9.6 JavaScript拼接图片url

使用window.devicePixelRatio获取设备像素比,遍历所有图片,替换图片地址:

const dpr = window.devicePixelRatio;

const images = document.querySelectorAll(‘img’);

images.forEach((img)=>{

img.src.replace(“.”, @${dpr}x.);

})

结束

一次完整的面试流程就是这样啦,小编综合了腾讯的面试题做了一份前端面试题PDF文档,里面有面试题的详细解析,分享给小伙伴们,有没有需要的小伙伴们都去领取!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
, “conardLi_2x.png” 2x );

}

只适用于背景图

9.5 srcset

使用img标签的srcset属性,浏览器会自动根据像素密度匹配最佳显示图片:

<img src=“conardLi_1x.png”

srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">

9.6 JavaScript拼接图片url

使用window.devicePixelRatio获取设备像素比,遍历所有图片,替换图片地址:

const dpr = window.devicePixelRatio;

const images = document.querySelectorAll(‘img’);

images.forEach((img)=>{

img.src.replace(“.”, @${dpr}x.);

})

结束

一次完整的面试流程就是这样啦,小编综合了腾讯的面试题做了一份前端面试题PDF文档,里面有面试题的详细解析,分享给小伙伴们,有没有需要的小伙伴们都去领取!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-pMhXif2k-1713467474885)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值