Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/BeaconLcp.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ class BeaconLcp {
return (
item.rect.width > 0 &&
item.rect.height > 0 &&
BeaconUtils.isIntersecting(item.rect)
BeaconUtils.isIntersecting(item.rect) &&
BeaconUtils.isElementVisible(item.element)
);
})
.map(item => ({
Expand Down
73 changes: 6 additions & 67 deletions src/BeaconPreloadFonts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
'use strict';

import BeaconUtils from "./Utils.js";

class BeaconPreloadFonts {
constructor(config, logger) {
this.config = config;
Expand Down Expand Up @@ -59,78 +62,14 @@ class BeaconPreloadFonts {
/**
* Checks if an element is visible in the viewport.
*
* This method checks if the provided element is visible in the viewport by
* considering its display, visibility, opacity, width, and height properties.
* It also excludes elements with transparent text properties.
* It returns true if the element is visible, and false otherwise.
* This method delegates to BeaconUtils.isElementVisible() for consistent
* visibility checking across all beacons.
*
* @param {Element} element - The element to check for visibility.
* @returns {boolean} True if the element is visible, false otherwise.
*/
isElementVisible(element) {
const style = window.getComputedStyle(element);
const rect = element.getBoundingClientRect();

// Exclude elements with transparent text properties
if (this.hasTransparentText(element)) {
return false;
}

return !(
style.display === 'none' ||
style.visibility === 'hidden' ||
style.opacity === '0' ||
rect.width === 0 ||
rect.height === 0
);
}

/**
* Checks if an element has transparent text properties.
*
* This method checks for specific CSS properties that make text invisible,
* such as `color: transparent`, `color: rgba(..., 0)`, `color: hsla(..., 0)`,
* `color: #...00` (8-digit hex with alpha = 0), and `filter: opacity(0)`.
*
* @param {Element} element - The element to check.
* @returns {boolean} True if the element has transparent text properties, false otherwise.
*/
hasTransparentText(element) {
const style = window.getComputedStyle(element);

// Defensive check for style properties
const color = style.color || '';
const filter = style.filter || '';

// Check for `color: transparent`
if (color === 'transparent') {
return true;
}

// Check for `color: rgba(..., 0)`
const rgbaMatch = color.match(/rgba\(\d+,\s*\d+,\s*\d+,\s*0\)/);
if (rgbaMatch) {
return true;
}

// Check for `color: hsla(..., 0)`
const hslaMatch = color.match(/hsla\(\d+,\s*\d+%,\s*\d+%,\s*0\)/);
if (hslaMatch) {
return true;
}

// Check for `color: #...00` (8-digit hex with alpha = 0)
const hexMatch = color.match(/#[0-9a-fA-F]{6}00/);
if (hexMatch) {
return true;
}

// Check for `filter: opacity(0)`
if (filter.includes('opacity(0)')) {
return true;
}

return false;
return BeaconUtils.isElementVisible(element);
}

/**
Expand Down
86 changes: 86 additions & 0 deletions src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,92 @@ class BeaconUtils {
return window.pageYOffset > 0 || document.documentElement.scrollTop > 0;
}

/**
* Checks if an element is visible in the viewport.
*
* This method checks if the provided element is visible in the viewport by
* considering its display, visibility, opacity, width, and height properties.
* It also excludes elements with transparent text properties.
* It returns true if the element is visible, and false otherwise.
*
* @param {Element} element - The element to check for visibility.
* @returns {boolean} True if the element is visible, false otherwise.
*/
static isElementVisible(element) {
const style = window.getComputedStyle(element);
const rect = element.getBoundingClientRect();

// Defensive check for style
if (!style) {
return false;
}

// Exclude elements with transparent text properties
if (this.hasTransparentText(element)) {
return false;
}

return !(
style.display === 'none' ||
style.visibility === 'hidden' ||
style.opacity === '0' ||
rect.width === 0 ||
rect.height === 0
);
}

/**
* Checks if an element has transparent text properties.
*
* This method checks for specific CSS properties that make text invisible,
* such as `color: transparent`, `color: rgba(..., 0)`, `color: hsla(..., 0)`,
* `color: #...00` (8-digit hex with alpha = 0), and `filter: opacity(0)`.
*
* @param {Element} element - The element to check.
* @returns {boolean} True if the element has transparent text properties, false otherwise.
*/
static hasTransparentText(element) {
const style = window.getComputedStyle(element);

// Defensive check for style properties
if (!style) {
return false;
}

const color = style.color || '';
const filter = style.filter || '';

// Check for `color: transparent`
if (color === 'transparent') {
return true;
}

// Check for `color: rgba(..., 0)`
const rgbaMatch = color.match(/rgba\(\d+,\s*\d+,\s*\d+,\s*0\)/);
if (rgbaMatch) {
return true;
}

// Check for `color: hsla(..., 0)`
const hslaMatch = color.match(/hsla\(\d+,\s*\d+%,\s*\d+%,\s*0\)/);
if (hslaMatch) {
return true;
}

// Check for `color: #...00` (8-digit hex with alpha = 0)
const hexMatch = color.match(/#[0-9a-fA-F]{6}00/);
if (hexMatch) {
return true;
}

// Check for `filter: opacity(0)`
if (filter.includes('opacity(0)')) {
return true;
}

return false;
}

}

export default BeaconUtils;
Loading