H5分层屏幕适配公式推导

转载请注明出处:http://hai.li/2018/03/14/h5-screen-adaptation-formula-derivation.html

此文为 h5 屏幕适配具体公式推导,原理和使用参考 http://hai.li/2018/03/14/h5-screen-adaptation.html

缩放

有时我们需要的是设计稿宽高比 v/g 大于屏幕宽高比 u/f 时设计稿宽 v1 等于屏幕宽 u ,否则设计稿高 g1 等于屏幕高 f。求满足要求得设计稿缩放值 s

由条件可得 
x1 = x*s
y1 = y*s
v1 = v*s
g1 = g*s
w1 = w*s
h1 = h*s

当 v/g >= u/f 时 两边乘 f/v 得
f/g >= u/v
由 v1 = u 得
v1 = v*s
   = u
s = u/v
即 f/g >= u/v 时 s = u/v

当 v/g < u/f 时 两边乘 f/v 得
f/g < u/v
由 g1 = f,得
g1 = g*s
   = f
s = f/g
即 f/g < u/v 时 s = f/g

即 s 为 f/g 和 u/v 最小值
即设计稿缩放值 s = Math.min(f/g, u/v)

内存优化

如果每一层都是宽 v1g1,层数一多,占用 gpu 内存就非常多,特别是需要做 css 动画时,大内存会导致动画卡顿,应当减小推到 gpu 内存的层实际面积减少内存占用。 如果拉伸设计稿 v*g 至 屏幕 u*f 大小,对应 w*h 区域坐标变成 (x3, y3),宽高变成 w3*h3 ,假设此时横向拉伸 sx 纵向拉伸 sy

由条件得
u = v*sx
f = g*sy
x3 = x*sx
y3 = y*sy
w3 = w*sx
h3 = h*sy

进而得
sx = u/v
sy = f/g
x3 = x*u/v
y3 = y*f/g
w3 = w*u/v
h3 = h*f/g

内存优化
(w3*h3)/(v1*g1) = ((w*u/v)*(h*f/g))/(v*s*g*s)
                = w*u*h*f/(v*v*g*g*s*s)

当 v/g >= u/f 时
v1 = v*s = u
u = v*sx
得 s = sx = u/v
w3 = w*sx
   = w*s
   = w1
(w3*h3)/(v1*g1) = w*u*h*f/(v*v*g*g*s*s)
                = w*h*f/(g*g*u) 
由 v/g >= u/f
得 g/v <= f/u
得 g/v*(w*h/(g*g) <= f/u*(w*h/(g*g))
得 w*h/(v*g) <= w*h*f/(g*g*u)
得 (w3*h3)/(v1*g1) >= w*h/(v*g)

当 v/g < u/f 时
g1 = g*s = f
f = g*sy
得 s = sy = f/g
h3 = h*sy
   = h*s
   = h1
(w3*h3)/(v1*g1) = w*u*h*f/(v*v*g*g*s*s)
                = w*u*h/(v*v*f)
由 v/g < u/f
得 v/g*(w*h/(v*v) < u/f*(w*h/(v*v))
得 w*h/(v*g) < w*u*h/(v*v*f)
得 (w3*h3)/(v1*g1) > w*h/(v*g)

即 (w3*h3)/(v1*g1) >= w*h/(v*g)
当 v/g >= u/f 时 v1 = u 且 w1 = w3
当 v/g < u/f 时 g1 = f 且 h1 = h3

所以可以构造出一个更小的层 w3*h3 且满足 w3 = w*u/v h3 = h*f/g ,元素在该区域内的保持不变形缩放,即可和设计稿整体在屏幕内缩放导致元素缩放一致。

如果仅将区域 w1*h1 推到 gpu 内存,则内存占用率达到最低点,相比推 v1*g1 减少了 1 - (w1*h1)/(v1*g1) = (w*h)/(v*g),而推 w3*h3 次之,减少了 1 - (w3*h3)/(v1*g1) <= 1 - w*h/(v*g)。 以 w = 544 h = 142 v = 1080 g = 1920 为例,推 w1*h1 减少了约 96.27%,而推 w3*h3 最多减少约 96.27% gpu 内存占用。

定位

缩放后还需要确定在容器中的定位,常见的就是贴边和居中。实际上就是求元素贴边或居中的坐标 (x2, y2)

已知设计稿宽 vg ,其中任意元素的宽 wh 和坐标 (x, y) ,横向左留白占总留白的比值为 m ,纵向上留白占总留白的比值为 n,假设设计稿尺寸到实际尺寸缩放了 s 倍,求经过屏幕适配后该元素的实际宽 w2h2和坐标(x2, y2)?

由条件可得 
x1 = x*s
y1 = y*s
v1 = v*s
g1 = g*s
w1 = w*s
h1 = h*s
m = x2/(u - v1)
n = y2/(f - g1)

继而得
y2 = n*(f - g1)
   = n*(f - g*s)
   = n*f - n*g*s
y2 + y1 = n*f - n*g*s + y1
        = n*f - n*g*s + y*s
        = n*f + (y - n*g)*s
        = n*f + (y - n*g)/h*h*s
        = n*f + (y - n*g)/h*h1

同理
x2 = m*(u - v1)
   = m*(u - v*s)
   = m*u - m*v*s
x2 + x1 = m*u - m*v*s + x1
        = m*u - m*v*s + x*s
        = m*u + (x - m*v)*s
        = m*u + (x - m*v)/w*w*s
        = m*u + (x - m*v)/w*w1

background-size 实现

假设对于区域 w3*h3, 求 w3*h3 内横向上左留白 x2 + x1 - x3 占总留白 h3 - h1 比值 p 和纵向上上留白 y2 + y1 - y3 占总留白 w3 - w1 比值 o

已知
x3 = x*u/v
y3 = y*f/g
w3 = w*u/v
h3 = h*f/g
p = (y2 + y1 - y3)/(h3 - h1)
o = (x2 + x1 - x3)/(w3 - w1)

得 p = (n*f - n*g*s + y*s - y*f/g)/(h*f/g - h*s)
= (n*(f - g*s) + y*(s - f/g))/(h*(f/g - s))
= n*(f - g*s)/(h*(f/g - s)) + y*(s - f/g)/(h*(f/g - s))
= n*(f - g*s)/(h/g*(f - g*s)) - y*(f/g - s)/(h*(f/g - s))
= n*g/h - y/h
= (n*g - y)/h

同理
o = m*v/w - x/w
  = (m*v - x)/w

svg 标签实现

已知 h3 = h*f/g
得  f = h3*g/h
y2 + y1 = n*f - n*g*s + y*s
        = n*h3*g/h + (y - n*g)*s
        = n*g/h*h3 + (y - n*g)/h*h*s
        = n*g/h*h3 + (y - n*g)/h*h1

同理
已知 w3 = w*u/v
得 u = w3*v/w
得 x2 + x1 = m*v/w*w3 + (x - m*v)/w*w1

方案完善

上面以刚好全部显示的屏幕适配方案,同理可推导刚好占满适配及拉伸适配

占满适配屏幕

原理

设计稿缩放值 s = Math.max(f/g, u/v)
内存优化 (w3*h3)/(v1*g1) >= w*h/(v*g)
当 v/g < u/f 时 v1 = u 且 w1 = w3
当 v/g >= u/f 时 g1 = f 且 h1 = h3
x1 = x*s
y1 = y*s
w1 = w*s
h1 = h*s
v1 = v*s
g1 = g*s
横向上左超出占总超出比值 m = x2/(v1 - u)
贴屏幕顶时 m = 0
垂直居中时 m = .5
贴屏幕顶时 m = 1 
纵向上上超出占总超出比值 n = y2/(g1 - f)
贴屏幕左时 n = 0
水平居中时 n = .5
贴屏幕右时 n = 1 
x2 = m*(v1 - u)
   = m*v*s - m*u
y2 = n*(g1 - f)
   = n*g*s - n*f
x1 - x2 = m*u - m*v*s + x*s
        = m*u + (x - m*v)/w*w1
        = m*v/w*w3 + (x - m*v)/w*w1
y1 - y2 = n*f - n*g*s + y*s
        = n*f + (y - n*g)/h*h1
        = n*g/h*h3 + (y - n*g)/h*h1
x3 = x*u/v
y3 = y*f/g
w3 = w*u/v
h3 = h*f/g
o = (x3 - x1 + x2)/(w3 - w1)
  = (x - m*v)/w
p = (y3 - y1 + y2)/(h3 - h1)
  = (y - n*g)/h