移动端面试问题笔记(一)

1. 1pxborder的问题

原因: 设备像素比不同

从移动端的角度说个具体的场景,以iphone6为例。

iphone6的屏幕宽度为375px,设计师做的视觉稿一般是750px,也就是2x,这个时候设计师在视觉稿上画了1px的边框,于是你就写了"border-width:1px",so...1px边框问题产生了

对设计师来说它的1px是相对于750px的(物理像素),对你来说你的1px是相对于375px的(css像素)"实际上你应该是border-width:0.5px"。

解决方案:

  1. 媒体查询+小数点写法

    .border { border: 1px solid #999 }
    @media screen and (-webkit-min-device-pixel-ratio: 2) {
    .border { border: 0.5px solid #999 }
    }
    @media screen and (-webkit-min-device-pixel-ratio: 3) {
    .border { border: 0.333333px solid #999 }
    }

  2. transform+伪类

利用伪类标签,根据父级定位,大小根据媒体查询缩放实现效果(注意别忘记了"transform-origin: left top;"

复制代码
<span class="border-1px">1像素边框问题</span>

// less
.border-1px{
  position: relative;
  &::before{
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    border:1px solid red;
    color: red;
    height: 200%;
    -webkit-transform-origin: left top;
    transform-origin: left top;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    pointer-events: none; /* 防止点击触发 */
    box-sizing: border-box;
    @media screen and (min-device-pixel-ratio:3),(-webkit-min-device-pixel-ratio:3){
      width: 300%;
      height: 300%;
      -webkit-transform: scale(0.33);
      transform: scale(0.33);
    }
  }
}
  1. window.devicePixelRatio+全局状态管理器修改class类名称

写好不同类对应的css样式,使用JavaScript的window.devicePixelRatio+全局状态管理器修改class类名称

注意:

一键换肤的功能也可以参考全局状态管理器修改class类名称达到目的

2. 2x,3x图的适配

原因:设备像素比

方案一:

媒体查询,根据不同的设备像素比填充相应的背景图片:

移动端开发过程中,因为手机的dpr(设备像素比不同),我们需要根据dpr来修改图标的大小:

  1. 通过mixin,动态修改图标的背景图片。通过@media (媒体查询),判断设备的dpr。

    bg-image(url) { background-image: url(url + "@2x.png");
    @media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3) {
    background-image: url($url + "@3x.png");
    }
    }

  2. css样式中调用 bg-image 方法

    div{
    width:30px;
    height:20px;
    background-size:30px 20px;
    background-repeat:no-repeat;
    bg-image('special_1');
    }

方案二:

写好不同类对应的css样式,使用JavaScript的window.devicePixelRatio+全局状态管理器修改class类名称

注意:

一键换肤的功能也可以参考全局状态管理器修改class类名称达到目的

3. 图片在安卓上,有些设备模糊的问题

原因:

今天迁移代码的时候,发现有些图片是.9.png格式,但是代码上又没这个9,我一开始以为这个9是这个图片名字里面的,不知道有.9.png格式的图片,后面百度了下,才发现有这种类型的图片格式,然后在图片的名字后面加上9就行了。

png格式图片和9.png格式图片区别:

9.png格式,其实相当于把一张png图分成了9个部分(九宫格),分别为4个角,4条边,以及一个中间区域,4个角是不做拉升的,所以还能一直保持圆角的清晰状态,而2条水平边和垂直边分别只做水平和垂直拉伸,所以不会出现边会被拉粗的情况,只有中间用黑线指定的区域做拉伸。结果是图片不会走样

4. 固定定位布局,键盘挡住输入框内容

在移动端开发的时候,用到了position:fixed的遮罩蒙层,在蒙层里又放置里输入框。当用户sh输入时,软键盘会弹起来,会遮罩住输入框。

通过resize() 方法触发 resize 事件,或规定当发生 resize 事件时运行的函数。

复制代码
var windheight = $(window).height();  /*未唤起键盘时当前窗口高度*/
        
$(window).resize(function(){
   var docheight = $(window).height();  /*唤起键盘时当前窗口高度*/        
   if(docheight < windheight){            /*当唤起键盘高度小于未唤起键盘高度时执行*/
      $(".submit").css("position","static");
   }else{
      $(".submit").css("position","fixed");
   }           

});

更合理的做法,应该是规避这个问题的发生。

在有position:fixed的弹层里,不应设置输入框。

5. click的300ms延迟问题和点击穿透问题

原因:

重点:由于移动端会有双击缩放的这个操作,因此浏览器在click之后要等待300ms,看用户有没有下一次点击,也就是这次操作是不是双击。

方案一:禁用缩放

复制代码
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">
复制代码

缺点:

通过完全禁用缩放来达到去掉点击延迟的目的。但是通常情况下,我们还是希望页面能通过双指缩放来进行缩放操作,比如放大一张图片,放大一段很小的文字。

方案二:更改默认的视口宽度

复制代码
<meta name="viewport" content="width=device-width">
  • 随着响应式设计的普及,很多站点都已经对移动端坐过适配和优化了,这个时候就不需要双击缩放了
  • 如果能够识别出一个网站是响应式的网站,那么移动端浏览器就可以自动禁掉默认的双击缩放行为并且去掉300ms的点击延迟。
  • 如果设置了上述meta标签,那浏览器就可以认为该网站已经对移动端做过了适配和优化,就无需双击缩放操作了。
  • 这个方案相比方案一的好处在于,它没有完全禁用缩放,而只是禁用了浏览器默认的双击缩放行为,但用户仍然可以通过双指缩放操作来缩放页面。

方案三: CSS touch-action

touch-action这个CSS属性。这个属性指定了相应元素上能够触发的用户代理(也就是浏览器)的默认行为。如果将该属性值设置为touch-action: none,那么表示在该元素上的操作不会触发用户代理的任何默认行为,就无需进行300ms的延迟判断。

方案四: FastClick

  • FastClickFT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。
  • FastClick的实现原理是在检测到touchend事件的时候,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后的click事件阻止掉。

点击穿透问题:

原因:

使用touchstart去代替click事件,但是在移动端浏览器,事件执行的顺序是touchstart > touchend > click.

使用touchstart去代替click事件有两个缺点:

第一:touchstart是手指触摸屏幕就触发,有时候用户只是想滑动屏幕,却触发了touchstart事件,这不是我们想要的结果;

第二:使用touchstart事件在某些场景下可能会出现点击穿透的现象。

解决方案:

  1. 只用touch

把页面内所有click全部换成touch事件(touchstart、'touchend'、'tap'),

  1. 只使用click(下下策)

  2. tap后延迟350ms再处理事件

  3. pointer-events

  • 比较麻烦且有缺陷,
  • 不建议使用
  • mask隐藏后,给按钮下面元素添上pointer-events: none;样式,让click穿过去,350ms后去掉这个样式,恢复响应
  • 缺陷是mask消失后的的350ms内,用户可以看到按钮下面的元素点着没反应,如果用户手速很快的话一定会发现
  1. fastclick

好用的解决方案,不介意多加载几KB的话,

不建议使用:

,因为有人遇到了bug,首先引入fastclick库,再把页面内所有touch事件都换成click,其实稍微有点麻烦,建议引入这几KB就为了解决点透问题不值得

6. iphone和ipad下输入框默认内阴影

解决方案

方法一:

复制代码
<!--如果 ui 样式里有边框,可以用外层盒子设置边框-->
input{
    border:none;
}

方法二:

复制代码
//在IOS下,input 和textarea表单默认会有个内阴影,一定程度上影响视觉一致,可通过设置下面代码去掉:

input{
    -webkit-appearance: none;
}

7. 防止升级中页面放大和缩小

复制代码
<meta name="viewport" content="width = device-width,inital-scale=1.0,maximun = 1.0,user-scalable = no">

8. flex布局

Flex 布局是什么?

Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。

任何一个容器都可以指定为 Flex 布局。

复制代码
.box{
  display: flex;
}

行内元素也可以使用 Flex 布局。

复制代码
.box{
  display: inline-flex;
}

Webkit 内核的浏览器,必须加上-webkit前缀。

复制代码
.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}

注意,设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。

容器的属性:

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

flex-direction属性

flex-direction属性决定主轴的方向(即项目的排列方向)。

复制代码
.box {
  flex-direction: row | row-reverse | column | column-reverse;
}

它可能有4个值。

  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。

flex-wrap属性

默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

复制代码
.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}

(1)nowrap(默认):不换行。

(2)wrap:换行,第一行在上方。

(3)wrap-reverse:换行,第一行在下方。

flex-flow属性

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

复制代码
.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content属性

justify-content属性定义了项目在主轴上的对齐方式。

复制代码
.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

align-items属性

align-items属性定义项目在交叉轴上如何对齐。

复制代码
.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

align-content属性

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

复制代码
.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

该属性可能取6个值。

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

项目的属性:

以下6个属性设置在项目上。

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

order属性

order属性定义项目的排列顺序,数值越小,排列越靠前,默认为0

复制代码
.item {
  order: <integer>;
}

flex-grow属性

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

复制代码
.item {
  flex-grow: <number>; /* default 0 */
}

flex-shrink属性

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

复制代码
.item {
  flex-shrink: <number>; /* default 1 */
}

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效。

flex-basis属性

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

复制代码
.item {
  flex-basis: <length> | auto; /* default auto */
}

它可以设为跟widthheight属性一样的值(比如350px),则项目将占据固定空间。

flex属性

flex属性是flex-grow,flex-shrinkflex-basis的简写,默认值为0 1 auto。后两个属性可选。

复制代码
.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

该属性有两个快捷值:auto(1 1 auto) 和 none (0 0 auto)。

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

align-self属性

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

复制代码
.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

9.px,em,rem,%,vw,vh,vw这些单位的区别?

1) px

px就是pixel的缩写,意为像素。px就是一张图片最小的一个点,一张位图就是千千万万的这样的点构成的,比如常常听到的电脑像素是1024x768的,表示的是水平方向是1024个像素点,垂直方向是768个像素点。

2) em

  • 参考物是父元素的font-size,具有继承的特点.
  • 如果自身定义了font-size按自身来计算(浏览器默认字体是16px),
  • 整个页面内1em不是一个固定的值

3) rem

css3新单位,相对于根元素html(网页)的font-size,不会像em那样,依赖于父元素的字体大小,而造成混乱

4) %

一般说是相对于父元素,但不是很准备

  • 对于普通定位来说是就是我们理解的父元素
  • 对于position:absolute的元素是相对于已经定位的父元素
  • 对于position:fixed的元素 是相对于ViewPort(可视窗口)

5) vw

css3新特性,viewpoint width的缩写,视窗宽度,1vw等于视窗宽度的1%

举个例子:浏览器宽度375px, 1 vw = 375px/100 = 3.75px。

6) vh

css3新单位.viewpoint height的缩写,视窗高度,1vh等于视窗高度的1%

7) vm

css3新单位,相对于视口的宽度或高度中较小的那个,其中最小的那个被均分为100单位的vm

eg:

浏览器高度900px,宽度1200px,取最小的浏览器高度,1vm=900px/100=9px

10. 移动端适配-dpr

定义:

  • 像素,又称为画素,是图像显示的基本单位,英文pixel
  • 像素是网页布局的基础.一个像素就是计算机能够显示一种特定颜色的最小区域.
  • 当设备尺寸相同但像素变得更密集时,屏幕能够显示的画面的过渡更细致,网站看起来更明快

ppi: 屏幕上每英寸可以显示的像素点的数量,即屏幕像素密度

分类:

像素分为2种: 设备像素和css像素

设备像素:

设备屏幕的物理像素,任何设备的物理像素都是固定的

css像素:

又称为逻辑像素,是为web开发者创造的,在css和JavaScript中使用的一个抽象的层

每一个css声明和几乎所有的JavaScript属性都使用css像素,因此实际上从来用不上设备像素,唯一的例外是screen.width/height

缩放:

  • 在桌面端,css的1个像素往往都是对应着电脑屏幕的1个物理像素
  • 而在手机端,由于屏幕尺寸的限制,缩放是经常的操作
  • 不论我们进行缩小或放大操作,元素设置的CSS像素(如width:300px)是始终不变的,而一个CSS像素对应多少个设备像素是根据当前的缩放比例来决定的

DPR:

设备像素比DPR(devicePixelRatio)是默认缩放为100%的情况下,设备像素和css像素的比值

复制代码
DPR=设备像素/css像素(某一方向上)

这里的css像素对应着以后要对应以后要提到的理想视口,其对应的JavaScript属性是screen.width/screen.height

而对于设备像素比DPR也有对应的JavaScript属性: window.devicePixelRatio

以iphone5为例,iphone5的CSS像素为320px*568px,DPR是2,所以其设备像素为640px*1136px

  • 宽度比和高度比:这两个比值都是 2,表示每个 CSS 像素在宽度和高度方向上分别对应 2 个设备像素。
  • 总像素比:这个值是 4,表示每个 CSS 像素对应的设备像素总数。具体来说,每个 CSS 像素对应 2x2 = 4 个设备像素。

为什么总像素比是 4?

  • 面积比:总像素比实际上是面积比。每个 CSS 像素对应的设备像素面积是 2x2 = 4 个设备像素。
  • 数学解释
    • 设备像素的总面积:640px * 1136px = 727,680

    • CSS 像素的总面积:320px * 568px = 181,760

    • 总像素比:727,680 / 181,760 = 4

      640(px) / 320(px) = 2
      1136(px) / 568(px) = 2
      640(px)*1136(px) / 320(px)*568(px) = 4

11.移动端扩展点击区域

该元素relative定位, 伪类使用absolute定位,上右下左都设置-10px

复制代码
extend-click()
  position: relative
  &:before
    content: ''
    position: absolute
    top: -10px
    left: -10px
    right: -10px
    bottom: -10px

12.上下拉动滚动条时卡顿,慢

复制代码
body
{
    -webkit-overflow-scrolling:touch;
    overflow-scrolling:touch;
}

13.长时间按住页面出现闪退

复制代码
element
{
    -webkit-touch-callout:none;
}

14.ios和Android下触摸元素时出现半透明灰色遮罩

复制代码
element
{
    -webkit-tap-highlight-color:rgba(255,255,255,0);
}

设置alpha值为0就可以去除本透明灰色遮罩,备注:transparent的属性值在android下无效。

15.active兼容处理即伪类:active失败

方法一:body添加ontouchstart

复制代码
<body ontouchstart=''>

方法二:js给document绑定touchstart或touchend事件

复制代码
<style>
    a
    {
        color:#000;
    }

    a:active
    {
        color:#fff;
    }

</style>

<a href=foo>bar</a>

<script>
    document.addEventListentener('touchstart',function(){},false);
</script>

16.webkit mask兼容处理

某些低端手机不支持css3mask,可以选择性的进降级处理

比如可以使用js判断来引用不同class:

复制代码
if('WebkitMask' in documnet.documentElement.style)
{
    alert('支持 mask')
}
else
{
    alert('不支持 mask')
}

17.pc端与移动端字体大小的问题

复制代码
html,body,form,fieldset,p,div,h1,h2,h3,h4,h5,h6
{
    -webkit-text-size-adjust:100%;
}

pc端字体正常显示,但ios真机就出现,h1、span等标签字体比较大。

复制代码
html
{
    -webkit-text-size-adjust:100%;/*ios端谷歌浏览器测试有效,Android端未测试*/
}

18.transition闪屏

// 设置内联的元素在3D空间如何实现: 保留3D

-webkit-transform-style: preserve-3D;

// 设置进行转换的元素的背面在面对用户时是否可见: 隐藏

-webkit-backface-visibility: hidden;

19.圆角bug

某些安卓手机圆角失效background-clip: padding-box;

20.如何解决禁用表单后移动端样式不统一的问题

复制代码
input:disabled{
    color:xxx;
    opacity:1;
    //text-fill-color文本填充颜色,只兼容webkit内核
    -webkit-text-fill-color:xxx;
    -webkit-opacity:1;
    font-size:16px;
}

21.移动端加入cursor: pointer点击时会出现一个背景

复制代码
*{ 
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent;
}

22.在安卓手机上的select有灰色背景

复制代码
select{appearance:none;
    -moz-appearance:none;
    -webkit-appearance:none;
    border:none;}
相关推荐
一路向北he1 分钟前
字节钢铁军团--“提供情境,而非控制”
java·开发语言·前端
kyriewen23 分钟前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒36 分钟前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
大圣编程2 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang2 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆3 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜3 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞5 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农7 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器