块的宽高及偏移位

179 阅读3分钟

块块的宽高及偏移位

复习一下的 background 模块: 盒模型刨去 margin, border, padding 后剩的就是 content

花式获取元素宽高

  • style
  • getComputedStyle (这个好)
  • offsetWidth, offsetHeight
  • currentStyle
  1. style (行内样式)

    通过style属性获取宽高

    1. 获取的宽高只是 content 的宽高, 即不包括 padding 和 border (当然更没有 margin)
    2. 只能获取通过行内样式设置的宽高
    3. 可以获取也可以设置
  2. getComputedStyle (重要)

    1. 获取的宽高不包括 边框和内边距
    2. 即可以获取行内设置的宽高也可以获取 CSS 设置的宽高
    3. 只支持获取, 不支持设置
    4. 上古浏览器用不了这个
  3. offsetWidth, offsetHeight

    1. 获取的宽高包含 ==border+padding+content==
    2. 即可以获取行内设置的宽高也可以获取 CSS 设置的宽高
    3. 只支持获取, 不支持设置
  4. currentStyle (上古, 废弃)

    1. 获取的宽高不包括 边框和内边距
    2. 即可以获取行内设置的宽高也可以获取 CSS 设置的宽高
    3. 只支持获取, 不支持设置
    4. 只支持 IE9 以下浏览器
    5. 所以 currentStyle 是 getComputed 的上古版本

拿元素宽高四种方式的辨析

宽高是哪部分的宽高

  1. getComputedStyle/currentStyle/style 获取的宽高只是 content 的宽高, 不包括 边框和内边距
  2. offsetWidth/offsetHeight (独特) 获取的宽高包括 边框和内边距

样式是哪里的样式

  1. getComputedStyle/currentStyle/offsetXXX 即可以获取行内,也可以获取外链和内联样式, 只支持获取, 不支持设置
  2. style 只能获取行内样式, 可以获取, 也可以设置

元素不同的偏移位们

偏移位三个族

  • offsetLeft, offsetTop
  • clientLeft, clientTop
  • scrollTop (也有 scrollLeft, 但是比较少用)

offsetLeft, offsetTop

简单来说, offset 族都是相对于最近层级的定位元素

  • offsetLeft, offsetTop
    • 获取元素到第一个定位祖先元素之间的偏移位
    • 如果没有祖先元素是定位的, 获取到相对于 body 的偏移位
  • offsetParent
    • 获取元素的第一个定位祖先元素
    • 如果没有祖先元素是定位的, 那么就是获取到的就是 body
<!-- offsetLeft, offsetTop -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript-获取元素位置-offsetLeft, offsetTop</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .father {
        width: 200px;
        height: 200px;
        margin-top: 100px;
        margin-left: 100px;
        background: blue;
        overflow: hidden;
        position: relative;
      }
      .son {
        width: 100px;
        height: 100px;
        margin-top: 100px;
        margin-left: 100px;
        background: red;
      }
    </style>
  </head>
  <body>
    <div class="father">
      <div class="son"></div>
    </div>
    <script>
      /*
       获取元素到第一个定位祖先元素之间的偏移位
       如果没有祖先元素是定位的, 那么就是获取到body的偏移位
      */
      let oSDiv = document.querySelector(".son");
      oSDiv.onclick = function () {
        console.log(oSDiv.offsetLeft); // 100
        console.log(oSDiv.offsetTop); // 100
      };
    </script>
  </body>
</html>
<!-- offsetParent -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript-offsetParent</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .grand-father {
        width: 300px;
        height: 300px;
        margin-top: 100px;
        margin-left: 100px;
        background: deeppink;
        overflow: hidden;
        position: relative;
      }
      .father {
        width: 200px;
        height: 200px;
        margin-top: 100px;
        margin-left: 100px;
        background: blue;
        overflow: hidden;
        position: relative;
      }
      .son {
        width: 100px;
        height: 100px;
        margin-top: 100px;
        margin-left: 100px;
        background: red;
      }
    </style>
  </head>
  <body>
    <div class="grand-father">
      <div class="father">
        <div class="son"></div>
      </div>
    </div>
    <script>
      let oSDiv = document.querySelector(".son");
      oSDiv.onclick = function () {
        console.log(oSDiv.offsetParent); // <div class="father">…</div>
      };
    </script>
  </body>
</html>

clientLeft, clientTop

  • clientWidth, clientHeight
    • clientWidth = content+padding
    • clientHeight = content+padding
  • clientLeft, clientTop
    • 左边框和顶部边框
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript-client族</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      div {
        width: 150px;
        height: 150px;
        padding: 100px;
        border: 50px solid #000;
        background: red;
        background-clip: content-box;
      }
    </style>
  </head>
  <body>
    <div id="box"></div>
    <script>
      let oDiv = document.querySelector("div");
      console.log(oDiv.clientWidth); // 350
      console.log(oDiv.clientHeight); // 350
      console.log(oDiv.clientLeft); // 50
      console.log(oDiv.clientTop); // 50
    </script>
  </body>
</html>

scrollTop

scrollWidth, scrollTop

  • 内容没有超出元素范围时
    • scrollWidth = content+padding == clientWidth
    • scrollHeight = content+padding == clientHeight
  • 内容超出元素范围时 (试过的)
    • 内容相对于初始位置的位移, 一旦开始滚动就会有输出
    • 小意外: 这里第二个页面滚动条出现后宽度缩水了! 从 200 缩水到了 183.
<!-- 内容没有超出块块的时候 -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript-scroll属性</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      div {
        width: 100px;
        height: 100px;
        padding: 50px;
        border: 50px solid #000;
        background: red;
        background-clip: content-box;
        color: deepskyblue;
        overflow: auto;
      }
    </style>
  </head>
  <body>
    <div id="box">
      我是内容<br />
      我是内容<br />
    </div>
    <script>
      let oDiv = document.querySelector("div");
      console.log(oDiv.scrollWidth); // 200
      console.log(oDiv.scrollHeight); // 200
      oDiv.onscroll = function () { // 没有滚动条
        console.log(oDiv.scrollTop);
      };
    </script>
  </body>
</html>
<!-- 内容超出块块的时候 -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript-scroll属性</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      div {
        width: 100px;
        height: 100px;
        padding: 50px;
        border: 50px solid #000;
        background: red;
        background-clip: content-box;
        color: deepskyblue;
        overflow: auto;
      }
    </style>
  </head>
  <body>
    <div id="box">
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
      我是内容<br />
    </div>
    <script>
      let oDiv = document.querySelector("div");
      console.log(oDiv.scrollWidth); // 183
      console.log(oDiv.scrollHeight); // 425	
      oDiv.onscroll = function () { // 一旦开始滚动, 就开始输出
        console.log(oDiv.scrollTop);
      };
    </script>
  </body>
</html>

可视区域的宽高

  • window.innerWidth, window.innerHeight (现代, 只在 IE9 及以上浏览器可用)
  • document.documentElement.clientWidth, document.documentElement.clientHeight (上古标准模式)
  • document.body.clientWidth, document.body.clientHeight (上古怪异模式):warning:

注意点:

  • 浏览器在渲染网页的时候有两种模式"标准模式"/"混杂(怪异)模式"
  • 默认情况下都是以标准模式来进行渲染的 (CSS1Compat)
  • 如果网页没有书写文档声明, 那么就会按照"混杂(怪异)模式"来进行渲染 的(BackCompat)
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>JavaScript-获取网页宽高</title>
  </head>
  <body>
    <script>
      let { width, height } = getScreen();
      console.log(width);
      console.log(height);

      function getScreen() {
        var width, height;
        if (window.innerWidth) {
          width = window.innerWidth;
          height = window.innerHeight;
        } else if (document.compatMode === "BackCompat") {
          console.log(document.compatMode);// BackCompat
          width = document.body.clientWidth;
          height = document.body.clientHeight;
        } else {
          console.log(document.compatMode);// CSS1Compat
          width = document.documentElement.clientWidth;
          height = document.documentElement.clientHeight;
        }
        return {
          width: width,
          height: height,
        };
      }
    </script>
  </body>
</html>
  • 关于 document 对象和 window 对象

    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>document 和 window</title>
        <script>
            console.log(window);
            console.log(document);
        </script>
      </head>
      <body>
          总之 window 是个大而全的对象, document 就是比较纯粹的 html 文档
      </body>
    </html>
    
    <!-- 文档声明加和不加行为是一样的, 应该是浏览器优化过了 -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
          <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>document.documentElement 和 window</title>
          <script>
              console.log(document); // 比 document.documentElement 多了个文档声明 (如果有的话)
              console.log(document.documentElement); // 和 line13 打印的数字相同
              console.log(document.documentElement.clientWidth); // 和 line14 打印的数字相同
              console.log(document.documentElement.clientHeight);
              console.log(window.innerWidth);
              console.log(window.innerHeight);
              // console.log(document.body.clientWidth); 这俩在现代浏览器里会报错
              // console.log(document.body.clientHeight);
          </script>
      </head>
      <body></body>
    </html>