导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

⭐️ 概览

滚动条偏移距离

常规

不常见

兼容图

Untitled

⭐️ 封装滚动条偏移距离

function getScrollOffset() {
	if (window.pageXOffset) {
  	return {
     left: window.pageXOffset,
    	top: window.pageYOffset
    }
  } else {
  	return {
    	left: document.body.scrollLeft + document.documentElement.scrollLeft,
      top: document.body.scrollTop + document.documentElement.scrollTop
    }
  }
}

浏览器的标准模式与怪异模式

<!DOCTYPE html> // 标准模式

document.compatMode // 标准模式 -> "CSS1Compat"
										// 怪异模式 -> "BackCompat"

浏览器可视区域的尺寸(窗口的宽高)

常规

IE9、IE8及一下

⭐️ 封装浏览器可视区域大小

function getViewportSize() {
	if (window.innerWidth) {
  	return {
    	width: window.innerWidth,
      height: window.innerHeight
    }
  } else {
  	if (document.compat === 'BackCompat') {
    	return {
      	width: document.body.clientWidth,
        height: document.body.clientHeight
      }
    } else {
    	return {
      	width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
      }
    }
  }
}

获取文档内容宽高

相当于:

⭐️ 封装文档内容宽高

function getScrollSize() {
	if (document.body.scrollWidth) {
  	return {
    	width: document.body.scrollWidth,
      height: document.body.scrollHeight
    }
  } else {
  	return {
    	width: document.documentElement.scrollWidth,
      height: document.documentElement.scrollHeight
    }
  }
}

⭐️ getBoundingClientRect()

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .box {
      position: absolute;
      left: 0;
      right: 0;
      width: 200px;
      height: 200px;
      background-color: pink;
      margin: 10px;
      padding: 10px;
    }
  </style>
</head>
<body>
  <div class="box"></div>
  <script>
    var box = document.getElementsByClassName('box')[0];

    var info = box.getBoundingClientRect(); // 不实时
		console.log(info);
    box.style.width = '500px';
  </script>
</body>
</html>

Untitled

offsetLeft / offsetTop

HTMLElement.offsetLeft 是一个只读属性,返回当前元素左上角相对 HTMLElement.offsetParent 节点的左边界偏移的像素值。

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .parent {
      position: relative;
      top: 100px;
      left: 100px;
      width: 300px;
      height: 300px;
      background-color: pink;
    }

    .son {
      position: absolute;
      top: 100px;
      left: 100px;
      width: 100px;
      height: 100px;
      background-color: purple;
    }
  </style>
</head>
<body>
  <div class="parent">
    <div class="son"></div>
  </div>
  <script>
    var parent = document.getElementsByClassName("parent")[0];
    var son = document.getElementsByClassName("son")[0];
    console.log({
      parent: {
        offsetLeft: parent.offsetLeft,
        offsetTop: parent.offsetTop
      }
    });
    console.log({
      son: {
        offsetLeft: son.offsetLeft,
        offsetTop: son.offsetTop
      }
    });
  </script>
</body>
</html>

Untitled

margin 塌陷

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    .parent {
      position: relative;
      top: 100px;
      left: 100px;
      width: 300px;
      height: 300px;
      background-color: pink;
    }

    .son {
      /* position: absolute; */
      /* top: 100px; */
      /* left: 100px; */
      width: 100px;
      height: 100px;
      margin: 100px;
      background-color: purple;
    }
  </style>
</head>
<body>
  <div class="parent">
    <div class="son"></div>
  </div>
  <script>
    var parent = document.getElementsByClassName("parent")[0];
    var son = document.getElementsByClassName("son")[0];
    console.log({
      parent: {
        offsetLeft: parent.offsetLeft,
        offsetTop: parent.offsetTop
      }
    });
    console.log({
      son: {
        offsetLeft: son.offsetLeft,
        offsetTop: son.offsetTop
      }
    });
  </script>
</body>
</html>

Untitled

解决方案1 - border 1 像素

.parent {
	position: relative;
  top: 100px;
  left: 100px;
  width: 300px;
  height: 300px;
  background-color: pink;
  border: 1px solid #000; // ←
}

Untitled

解决方案2 - 触发 BFC

.parent {
	position: absolute; // ←
  top: 100px;
  left: 100px;
  width: 300px;
  height: 300px;
  background-color: pink;
}

Untitled

或者

.parent {
	position: relative;
  top: 100px;
  left: 100px;
  width: 300px;
  height: 300px;
  background-color: pink;
  overflow: hidden; // ←
}

Untitled

⭐️ offsetLeft / offsetTop 只认有定位的父级元素

如果上级是定位元素,就返回相对于上级定位元素的左边界偏移像素值,如果没有就一直往上找,直到找到 body 为止

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    .parent {
      width: 300px;
      height: 300px;
      margin: 100px;
      background-color: pink;
      overflow: hidden;
    }

    .son {
      width: 100px;
      height: 100px;
      margin: 100px;
      background-color: purple;
    }
  </style>
</head>
<body>
  <div class="parent">
    <div class="son"></div>
  </div>
  <script>
    var parent = document.getElementsByClassName("parent")[0];
    var son = document.getElementsByClassName("son")[0];
    console.log({
      parent: {
        offsetLeft: parent.offsetLeft,
        offsetTop: parent.offsetTop
      }
    });
    console.log({
      son: {
        offsetLeft: son.offsetLeft,
        offsetTop: son.offsetTop
      }
    });
  </script>
</body>
</html>

Untitled

⭐️ offsetParent 获取带有定位的父级

父级有定位找距父级距离,没定位找可视距离位置

由于 parent 不是定位元素,所以 son 的 offsetParent 是 body:

Untitled

一旦 parent 是定位元素,例如设置 position: relative ,此时 son 的 offsetParent 就是 .parent 了:

Untitled

⭐️ 查找某个元素距离 document 的边距

function getElemDocPostion(el) {
  var parent = el.offsetParent,
      offsetLeft = el.offsetLeft,
      offsetTop = el.offsetTop;
  
  while(parent) {
  	offsetLeft += parent.offsetLeft;
    offsetTop += parent.offsetTop;
    parent = parent.offsetParent;
  }
  
  return {
  	left: offsetLeft,
    top: offsetTop
  }
}

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    .grandPa {
      position: absolute;
      top: 100px;
      left: 100px;
      width: 360px;
      height: 360px;
      background-color:lightskyblue;
    }

    .parent {
      position: absolute;
      top: 30px;
      left: 30px;
      width: 300px;
      height: 300px;
      background-color: pink;
      overflow: hidden;
    }

    .son {
      width: 100px;
      height: 100px;
      margin: 100px;
      background-color: purple;
    }
  </style>
</head>
<body>
  <div class="grandPa">
    <div class="parent">
      <div class="son"></div>
    </div>
  </div>
  <script>
    var parent = document.getElementsByClassName("parent")[0];
    var son = document.getElementsByClassName("son")[0];

    function getElemDocPostion(el) {
      var parent = el.offsetParent,
          offsetLeft = el.offsetLeft,
          offsetTop = el.offsetTop;
      
      while(parent) {
        offsetLeft += parent.offsetLeft;
        offsetTop += parent.offsetTop;
        parent = parent.offsetParent;
      }
      
      return {
        left: offsetLeft,
        top: offsetTop
      }
    }

    console.log(getElemDocPostion(son));
  </script>
</body>
</html>

Untitled

⭐️ 操作滚动条

window.scroll(x, y)/window.scrollTo(x, y)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .box {
      width: 3000px;
      height: 5000px;
      border: 5px solid pink;
    }
  </style>
</head>
<body>
  <div class="box">
    asdasdasdasdasdasdasd,asdasdasdasdasdasdasd,asdasdasdasdasdasdasd,asdasdasdasdasdasdasd
  </div>
  <script>
    setTimeout(() => {
      window.scroll(800, 800);
    }, 1000);
  </script>
</body>
</html>

Untitled

<!DOCTYPE html>
<html lang="en">
<head>
  ...
</head>
<body>
  ...
  <script>
    setTimeout(() => {
      window.scrollTo(1000, 1000);
    }, 1000);
  </script>
</body>
</html>

Untitled

window.scrollBy(x, y)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      margin: 0;
      padding: 0;
    }
    .box {
      width: 3000px;
      height: 5000px;
      border: 5px solid pink;
    }
  </style>
</head>
<body>
  <div class="box">
    asdasdasdasdasdasdasd,asdasdasdasdasdasdasd,asdasdasdasdasdasdasd,asdasdasdasdasdasdasd
  </div>
  <script>
    setInterval(() => {
      window.scrollBy(200, 200);
    }, 1000);
  </script>
</body>
</html>