Web

Check Element Visibility with JavaScript: CSS Properties Guide

Learn how to check if DOM elements are visible using pure JavaScript. Examine display, visibility, opacity and other CSS properties that affect visibility.

1 answer 1 view

How can I check if a DOM element is visible using pure JavaScript without jQuery? What CSS properties should I examine to determine element visibility, including display, visibility, and other potential attributes that might affect visibility?

To check if a DOM element is visible using pure JavaScript, you need to examine multiple CSS properties including display, visibility, opacity, and element dimensions. The modern approach uses the Element.checkVisibility() method, while traditional methods involve checking the element’s style properties and comparing offset dimensions. Understanding how different CSS properties affect visibility is crucial for accurate detection.


Contents


Understanding CSS Properties That Affect Element Visibility

When checking if an element is visible with JavaScript, you need to understand several CSS properties that can affect visibility. The most important properties are display, visibility, and opacity, but there are others that might hide elements in subtle ways.

The Display Property

The display property is one of the most common ways to hide elements in CSS. When set to none, the element is completely removed from the document flow and doesn’t render at all. This means it doesn’t take up space and isn’t accessible to screen readers.

javascript
// Check if display is set to 'none'
function isDisplayNone(element) {
 const style = window.getComputedStyle(element);
 return style.display === 'none';
}

The Visibility Property

Unlike display: none, the visibility: hidden property keeps the element in the document flow but makes it invisible. The space it occupies is preserved, and it’s still interactive (though you can’t see it).

javascript
// Check if visibility is set to 'hidden'
function isVisibilityHidden(element) {
 const style = window.getComputedStyle(element);
 return style.visibility === 'hidden';
}

The Opacity Property

Elements with opacity: 0 are technically still visible but fully transparent. They take up space and are interactive, making them different from elements with display: none or visibility: hidden.

javascript
// Check if opacity is 0
function isOpacityZero(element) {
 const style = window.getComputedStyle(element);
 return parseFloat(style.opacity) === 0;
}

Other Visibility-Affecting Properties

Several other properties can affect whether an element appears visible:

  • Height and width: If both are set to 0, the element won’t be visible
  • Overflow: When set to hidden, content outside the element’s bounds is clipped
  • Clip-path: Can hide portions or all of an element
  • Content-visibility: A newer property that can skip rendering of offscreen content
  • Transform: Can scale elements to zero size or move them off-screen

What makes visibility checking complex is that these properties can be inherited from parent elements. An element might have visible styles itself, but if its parent is hidden, the element won’t be visible either.


Modern JavaScript Methods for Checking Element Visibility

The modern approach to checking element visibility in JavaScript uses the Element.checkVisibility() method, introduced in the DOM Living Standard. This method provides a straightforward way to determine if an element is visible according to the CSS rules.

The checkVisibility() Method

The checkVisibility() method checks if an element is visible based on various criteria, making it more comprehensive than traditional manual checks.

javascript
// Basic usage
const isVisible = element.checkVisibility();

Parameters and Options

The method accepts an options object to specify which visibility checks to perform:

javascript
const isVisible = element.checkVisibility({
 checkOpacity: true, // Consider opacity
 checkVisibilityCSS: true, // Consider visibility property
 displayCheck: 'non-contents' // Check display property
});

The displayCheck parameter can have these values:

  • 'none': Only check if display is ‘none’
  • 'non-contents': Check if display is ‘none’ or contents
  • 'parent': Check if display is ‘none’ or ‘contents’, or if parent has display ‘none’

Complete Example

Here’s a comprehensive example using checkVisibility():

javascript
function isElementVisible(element, options = {}) {
 return element.checkVisibility({
 checkOpacity: options.checkOpacity !== false,
 checkVisibilityCSS: options.checkVisibilityCSS !== false,
 displayCheck: options.displayCheck || 'non-contents'
 });
}

// Usage
const myElement = document.getElementById('myElement');
const visible = isElementVisible(myElement);

Browser Compatibility

The checkVisibility() method is supported in modern browsers:

  • Chrome 111+
  • Firefox 110+
  • Safari 16.4+
  • Edge 111+

For older browsers, you’ll need to use traditional methods (discussed in the next section).


Traditional JavaScript Techniques for Visibility Detection

Before checkVisibility() was available, developers used various manual techniques to determine element visibility. These methods are still useful for understanding how visibility works and for supporting older browsers.

Checking Inline Styles

The simplest approach is to check the element’s inline style properties:

javascript
function isVisibleByInlineStyle(element) {
 return element.style.display !== 'none' && 
 element.style.visibility !== 'hidden' && 
 element.style.opacity !== '0';
}

However, this approach only checks styles applied directly to the element, not inherited styles or styles from stylesheets.

Using getComputedStyle

To check all computed styles (including inherited ones), use window.getComputedStyle():

javascript
function isElementVisible(element) {
 const style = window.getComputedStyle(element);
 
 // Check display property
 if (style.display === 'none') return false;
 
 // Check visibility property
 if (style.visibility === 'hidden') return false;
 
 // Check opacity
 if (parseFloat(style.opacity) === 0) return false;
 
 // Check if element has dimensions
 if (element.offsetWidth === 0 && element.offsetHeight === 0) return false;
 
 return true;
}

Checking Parent Elements

Since visibility can be inherited, you need to check parent elements:

javascript
function isElementVisibleInDOM(element) {
 // Check element itself
 const style = window.getComputedStyle(element);
 if (style.display === 'none' || style.visibility === 'hidden') return false;
 
 // Check if element is in document
 if (!document.body.contains(element)) return false;
 
 // Check parent elements recursively
 let parent = element.parentElement;
 while (parent) {
 const parentStyle = window.getComputedStyle(parent);
 if (parentStyle.display === 'none') return false;
 parent = parent.parentElement;
 }
 
 return true;
}

Viewport Visibility

To check if an element is visible in the viewport (not just visible in general), use getBoundingClientRect():

javascript
function isElementInViewport(element) {
 const rect = element.getBoundingClientRect();
 return (
 rect.top >= 0 &&
 rect.left >= 0 &&
 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
 rect.right <= (window.innerWidth || document.documentElement.clientWidth)
 );
}

Advanced Visibility Checking Considerations

When implementing visibility checking in real-world applications, you need to consider several advanced factors that can affect the accuracy of your detection.

Performance Considerations

Visibility checking can be expensive, especially when performed frequently or on many elements. Here are some optimization strategies:

  1. Throttle checks: Use techniques like requestAnimationFrame or throttling to limit how often visibility checks occur.

  2. Caching: Cache results if the element’s styles haven’t changed.

  3. Selective checking: Only check properties that are likely to change.

javascript
function throttle(func, limit) {
 let inThrottle;
 return function() {
 const args = arguments;
 const context = this;
 if (!inThrottle) {
 func.apply(context, args);
 inThrottle = true;
 setTimeout(() => inThrottle = false, limit);
 }
 };
}

const throttledCheck = throttle(isElementVisible, 200);

CSS-in-JS and Shadow DOM

With modern web frameworks and shadow DOM, traditional visibility checking might not work as expected:

  1. CSS-in-JS: Libraries like styled-components or Emotion apply styles dynamically, which might not be immediately reflected in getComputedStyle().

  2. Shadow DOM: Elements inside shadow DOM have their own styling context. You need to check the host element’s visibility as well.

javascript
function isShadowElementVisible(element) {
 // Check if in shadow DOM
 if (element.getRootNode() instanceof ShadowRoot) {
 const host = element.getRootNode().host;
 return isElementVisible(host) && isElementVisible(element);
 }
 return isElementVisible(element);
}

Handling Transitions and Animations

Elements might be in transition between visible and hidden states. Consider the transition and animation properties when checking visibility.

javascript
function isElementVisibleConsideringTransitions(element) {
 const style = window.getComputedStyle(element);
 
 // Check if element has any transitions or animations
 if (style.transition !== 'none' || style.animationName !== 'none') {
 // The element might be transitioning, so check if it's actually visible
 return element.getClientRects().length > 0;
 }
 
 return isElementVisible(element);
}

Cross-Browser Compatibility

Different browsers might handle visibility differently, especially with newer CSS features. Test across target browsers and implement fallbacks:

javascript
function isElementVisibleCrossBrowser(element) {
 // Modern browsers
 if (typeof element.checkVisibility === 'function') {
 return element.checkVisibility();
 }
 
 // Fallback for older browsers
 return isElementVisible(element);
}

Practical Examples and Implementation Tips

Here are practical implementations and tips for checking element visibility in real-world scenarios.

Complete Visibility Check Function

This comprehensive function checks multiple aspects of visibility:

javascript
/**
 * Checks if an element is visible in the DOM
 * @param {HTMLElement} element - The element to check
 * @param {Object} options - Configuration options
 * @param {boolean} [options.checkOpacity=true] - Whether to check opacity
 * @param {boolean} [options.checkParentElements=true] - Whether to check parent elements
 * @param {boolean} [options.checkViewport=false] - Whether to check if element is in viewport
 * @param {boolean} [options.checkShadowDOM=true] - Whether to check shadow DOM elements
 * @returns {boolean} - True if element is visible
 */
function isElementVisible(element, options = {}) {
 if (!element) return false;
 
 // Check if element is in document
 if (!document.body.contains(element)) return false;
 
 // Check shadow DOM
 if (options.checkShadowDOM !== false && element.getRootNode() instanceof ShadowRoot) {
 const host = element.getRootNode().host;
 if (!isElementVisible(host, options)) return false;
 }
 
 // Modern method
 if (typeof element.checkVisibility === 'function') {
 return element.checkVisibility({
 checkOpacity: options.checkOpacity !== false,
 checkVisibilityCSS: true,
 displayCheck: 'non-contents'
 });
 }
 
 // Fallback for older browsers
 const style = window.getComputedStyle(element);
 
 // Check display property
 if (style.display === 'none') return false;
 
 // Check visibility property
 if (style.visibility === 'hidden') return false;
 
 // Check opacity
 if (options.checkOpacity !== false && parseFloat(style.opacity) === 0) return false;
 
 // Check dimensions
 if (element.offsetWidth === 0 && element.offsetHeight === 0) return false;
 
 // Check parent elements
 if (options.checkParentElements !== false) {
 let parent = element.parentElement;
 while (parent) {
 const parentStyle = window.getComputedStyle(parent);
 if (parentStyle.display === 'none') return false;
 parent = parent.parentElement;
 }
 }
 
 // Check viewport
 if (options.checkViewport) {
 const rect = element.getBoundingClientRect();
 if (rect.width === 0 || rect.height === 0) return false;
 
 const isVisibleInViewport = (
 rect.top >= 0 &&
 rect.left >= 0 &&
 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
 rect.right <= (window.innerWidth || document.documentElement.clientWidth)
 );
 
 return isVisibleInViewport;
 }
 
 return true;
}

Event-Based Visibility Checking

For dynamic content that changes visibility, use event listeners:

javascript
// Create a visibility observer
const visibilityObserver = new MutationObserver((mutations) => {
 mutations.forEach((mutation) => {
 mutation.addedNodes.forEach((node) => {
 if (node.nodeType === Node.ELEMENT_NODE) {
 checkVisibilityForElement(node);
 }
 });
 
 mutation.removedNodes.forEach((node) => {
 if (node.nodeType === Node.ELEMENT_NODE) {
 checkVisibilityForElement(node);
 }
 });
 });
});

// Observe changes to DOM
visibilityObserver.observe(document.body, {
 childList: true,
 subtree: true
});

function checkVisibilityForElement(element) {
 if (isElementVisible(element)) {
 console.log(`Element ${element.id || element.tagName} is visible`);
 } else {
 console.log(`Element ${element.id || element.tagName} is not visible`);
 }
}

Performance Optimization for Large DOMs

For applications with many elements, optimize visibility checking:

javascript
// Batch visibility checking
function batchVisibilityCheck(elements, callback) {
 const results = [];
 
 // Use requestAnimationFrame for better performance
 requestAnimationFrame(() => {
 elements.forEach((element, index) => {
 results[index] = {
 element,
 visible: isElementVisible(element)
 };
 });
 
 callback(results);
 });
}

// Usage
const allElements = document.querySelectorAll('.content-item');
batchVisibilityCheck(allElements, (results) => {
 results.forEach(result => {
 if (result.visible) {
 // Handle visible element
 }
 });
});

Common Pitfalls to Avoid

  1. Only checking inline styles: Always use getComputedStyle() to check all styles, not just inline ones.
  2. Ignoring parent elements: Remember that an element can be hidden by its parent’s styles.
  3. Forgetting about viewport visibility: An element might be visible in the DOM but not in the current viewport.
  4. Not handling transitions: Elements might be transitioning between visible and hidden states.
  5. Overlooking performance: Visibility checking can be expensive, especially on large DOMs.

Sources

  1. Element.checkVisibility() - MDN Web Docs — Comprehensive documentation on the modern checkVisibility method: https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility
  2. How to Check if an Element is Visible in JavaScript - Practical guide with examples and implementation tips: https://coreui.io/blog/how-to-check-if-an-element-is-visible-in-javascript/
  3. How to Check an Element’s Visibility in JavaScript - Detailed explanation of various visibility checking techniques: https://www.educative.io/answers/how-to-check-an-elements-visibility-in-javascript
  4. visibility-hidden vs. display-none vs. opacity0 - Stack Overflow discussion comparing different CSS properties for hiding elements: https://stackoverflow.com/questions/14731049/visibilityhidden-vs-displaynone-vs-opacity0
  5. CSS opacity Property - MDN Web Docs — Documentation on the CSS opacity property and its effect on visibility: https://developer.mozilla.org/en-US/docs/Web/CSS/opacity
  6. Visibility - CSS-Tricks — In-depth explanation of the CSS visibility property and its behavior: https://css-tricks.com/almanac/properties/v/visibility/

Conclusion

Checking if a DOM element is visible using pure JavaScript requires understanding multiple CSS properties and their interactions. The modern Element.checkVisibility() method provides a comprehensive solution, while traditional techniques involving getComputedStyle() and dimension checks remain valuable for browser compatibility.

Key considerations include examining the display, visibility, and opacity properties, checking parent elements, and optionally verifying viewport visibility. For optimal performance, implement throttling, batch processing, and selective checking, especially in applications with large DOMs.

Whether you’re implementing lazy loading, accessibility features, or dynamic interactions, accurate visibility detection is essential. Choose the approach that best fits your browser compatibility requirements and performance needs, and always test thoroughly across different scenarios to ensure reliable results.

Authors
Verified by moderation