
用 CSS 和 JavaScript 实现对联广告代码
对联广告通常由左右两块竖向创意组成,分别固定在网页内容区域两侧。用户滚动页面时,广告仍停留在视口中,因而能获得较稳定的展示位置。它适合桌面端内容页、活动页等左右留白充足的页面;如果页面窄、内容本身已占满视口,或者广告会遮挡操作控件,就不适合强行展示。
实现这类广告不只是给两个元素设置 position: fixed。还要考虑视口宽度、页面内容边界、关闭行为、键盘操作、移动端展示、广告链接的安全性,以及广告平台或站点自身的规范。下面从布局策略开始,给出一份可直接运行的完整示例。
一、先确定展示边界
对联广告一般贴近内容容器的左右两侧,而不是固定贴在浏览器窗口边缘。假设内容区最大宽度为 1200px,广告与内容间距为 24px,那么当视口宽度足够时,左右广告可按内容区边缘定位;当视口变窄时,则应隐藏广告或切换到其他形式。
需要特别区分“内容区宽度”和“视口宽度”。前者由页面布局决定,后者由浏览器窗口决定。若页面有侧边栏、浏览器缩放、滚动条或嵌入容器,实际可用空间还可能进一步减少。因此,阈值不应被当作所有网站通用的标准,而应结合页面实际布局测试。
- 适用场景:桌面端宽屏页面,左右留白较多,且广告不会压住正文、导航、按钮等关键内容。
- 不适用场景:窄屏移动端、弹窗密集的页面、需要持续展示重要操作控件的页面,或广告遮挡会妨碍阅读和交互的页面。
- 必要原则:关闭入口要清晰可操作;广告与页面内容之间要留出空间;用户关闭后,不应在同一页面会话中立刻重新出现。
二、完整可运行示例
下面的示例使用 CSS 固定左右广告,并在较窄视口隐藏广告。JavaScript 只负责关闭行为和安全设置链接地址,不参与布局计算。保存为 HTML 文件即可本地查看。示例中的文案和链接是占位内容,正式投放时应替换为经过审核的创意和目标地址。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>对联广告示例</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
color: #222;
font: 16px/1.7 system-ui, sans-serif;
}
.page {
width: min(100% - 32px, 1200px);
margin: 0 auto;
padding: 24px 0 80px;
}
.side-ad {
position: fixed;
top: 50%;
z-index: 1000;
width: 120px;
height: 300px;
transform: translateY(-50%);
display: grid;
place-items: center;
overflow: hidden;
border: 1px solid #d8d8d8;
border-radius: 8px;
background: linear-gradient(160deg, #fff3dc, #f5d39c);
color: #392710;
text-align: center;
text-decoration: none;
box-shadow: 0 4px 16px rgb(0 0 0 / 12%);
}
.side-ad--left {
right: calc(50% + 600px + 24px);
}
.side-ad--right {
left: calc(50% + 600px + 24px);
}
.side-ad__content {
padding: 12px;
}
.side-ad__label {
display: block;
margin-bottom: 12px;
color: #5e5e5e;
font-size: 12px;
}
.side-ad__title {
display: block;
font-size: 20px;
font-weight: 700;
}
.side-ad__button {
display: inline-block;
margin-top: 16px;
padding: 6px 12px;
border-radius: 4px;
background: #743e12;
color: #fff;
font-size: 14px;
}
.side-ad__close {
position: absolute;
top: 4px;
right: 4px;
z-index: 1;
width: 28px;
height: 28px;
border: 0;
border-radius: 50%;
background: rgb(255 255 255 / 90%);
color: #222;
font: inherit;
line-height: 1;
cursor: pointer;
}
.side-ad__close:focus-visible {
outline: 3px solid #1769aa;
outline-offset: 2px;
}
/* 内容区两侧空间不足时隐藏,避免压住页面内容 */
@media (max-width: 1520px) {
.side-ad {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
}
}
</style>
</head>
<body>
<main class="page">
<h1>页面内容</h1>
<p>将浏览器窗口调整到足够宽,可以看到页面两侧的对联广告。窗口较窄时,广告会自动隐藏。</p>
<p>这里可以放文章、商品介绍或其他页面内容。实际项目中应根据内容容器宽度和广告尺寸重新计算展示阈值。</p>
</main>
<aside class="side-ad-pair" aria-label="页面广告">
<a class="side-ad side-ad--left" data-ad="left"
href="https://example.com/campaign"
target="_blank" rel="noopener noreferrer"
aria-label="了解左侧广告活动">
<span class="side-ad__content">
<span class="side-ad__label">广告</span>
<span class="side-ad__title">发现新活动</span>
<span class="side-ad__button">了解详情</span>
</span>
</a>
<a class="side-ad side-ad--right" data-ad="right"
href="https://example.com/campaign"
target="_blank" rel="noopener noreferrer"
aria-label="了解右侧广告活动">
<span class="side-ad__content">
<span class="side-ad__label">广告</span>
<span class="side-ad__title">更多精彩内容</span>
<span class="side-ad__button">立即查看</span>
</span>
</a>
<button class="side-ad__close" type="button"
aria-label="关闭对联广告">×</button>
</aside>
<script>
(() => {
const pair = document.querySelector(".side-ad-pair");
if (!pair) return;
const closeButton = pair.querySelector(".side-ad__close");
const storageKey = "sideAdPairClosed";
// 示例仅允许 example.com 域名;正式项目应替换为自己的可信域名列表。
const allowedHosts = new Set(["example.com"]);
const adUrl = "https://example.com/campaign";
function isAllowedUrl(value) {
try {
const url = new URL(value, window.location.href);
return url.protocol === "https:" && allowedHosts.has(url.hostname);
} catch {
return false;
}
}
if (isAllowedUrl(adUrl)) {
pair.querySelectorAll("a[data-ad]").forEach((link) => {
link.href = adUrl;
});
} else {
// 地址不符合当前白名单时,不展示可点击广告。
pair.hidden = true;
return;
}
try {
if (sessionStorage.getItem(storageKey) === "1") {
pair.hidden = true;
}
} catch {
// 存储不可用时继续展示;关闭仍可在当前页面生效。
}
closeButton.addEventListener("click", () => {
pair.hidden = true;
try {
sessionStorage.setItem(storageKey, "1");
} catch {
// 隐私模式或浏览器策略可能禁用存储,不影响关闭操作。
}
});
})();
</script>
</body>
</html>
三、CSS 布局为什么这样写
1. 用固定定位保持在视口中
position: fixed 将广告相对于视口定位,因此页面滚动时广告位置不随正文移动。示例用 top: 50% 和 transform: translateY(-50%) 垂直居中。这是一种常见做法,但广告高度如果接近或超过视口高度,顶部或底部仍可能被裁切。实际使用时应保证广告高度合理,或改成顶部定位并为视口留出间距。
左右定位使用 calc(50% + 600px + 24px)。其中 50% 是视口宽度的一半,600px 是示例内容最大宽度的一半,24px 是广告与内容区的间距。右侧采用 left,左侧采用 right,这样两块广告会分别落在居中内容区外侧。若修改了内容容器的最大宽度或间距,也要同步调整这里的数值。
示例在视口宽度小于 1520px 时隐藏广告:内容宽度最多为 1200px,两侧各需要 120px 广告和 24px 间距,总和为 1488px。断点略高于这个理论值,预留了少量缓冲。但这只是示例配置,不是浏览器、广告平台或 CSS 规定的固定限制。页面若有额外边距、滚动条或更宽的广告,应通过实际测试调整断点。
z-index 只决定广告在当前层叠上下文中的前后关系,并不能保证它一定压过页面上的所有元素。祖先元素的 transform、filter、opacity 等属性可能创建新的层叠上下文,影响固定定位或层级表现。优先检查页面结构,不要一遇到遮挡就把 z-index 无限调大。
2. 窄屏隐藏比硬挤更稳妥
桌面双侧广告直接搬到手机上,常会遮住正文或占用过多宽度。示例使用媒体查询隐藏整组广告。也可以在移动端改成底部横幅、正文内广告或由广告系统提供的响应式版位,但应作为单独的布局方案设计,不要简单缩小对联尺寸后继续覆盖内容。
在需要覆盖刘海屏或系统安全区域的布局中,可以结合 env(safe-area-inset-*) 调整边距。不过,安全区变量只提供设备安全区域相关的 inset 值,不会自动判断广告是否遮挡页面按钮,也不能代替响应式断点和人工验收。
四、JavaScript 负责什么
示例中的脚本承担两项任务:用户点击关闭按钮后隐藏广告;验证广告目标地址是否符合预设的 HTTPS 协议和主机名白名单。布局仍交给 CSS 管理,避免脚本在每次滚动、缩放时频繁写入样式。
关闭按钮使用原生 <button>,可通过键盘聚焦和回车、空格键操作。关闭区域不嵌套在广告链接里,避免用户想关闭广告时误触跳转。关闭状态写入 sessionStorage,通常在当前标签页会话中保留;浏览器关闭后是否保留由浏览器实现决定。若产品要求跨会话记忆,需评估使用 localStorage 或服务端状态的必要性,并考虑隐私告知、存储策略和用户清除数据的情况。
Web Storage 可能因浏览器设置、隐私模式或安全策略而不可用,因此读写都放在 try/catch 中。即使存储失败,关闭按钮仍会在当前页面立即隐藏广告。不能把存储成功当作功能正常的前提。
五、参数限制:哪些是示例值,哪些不是
CSS 的宽度、高度、断点和层级数值都是站点设计参数,不存在适用于所有页面的统一最大值或最小值。示例的 120px 宽、300px 高和 1520px 断点,仅服务于展示布局计算。改动后要同时检查视口较窄、缩放比例变化、内容长度变化及广告素材实际尺寸。
JavaScript 中的 allowedHosts 是业务白名单,不是浏览器对安全 URL 的标准配置。应填写明确、可信且确实需要的域名,避免用过宽的字符串包含判断。例如,简单检查网址是否“包含”某个域名,可能错误放行相似域名。示例使用 URL 解析地址,再分别检查协议和 hostname,但这仍只是客户端校验,不能代替服务端对广告配置、跳转目标和素材来源的审核。
示例只允许 https:。如果业务确实需要其他协议或第三方跳转,应先确认其来源可信、链路符合站点和平台规则,再调整校验逻辑。不要接受未经审核的任意 URL,也不要把广告配置拼进 innerHTML 后直接渲染。若要展示由数据提供的标题,应优先使用 textContent;HTML 内容则必须经过适当的可信生成或消毒流程。
六、常见错误与排查方法
只设置左右边距,没有设置窄屏规则
结果是广告在中等宽度窗口中压住正文。应从内容容器宽度、广告宽度和间距推导最小展示宽度,再通过媒体查询隐藏或切换布局,并在真实页面中验证,而不是只在一个大屏窗口里预览。
关闭按钮被广告链接覆盖
若把关闭按钮放进链接元素,点击按钮可能同时触发跳转,键盘交互也容易混乱。关闭按钮应与广告链接同级,并放在独立的容器中。关闭操作最好有清楚的可访问名称,不能只依赖一个视觉上很小的叉号。
用滚动事件反复修改位置
固定定位已经能跟随视口,不需要在 scroll 事件中持续改写 top。这类写法容易造成布局抖动和不必要的工作。只有在确实需要根据滚动阶段改变行为时,才增加脚本逻辑,并使用节流或合适的观察机制。
关闭后刷新页面又立即出现
如果产品期望关闭状态在当前标签页会话内持续,应保存状态并在初始化时读取。示例以 sessionStorage 实现这一行为。若页面由客户端路由切换,组件可能被重新挂载,也要确保状态读取逻辑能在组件重建时执行。
广告出现后遮住页头或关键按钮
固定定位元素不参与正常文档流,页面不会自动为它们预留位置。除了设置断点,还要检查页头、浮动客服、Cookie 提示、视频控件等其他固定元素,协调层级和展示范围。广告不能仅因为层级足够高就视为可用。
七、上线前检查清单
- 在不同桌面宽度、浏览器缩放比例和页面滚动位置检查广告是否压住正文或关键控件。
- 确认小屏时广告会隐藏或切换到经过设计的替代版式。
- 使用鼠标、键盘和触摸操作测试链接与关闭按钮,确认焦点状态清晰、关闭不会误跳转。
- 检查关闭状态存储不可用时,页面仍可正常关闭广告。
- 确认目标地址来自可信配置,使用 HTTPS,并符合站点、广告平台和适用法律法规的要求。
- 若广告涉及个性化投放、第三方追踪或存储,应按适用的隐私规则处理同意、告知和数据使用,不能仅凭前端代码推断已满足合规要求。
对联广告的实现重点不是让广告“始终显示”,而是在空间足够、不会妨碍用户操作的条件下展示。把定位计算、窄屏策略、关闭状态和链接校验分别处理,再结合页面真实布局测试,比单纯增加层级或堆叠事件监听更可靠。








