彻底弄懂元素样式、位置、大小相关计算

2,606 阅读12分钟

简介

在我们日常开发中偶尔会碰到获取元素样式、设置某元素样式、计算元素位置、计算滚动距离等需求。但是js中关于元素位置、样式、大小的api种类繁多,稍不留神就会搞不清楚。今天笔者就带你彻底弄清楚,让你在这类问题上不再迷茫。

本文分元素样式的获取和设置、元素位置大小计算、屏幕和窗口位置大小计算三部分来讲解,读完本文你将会学会

  1. 元素样式的获取的各种方法以及区别,在哪种情况是使用哪种方式最合适。
  2. 元素大小位置计算,弄懂了clientscrolloffset三类api的区别。
  3. screen、window对象关于位置、大小api,以及各自的区别。

元素样式的获取和设置

el.stylegetComputedStyle 用来获取和设置元素样式。el.className、el.classList 用来获取和设置元素类名。el.getBoundingClientRect用来获取元素的位置和大小。

image.png

el.style

通过获取元素的style属性来获取元素样式。

语法

<head>
  <style>
      .div1 {
        color: red;
      }
  </style>
</head>

<div id="div1" class="div1" style="font-size: 18px">style测试</div>
const div1 = document.querySelector("#div1");
console.log(div1.style.fontSize); // 18px 
console.log(div1.style.color); // 获取不到该样式

特点

  1. 这种方式获取的样式属性值是驼峰式。
  2. 这种方式只能获取到元素的内联样式。
  3. 我们可以通过该方法设置元素样式。

常用方法

cssText

我们还可以使用cssText来获取样式的字符串。

console.log(div1.style.cssText); // font-size: 18px;

setProperty

我们可以使用setProperty方法来设置元素样式。

注意我们设置元素样式的属性不是驼峰式写法。

div1.style.setProperty("font-weight", 600);
console.log(div1.style.fontWeight); // 600

// 当然这种方式也是可以的
div1.style.fontWeight = 600;
console.log(div1.style.fontWeight); // 600

getPropertyValue

我们可以使用getPropertyValue方法来获取元素样式。

注意我们获取元素样式的属性不是驼峰式写法。

div1.style.getPropertyValue("font-size"); // 18px

// 当然这种方式也是可以的
console.log(div1.style.fontSize)

removeProperty

我们可以使用removeProperty方法来移除元素某样式。

div1.style.removeProperty("font-weight");

// 当然这种方式也是可以的
div1.style.fontWeight = "";

getComputedStyle(ele)

该方法挂载在window对象下,我们使用的时候可以省略window

语法

<head>
  <style>
      .div1 {
        color: red;
      }
  </style>
</head>

<div id="div1" class="div1" style="font-size: 18px">style测试</div>
const div1 = document.querySelector("#div1");
console.log(getComputedStyle(div1).fontSize); // 18px
console.log(getComputedStyle(div1).color); // rgb(255, 0, 0)

特点

  1. 这种方式获取的样式属性值是驼峰式。
  2. 能获取元素渲染后的所有样式包括内联和不内联样式
  3. 只能获取元素的样式不能设置元素的样式。

el.getBoundingClientRect()

该方法能获取元素的长度和宽度(width、height)。并且能获取元素相对于浏览器窗口的位置信息(left、right、top、bottom)。

语法

<head>
  <style>
      .div1 {
        color: red;
      }
  </style>
</head>

<div id="div1" class="div1" style="font-size: 18px">style测试</div>

这里需要注意的是,距离计算只相对窗口顶部和左边计算。(bottom、right的计算需要注意)

const div1 = document.querySelector("#div1");

// bottom: 33 元素下边框距离视口顶部的距离
// height: 25 元素高度
// left: 8 元素左边框距离视口左部的距离
// right: 342 元素右边框距离视口左部的距离
// top: 8 元素上边框距离视口顶部的距离
// width: 334 元素的宽度
// x: 8 元素左上角相对于视口左侧的距离
// y: 8 元素左上角相对于视口顶部的距离

console.log(div1.getBoundingClientRect());

特点

  1. 该方法只能获取元素位置和大小信息,不能获取到其他样式信息。
  2. 该方法不能设置元素样式。

el.className、el.classList

除了前面介绍的获取样式,我们还可以获取到类名,然后通过添加类名的方式给元素添加新的样式。

语法

console.log(div1.classList.value); // div1
console.log(div1.className); // div1
div1.className += " div2"; // 添加新类名 div2

特点

  1. el.className获取的是元素的类名字符串,我们可以使用该方法获取类名或者添加新的类名。
  2. el.classList.value获取的是类名字符串,如果单纯的想获取类名可以使用该方法。

总结

  1. 当我们需要设置某元素样式的时候我们可以使用ele.style方法。
  2. 当我们需要获取元素渲染后的所有样式的时候我们可以使用getComputedStyle(ele)方法。
  3. 当我们需要获取类名或者批量设置元素样式的时候可以使用className方法。
  4. 当我们需要计算元素位置,或者计算元素是否在可视窗口内或者元素大小的时候我们可以使用ele.getBoundingClientRect()方法。

有了上面获取元素样式的基础下面我们再来介绍一些元素位置、大小的api

元素位置、大小计算

关于元素位置大小计算主要有clientscrolloffset三类api

image.png

client

client可以简单理解为元素可视大小。

clientWidth、clientHeight

clientWidth 为可视宽度,宽度包含内边距(padding)。不包含边框(border)、外边距(margin)、滚动条。

clientHeight 为可视高度,高度包含内边距(padding)。不包含边框(border)、外边距(margin)、滚动条。

clientTop、clientLeft

clientTop获取的是元素上边框的高度。

clientLeft获取的是元素左边框的宽度。

WX20220310-101109.png

参看上面的例子

  1. clientWidth400px - 滚动条15px + 左右内边距20 = 405px
  2. clientHeight200px - 滚动条15px + 上下内边距20 = 205px
  3. clientTop为上边框高度10px
  4. clientLeft为左边框宽度10px

scroll

scroll可以简单理解为元素实际大小(可滚动大小)。

scrollWidth、scrollHeight

scrollWidth当元素没滚动条的时候和clientWidth一样,为可视宽度。当有滚动条的时候为可滚动的宽度。宽度包含内边距(padding)和滚动条。不包含边框(border)、外边距(margin)。

scrollHeight当元素没滚动条的时候和clientHeight一样,为可视高度。当有滚动条的时候为可滚动的高度。高度包含内边距(padding)和滚动条。不包含边框(border)、外边距(margin)。

scrollTop、scrollLeft

scrollTop获取的是容器元素在y轴上滚动的距离。

scrollLeft获取的是容器元素在x轴上滚动的距离。

WX20220310-102331.png

参看上面的例子,我们在这里使用了box1.scrollBy(20, 10);模拟滚动。

  1. scrollWidth600px + 左右内边距20 = 620px
  2. scrollHeight500px + 上下内边距20 = 520px
  3. clientTop 为在y轴上滚动的距离10px
  4. clientLeft 为在x轴上滚动的近距离20px

offset

offset可以简单理解为元素占据大小(在文档中的占据空间大小)。

offsetWidth、offsetHeight

offsetWidth 宽度包含内边距(padding)、边框(border)、滚动条。不包含外边距(margin)。

offsetHeight 高度包含内边距(padding)、边框(border)、滚动条。不包含外边距(margin)。

offsetParent

offsetParent是一个只读属性,获得元素最近并采用定位的祖先元素或者最近的 tabletdth元素,再没找到就获取body元素,用于offsetLeftoffsetTop的计算。

offsetLeft、offseTop

offsetLeft相对offsetParent水平偏移距离。

offseTop相对offsetParent垂直偏移距离。

参看上面的例子

WX20220310-103646.png

  1. offsetWidth400px - 滚动条15px + 滚动条15px + 左右内边距20 + 左右边框宽度20px = 440px
  2. offsetHeight200px - 滚动条15px + 滚动条15px + 上下内边距20 + 上下边框宽度20px = 240px
  3. offsetParent 因为外面没包裹其他元素,所以直接返回body元素。
  4. offsetTop 因为margin20px所以相对于body垂直偏移距离为20px
  5. offsetLeft 因为margin20px所以相对于body水平偏移距离为20px

屏幕和窗口位置、大小计算

image.png

screen

屏幕相关属性的获取。

width、height

这里 screen.width、screen.height获取的是电脑屏幕的宽度和高度,跟我们浏览器大小是无关的。

availWidth、availHeight

这里 screen.availWidth、screen.availHeight获取的是电脑屏幕的实际宽度和实际高度,如果有任务栏是需要去掉的。跟我们浏览器大小是无关的。

window

浏览器窗口相关属性的获取。

outerWidth、outerHeight

outerWidth返回的是浏览器整个的宽度,如果浏览器最大化的话和screen.availWidth值相等。

outerHeight返回的是浏览器整个的高度,如果浏览器最大化的话和screen.availHeight值相等。

innerWidth、innerHeight

innerWidth返回的是浏览器文档可视的宽度,只包括滚动条,不包括顶部的tab、和书签栏。

innerHeight返回的是浏览器文档可视的高度,只包括滚动条,不包括顶部的tab、和书签栏。

screenX、screenLeft

window.screenX、window.screenLeft获取的是浏览器窗口左上角相对于屏幕左边框的距离。

ie不支持window.screenX火狐不支持window.screenLeft

screenY、screenTop

window.screenY、window.screenTop获取的是浏览器窗口左上角相对于屏幕上边框的距离。

ie不支持window.screenY火狐不支持window.screenTop

scrollX、scrollY

window.scrollX返回的是窗口在x轴上滚动的距离。

window.scrollY返回的是窗口在y轴上滚动的距离。

pageXOffset、pageYOffset

window.pageXOffset返回的是窗口在x轴上滚动的距离。

window.pageYOffset返回的是窗口在y轴上滚动的距离。

注意:

这里scrollX、scrollY、pageXOffset、pageYOffset需要和上面的scrollTopscrollLeft区分,这四个api只在window对象上有。

相对于scrollXscrollYpageXOffsetpageYOffset兼容性更好,一般我们只用 pageXOffsetpageYOffset就行了。但两者都不兼容IE9以下。

事件对象Event中的screenX、clientX、pageX、layerX、offsetX

事件对象中通常有screenX、clientX、pageX、layerX、offsetX这几个对象,他们都代表着什么意思,以及他们之间的差别我相信很多小伙伴还不是很清楚,所以今天笔者再来总结一下。

我们这里先准备父子两个元素,父元素有边框10px,内边距20px,宽高200px。子元素有边框20px,内边距30px,宽高100px。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>offsetX、clientX、screenX、pageX、layerX</title>
    <style>
      .div1 {
        width: 200px;
        height: 200px;
        border: grey solid 10px;
        padding: 20px;
        background-color: aqua;
        position: relative;
        
        // margin-top: 200px; //演示浏览器滚动条时打开
      }

      .div2 {
        width: 100px;
        height: 100px;
        padding: 30px;
        border: forestgreen solid 20px;
        background-color: blanchedalmond;
      }
    </style>
  </head>
  <body>
    <div class="div1" onclick="handleClick(event)">
      <div class="div2"></div>
    </div>

    <script>
      const handleClick = (e) => {
        console.log(e);
        console.log("screenX: ", e.screenX);
        console.log("screenY: ", e.screenY);

        console.log("clientX: ", e.clientX);
        console.log("clientY: ", e.clientY);

        console.log("pageX: ", e.pageX);
        console.log("pageY: ", e.pageY);

        console.log("offsetX: ", e.offsetX);
        console.log("offsetY: ", e.offsetY);

        console.log("layerX: ", e.layerX);
        console.log("layerY: ", e.layerY);
      };
    </script>
  </body>
</html>

父子盒子样式如下

image.png

image.png

下面正式进入正题

screenX、screenY

screenX、screenY是我们鼠标位置相对电脑屏幕左上角x轴和y轴的距离。

假设笔者鼠标点击的是点的位置,那么它的screenX、screenY就是笔者画红框的长度和宽度。它是根据屏幕计算的,跟浏览器大小无关。

image.png

clientX、clientY

clientX、clientY是我们鼠标位置相对浏览器可视窗口x轴和y轴的距离。

假设笔者鼠标点击的是点的位置,那么它的clientX、clientY就是笔者画红框的长度和宽度。它是根据浏览器计算的。

它是根据可视窗口计算的,也就是会除掉浏览器书签栏、导航栏的大小。

image.png

绿色框框是clientX、clientY,红色框框是screenX、screenY

因为笔者演示的时候浏览器是全屏,所以screenX是等于clientX的,因为浏览器顶部有书签栏、导航栏所以screenY是大于clientY

pageX、pageY

pageX、pageY是我们鼠标位置相对浏览器文档对象,x轴和y轴的距离。

怎么理解这句话呢?其实我们跟clientX、clientY对比就很容易理解了。

在没有出现滚动条的时候,其实可视窗口就等于文档对象的大小,所以pageX、pageY是和clientX、clientY相等的。

我们来先看一个没有出现滚动条的例子,

image.png

可以看到 pageX、pageYclientX、clientY 大小是一样的,都是红色框框的大小。

当页面出现滚动条的时候,两者才会有差异,因为一个是相对浏览器可视窗口,一个是相对document文档对象。

我们再来看一个有滚动条的例子,

image.png

可以看到,当y轴出现滚动条的时候,clientYpageY的大小就有区别了。

clientY是相对可视窗口计算的,所以是绿色框框的大小,pageY是相对文档对象 document计算的,所以它在绿色框框的基础上加上滚动条滚动的距离。大概就是红色框框的大小。

看到这,小伙伴们应该明白了吧,一个是相对浏览器可视窗口,一个是相对文档对象 document(页面大小)计算。

offsetX、offsetY

offsetX、offsetY是相对元素自身padding-box左上角的位置计算的。

我们点击下点的位置,看看offsetX、offsetY是多少。

image.png

可以看到,大小就是自身内边距的大小,它是相对自身padding-box左上角计算的,是不包括边框的。

当我们点击绿色边框,可以看到它出现了负值。

image.png

这里一定要注意它是相对自身padding-box左上角计算的。

layerX、layerY

layerX、layerY是相对带定位的父元素border-box左上角的位置计算的。如果没有带定位的父元素那么就是相对文档对象计算。

我们点击下点的位置,看看layerX、layerY是多少。

image.png

可以看到,大小就是自身内边距30 + 自身边框20 + 父元素内边距20 + 父元素边框 10(大概是80),它是相对父元素border-box左上角的位置计算的。注意带上父元素边框的距离。

总结

  1. screenX、screenY很好理解,是相对屏幕计算。
  2. clientX、clientYpageX、pageY我们对比就很容易理解,一个是相可视窗口左上角,一个是相对文档左上角。
  3. offsetX、offsetYlayerX、layerY 我们也是通过对比理解,一个是相对自身padding-box左上角,一个是相对父元素padding-box左上角计算的。

后记

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!