Utilities

LazyLoad

Puts its content on the page only once it is scrolled near, holding its height until then.

#utility#loading#media#page#interactive

Demo

Preview

Paragraph 1. Keep scrolling: the pictures below are not on the page yet.

Paragraph 2. Keep scrolling: the pictures below are not on the page yet.

Paragraph 3. Keep scrolling: the pictures below are not on the page yet.

Paragraph 4. Keep scrolling: the pictures below are not on the page yet.

Paragraph 5. Keep scrolling: the pictures below are not on the page yet.

Paragraph 6. Keep scrolling: the pictures below are not on the page yet.

Paragraph 7. Keep scrolling: the pictures below are not on the page yet.

Paragraph 8. Keep scrolling: the pictures below are not on the page yet.

The end.

Not loaded yet: scroll the box.

Loading…

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/lazy_load.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/lazy_load.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/lazy_load.qwe
component LazyLoadDemoLive() {    state shown = 0    <div.demo-stack>        <div id="lazy-load-demo-box" tabindex="0" aria-label="A long page"             style="height: 240px; overflow: auto; border: 1px solid var(--ui-border); border-radius: var(--ui-radius); padding: 0 16px">            {for i in range(1, 9) => <p key={i}>Paragraph {i}. Keep scrolling: the pictures below are not on the page yet.</p>}            <LazyLoad scroller="lazy-load-demo-box" margin="40px" height="120px" on_show={() => { shown += 1 }}>                <div id="lazy-load-demo-content" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px">                    {for i in range(3) => <div key={i} style="height: 120px; border-radius: var(--ui-radius); background: var(--ui-accent-soft); display: grid; place-items: center">Picture {i + 1}</div>}                </div>            </LazyLoad>            <p>The end.</p>        </div>        <p.demo-note>{shown == 0 ? "Not loaded yet: scroll the box." : "Loaded once it came near."}</p>    </div>}view LazyLoadDemo() =    <div.demo-stack>        <LazyLoadDemoLive/>        <LazyLoad height="100px" placeholder="Loading…">            <div style="padding: 14px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius)">This block, placed in the page, was made when the gallery scrolled near it.</div>        </LazyLoad>    </div>

Source

ui/lazy_load.qwe
// LazyLoad: puts its content on the page only once it is scrolled near, for a// heavy part low on a page: a map, a chart, an embedded video, a grid of// pictures. Until then it is a placeholder of the height you give, so the page// does not jump. The content comes from the server as data and is made in the// browser when its time comes; what it holds (images, iframes) loads then.////   <LazyLoad height="320px"><iframe src="https://www.youtube.com/embed/..." ...></iframe></LazyLoad>//   <LazyLoad height="200px" margin="0px" placeholder="Loading the picture…"><img src="/big.jpg" alt="..."/></LazyLoad>//// children: the content. height: the placeholder's height, a CSS length// ("200px"). margin: how far ahead it loads, a CSS length ("300px"); "0px" is// only when in view. placeholder: text shown in the grey box until then// (inside one of your components, markup too: a Skeleton). scroller: the id of the scrolling box it is in, when not the// window. label: what the placeholder is called for screen readers// ("Content loading"). on_show(): inside one of your components, called with// nothing when the content is put on the page.import ui/theme.qwe use ui_clslet lazy_load_css = css`.ui-lazy { display: block; min-width: 0; }.ui-lazy-wait { display: grid; place-items: center; min-height: var(--h, 200px); border-radius: var(--ui-radius); background: var(--ui-subtle);  color: var(--ui-muted); font: 13px/1.4 var(--ui-font); }.ui-lazy-shown { animation: ui-lazy-in .25s ease-out; }@keyframes ui-lazy-in { from { opacity: 0; } }@media (prefers-reduced-motion: reduce) { .ui-lazy-shown { animation: none; } }`component LazyLoad(height: str = "200px", margin: str = "300px", placeholder = null, scroller: str? = null,                   label: str = "Content loading", on_show = null, class: str? = null, children) {    style global lazy_load_css    state seen = false    <div class={ui_cls(["ui-lazy", seen && "ui-lazy-shown", class])}         @mount={(el) => {             let root = scroller != null ? js("document.getElementById", scroller) : null             let w = js_new("IntersectionObserver", (entries, obs) => {                 if !seen && any(entries, (en) => en.isIntersecting) {                     seen = true                     obs.disconnect()                     on_show && on_show()                 }             }, { root, rootMargin: margin })             w.observe(el)             () => w.disconnect()         }}>        {seen            ? children            : <div.ui-lazy-wait style={`--h: ${height}`} role="status" aria-label={label}>{placeholder}</div>}    </div>}
Thread
67Useful? Like it, or add to its thread below.

Thread 0 posts

On LazyLoad: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.