AdSlot
An advertisement's place kept at its size so the story never jumps: standard sizes by name, another on phones, a clear label, a placeholder, sticky in a rail.
Demo
The story runs here, in the wider column. The rectangle beside it is sticky: beside a story taller than itself, it stays in view as the page scrolls.
An empty slot without a placeholder above still keeps its 320 by 100 pixels, and has no label.
Get it
It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.
$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/ad_slot.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/ad_slot.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/ad_slot.qwe
// The paper's own ad for the demo, drawn here: no network, no one else's brand.let ad_slot_demo_house = "data:image/svg+xml," + url_encode(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 250"><rect width="300" height="250" fill="#14213d"/><circle cx="250" cy="40" r="70" fill="#fca311" opacity=".9"/><text x="24" y="120" fill="#fff" font-family="Georgia, serif" font-size="30" font-weight="700">The Ledger</text><text x="24" y="152" fill="#e5e5e5" font-family="Arial, sans-serif" font-size="15">Every story, every morning.</text><rect x="24" y="182" width="150" height="38" rx="19" fill="#fca311"/><text x="99" y="206" fill="#14213d" font-family="Arial, sans-serif" font-size="15" font-weight="700" text-anchor="middle">$1 a week</text></svg>`)view AdSlotDemo() = <div.demo-stack style="gap: 28px"> <AdSlot id="ad-slot-demo-top" size="leaderboard" mobile="mobile_banner" slot="home-top"/> <div style="display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 24px; align-items: start"> <div style="display: grid; gap: 12px"> <p class="demo-note" style="font-size: 15px">The story runs here, in the wider column. The rectangle beside it is sticky: beside a story taller than itself, it stays in view as the page scrolls.</p> <AdSlot id="ad-slot-demo-blank" size="mobile_large" placeholder={false} label="" align="start" slot="in-article-2"/> <p class="demo-note">An empty slot without a placeholder above still keeps its 320 by 100 pixels, and has no label.</p> </div> <AdSlot id="ad-slot-demo-rail" size="rectangle" sticky={true} slot="article-rail"> <a href="#subscribe"><img src={ad_slot_demo_house} alt="The Ledger: every story, every morning. $1 a week." width="300" height="250"/></a> </AdSlot> </div> </div>Source
ui/ad_slot.qwe
// AdSlot: a place for an advertisement in a news page, kept at its size before the// ad comes, so the story does not jump when it does: the standard sizes by name// (a 728 by 90 leaderboard, a 300 by 250 rectangle, ...), another size where the// screen is narrow, "Advertisement" over it so readers can tell it from the news,// and a quiet placeholder while it is empty. It can stay in view in a side column.//// <AdSlot size="leaderboard" mobile="mobile_banner" slot="home-top"/>// <AdSlot size="rectangle" sticky={true} slot="article-rail"><iframe src="..." title="Advertisement"></iframe></AdSlot>//// size: "leaderboard" (728×90, default), "billboard" (970×250), "rectangle"// (300×250), "halfpage" (300×600), "skyscraper" (160×600), "mobile_banner"// (320×50) or "mobile_large" (320×100); width and height (pixels) give another.// mobile: the size to use under 760px wide (a name as above), when the first is too// wide there. slot: the ad server's name for the place, put in data-slot (and the// element's id is `id`). The ad itself is its children (an <iframe>, an <ins>, an// <img> in a link); without it, the slot shows a faint placeholder with its size,// or nothing if placeholder={false}, keeping the space either way. label: the word// over it ("Advertisement"; "" for none, screen readers still hear it). sticky: it// stays in view as the page scrolls, in a column taller than itself (top: 16px).// align: "center" (default) or "start".import ui/theme.qwe use ui_clslet ad_slot_css = css`.ui-adslot { display: grid; justify-items: center; gap: 4px; min-width: 0; margin: 0; color: var(--ui-muted); font: 11px/1.3 var(--ui-font); }.ui-adslot-start { justify-items: start; }.ui-adslot-sticky { position: sticky; top: 16px; align-self: start; }.ui-adslot-label { letter-spacing: .1em; text-transform: uppercase; }.ui-adslot-box { position: relative; display: grid; place-items: center; width: min(var(--w), 100%); height: var(--h); overflow: hidden; background: var(--ui-subtle); }.ui-adslot-box > :is(iframe, img, ins, a, div) { display: block; width: 100%; height: 100%; border: 0; }.ui-adslot-box > a > img { display: block; width: 100%; height: 100%; object-fit: cover; }.ui-adslot-empty { border: 1px dashed var(--ui-border); background: repeating-linear-gradient(-45deg, transparent 0 8px, color-mix(in srgb, var(--ui-border) 45%, transparent) 8px 9px), var(--ui-subtle); }.ui-adslot-blank { border: 0; background: transparent; }.ui-adslot-size { padding: 2px 8px; border-radius: 999px; background: var(--ui-surface); color: var(--ui-muted); font-size: 12px; font-variant-numeric: tabular-nums; }@media (max-width: 760px) { .ui-adslot-mobile .ui-adslot-box { width: min(var(--mw), 100%); height: var(--mh); } .ui-adslot-mobile .ui-adslot-wide { display: none; }}@media (min-width: 761px) { .ui-adslot-narrow { display: none; } }`// A size's width and height: "rectangle" is [300, 250].fn ad_slot_size(name: str?) -> list = match name { "billboard" => [970, 250] "rectangle" => [300, 250] "halfpage" => [300, 600] "skyscraper" => [160, 600] "mobile_banner" => [320, 50] "mobile_large" => [320, 100] _ => [728, 90]}view AdSlot(size: str = "leaderboard", width: int? = null, height: int? = null, mobile: str? = null, slot: str? = null, label: str = "Advertisement", placeholder: bool = true, sticky: bool = false, align: str = "center", id: str? = null, class: str? = null, children = null) { style global ad_slot_css let named = ad_slot_size(size) let w = width ?? named[0] let h = height ?? named[1] let m = mobile != null ? ad_slot_size(mobile) : null // No children is null on some Quillo versions and empty HTML on others: both are empty. let empty = children == null || str(children) == "" <aside class={ui_cls(["ui-adslot", m != null && "ui-adslot-mobile", sticky && "ui-adslot-sticky", align == "start" && "ui-adslot-start", class])} id={id} aria-label={label != "" ? label : "Advertisement"} data-slot={slot} data-size={`${w}x${h}`} style={`--w: ${w}px; --h: ${h}px${m != null ? `; --mw: ${m[0]}px; --mh: ${m[1]}px` : ""}`}> {label != "" && <span.ui-adslot-label aria-hidden="true">{label}</span>} <div class={ui_cls(["ui-adslot-box", empty && (placeholder ? "ui-adslot-empty" : "ui-adslot-blank")])}> {empty ? placeholder && [ <span class="ui-adslot-size ui-adslot-wide" aria-hidden="true">{w} × {h}</span>, m != null && <span class="ui-adslot-size ui-adslot-narrow" aria-hidden="true">{m[0]} × {m[1]}</span>, ] : children} </div> </aside>}Related
SectionFrontA section's front: the lead story large with its picture and dek, the next stories beside it, and a column of more headlines; one column where narrow.9 views · 9 downloadsAspectRatioKeeps what it holds at a shape (16/9, 4/3, 1): an image or a video fills a box of the right height.9 views · 7 downloadsBrowserFrameA mock browser window around its content, with the address in its bar, for screenshots and demos.7 views · 6 downloadsEmbedFrameAnother page in a frame that keeps its shape and fills its width, with a title, permissions and a sandbox.5 views · 4 downloadsMediaCardA card with a picture (or any media) on top or at the side, then a meta line, title, text and actions.6 views · 6 downloadsTickerA news ticker: a labelled strip of headlines sliding past, each a link when it has one, in CSS alone.6 views · 9 downloads
Thread
Thread 0 posts
On AdSlot: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.