欢迎测评:前端工程师 

在页面上加些代码,让页面白屏幕,有哪些方式呢?如何防御呢?

本文介绍了 8 种让页面白屏的方法。在防御方法中,包含了一些你可能不知道的冷知识,如:判断元素是否被遮挡。

方法1: 隐藏根节点

html {
  display:none !important;
}

选择器用 body 也能达到一样的效果。

当页面是深色模式时,添加上面的代码页面后,页面是黑色的。需要取消深色模式:删除下面的代码:

<meta name="color-scheme" content="dark" >

方法2: 让根节点不可见

设置可见性的属性:

html {
  visibility: hidden !important;
}

或者,设置透明度为完全透明:

html {
  opacity: 0 !important;
}

方法3: 大小设为0,超出隐藏

body {
  width: 0 !important;
  height: 0 !important;
  overflow: hidden !important;
}

选择器用 html 没有效果。

方法4: 偏移出屏幕

用 fixed 定位:

html {
  position: fixed;
  left: -99999px;
}

或者,用 transform

html {
  transform: translateX(-99999px);
}

方法5: 遮挡页面

用全屏的白色元素遮挡页面。

html::before {
  content: '';
  position: fixed;
  z-index: 999999;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  background: #fff;
}

方法6: 缩小

html {
  transform: scale(0.0000000000001);
}

方法7: 清空页面内容

document.documentElement.innerHTML = ''

方法8: 页面跳转到一个空白页面

location.href = '空白页面URL'

这个方法有点皮~

防御

检测白屏的样式

通过轮训检查根节点上,是否有导致白屏的样式。如果有,则刷新页面。例如:

setInterval(() => {
    if(hasWhitePageStyle()) {
        location.reload()
    }
},  100)

通过这种方式,可以防御方法 1 ~ 6。我们来看具体的检查方法。

根节点是否隐藏检查

const root = document.documentElement
const body = document.body
if(
  getComputedStyle(root, null).display === 'none' ||
  getComputedStyle(body, null).display === 'none'
) {
  return true // 根节点被隐藏
}

根节点是否可见检查

if(
  getComputedStyle(root, null).visibility === 'hidden' ||
  getComputedStyle(body, null).visibility === 'hidden'
) {
  return true // 不可见
}

if(
  getComputedStyle(root, null).opacity < 0.1 || 
  getComputedStyle(body, null).opacity < 0.1 ||
) {
  return true // 不可见
}

大小为 0 检查

const {width, height } = body.getBoundingClientRect()
if(width === 0 || height === 0) {
  return true // 大小为 0
}

偏移出屏幕检查

const {left, right, top, bottom } = body.getBoundingClientRect()
if(
  left > window.innerWidth || 
  right < 0 || 
  top > window.innerHeight || 
  bottom < 0 
) {
  return true // 偏移出屏幕
}

遮挡检查

document.elementFromPoint(x, y)[1] 返回某个坐标点下最上层的元素。如果元素没有被遮挡,则在该 API 中传入元素的上下左右四个坐标点,返回的均为该元素。

假设页面上有个 id 为 tar 的元素,如果该元素未被遮挡,则认为页面被遮挡。

const tarElem = document.getElementById('tar')
const {left, right, top, bottom} = tarElem.getBoundingClientRect()
if(
  document.elementFromPoint(left, top) === tar &&
  document.elementFromPoint(left, bottom) === tar &&
  document.elementFromPoint(right, top) === tar &&
  document.elementFromPoint(right, bottom) === tar &&
) {
  return true// 未被遮挡
}

防止修改 DOM

MutationObserver API[2] 可以监控 DOM 的变动。用该 API 可以防御页面内容被清空。代码如下:

// 监控 属性,子节点和后代节点的变动
const config = { attributes: true, childList: true, subtree: true };
const observer = new MutationObserver((mutationsList) => {
  for(let mutation of mutationsList) {// 页面DOM变动
    location.reload()
  }
})
window.addEventListener('DOMContentLoaded', () => {
  observer.observe(document.documentElement, config);
})

防止页面跳转

目前没有找到防御的方法。尝试过以下方法。

重置 window.location

执行:

window = {}

window.location 仍然在。

执行:

const location = '' 

function location () {}

都会报错。

执行:

window.location = {} 

页面直接跳转了。

将 window.location 设置为只读

做了如下尝试,均不行:

Object.freeze(window) // 报错
Object.freeze(window.location) // 无效
// 报错
Object.defineProperty(window, "location", {"writable": false})
// 报错
Object.defineProperty(location, "false", {"writable": false})