개발 slecs

광고 게이트 모달을 레이아웃 레벨에서 분리 구현

목차

광고 게이트 모달 작업을 마무리했다. AdGateModal.astro 컴포넌트 신규 추가 + Layout.astro 연동 — 변경 파일 수는 두 개지만 내부적으로 꽤 많은 결정이 있었던 작업이었음.


배경: 왜 게이트 모달인가

사이트 레이아웃 레벨에서 광고를 제어해야 하는 시나리오가 생겼다. 단순히 배너 하나 꽂는 게 아니라, 특정 조건에서 콘텐츠 접근 전에 광고 노출을 강제하는 "게이트" 구조가 필요했던 것. 이런 패턴은 미디어/콘텐츠 서비스에서 종종 쓰는데, 유저 경험과 수익 사이 트레이드오프가 꽤 예민하다.

레이아웃 수준에서 처리하기로 결정한 이유도 거기 있었다. 개별 페이지마다 모달 로직을 심으면 나중에 정책이 바뀔 때마다 페이지를 하나씩 건드려야 한다. Layout.astro 한 곳에서 게이트 모달 마운트를 책임지게 만들면, 이후 운영 정책이 달라져도 레이아웃 파일 한 곳만 수정하면 된다. "변경이 일어날 가능성이 높은 부분은 한 곳에 모아라" — 꽤 오래된 원칙인데 레이아웃 설계에서 특히 잘 맞는다.


AdSlot 마커 패턴 — 핵심 설계 결정

이번 작업에서 가장 시간을 쓴 부분이 AdSlot 마커 패턴 도입이었다. 방식은 간단하다. HTML에 실제 광고 코드를 직접 박지 않고, 마커 역할을 하는 플레이스홀더를 먼저 심어두고, 빌드 후처리(build-ads.js) 단계에서 그 마커를 찾아 실제 광고 코드로 치환하는 구조.

<!-- 마커 패턴 예시 -->
<div data-ad-slot="gate-modal" data-ad-type="interstitial"></div>
// build-ads.js 후처리 개념 (단순화)
const markers = document.querySelectorAll('[data-ad-slot]');
markers.forEach(marker => {
  const slotId = marker.dataset.adSlot;
  const adFragment = resolveAdFragment(slotId);
  marker.replaceWith(adFragment);
});

이 패턴을 선택한 이유가 몇 가지 있었음.

  • 광고 코드 오염 방지: 광고 서드파티 스크립트를 Astro 컴포넌트 소스에 직접 넣으면 코드 리뷰할 때 노이즈가 심하다. 마커만 소스에 두고, 실제 광고 코드는 빌드 단계에서 주입하면 소스가 깔끔하게 유지됨.
  • 빌드 환경 분기 용이: 개발 환경에서는 마커 자체를 비워두거나 mock으로 대체하고, 프로덕션 빌드 때만 실제 광고를 주입하는 게 쉬워진다.
  • 광고 코드 교체 비용 최소화: 광고 플랫폼이나 슬롯 ID가 바뀔 때 컴포넌트 소스를 건드리지 않아도 된다. build-ads.js 설정만 갱신하면 끝.
접근 방식 소스 가독성 환경별 분기 광고 코드 교체 비용
컴포넌트 직접 삽입 낮음 조건부 렌더 필요 컴포넌트 수정 필요
AdSlot 마커 + 후처리 높음 후처리 분기로 처리 후처리 설정만 변경
SSR 서버 주입 중간 서버 로직 분기 서버 로직 수정 필요

팀 내에서도 처음에는 "후처리 단계를 하나 더 추가하는 게 맞냐"는 의견이 있었다. 빌드 파이프라인이 복잡해진다는 우려. 근데 이미 Astro 자체가 빌드 타임 처리를 적극 활용하는 프레임워크고, 광고 코드는 변경 빈도가 높은 외부 의존성이라는 점에서 후처리 분리가 더 낫다고 판단했다. 이런 트레이드오프를 팀과 공유하고 빠르게 합의를 끌어내는 게 총괄 입장에서 중요한 일이기도 하다.


Layout.astro 연동에서 주의했던 것

AdGateModal.astroLayout.astro에 연동할 때 한 가지 신경 쓴 부분이 있었다. 게이트 모달은 페이지 콘텐츠 위에 오버레이로 올라오는 구조라서, DOM 삽입 위치가 중요하다. body 최하단에 넣어야 z-index 이슈나 스크롤 잠금 처리가 자연스럽게 동작한다. head 근처나 콘텐츠 중간에 끼면 레이아웃이 밀리거나 스크린리더가 순서를 잘못 읽는 문제가 생길 수 있음.

접근성 측면에서도 게이트 모달은 꽤 예민한 컴포넌트다. 모달이 열렸을 때 포커스 트랩, 배경 스크롤 잠금, aria-modal 속성 — 이 세 가지를 빠뜨리면 키보드 사용자나 스크린리더 사용자 입장에서 사실상 쓸 수 없는 UI가 된다. 이번에 마커 패턴에 집중하다 보니 접근성 처리를 별도 태스크로 빼두기는 했는데, 나중에 짚고 넘어가야 할 부분이다.


회고

후처리 빌드 스텝을 추가할 때마다 항상 드는 생각인데, "이게 정말 필요한 복잡도인가"를 한 번 더 묻는 습관이 중요하다. 이번엔 타당한 이유가 있었고, 팀도 납득했다. 그냥 "빠르게 넣자"는 압박 아래 광고 코드를 컴포넌트에 직접 박았다가 나중에 교체 비용을 치르는 상황을 몇 번 봐왔기 때문에, 초기 설계에 조금 더 투자하는 쪽을 선택했음.

AdGateModal.astro 코드 리뷰를 팀원이랑 같이 했는데, 마커 패턴 자체가 생소한 접근이라 설명하는 데 시간을 좀 썼다. 이런 낯선 패턴을 도입할 때는 코드 자체보다 "왜 이 방식인가" 를 문서화하거나 코멘트로 남기는 게 더 가치 있다는 걸 다시 느꼈다. 다음번에 비슷한 패턴 작업 때는 ADR(Architecture Decision Record) 형태로 짧게라도 남겨두는 게 좋을 것 같다.

다음은 접근성 태스크 처리 차례.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.