MODULE
CTA strip
The small ask, with something beside it. A house ad: a bit of art, three lines at most, and exactly one control.
The strip
Art at the start, copy filling the middle, the control at the end. Drag the handle in and watch the row fold β there is no breakpoint in this.
<aside class="cta-strip" style="width:100%">
<div class="cta-strip-art">
<div class="frame" style="--ratio:3/4">
<img src="/scenery/sprig.webp" alt="One leaf in a glass, on white" loading="lazy" decoding="async" />
</div>
</div>
<div class="cta-strip-body">
<p class="cta-strip-kicker">THE LETTER</p>
<p class="cta-strip-title">One a month, and nothing else ever.</p>
<p class="cta-strip-note">What shipped, what broke, and the measurement that changed my mind. Leave from the first one if it is not for you.</p>
</div>
<div class="cta-strip-action">
<a href="#" class="btn btn-primary">SIGN ME UP</a>
</div>
</aside>Every part is optional
No art and no note. It is still a strip, and it still asks for one thing.
<!-- Every part is optional. No art, no note, and it is still a strip: a line
of copy and one control. -->
<aside class="cta-strip" style="width:100%">
<div class="cta-strip-body">
<p class="cta-strip-kicker">STILL READING</p>
<p class="cta-strip-title">The whole thing is on the shelf, free.</p>
</div>
<div class="cta-strip-action">
<a href="#" class="btn">READ THE SOURCE</a>
</div>
</aside>The art slot takes anything a picture goes in
A clip here, so the ask has something moving beside it. The strip does not know what a video is.
<!-- The art slot takes whatever a picture box is β here a `clip`, so the ask
has something moving beside it. The strip never mentions one.
The ground takes a ROLE, never a colour: dropped on a band that is already
raised, a strip asks for the sunk surface and reads as a panel again. -->
<aside class="cta-strip" style="width:100%; --cta-strip-surface:var(--ds-sunk); --cta-strip-art:170px">
<div class="cta-strip-art">
<div class="frame clip" style="--ratio:9/16" x-ds-clip
data-label-play="Play the clip" data-label-pause="Pause the clip">
<video muted loop playsinline preload="none" poster="/gallery/rico-18.avif" controls>
<source src="/gallery/rico-18.webm" type="video/webm" />
<source src="/gallery/rico-18.mp4" type="video/mp4" />
</video>
<button class="clip-toggle" type="button" hidden></button>
</div>
</div>
<div class="cta-strip-body">
<p class="cta-strip-kicker">HE HAS OPINIONS</p>
<p class="cta-strip-title">Somebody here works for biscuits.</p>
<p class="cta-strip-note">Ten years on the job, never a sick day, and he has yet to ask anyone what the deadline is.</p>
</div>
<div class="cta-strip-action">
<a href="#" class="btn btn-primary">PAY HIM IN BISCUITS</a>
</div>
</aside>Saying where the control goes
`cta-strip-fine` is the small print under the control β where it takes you, what it will ask for. A reader is owed that before they press, not after. It is not the second action the slot refuses; it is a caption on the first one.
<aside class="cta-strip" style="width:100%">
<div class="cta-strip-body">
<p class="cta-strip-kicker">THE TIN</p>
<p class="cta-strip-title">Free, and it stays free.</p>
<p class="cta-strip-note">If it saved you an afternoon, you could buy the afternoon back for the price of a coffee.</p>
</div>
<div class="cta-strip-action">
<a href="#" class="btn btn-primary">BUY US ONE</a>
<p class="cta-strip-fine">Opens the checkout in this tab, and asks for a card rather than an account.</p>
</div>
</aside>Reference
Read from modules/cta-strip.css when this page was built, so it cannot fall behind the stylesheet.
.cta-strip.cta-strip-art.cta-strip-body.cta-strip-action.cta-strip-fine.cta-strip-kicker.cta-strip-title.cta-strip-note--cta-strip-gap β falls back to --ds-gap-loose--cta-strip-pad β falls back to --ds-pad-card--cta-strip-surface β falls back to --ds-raised--cta-strip-art β falls back to --ds-cta-strip-art--cta-strip-copy β falls back to --ds-cta-strip-copy--cta-strip-fine β falls back to --ds-cta-strip-fine--cta-strip-title β falls back to --ds-cta-strip-title--cta-strip-measure β falls back to --ds-measure-wide--ds-accent--ds-font-body--ds-font-display--ds-gap--ds-hairline--ds-ink--ds-ink-faint--ds-ink-soft--ds-radius--ds-rule--ds-shadow-raised--ds-text-caption--ds-text-h3--ds-text-label--ds-text-small--ds-track-meta--ds-track-snug--ds-weight-displayNotes
CTA slab is the cream block that asks for the work: one per page, the single warm surface in the design, and its whole power is that nothing else looks like it. This is the one you may have several of.
So the question is not which looks better. Reach for the slab when the ask is the page. Reach for this when the ask sits beside the page β under an article, at the foot of a download, in a rail β quiet enough not to compete with what somebody came for, and loud enough to be taken on the way past.
Nothing stops you putting a second button in cta-strip-action, and the day you do, the strip has stopped asking for one thing. If there is a genuine alternative it goes in the note as a link, where it reads as the second choice it is.
There is deliberately no cta-strip-media. The art slot reserves a width and gets out of the way β a frame, a clip, a <picture>, a stencil over any of them. Writing a ratio and a crop in here would be a fourth spelling of a picture box, and a fourth drifts from all three the first week nobody looks.
Same for the control. It is a btn, a link, or somebody else's sponsor button pasted in whole β the strip only holds the space for it.
It ships --ds-raised, which is the held surface rather than "grey": on the page ground a strip reads as a panel in both themes. Dropped into a band that is already raised it disappears, and that is what --cta-strip-surface is for β hand it another role, as the third specimen does, never a colour written at the call site.
Three declarations, and between them they cover every width. The copy carries a flex-grow, so on a full row it eats every pixel of slack β art at the start, control at the end. The strip carries justify-content: center, which does nothing while the copy is doing that, because there is no free space left for it to distribute.
Narrow the box and the copy wraps to a line of its own. Now the art is alone with slack around it, and the same centring declaration finally has something to do. One property, two behaviours, and the engine decides which β rather than a query somewhere deciding it for both.
The first version instead gave the copy a huge grow ratio (flex: 999 1 β¦) so that the art would take a wrapped line for itself. It works. It also lets the art creep a fraction of a pixel wider on every full row, which is a rounding error nobody would ever find and nobody should have to.
So a theme that rounds its frames will round the art inside a square strip. Shipped square, as mount is and for the same reason: the fix when it bites is overflow: hidden here plus a radius, and that clips an outset focus ring β and there is a focusable control in here by definition. Stated rather than guessed at.