# 获取 dom 元素信息

这个方法在 PC 端和移动端都能支持。

export const getDomInfo = (classname: string) => {
  return (
    document.getElementsByClassName(classname)[0]?.getBoundingClientRect() || {}
  );
};
1
2
3
4
5

# scrollTop 兼容性

  1. 以下获取 scrollTop 的方法在 PC 端和苹果手机上能生效,但是安卓手机上不生效:
const handleScroll = (e) => {
  const scrollTop = e.srcElement.documentElement.scrollTop;
};

const scrollTop = document.documentElement.scrollTop;
1
2
3
4
5
  1. 以下获取 scrollTop 的方法在 PC 端和苹果手机上不生效,只在安卓手机上生效:
const scrollTop = document.body.scrollTop;
1
  1. 以下获取 scrollTop 的方法在 PC 端和移动端都生效:
// window.pageYOffset 是一个只读属性
const scrollY = window.pageYOffset;

// 在 PC 端 document.scrollingElement 就是 document.documentElement
// 在移动端 document.scrollingElement 就是 document.body
const scrollTop = document.scrollingElement.scrollTop;
1
2
3
4
5
6

window.pageYOffset 对 IE 和移动端的支持都不错,能支持到 IE9+ 和 Android 4+。

document.scrollingElement 对 IE 的兼容性不好,移动端就还不错,能支持到 Android 5+。可以使用 document.scrollingElement 的 Polyfill (opens new window) 兼容一些老旧设备。

  1. 之前 scrollTop 常见的兼容性写法如下:
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
1

不过现在可以不用这么写了,如果只是想要获取窗体的滚动高度,直接使用 window.pageYOffset;如果需要设置窗体的滚动高度,直接使用 document.scrollingElement 就可以了。

# getBoundingClientRect().top 判断在真机上会一直闪

移动端常见的一些吸顶效果是需要通过 scrollTop 或者 getBoundingClientRect().top 来判断的,只有当滚动到一定位置时才展示吸顶效果(通过添加类名或者控制显示隐藏)。

下面这两种方法,前者在真机上是正常的吸顶效果,但是后者在真机上看到的效果是会一直闪,很不好,不知道啥原因。

const handleScroll = () => {
  const scrollY = window.pageYOffset;
  if (scrollY > 127) {
    setFixed(true);
  } else {
    setFixed(false);
  }
};
1
2
3
4
5
6
7
8
const handleScroll = () => {
  const top = document
    .getElementsByClassName(classname)[0]
    ?.getBoundingClientRect().top;
  if (top <= 0) {
    setFixed(true);
  } else {
    setFixed(false);
  }
};
1
2
3
4
5
6
7
8
9
10

# 安卓手机企微环境 wx.miniProgram 为 undefined

如标题所示,在苹果手机上的企微里是正常的,但是在安卓手机上的企微里就报错了,开发时注意做好容错处理。

企业微信-微信小程序 API 支持情况 (opens new window)

# 移动端 1px 问题及解决方案

1px 问题指的是在一些 Retina 屏幕 的机型上,移动端页面的 1px 会变得很粗,呈现出不止 1px 的效果。

产生这个问题的原因很简单,CSS 中的 1px 并不能和移动设备上的 1px 划等号。它们之间的比例关系有一个专门的属性来描述:

// 设备像素比
window.devicePixelRatio = 设备的物理像素 / CSS 像素
1
2

一个物理像素等于多少个设备像素取决于移动设备的屏幕特性(是否是 Retina)和用户缩放比例。

比如如果设备像素比为 2,那么就意味着 1px 的 CSS 像素,在移动端上会用 2 个物理像素来进行渲染,所以实际看到的一定会比 1px 粗一些。

目前针对 1px 问题推荐的解决方法是伪元素先放大后缩小或者设置 viewport 来解决问题

# 伪元素先放大后缩小

在目标元素的后面追加一个 ::after 伪元素,让这个元素布局为 absolute 之后,整个伸展开铺在目标元素上,然后把它的宽和高都设置为目标元素的两倍,border 值设为 1px。接着借助 CSS 动画特效中的放缩能力,把整个伪元素缩小为原来的 50%。此时,伪元素的宽高刚好可以和原有的目标元素对齐,而 border 也缩小为了 1px 的二分之一,间接地实现了 0.5px 的效果。

目前大部分移动端 UI 采用该方案,全机型兼容。

.border_base(@scalew: 1, @scaleh: 1, @radius: 0) {
  position: relative;
  &::after {
    position: absolute;
    content: '';
    left: 0;
    top: 0;
    width: 100% * @scalew;
    height: 100% * @scaleh;
    // @TODO transform-origin: 5% 在 ios 与安卓下的表现不一致,所以暂时不用这种方式
    transform-origin: ((1 - @scalew)/2 * 100%) ((1 - @scaleh)/2 * 100%);
    pointer-events: none; /* 防止点击触发 */
    border-radius: @radius;
  }
  @media only screen and (-webkit-min-device-pixel-ratio: 2) {
    &::after {
      width: 200% * @scalew;
      height: 200% * @scaleh;
      transform: scale(0.5);
      border-radius: @radius*2;
    }
  }
  @media only screen and (-webkit-min-device-pixel-ratio: 3) {
    &::after {
      width: 300% * @scalew;
      height: 300% * @scaleh;
      transform: scale(0.333);
      border-radius: @radius*3;
    }
  }
}

.border_1px(@color: #ccc, @radius: 0) {
  .border_base(1, 1, @radius);
  &::after {
    border: 1px solid @color;
  }
}

.border_1px_top(@color: #ccc, @scalew: 1) {
  .border_base(@scalew, 1);
  &::after {
    border-top: 1px solid @color;
  }
}

.border_1px_bottom(@color: #ccc, @scalew: 1) {
  .border_base(@scalew, 1);
  &::after {
    border-bottom: 1px solid @color;
  }
}

.border_1px_left(@color: #ccc, @scaleh: 1) {
  .border_base(1, @scaleh);
  &::after {
    border-left: 1px solid @color;
  }
}

.border_1px_right(@color: #ccc, @scaleh: 1) {
  .border_base(1, @scaleh);
  &::after {
    border-right: 1px solid @color;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

# 设置 viewport 来解决问题

利用 viewport + rem + js 来实现,边框直接写上 1px 会自动转换。

这种方式也是全机型兼容,代码里可以直接写 1px 简单方便!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      id="WebViewport"
      content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <title>Document</title>
    <style type="text/css"></style>
  </head>
  <body>
    <script type="text/javascript">
      let viewport = document.querySelector("meta[name=viewport]");
      // 根据设备像素设置 viewport
      if (window.devicePixelRatio == 1) {
        viewport.setAttribute(
          "content",
          "width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
        );
      }
      if (window.devicePixelRatio == 2) {
        viewport.setAttribute(
          "content",
          "width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no"
        );
      }
      if (window.devicePixelRatio == 3) {
        viewport.setAttribute(
          "content",
          "width=device-width, initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no"
        );
      }
      function resize() {
        const width = screen.width > 750 ? "75px" : screen.width / 10 + "px";
        document.getElementsByTagName("html")[0].style.fontSize = width;
      }
      window.onresize = resize;
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
上次更新时间: 2023年12月04日 16:00:20