SSR应用如何在初始GET请求中传递window.innerWidth实现响应式样式适配
首先明确一个核心逻辑:浏览器发起index.html的初始GET请求时,还未下载、运行当前站点的任何前端代码,此时根本无法获取window对象的属性,自然也不可能直接在初始请求中携带window.innerWidth值。你可以根据业务场景选择以下几种可行方案:
方案1:轻量跳转携带宽度参数
首次请求时服务端先返回一个无业务内容的极简HTML,仅执行一段JS获取宽度后将宽度作为查询参数拼接在URL中重新跳转,此时第二次请求服务端即可直接从请求参数中读取宽度。
极简跳转页示例代码:
<!DOCTYPE html> <script> const width = window.innerWidth // 拼接参数跳转,保留原有路径、hash location.href = `${location.origin}${location.pathname}?width=${width}${location.hash}` </script>
服务端获取方式:
export function getServerSideProps(context) { const width = context.req.query.width return { props: { width }, }; }
优缺点:首次访问就能拿到正确宽度适配页面,缺点是会多一次跳转,首次加载速度稍慢。
方案2:Cookie持久化存储宽度
用户首次访问时,前端在客户端获取window.innerWidth写入Cookie,后续所有页面请求都会自动携带Cookie,服务端可直接从Cookie中读取宽度值。
前端存Cookie示例:
document.cookie = `client_width=${window.innerWidth}; path=/; max-age=2592000`
服务端获取方式:
export function getServerSideProps(context) { // 从请求头的Cookie中解析出client_width const width = context.req.headers.cookie?.match(/client_width=(\d+)/)?.[1] return { props: { width: width || 1920 }, // 给默认值兼容首次无Cookie的情况 }; }
优缺点:无额外跳转,缺点是用户首次访问时Cookie还未生成,第一次渲染拿不到正确宽度,后续访问/刷新才会生效,适合用户重复访问率高的站点。
方案3:优先使用CSS原生响应式(更推荐)
如果只是做响应式样式,不需要依赖宽度做特殊的服务端业务逻辑,更建议直接用CSS媒体查询实现适配:SSR返回的HTML携带完整的CSS媒体查询规则,客户端拿到后直接就能按屏幕尺寸渲染正确样式,完全不需要依赖JS传值,也不会出现布局闪烁、内容留空的问题。
如果必须要JS逻辑配合适配,也可以给宽度设置一个符合大部分用户的默认值做服务端渲染,客户端注水完成后再更新为真实宽度,同时搭配CSS骨架屏避免布局偏移,这也是目前绝大多数SSR框架的推荐实践。
内容的提问来源于stack exchange,提问作者Q. Q. McAcka

