移植simplified-twitter到Safari时window.innerWidth设置无效问题
哦,这个坑我踩过!你遇到的核心问题是:window.innerWidth是只读属性——浏览器根本不允许你直接赋值修改它,这个操作会被默默忽略,不会抛出任何错误,这就导致你看起来执行了赋值,但实际视口宽度完全没变化。
而document.body.style.paddingLeft能生效,是因为这是修改DOM元素的内联样式,属于可写的属性,和innerWidth的只读特性完全不同。
为什么会这样?
window.innerWidth是浏览器提供的一个计算属性,它返回的是当前浏览器视口的实际宽度(不包括浏览器边框、滚动条等),这个值由浏览器自身维护,只能被动读取,不能主动修改。你强行赋值的代码window.innerWidth = Math.min(win.outerWidth, 800)其实没有任何实际作用。
正确的解决思路
既然不能修改视口的实际宽度,我们可以换个思路:通过控制Twitter页面的内容容器宽度,来实现你想要的“窄版”效果,同时保留响应式逻辑的触发。
这里提供两种可行的方案:
方案1:直接限制内容容器宽度(推荐)
找到Twitter页面的主内容容器(比如通过开发者工具查看,通常是带有data-testid="primaryColumn"属性的元素),给它设置最大宽度,替代修改innerWidth的操作:
function update(win = window) { const targetWidth = Math.min(win.outerWidth, 800); // 替换成Twitter实际的主容器选择器,找不到的话用document.body兜底 const mainContent = document.querySelector('[data-testid="primaryColumn"]') || document.body; // 限制内容最大宽度 mainContent.style.maxWidth = `${targetWidth}px`; // 保持原有的paddingLeft逻辑 document.body.style.paddingLeft = targetWidth >= 800 ? '176px' : null; } function triggerUpdate() { setTimeout(() => window.dispatchEvent(new Event('resize')), 1) } window.onresize = e => update(e.target || window) window.onload = triggerUpdate document.addEventListener('visibilitychange', triggerUpdate) triggerUpdate()
这种方式更符合页面布局的逻辑,不会干扰浏览器原生的视口计算,也能达到你想要的视觉效果。
方案2:重写innerWidth的getter(不推荐,有副作用)
如果你的场景必须让其他脚本读取到innerWidth为800,可以通过Object.defineProperty重写这个属性的getter,但要注意这可能会影响页面上依赖视口宽度的其他功能(比如Twitter自身的响应式逻辑):
// 重写innerWidth的getter const originalInnerWidth = Object.getOwnPropertyDescriptor(window, 'innerWidth'); Object.defineProperty(window, 'innerWidth', { get: function() { return Math.min(originalInnerWidth.get.call(this), 800); } }); // 保留你原有的其他逻辑 function update(win = window) { document.body.style.paddingLeft = Math.min(win.outerWidth, 800) >= 800 ? '176px' : null; } function triggerUpdate() { setTimeout(() => window.dispatchEvent(new Event('resize')), 1) } window.onresize = e => update(e.target || window) window.onload = triggerUpdate document.addEventListener('visibilitychange', triggerUpdate) triggerUpdate()
这种方式只是“欺骗”了读取innerWidth的脚本,实际视口宽度并没有改变,所以只在特殊场景下使用。
总结
优先选择方案1,通过控制页面内容容器的宽度来实现需求,这是最安全、最符合Web标准的方式。直接修改innerWidth的思路从一开始就行不通,因为它是浏览器维护的只读属性。
内容的提问来源于stack exchange,提问作者bcye

