如何根据视口条件性添加#include文件?
为什么你的方法没用?
首先得明确:<!--#include-->是服务器端包含(SSI)指令,它在服务器把页面发送给浏览器之前就已经执行完毕了。而媒体查询是浏览器拿到页面之后才会解析的客户端逻辑——服务器根本不知道用户的视口大小,自然没法根据这个条件来决定要不要包含某个文件。所以你把include放在带.visible-phone的div里,服务器还是会把phone-header.inc的内容塞进页面里,只是浏览器后来用CSS把它隐藏了而已,并不是真正的“条件性添加”。
可行的解决方案
根据你的需求,这里有几种常用的处理方式,你可以根据自己的场景选择:
方案1:CSS控制双包含(简单易实现)
如果你能接受同时加载两个header的内容(差异不大的话,性能影响可以忽略),可以直接把两个header都include进来,然后用媒体查询控制它们的显示/隐藏。这样不需要JS,对无JS环境友好:
<!-- 桌面端头部 --> <div class="header-desktop"> <!--#include virtual="/main/header.inc"--> </div> <!-- 移动端头部 --> <div class="header-mobile"> <!--#include virtual="/main/phone-header.inc"--> </div> <style> /* 默认显示桌面端,隐藏移动端 */ .header-mobile { display: none; } /* 视口小于600px时切换为移动端 */ @media all and (max-width: 599px) { .header-desktop { display: none; } .header-mobile { display: block; } } </style>
方案2:JavaScript动态加载(真正的条件加载)
如果想避免加载不需要的内容,用JS在客户端根据视口大小动态请求对应的header文件,然后插入到页面中。这种方式只会加载当前需要的那个header:
<!-- 用来放置头部的容器 --> <div id="header-container"></div> <script> // 定义加载头部的函数 function loadAppropriateHeader() { const container = document.getElementById('header-container'); const headerUrl = window.innerWidth >= 600 ? '/main/header.inc' : '/main/phone-header.inc'; // 发起请求加载对应头部 fetch(headerUrl) .then(response => { if (!response.ok) throw new Error('加载头部失败'); return response.text(); }) .then(html => { container.innerHTML = html; }) .catch(err => console.error(err)); } // 页面加载完成后执行一次 window.addEventListener('load', loadAppropriateHeader); // 窗口大小改变时重新加载(可选,根据需求决定) window.addEventListener('resize', loadAppropriateHeader); </script>
方案3:服务器端检测(基于用户代理)
如果必须在服务器端完成条件包含,可以尝试通过用户代理(User Agent)字符串判断设备类型,然后用SSI的条件指令来选择include的文件。不过这种方法有局限性:用户代理可以伪造,而且平板/大屏手机的区分比较模糊。
如果你的服务器支持SSI条件判断(比如Apache的mod_include),可以这样写:
<!--#if expr="$HTTP_USER_AGENT = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i" --> <!--#include virtual="/main/phone-header.inc"--> <!--#else --> <!--#include virtual="/main/header.inc"--> <!--#endif -->
注意:要确保服务器开启了SSI支持,并且页面文件后缀是.shtml(或者配置了让服务器解析其他后缀的SSI指令)。
总结
如果追求简单,方案1最省心;如果在意加载性能,方案2更合适;如果必须服务器端处理,方案3可以试试,但要注意它的局限性。
内容的提问来源于stack exchange,提问作者Jon

