<section class="section container basicSection">
<header class="section__header">
<h2 class="h6 accent-primary">Heading Placeholder</h2>
<h3>
Ipsum nihil earum blanditiis dolore mollitia Adipisci voluptate.
</h3>
<p>
Elit numquam corrupti magni sapiente non? Tenetur corporis ipsa voluptatibus vitae numquam Exercitationem distinctio vero nesciunt fuga molestiae Repellat dignissimos cumque est quisquam veniam Repellat nobis earum quo distinctio repellendus!
</p>
</header>
<div class="basicSection__content">
<div class="basicSection__media media accent-primary" style="--aspect-ratio: 634 / 368">
<p-lazy>
<video class="media__content" inert controls autoplay playsinline>
<source data-src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<template #placeholder="{ load, modifier }">
<picture class="media__mask" :class="modifier">
<img class="media__maskImg" srcset="https://unsplash.it/634/368?random&gravity=center" alt="">
</picture>
<button class="media__trigger" @click="load" :class="modifier">
<svg class="media__icon icon" viewBox="0 0 96 96"><use href="/main-icons-sprite.svg#play" /></svg>
</button>
</template>
</p-lazy>
</div>
</div>
<footer class="section__footer">
<p>
Amet omnis eos omnis error beatae deleniti. Veritatis tempore vero!
</p>
<div class="actions">
<a class="button" href="#">Learn More</a>
</div>
</footer>
</section>
<section class="section container basicSection accent-primary">
<header class="section__header">
<h2 class="h6">Heading Placeholder</h2>
<h3>
Ipsum nihil earum blanditiis dolore mollitia Adipisci voluptate.
</h3>
</header>
<div class="basicSection__content">
<div class="basicSection__image">
<div class="placeholder" style="aspect-ratio: 634 / 368"></div>
</div>
</div>
</div>
</section>
<section class="section container basicSection accent-secondary">
<div class="basicSection__content">
<div class="basicSection__text">
<h2 class="h6">Heading Placeholder</h2>
<h3>Adipisicing tempora culpa a unde molestiae. Tenetur ducimus facilis.</h3>
<p>Mauris euismod sit amet dolor vel vehicula. Nulla lacinia augue sem, accumsan luctus nunc facilisis Duis ex libero, auctor a semper in, condimentum sit amet enim. Vestibulum et consectetur arcu. <a href="#">Nam nunc justo,</a> varius id metus eu praesent dictum sit amet quam efficitur placerat. </p>
</div>
</div>
</section>
@use "@imarc/pronto/resources/styles/imported" as *;
.basicSection {
$b: &;
@include at(md) {
--columns: 2;
}
&__content {
display: grid;
grid: auto / subgrid;
gap: 1rem var(--root-gap);
&.-center {
align-items: center;
}
> :first-child:last-child {
grid-column: 1 / -1;
}
}
// Natural content order for mobile
&__image {
order: 1;
}
&__testimonial {
order: 2;
}
&__media {
order: 3;
}
&__text {
order: 4;
}
&__cta {
order: 5;
}
&__text,
&__image,
&__media,
&__cta,
&__testimonial {
@include at(md) {
order: unset;
grid-column: span var(--span, 1);
}
}
&.-wide {
@include at(md) {
--columns: 3;
:is(#{$b}__text, #{$b}__image, #{$b}__media, #{$b}__cta, #{$b}__testimonial) {
&.-wide {
grid-column: span var(--span, 2);
}
}
}
}
}
<script setup>
import { computed, ref, nextTick, useTemplateRef } from 'vue'
/**
* PLazy is a vue component that lazy loads its content after it's been clicked.
*
* @slot default - the content to lazyload. It will remove inert attributes, change data-src
* attributes to src attributes, and call .load() on videos.
* @slot placeholder - the content to display before it's lazyloaded. The following properties
* are exposed to this slot:
* load {function} - function to call to load the content.
* loaded {boolean} - whether the content is loaded or not.
* modifier {string} - either '-loaded' or '' based on loaded.
*/
const loaded = ref(false)
const content = useTemplateRef('content')
const modifier = computed(() => loaded.value ? '-loaded' : '')
const load = async () => {
if (loaded.value) return
await nextTick()
const promises = []
/* Change data-src attributes to src attributes */
content.value.querySelectorAll('[data-src]')
.forEach(element => element.setAttribute('src', element.dataset.src))
/* remove inert attribute */
content.value.querySelectorAll('[inert]')
.forEach(element => element.inert = false)
/* load videos */
content.value.querySelectorAll('video')
.forEach(element => {
element.load()
promises.push(new Promise(resolve => {
element.addEventListener('loadeddata', resolve, { once: true })
}))
})
/* load iframes */
content.value.querySelectorAll('iframe')
.forEach(element => {
promises.push(new Promise(resolve => {
element.addEventListener('load', resolve, { once: true })
}))
})
/* wait for all videos and iframes to load, then update loaded.value */
Promise.all(promises).then(() => loaded.value = true)
}
</script>
<template>
<div ref="content">
<slot name="default"></slot>
</div>
<slot name="placeholder" v-bind="{ load, loaded, modifier }"></slot>
</template>
<style scoped>
div {
container-type: size;
}
</style>