DEV Community

悦者生存
悦者生存

Posted on

how to deal with whether the dom in the visual area?

Hi there 🙌

what knowledge can we learn through this article?

  1. what the different between viewport and DOM Layout?
  2. width, innerWidth(window.innerWidth for viewport width), clientWidth, offsetWidth, scrollWidth?
  3. how to use getBoundingClientRect()
  4. how to use Intersection Observer API
  5. practical Application Scenarios
    • Image/Component Lazy Loading
    • Infinite Scrolling
    • Element Exposure Statistics

use getBoundingClientRect()

getBoundingClientRect() is a native DOM method that returns a DOMRect object containing the element’s position relative to the top-left corner of the viewport (properties like top/bottom/left/right) and dimensions (width/height). It eliminates the need to manually accumulate offset values, simplifying calculations.

Judgment Conditions (Vertical Visibility Example)

  • Partially visible: rect.top < window.innerHeight && rect.bottom > 0 (the element’s top is above the viewport’s bottom, and its bottom is below the viewport’s top)
  • Fully visible: rect.top >= 0 && rect.bottom <= window.innerHeight

Code Example

function isInViewport(elem) {
  const rect = elem.getBoundingClientRect();
  const viewportWidth = window.innerWidth;
  const viewportHeight = window.innerHeight;

  // Check for partial visibility (vertical + horizontal)
  return (
    rect.top < viewportHeight && 
    rect.bottom > 0 && 
    rect.left < viewportWidth && 
    rect.right > 0
  );
}

// Optimization: Add throttling to the scroll event (avoid frequent calculations)
function throttle(fn, delay = 100) {
  let lastTime = 0;
  return () => {
    const now = Date.now();
    if (now - lastTime > delay) {
      fn();
      lastTime = now;
    }
  };
}

window.addEventListener('scroll', throttle(() => {
  const target = document.getElementById('target');
  if (isInViewport(target)) {
    target.style.backgroundColor = 'red';
  }
}));
Enter fullscreen mode Exit fullscreen mode

use intersection observer API

The Intersection Observer is a browser-provided asynchronous observation API designed to detect the "intersection state" (whether they overlap, and the overlap ratio) between a "target element" and a "root element" (default: the viewport). It eliminates manual position calculations in scroll events and offers excellent performance (browser-internal optimizations avoid reflows/repaints), making it the preferred choice for modern front-end development.

Code Example(Basic Usage: Viewport Detection)

// 1. Create an Observer instance
const observer = new IntersectionObserver((entries) => {
  // entries: Array of intersection details for observed elements (may include multiple elements)
  entries.forEach(entry => {
    // entry.isIntersecting: Whether the element intersects with the root (entered the viewport)
    if (entry.isIntersecting) {
      console.log('Element entered the viewport', entry.target);
      // Optional: Stop observing (e.g., for lazy loading images, only need one detection)
      observer.unobserve(entry.target);
    } else {
      console.log('Element left the viewport', entry.target);
    }
  });
}, {
  // Configuration: Root = viewport, detect 100px early
  rootMargin: '100px 0px',
  // Trigger callback when overlap ratio reaches 10%
  threshold: 0.1
});

// 2. Observe the target element
const target = document.getElementById('target');
observer.observe(target);

// 3. (Optional) Stop observing all elements (e.g., when a component is destroyed)
// observer.disconnect();
Enter fullscreen mode Exit fullscreen mode

Advanced Usage: Observe a Custom Scroll Container

To detect if an element is within a custom scroll container (instead of the viewport), set root to the container element:

const scrollContainer = document.getElementById('scroll-container');
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('Element entered the scroll container’s viewport');
    }
  });
}, {
  root: scrollContainer, // Root = custom scroll container
  rootMargin: '0px',
  threshold: 1 // Trigger when fully visible
});
Enter fullscreen mode Exit fullscreen mode

Pros & Cons
✅ Pros:
Asynchronous execution (does not block the main thread), ensuring excellent performance (no scroll event jank).
Supports early/late detection (rootMargin) and precise overlap ratio monitoring (threshold).
Concise code (no manual position calculations).
❌ Cons: Limited compatibility (supports IE11+, Chrome 51+, Firefox 55+); older browsers require a polyfill (e.g., the intersection-observer library via npm).

Top comments (0)