在一些复杂的页面中, 经常会用 JavaScript 产生一些 DOM 元素的动态效果(滚动到页面某个位置)或者做一些自适应的调整(超出屏幕边缘, 向可视区域调整元素位置),这个时候我们经常会做一些元素位置和尺寸的计算。浏览器兼容性问题也是不可忽略的一部分,要想写出预想效果的 JavaScript 代码,需要了解一些基本知识。
每个 HTML 元素都有下列属性:
下面是具体解释:
写了两个 demo 对应理解:
当我们计算一个 DOM 元素位置也就是坐标的时候,会涉及到两种坐标系: 文档坐标 和 视口坐标。
浏览器呈现给人眼看到网页的那部分就是视口, 不包含浏览器外壳(菜单,工具栏,状态栏等
我们经常用到的 document 就是整个网页,而不仅仅是从视口看到的那部分内容,还包括因为窗口大小限制而出现滚动条的部分,它的左上角就是我们所谓相对于文档坐标的原点
如果文档小于等于视口, 则不会出现滚动条, 文档左上角和视口左上角相同
因此, 在两种坐标系之间进行切换, 需要加上或减去滚动的偏移量
为了在坐标系之间进行转换, 需要判定浏览器窗口的滚动条位置:
function getScrollOffsets(w) {
var w = w || window;
if (w.pageXoffset != null) { // > IE8
return { x: w.pageXoffset, y: pageYoffset };
}
var d = w.document.documentElement; // 标准模式
if (document.compatMode == "BackCompat") { // 怪异模式
d = w.document.body;
}
return { x: d.scrollLeft, y: d.scrollTop };
}
function getViewportSize(w) {
var w = w || window;
if (w.innerWidth != null) {
return { width: w.innerWidth, height: w.innerHeight };
}
var d = w.document.documentElement; // 标准模式
if (document.compatMode == "BackCompat") { // 怪异模式
d = w.document.body;
}
return { width: d.clientWidth, height: d.clientHeight };
}
function getPageSize(w) {
var w = w || window;
var d = w.document.documentElement; // 标准模式
if (document.compatMode == 'BackCompat') { // 标准模式
d = w.document.body;
}
// 无滚动条时, clientWidth 与 scrollWidth 相同, 但由于不同浏览器处理方式不一致, 因此应该取其中较大值
return {
width: Math.max(d.scrollWidth, d.clientWidth),
height: Math.max(d.scrollHeight, d.clientHeight)
};
}
得到元素的文档坐标, 如果浏览器有滚动条, 可以滚动浏览器到指定元素
function getElementScrollCoords(element) {
var actualLeft = element.offsetLeft, actualTop = element.offsetTop;
var current = element.offsetParent;
while (current !== null){
// 注意要加上边界宽度
actualLeft += (current.offsetLeft + current.clientLeft);
actualTop += (current.offsetTop + current.clientTop);
current = current.offsetParent;
}
return {x: actualLeft, y: actualTop}
}
function getElementViewportCoords(element) {
var scrollCoords = getElementScrollCoords(element);
var scrollOffsets = getScrollOffsets();
// 视口坐标 = 文档坐标 - 滚动条坐标
return {
x: scrollCoords.x - scrollOffsets.x,
y: scrollCoords.y - scrollOffsets.y
}
}
// 或者使用 element.getBoundingClientRect()
function getElementViewportCoords(element) {
var clientRect = element.getBoundingClientRect();
return {
x: clientRect.left,
y: clientRect.top
}
}