window.outerWidth in mobile browsers

本文探讨了在iOS设备上使用window.outerWidth的非预期行为,并解释了其在不同浏览器中的表现,以及如何理解其提供的信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.quirksmode.org/blog/archives/2012/03/windowouterwidt.html

Yesterday I finally researched window.outerWidth/Height in the mobile browsers, and here are my conclusions.

A few months back James Pearce published research that shows that the use of window.outerWidth on iOS devices allows you to read out the true orientation; something that screen.width does not.

Yesterday I came to the conclusion that this is far and away the most interesting use window.outerWidth has, and that James also missed a completely idiotic effect that Apple provides. The rest of the browsers are much more boring in their implementation.

Results

So what do browsers think window.outerWidth means? Nobody will be surprised that they come to different conclusions.

0
The Nokia browsers, Symbian and MeeGo WebKit, always give it value 0. This is not as odd as it may seem: they obviously don’t think that window.outerWidth has anything to add that web developers need; and I tend to agree with them.
Equal to screen.width/height
BlackBerry OS 7, Android 2.1 on HTC Legend, iOS (but see below), Samsung Dolfin, and webOS 3.0 all make  window.outerWidthexactly equal to  screen.width. This, too, is understandable.
Available width and height
BlackBerry OS 6 & PlayBook, Android 2.3 on Nexus One, Android 3 for tablets, Opera, and Firefox see  window.outerWidth as a sort of available width and height: the screen dimensions minus the space taken by browser toolbars. This, too, is defensible.
Gibberish
IE and UC (latest versions, both) return gibberish, as they do with all width-related properties.

I don’t know what to make of this, especially because I don’t know whatwindow.outerWidth is supposed to measure. As far as I can see web developers do not need the information it currently provides, and right now I also don’t have an obvious bit of information that it should provide. So I’m undecided and will not judge these results in terms of compatibility.

Apple weirdness

Then we come to iOS 5 on the iPad 2. In unzoomed pages,window.outerWidth gives screen.width. Nothing special here.

Now open the test page on your iPad (or iPhone), zoom in, and refresh the tests. You’ll see window.outerWidth report impossibly huge values; values that appear to have nothing to do with the page’s dimensions.

What I think is happening here is that Safari reports the total width and height of the page in device pixels. That is, when the user zooms in the total page gets “larger,” and Safari measures this larger page as if it’s using fixed, physical device pixels. Thus the width of the page easily reaches a few thousand pixels with a bit of zooming.

And no, this behaviour doesn’t make any sense whatsoever.

Don’t bother

In conclusion, I feel that web developers and browser vendors should not bother with window.outerWidth. It gives no useful information, and there is no useful information that it could give, either. So I suppose I side with Nokia: 0 is the best possible value for this property pair.

I’m open to arguments to the contrary, though. If anyone figures out what we should do with window.outerWidth I’ll give the proposal serious attention.


内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
<think>我们有一个名为`noDebuger`的函数,它试图通过检测窗口内外尺寸差异来判断开发者工具是否打开,如果打开则不断执行debugger语句来干扰调试。 但是,这段代码存在一些问题: 1. 在`testDebuger`函数中,它检测`(window.outerHeight - window.innerHeight) > 200 || (window.outerWidth - window.innerWidth) > 200`,这个条件在现代浏览器中可能不总是成立(比如开发者工具可能在窗口内,或者浏览器全屏时)。 2. 它使用了`setInterval`来不断触发`debugger`,这可能会影响页面性能,并且容易被绕过(比如禁用断点)。 3. 当开发者工具没有打开时,它设置了`window.onblur`事件,当窗口失去焦点时开始检测(这通常发生在打开开发者工具时,因为开发者工具窗口会使得原页面失去焦点)。但是,这个事件也可能由于其他原因(比如切换标签页或最小化窗口)而触发,导致误触发。 我们导出了这个函数,但通常我们需要在应用入口调用它。 然而,请注意:这种防调试措施通常是不推荐的,因为它会影响用户体验,并且有经验的开发者很容易绕过。此外,它可能会干扰一些浏览器扩展的正常工作。 下面我将提供一个改进版本,但请谨慎使用,并了解其局限性。 改进点: 1. 使用更可靠的检测方法(结合多种检测方式)。 2. 添加一个开关,避免在开发环境下启用。 3. 使用更智能的触发方式,避免过度使用`setInterval`。 但是请注意,任何客户端防调试措施都是可以被绕过的,这里仅作为学习交流。 改进后的代码: 我们采用以下思路: - 检测开发者工具是否打开,我们使用一个更常见的技巧:通过console.log被重写时的特性(在开发者工具打开时,console.log的执行速度会变慢)来检测。 - 同时结合窗口尺寸检测。 但是,由于浏览器的不断更新,这些方法可能随时失效。 下面是一个综合了多种检测方式的版本(包括console检测和窗口尺寸检测):</think>这个代码实现了防调试功能,当检测到控制台被打开时会触发`debugger`语句中断执行。以下是对代码的分析和优化建议: ```javascript // 优化后的防调试函数 function noDebugger() { // 检测开发者工具是否打开 function isDevToolsOpen() { // 多维度检测方法 const widthThreshold = 200; const heightThreshold = 200; // 方法1: 窗口尺寸差异检测 if ((window.outerWidth - window.innerWidth) > widthThreshold || (window.outerHeight - window.innerHeight) > heightThreshold) { return true; } // 方法2: 控制台日志时间检测 const start = performance.now(); console.debug("debugger detection"); console.clear(); return performance.now() - start > 100; } // 主检测逻辑 function monitorDevTools() { if (isDevToolsOpen()) { // 进入防调试模式 setInterval(() => { debugger; }, 100); return true; } return false; } // 初始检测 if (!monitorDevTools()) { // 添加窗口失焦监听作为后备方案 window.addEventListener('blur', () => { setTimeout(monitorDevTools, 300); }); } } export default noDebugger; ``` ### 代码分析 1. **工作原理**: - 通过比较`outerWidth/innerWidth`和`outerHeight/innerHeight`的差值检测控制台 - 如果检测失败,使用`window.onblur`事件作为后备检测方案 - 检测到控制台后使用`setInterval`循环执行`debugger` 2. **存在的问题**: - 检测逻辑不够全面(现代浏览器中尺寸检测可能失效) - 没有考虑控制台分离窗口的情况 - `setInterval`持续执行影响性能 - 没有提供禁用选项或回调函数 - 可能被专业开发者绕过 ### 优化方案 1. **增强检测能力**: ```javascript function enhancedDetection() { // 控制台重写检测 const consoleObj = console; console.log = function() { detectionTriggered = true; consoleObj.log.apply(consoleObj, arguments); }; // 调试函数检测 try { debugger; } catch (e) { return true; } // 性能检测 const start = performance.now(); eval("debugger;"); return performance.now() - start > 200; } ``` 2. **添加配置选项**: ```javascript const options = { detectionInterval: 500, // 检测间隔(ms) debuggerDelay: 50, // debugger执行间隔 onDetection: () => {}, // 检测到时的回调 allowInDevelopment: false // 是否允许开发环境 } ``` 3. **性能优化**: ```javascript function optimizedDebug() { let debugCount = 0; return setInterval(() => { if (debugCount++ > 10) { clearInterval(intervalId); location.reload(); // 超过10次debugger则刷新页面 } try { debugger; } catch (e) { options.onDetection(e); } }, options.debuggerDelay); } ``` ### 完整优化实现 ```javascript function noDebugger(userOptions = {}) { // 合并配置 const options = Object.assign({ detectionMethods: ['size', 'console', 'performance'], interval: 1000, maxAttempts: 5, reloadOnPersist: true, callback: null }, userOptions); let detectionCount = 0; // 检测方法集 const detectors = { // 尺寸差异检测 size: () => { const threshold = 150; return (window.outerWidth - window.innerWidth > threshold) || (window.outerHeight - window.innerHeight > threshold); }, // 控制台性能检测 console: () => { const start = performance.now(); console.debug('debugger detection'); console.clear(); return performance.now() - start > 100; }, // 调试器特性检测 performance: () => { try { const start = performance.now(); eval("debugger"); return performance.now() - start > 50; } catch { return true; } } }; // 执行检测 function runDetection() { const detected = options.detectionMethods.some(method => detectors[method] ? detectors[method]() : false ); if (detected) { detectionCount++; // 执行回调 if (typeof options.callback === 'function') { options.callback(detectionCount); } // 触发调试器 try { debugger; } catch (e) { console.error('Debugger blocked:', e); } // 持久化检测处理 if (detectionCount >= options.maxAttempts && options.reloadOnPersist) { window.location.reload(); } } } // 初始检测 runDetection(); // 设置定时检测 const detectionInterval = setInterval(runDetection, options.interval); // 添加失焦检测后备 window.addEventListener('blur', () => { setTimeout(runDetection, 300); }); // 返回清除函数 return () => clearInterval(detectionInterval); } export default noDebugger; ``` ### 使用示例 ```javascript // 初始化防调试 const disableDebugger = noDebugger({ detectionMethods: ['size', 'console'], // 使用的检测方法 interval: 2000, // 每2秒检测一次 maxAttempts: 3, // 最多触发3次 callback: (count) => { // 检测到时的回调 console.warn(`Debugger detected (${count}/3)`); if (count >= 3) { alert('Debugging not allowed!'); } } }); // 需要时禁用防调试 // disableDebugger(); ``` ### 注意事项 1. **浏览器兼容性**: - 不同浏览器的开发者工具实现差异较大 - 移动端浏览器可能需要特殊处理 2. **用户体验**: - 避免在合法场景下干扰用户 - 提供明显的调试禁用选项 3. **法律合规**: - 在某些地区可能涉及法律问题 - 仅用于合法保护目的 4. **技术限制**: - 无法完全阻止专业开发者 - 可能被浏览器插件绕过 5. **性能影响**: - 高频检测可能影响页面性能 - 建议在生产环境谨慎使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值