如何判断包含::before/::after伪元素的元素是否完全显示在视窗内
如何判断包含
::before、::after伪元素的元素是否完全显示在浏览器视窗中? 要解决这个问题,我们需要扩展原有的getBoundingClientRect()判断逻辑,将伪元素的尺寸和位置纳入计算范围,最终判断包含主元素和伪元素的整体区域是否完全处于视窗内。
修改后的判断函数
function isElementInViewportWithPseudo(el) { // 处理jQuery对象,转为DOM节点 if (typeof jQuery === "function" && el instanceof jQuery) { el = el[0]; } // 获取主元素的视窗边界(border box) const mainRect = el.getBoundingClientRect(); // 初始化合并后的边界为主体元素的边界 let mergedRect = { top: mainRect.top, left: mainRect.left, bottom: mainRect.bottom, right: mainRect.right }; // 定义获取伪元素视窗边界的辅助函数 const getPseudoRect = (pseudoSelector) => { const pseudoStyle = getComputedStyle(el, pseudoSelector); // 伪元素不存在(content为none或隐藏)则返回null if (pseudoStyle.content === 'none' || pseudoStyle.display === 'none') { return null; } // 获取主元素的边框、内边距计算值 const elStyle = getComputedStyle(el); const elBorderTop = parseFloat(elStyle.borderTopWidth) || 0; const elBorderLeft = parseFloat(elStyle.borderLeftWidth) || 0; const elPaddingTop = parseFloat(elStyle.paddingTop) || 0; const elPaddingLeft = parseFloat(elStyle.paddingLeft) || 0; // 计算主元素padding box的视窗位置(伪元素的定位基准) const paddingBoxTop = mainRect.top + elBorderTop + elPaddingTop; const paddingBoxLeft = mainRect.left + elBorderLeft + elPaddingLeft; // 伪元素的偏移、外边距计算值 const pseudoTop = parseFloat(pseudoStyle.top) || 0; const pseudoLeft = parseFloat(pseudoStyle.left) || 0; const pseudoMarginTop = parseFloat(pseudoStyle.marginTop) || 0; const pseudoMarginLeft = parseFloat(pseudoStyle.marginLeft) || 0; // 伪元素的完整border box尺寸(包含内边距、边框) const pseudoWidth = (parseFloat(pseudoStyle.width) || 0) + (parseFloat(pseudoStyle.paddingLeft) || 0) + (parseFloat(pseudoStyle.paddingRight) || 0) + (parseFloat(pseudoStyle.borderLeftWidth) || 0) + (parseFloat(pseudoStyle.borderRightWidth) || 0); const pseudoHeight = (parseFloat(pseudoStyle.height) || 0) + (parseFloat(pseudoStyle.paddingTop) || 0) + (parseFloat(pseudoStyle.paddingBottom) || 0) + (parseFloat(pseudoStyle.borderTopWidth) || 0) + (parseFloat(pseudoStyle.borderBottomWidth) || 0); // 计算伪元素border box在视窗中的绝对位置 const top = paddingBoxTop + pseudoTop - pseudoMarginTop; const left = paddingBoxLeft + pseudoLeft - pseudoMarginLeft; const bottom = top + pseudoHeight; const right = left + pseudoWidth; return { top, left, bottom, right }; }; // 合并before伪元素的边界 const beforeRect = getPseudoRect(':before'); if (beforeRect) { mergedRect.top = Math.min(mergedRect.top, beforeRect.top); mergedRect.left = Math.min(mergedRect.left, beforeRect.left); mergedRect.bottom = Math.max(mergedRect.bottom, beforeRect.bottom); mergedRect.right = Math.max(mergedRect.right, beforeRect.right); } // 合并after伪元素的边界 const afterRect = getPseudoRect(':after'); if (afterRect) { mergedRect.top = Math.min(mergedRect.top, afterRect.top); mergedRect.left = Math.min(mergedRect.left, afterRect.left); mergedRect.bottom = Math.max(mergedRect.bottom, afterRect.bottom); mergedRect.right = Math.max(mergedRect.right, afterRect.right); } // 获取视窗尺寸 const viewportHeight = window.innerHeight || document.documentElement.clientHeight; const viewportWidth = window.innerWidth || document.documentElement.clientWidth; // 判断合并后的整体区域是否完全在视窗内 return ( mergedRect.top >= 0 && mergedRect.left >= 0 && mergedRect.bottom <= viewportHeight && mergedRect.right <= viewportWidth ); }
函数工作原理
- 处理输入元素:将jQuery对象转为DOM节点,确保后续API调用兼容。
- 初始化主元素边界:获取主元素的视窗边界,作为初始的整体边界。
- 伪元素边界计算:
- 通过
getComputedStyle获取伪元素的计算样式,判断伪元素是否存在。 - 基于主元素的padding box计算伪元素的定位基准(符合CSS绝对定位规则)。
- 计算伪元素的完整border box尺寸(包含内边距、边框)和绝对视窗位置,同时考虑外边距的偏移影响。
- 通过
- 合并边界:将主元素和伪元素的边界合并,得到能覆盖所有区域的最小矩形(取最上/左、最下/右的极值)。
- 视窗判断:使用合并后的边界判断是否完全处于视窗内。
使用示例
替换原代码中的isElementInViewport为上述函数即可:
$(document).ready(function() { console.log("Is visible (with pseudo): " + isElementInViewportWithPseudo($(".a"))); }) $(window).on('resize', function() { console.log("Is visible (with pseudo): " + isElementInViewportWithPseudo($(".a"))); })
这样就能准确识别示例中主元素虽在视窗内,但::after伪元素超出视窗的情况,返回正确的可见性判断结果。
内容的提问来源于stack exchange,提问作者user20417316
相关产品推荐
相关产品推荐

