Background: Recently, in the product list project iteration, we need to add a distribution product advertising space at the bottom of the product list. In addition, we have received a buried demand for product exposure, and we need to know that the product appears in the user viewport before conducting data statistics!

Based on the idea of virtual DOM data driven, the least advocated is the DOM manipulation of the jquery era! But at present, some complex pages often use javascript to process some DOM elements, to achieve some dynamic effects; The most common is the calculation of the location and size of some elements, but browser compatibility is also a big part of this. To write desired JavaScript code, you need to know the basics.

The basic concept

Page size: The total area of a web page is its size. Typically, the size of a web page is determined by the content and CSS style sheets. Viewing window size: The area of the web page that is viewed in the browser window, also known as a viewport. If the content of a web page is fully displayed in the browser (and no scroll bars), the size of the web page is equal to the size of the browser window. If not, scroll through the browser window to show each part of the page.

Base element attributes

Each HTML element has the following attributes.

offsetWidth clientWidth scrollWidth
offsetHeight clientHeight scrollHeight
offsetLeft clientLeft scrollLeft
offsetTop clientTop scrollTop

To understand these properties, we need to know that the actual content of an HTML element may be larger than the box assigned to hold the content, so there may be a scroll bar. The content area is the viewport, and the element’s scroll bar position needs to be taken into account when the actual content is larger than the viewport.

  • ClientHeight and clientWidth are used to describe the inner size of an element. They refer to the content of an element plus the inner margin, excluding the border (actually included in IE), margin, and scrollbar
  • OffsetHeight and offsetWidth are used to describe the outer dimensions of an element. They refer to the element content + inner margin + border, excluding margins and scrollbars
  • ClinetTop and clinetLeft return the horizontal and vertical distance between the edge of the inner margin and the outer edge of the border, that is, the left, upper border width
  • OffsetTop and offsetLeft represent the distance between the upper left corner of the element (the outer border) and the upper left corner of the positioned parent container (the offsetParent object)
  • The offsetParent object refers to the element’s nearest relative and absolute ancestors, which are recursively traced and return null if none of the ancestors are located

Gets the viewport size

Each element on a web page has the clientHeight and clientWidth attributes. These two attributes refer to the visual area occupied by the content of the element plus the padding, excluding the border and scrollbar space.

Therefore, the clientHeight and clientWidth attributes of the Document element represent the size of the page

function getViewport() {
  if(!document) {
    return{}}if (document.compatMode === 'BackCompat') {
    return {
      width: document.body.clientWidth,
      height: document.body.clientHeight
    };
  }
  return {
    width: document.documentElement.clientWidth,
    height: document.documentElement.clientHeight
  };
}
Copy the code

The getViewport function above returns the height and width of the browser window. There are three things to pay attention to when using:

  • This function must run after the page has loaded, otherwise the document object has not been generated and the browser will report an error.
  • In most cases, it is the document. The documentElement. ClientWidth returns the correct value. In IE6 quirks mode, however, the document. The body. The clientWidth return the correct value, so the function of joined the document mode of judgment
  • ClientWidth and clientHeight are both read-only properties and cannot be assigned.

Another way to get the viewport size

Each element in a web page also has srcollHeight and scrollWidth attributes, which refer to the visual area of the element including scrolling. So, the scrollHeight and scrollWidth properties of the Document object are the size of the page, which means all the lengths and widths that the scroll bar has been rolled across.

The getPagearea() function can be written like the getViewport function.

function getPagearea() {
 if (document.compatMode == 'BackCompat') {    return{       width:Math.max(document.body.scrollWidth, document.body.clientWidth),       height:Math.max(document.body.scrollHeight, document.body.clientHeight) };   }  return {
    width: Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth),   height:Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight)     }; }Copy the code

Coordinates relative to the document and viewport

When we calculate the position of a DOM element, or coordinate, there are two coordinate systems involved, document coordinate __ and viewport coordinate __. The document we often use is the entire page, not just the visible part of the window, but also the part that has scroll bars due to window size limits, and its upper left corner is what we call the origin of the coordinates relative to the document.

Viewports are the part of the browser that displays document content. They do not include the browser shell (menu, toolbar, status bar, etc.), the part of the current window that displays the page, and do not include the scroll bar.

If the document is smaller than the viewport, there is no scroll. The upper left corner of the document is the same as the upper left corner of the viewport. Generally speaking, to switch between two coordinate systems, you need to add or subtract the scroll offset.

To convert between coordinate systems, we need to determine the position of the browser window scroll bar. The pageXoffset and pageYoffset of the Window object provide these values, except for IE 8 and earlier. The scrollbar position can also be obtained from the scrollLeft and scrollTop properties, which are normally obtained by querying the document root (document.documentElement), but must be queried on the document body in weird mode.

Document coordinates

Any HTML element has offectLeft and offectTop attributes that return the X and Y coordinates of the element. For many elements, these values are document coordinates, but for locating the descendants of the element and some other elements (table cells), the coordinates relative to the ancestors are returned. We can do this simply by recursively adding up

function getElementPosition(e) {
  let x = 0;
  let y = 0;
  while(e ! =null) {
    x += e.offsetLeft;
    y += e.offsetTop;
    e = e.offsetParent;
  }
  return { x, y };
}
Copy the code

However, this function does not always calculate the correct value, and it does not work when the document contains a scroll bar. We can only use this method when there is no scroll bar, but we use this principle to calculate the coordinates of some elements relative to a parent element.

Quick way:

The relative positions of web elements are:

let X = element.getBoundingClientRect().left;
let Y = element.getBoundingClientRect().top;
Copy the code

The viewport coordinates

Calculating viewport coordinates is much easier by calling the element’s getBoundingClientRect method. The left, right, top, and bottom method returns an object representing the coordinates of the four positions of the element relative to the viewport. The coordinates returned by getBoundingClientRect contain the inner margin and border of the element, not the margin. Compatibility is good, very easy to use

function getElementViewTop(element) {
  let actualTop = element.offsetTop;
  let current = element.offsetParent;
  let elementScrollTop;

  while(current ! = =null) {
    actualTop += current.offsetTop;
    current = current.offsetParent;
  }

  if (document.compatMode == 'BackCompat') {
    elementScrollTop = document.body.scrollTop;
  } else {
    elementScrollTop = document.documentElement.scrollTop;
  }

  return actualTop - elementScrollTop;
}


function getElementViewLeft(element) {
  let actualLeft = element.offsetLeft;
  let current = element.offsetParent;
  let elementScrollLeft;

  while(current ! = =null) {
    actualLeft += current.offsetLeft;
    current = current.offsetParent;
  }

  if (document.compatMode == 'BackCompat') {
    elementScrollLeft = document.body.scrollLeft;
  } else {
    elementScrollLeft = document.documentElement.scrollLeft;
  }

  return actualLeft - elementScrollLeft;
}
Copy the code

Quick way:

Use the getboundingClientRect() method. It returns an object containing the attributes left, top, width, height, and so on.

let X = element.getBoundingClientRect().left;
let Y = element.getBoundingClientRect().top;
Copy the code

Add the rolling distance to get the absolute position:

const X= element.getBoundingClientRect().left+document.documentElement.scrollLeft;
const Y =element.getBoundingClientRect().top+document.documentElement.scrollTop;
Copy the code