28 CSS Close Buttons06 / 28
IAB Mobile Ad Banner Close Button
The ad-tech compliance pattern: a visually small × on a mobile banner ad whose real tap target is inflated to 48×48px with pure padding — WCAG 2.5.8 and Google Better Ads guidance satisfied without visually crowding a 50px-tall creative. The demo overlays a translucent debug outline you can toggle in CSS to SEE the invisible target.
Published
The code
<section class="ccb-06" aria-label="Mobile ad banner close button demo">
<div class="ccb-06__slot">
<div class="ccb-06__ad">
<div class="ccb-06__creative">
<span class="ccb-06__brand">SUMMER SALE</span>
<span class="ccb-06__copy">Up to 60% off — today only</span>
</div>
<button class="ccb-06__close" type="button" aria-label="Close ad"><span class="ccb-06__dot" aria-hidden="true"></span></button>
</div>
<p class="ccb-06__note">Dashed ring = the real 48×48 tap target (set <code>--debug:0</code> to hide)</p>
</div>
</section><section class="ccb-06" aria-label="Mobile ad banner close button demo">
<div class="ccb-06__slot">
<div class="ccb-06__ad">
<div class="ccb-06__creative">
<span class="ccb-06__brand">SUMMER SALE</span>
<span class="ccb-06__copy">Up to 60% off — today only</span>
</div>
<button class="ccb-06__close" type="button" aria-label="Close ad"><span class="ccb-06__dot" aria-hidden="true"></span></button>
</div>
<p class="ccb-06__note">Dashed ring = the real 48×48 tap target (set <code>--debug:0</code> to hide)</p>
</div>
</section>.ccb-06,
.ccb-06 *,
.ccb-06 *::before,
.ccb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-06 {
--d: 20px;
--debug: 1;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: oklch(0.94 0.01 80);
}
.ccb-06 .ccb-06__slot {
width: min(360px,100%);
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
}
.ccb-06 .ccb-06__ad {
position: relative;
width: 100%;
height: 64px;
border-radius: 10px;
background: linear-gradient(100deg,oklch(0.62 0.19 40),oklch(0.55 0.21 20));
box-shadow: 0 14px 30px -16px oklch(0.45 0.15 30 / .6);
}
.ccb-06 .ccb-06__creative {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 3px;
padding: 0 16px;
color: #fff;
}
.ccb-06 .ccb-06__brand {
font: 800 15px/1 'Segoe UI',system-ui,sans-serif;
letter-spacing: .06em;
}
.ccb-06 .ccb-06__copy {
font-size: 11.5px;
opacity: .9;
}
.ccb-06 .ccb-06__close {
position: absolute;
top: 0;
inset-inline-end: 0;
margin: -14px -14px 0 0;
padding: 14px;
border: none;
background: transparent;
cursor: pointer;
outline: calc(var(--debug) * 1.5px) dashed oklch(0.55 0.15 30 / .65);
outline-offset: -2px;
border-radius: 14px;
}
.ccb-06 .ccb-06__dot {
position: relative;
display: block;
width: var(--d);
height: var(--d);
border-radius: 50%;
background: rgba(20,16,14,.72);
transition: transform .15s ease;
}
.ccb-06 .ccb-06__dot::before,
.ccb-06 .ccb-06__dot::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: calc(var(--d) * .5);
height: 1.5px;
border-radius: 2px;
background: #fff;
}
.ccb-06 .ccb-06__dot::before {
transform: translate(-50%,-50%) rotate(45deg);
}
.ccb-06 .ccb-06__dot::after {
transform: translate(-50%,-50%) rotate(-45deg);
}
.ccb-06 .ccb-06__close:hover .ccb-06__dot {
transform: scale(1.1);
}
.ccb-06 .ccb-06__close:active .ccb-06__dot {
transform: scale(.9);
}
.ccb-06 .ccb-06__close:focus-visible {
outline: 3px solid oklch(0.5 0.18 30);
outline-offset: 0;
}
.ccb-06 .ccb-06__note {
font-size: 11.5px;
color: oklch(0.5 0.03 60);
text-align: center;
}
.ccb-06 .ccb-06__note code {
font-family: ui-monospace,Menlo,monospace;
font-size: 10.5px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-06 .ccb-06__dot {
transition: none;
}
}.ccb-06,
.ccb-06 *,
.ccb-06 *::before,
.ccb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-06 {
--d: 20px;
--debug: 1;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: oklch(0.94 0.01 80);
}
.ccb-06 .ccb-06__slot {
width: min(360px,100%);
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
}
.ccb-06 .ccb-06__ad {
position: relative;
width: 100%;
height: 64px;
border-radius: 10px;
background: linear-gradient(100deg,oklch(0.62 0.19 40),oklch(0.55 0.21 20));
box-shadow: 0 14px 30px -16px oklch(0.45 0.15 30 / .6);
}
.ccb-06 .ccb-06__creative {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 3px;
padding: 0 16px;
color: #fff;
}
.ccb-06 .ccb-06__brand {
font: 800 15px/1 'Segoe UI',system-ui,sans-serif;
letter-spacing: .06em;
}
.ccb-06 .ccb-06__copy {
font-size: 11.5px;
opacity: .9;
}
.ccb-06 .ccb-06__close {
position: absolute;
top: 0;
inset-inline-end: 0;
margin: -14px -14px 0 0;
padding: 14px;
border: none;
background: transparent;
cursor: pointer;
outline: calc(var(--debug) * 1.5px) dashed oklch(0.55 0.15 30 / .65);
outline-offset: -2px;
border-radius: 14px;
}
.ccb-06 .ccb-06__dot {
position: relative;
display: block;
width: var(--d);
height: var(--d);
border-radius: 50%;
background: rgba(20,16,14,.72);
transition: transform .15s ease;
}
.ccb-06 .ccb-06__dot::before,
.ccb-06 .ccb-06__dot::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: calc(var(--d) * .5);
height: 1.5px;
border-radius: 2px;
background: #fff;
}
.ccb-06 .ccb-06__dot::before {
transform: translate(-50%,-50%) rotate(45deg);
}
.ccb-06 .ccb-06__dot::after {
transform: translate(-50%,-50%) rotate(-45deg);
}
.ccb-06 .ccb-06__close:hover .ccb-06__dot {
transform: scale(1.1);
}
.ccb-06 .ccb-06__close:active .ccb-06__dot {
transform: scale(.9);
}
.ccb-06 .ccb-06__close:focus-visible {
outline: 3px solid oklch(0.5 0.18 30);
outline-offset: 0;
}
.ccb-06 .ccb-06__note {
font-size: 11.5px;
color: oklch(0.5 0.03 60);
text-align: center;
}
.ccb-06 .ccb-06__note code {
font-family: ui-monospace,Menlo,monospace;
font-size: 10.5px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-06 .ccb-06__dot {
transition: none;
}
}/* No JavaScript — padding inflates a 20px visual to a 48×48 tap target; the dashed outline visualises it (--debug:0 hides). */
/* No JavaScript — padding inflates a 20px visual to a 48×48 tap target; the dashed outline visualises it (--debug:0 hides). */Here's a working CSS Close Button from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: IAB Mobile Ad Banner Close Button
Source: https://codefronts.com/components/css-close-buttons/iab-mobile-ad-banner-close-button/
The ad-tech compliance pattern: a visually small × on a mobile banner ad whose real tap target is inflated to 48×48px with pure padding — WCAG 2.5.8 and Google Better Ads guidance satisfied without visually crowding a 50px-tall creative. The demo overlays a translucent debug outline you can toggle in CSS to SEE the invisible target.
## HTML
```html
<section class="ccb-06" aria-label="Mobile ad banner close button demo">
<div class="ccb-06__slot">
<div class="ccb-06__ad">
<div class="ccb-06__creative">
<span class="ccb-06__brand">SUMMER SALE</span>
<span class="ccb-06__copy">Up to 60% off — today only</span>
</div>
<button class="ccb-06__close" type="button" aria-label="Close ad"><span class="ccb-06__dot" aria-hidden="true"></span></button>
</div>
<p class="ccb-06__note">Dashed ring = the real 48×48 tap target (set <code>--debug:0</code> to hide)</p>
</div>
</section>
```
## CSS
```css
.ccb-06,
.ccb-06 *,
.ccb-06 *::before,
.ccb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-06 {
--d: 20px;
--debug: 1;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: oklch(0.94 0.01 80);
}
.ccb-06 .ccb-06__slot {
width: min(360px,100%);
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
}
.ccb-06 .ccb-06__ad {
position: relative;
width: 100%;
height: 64px;
border-radius: 10px;
background: linear-gradient(100deg,oklch(0.62 0.19 40),oklch(0.55 0.21 20));
box-shadow: 0 14px 30px -16px oklch(0.45 0.15 30 / .6);
}
.ccb-06 .ccb-06__creative {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 3px;
padding: 0 16px;
color: #fff;
}
.ccb-06 .ccb-06__brand {
font: 800 15px/1 'Segoe UI',system-ui,sans-serif;
letter-spacing: .06em;
}
.ccb-06 .ccb-06__copy {
font-size: 11.5px;
opacity: .9;
}
.ccb-06 .ccb-06__close {
position: absolute;
top: 0;
inset-inline-end: 0;
margin: -14px -14px 0 0;
padding: 14px;
border: none;
background: transparent;
cursor: pointer;
outline: calc(var(--debug) * 1.5px) dashed oklch(0.55 0.15 30 / .65);
outline-offset: -2px;
border-radius: 14px;
}
.ccb-06 .ccb-06__dot {
position: relative;
display: block;
width: var(--d);
height: var(--d);
border-radius: 50%;
background: rgba(20,16,14,.72);
transition: transform .15s ease;
}
.ccb-06 .ccb-06__dot::before,
.ccb-06 .ccb-06__dot::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: calc(var(--d) * .5);
height: 1.5px;
border-radius: 2px;
background: #fff;
}
.ccb-06 .ccb-06__dot::before {
transform: translate(-50%,-50%) rotate(45deg);
}
.ccb-06 .ccb-06__dot::after {
transform: translate(-50%,-50%) rotate(-45deg);
}
.ccb-06 .ccb-06__close:hover .ccb-06__dot {
transform: scale(1.1);
}
.ccb-06 .ccb-06__close:active .ccb-06__dot {
transform: scale(.9);
}
.ccb-06 .ccb-06__close:focus-visible {
outline: 3px solid oklch(0.5 0.18 30);
outline-offset: 0;
}
.ccb-06 .ccb-06__note {
font-size: 11.5px;
color: oklch(0.5 0.03 60);
text-align: center;
}
.ccb-06 .ccb-06__note code {
font-family: ui-monospace,Menlo,monospace;
font-size: 10.5px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-06 .ccb-06__dot {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — padding inflates a 20px visual to a 48×48 tap target; the dashed outline visualises it (--debug:0 hides). */
```Here's a working CSS Close Button from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: IAB Mobile Ad Banner Close Button
Source: https://codefronts.com/components/css-close-buttons/iab-mobile-ad-banner-close-button/
The ad-tech compliance pattern: a visually small × on a mobile banner ad whose real tap target is inflated to 48×48px with pure padding — WCAG 2.5.8 and Google Better Ads guidance satisfied without visually crowding a 50px-tall creative. The demo overlays a translucent debug outline you can toggle in CSS to SEE the invisible target.
## HTML
```html
<section class="ccb-06" aria-label="Mobile ad banner close button demo">
<div class="ccb-06__slot">
<div class="ccb-06__ad">
<div class="ccb-06__creative">
<span class="ccb-06__brand">SUMMER SALE</span>
<span class="ccb-06__copy">Up to 60% off — today only</span>
</div>
<button class="ccb-06__close" type="button" aria-label="Close ad"><span class="ccb-06__dot" aria-hidden="true"></span></button>
</div>
<p class="ccb-06__note">Dashed ring = the real 48×48 tap target (set <code>--debug:0</code> to hide)</p>
</div>
</section>
```
## CSS
```css
.ccb-06,
.ccb-06 *,
.ccb-06 *::before,
.ccb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-06 {
--d: 20px;
--debug: 1;
font-family: 'Segoe UI',system-ui,sans-serif;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: oklch(0.94 0.01 80);
}
.ccb-06 .ccb-06__slot {
width: min(360px,100%);
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
}
.ccb-06 .ccb-06__ad {
position: relative;
width: 100%;
height: 64px;
border-radius: 10px;
background: linear-gradient(100deg,oklch(0.62 0.19 40),oklch(0.55 0.21 20));
box-shadow: 0 14px 30px -16px oklch(0.45 0.15 30 / .6);
}
.ccb-06 .ccb-06__creative {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 3px;
padding: 0 16px;
color: #fff;
}
.ccb-06 .ccb-06__brand {
font: 800 15px/1 'Segoe UI',system-ui,sans-serif;
letter-spacing: .06em;
}
.ccb-06 .ccb-06__copy {
font-size: 11.5px;
opacity: .9;
}
.ccb-06 .ccb-06__close {
position: absolute;
top: 0;
inset-inline-end: 0;
margin: -14px -14px 0 0;
padding: 14px;
border: none;
background: transparent;
cursor: pointer;
outline: calc(var(--debug) * 1.5px) dashed oklch(0.55 0.15 30 / .65);
outline-offset: -2px;
border-radius: 14px;
}
.ccb-06 .ccb-06__dot {
position: relative;
display: block;
width: var(--d);
height: var(--d);
border-radius: 50%;
background: rgba(20,16,14,.72);
transition: transform .15s ease;
}
.ccb-06 .ccb-06__dot::before,
.ccb-06 .ccb-06__dot::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: calc(var(--d) * .5);
height: 1.5px;
border-radius: 2px;
background: #fff;
}
.ccb-06 .ccb-06__dot::before {
transform: translate(-50%,-50%) rotate(45deg);
}
.ccb-06 .ccb-06__dot::after {
transform: translate(-50%,-50%) rotate(-45deg);
}
.ccb-06 .ccb-06__close:hover .ccb-06__dot {
transform: scale(1.1);
}
.ccb-06 .ccb-06__close:active .ccb-06__dot {
transform: scale(.9);
}
.ccb-06 .ccb-06__close:focus-visible {
outline: 3px solid oklch(0.5 0.18 30);
outline-offset: 0;
}
.ccb-06 .ccb-06__note {
font-size: 11.5px;
color: oklch(0.5 0.03 60);
text-align: center;
}
.ccb-06 .ccb-06__note code {
font-family: ui-monospace,Menlo,monospace;
font-size: 10.5px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-06 .ccb-06__dot {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — padding inflates a 20px visual to a 48×48 tap target; the dashed outline visualises it (--debug:0 hides). */
```How this works
The button's visual is a 20px circle with a 10px ×, but its true box is padding:14px around it — 48×48px of tappable area bleeding beyond the banner's corner via negative margin. Padding (not margin) is the trick: padding is inside the border box, so every pixel of it receives the tap.
The demo ships a --debug:1 custom property that paints the real hit area as a dashed overlay — flip it to 0 for production. This visualisation habit catches the classic ad-close failure: a 16px target that makes users fat-finger into the ad (which is precisely the dark pattern IAB's LEAN standards and Google's Better Ads rules penalise).
Make it yours
- Flip
--debugto 0 to hide the hit-area visualisation. - Scale the visible glyph via
--dwithout ever touching the 48px target. - Move the button fully inside the creative (drop the negative margins) for interstitial formats.
- Add a 1px white outline around the circle when creatives run on unpredictable imagery.
Gotchas — read before shipping
- Never shrink the tap target to match the visual — mis-taps that open the ad are a policy violation, not a conversion.
- Negative margins pull the button over adjacent page content; make sure nothing interactive sits under the overhang.
- Keep contrast ≥3:1 between the × and the circle fill across every creative the slot can serve.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 113+ | 111+ |
Nothing exotic — the entire pattern is padding, border-radius and one outline.