用 CSS 和 JavaScript 实现对联广告代码

用 CSS 和 JavaScript 实现对联广告代码

用 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,并符合站点、广告平台和适用法律法规的要求。
  • 若广告涉及个性化投放、第三方追踪或存储,应按适用的隐私规则处理同意、告知和数据使用,不能仅凭前端代码推断已满足合规要求。

对联广告的实现重点不是让广告“始终显示”,而是在空间足够、不会妨碍用户操作的条件下展示。把定位计算、窄屏策略、关闭状态和链接校验分别处理,再结合页面真实布局测试,比单纯增加层级或堆叠事件监听更可靠。

© 版权声明

相关文章