Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <article>
	<h1>Figure Glow and Lightbox </h1>

	<figure class="left">
		<img src="https://images.unsplash.com/photo-1498081959737-f3ba1af08103" alt="Palm trees against a colourful sky." />
		<figcaption>Palm Trees</figcaption>
	</figure>

	<p>Lorem ipsum odor amet, consectetuer adipiscing elit. Dui fames viverra ultrices nulla augue, suscipit mollis ligula. Leo egestas interdum dapibus egestas est neque ligula dictum. Lectus dictum parturient eget proin mauris ornare scelerisque dui pretium. Mollis neque ex mus non lobortis mauris ad. Facilisi et viverra ullamcorper nullam ex. Sodales sociosqu eu rutrum erat ipsum, volutpat porttitor mattis. Senectus lectus dis diam fringilla, class dapibus mollis.</p>

	<p>Nostra maximus volutpat, etiam placerat varius eros. Rutrum tempor blandit placerat pretium netus sit nullam sollicitudin. Quam pulvinar orci finibus vel sapien sapien tempus. Orci at maecenas parturient facilisi senectus enim rhoncus. Porttitor neque nam mus dui taciti turpis platea. Lacinia nibh ornare odio vestibulum ex curabitur. Fames fusce vitae sed aenean quisque. Platea ut quam volutpat pulvinar sem. Molestie neque euismod netus arcu purus natoque?</p>

	<p>Quis augue tempus quisque ultricies; in lectus metus. Rhoncus vitae nunc habitant habitant; egestas porta scelerisque. Vivamus cursus interdum in sem turpis tincidunt laoreet varius. Tristique velit est ipsum ac in. Sagittis ornare imperdiet suspendisse porta platea tristique per. Accumsan integer sociosqu semper leo natoque dictum laoreet. Mi mus vestibulum donec etiam leo feugiat parturient.</p>

	<figure class="right">
		<img src="https://images.unsplash.com/photo-1496033604106-04799291ee86" alt="A basketball court with a aparments in the background." />
		<figcaption>A Basketball Court</figcaption>
	</figure>

	<p>Lorem ipsum odor amet, consectetuer adipiscing elit. Dui fames viverra ultrices nulla augue, suscipit mollis ligula. Leo egestas interdum dapibus egestas est neque ligula dictum. Lectus dictum parturient eget proin mauris ornare scelerisque dui pretium. Mollis neque ex mus non lobortis mauris ad. Facilisi et viverra ullamcorper nullam ex. Sodales sociosqu eu rutrum erat ipsum, volutpat porttitor mattis. Senectus lectus dis diam fringilla, class dapibus mollis.</p>

	<p>Nostra maximus volutpat, etiam placerat varius eros. Rutrum tempor blandit placerat pretium netus sit nullam sollicitudin. Quam pulvinar orci finibus vel sapien sapien tempus. Orci at maecenas parturient facilisi senectus enim rhoncus. Porttitor neque nam mus dui taciti turpis platea. Lacinia nibh ornare odio vestibulum ex curabitur. Fames fusce vitae sed aenean quisque. Platea ut quam volutpat pulvinar sem. Molestie neque euismod netus arcu purus natoque?</p>

	<p>Quis augue tempus quisque ultricies; in lectus metus. Rhoncus vitae nunc habitant habitant; egestas porta scelerisque. Vivamus cursus interdum in sem turpis tincidunt laoreet varius. Tristique velit est ipsum ac in. Sagittis ornare imperdiet suspendisse porta platea tristique per. Accumsan integer sociosqu semper leo natoque dictum laoreet. Mi mus vestibulum donec etiam leo feugiat parturient.</p>

	<figure>
		<img src="https://images.unsplash.com/photo-1533015876763-16ee187b8dd0" alt="Colourful apparments in a row." />
		<figcaption>Appartments</figcaption>
	</figure>

	<p>Bibendum scelerisque donec consequat maximus dapibus vitae, felis nisl luctus. Curabitur ex curae ligula mattis facilisis ut dolor pretium placerat. Efficitur leo imperdiet mauris mattis convallis, massa pulvinar duis? Aenean imperdiet hac condimentum rhoncus aliquet felis tempus curae. Justo egestas natoque at donec ante enim; eget curabitur. Diam cursus aliquet sapien convallis pretium taciti. Fusce sed potenti efficitur phasellus natoque per. Phasellus pretium semper aliquam ante enim sapien a viverra conubia.</p>

	<p>Efficitur tellus facilisis nascetur, bibendum nunc sit. Finibus adipiscing vestibulum proin dis nascetur dui enim faucibus. Ut volutpat integer, suscipit netus orci fringilla commodo feugiat. Sociosqu gravida posuere egestas praesent fames egestas. Torquent lobortis maecenas, neque id bibendum faucibus quisque. Dis phasellus tristique dignissim himenaeos accumsan tortor venenatis. Porta tellus aliquet euismod sollicitudin posuere torquent. Iaculis enim semper penatibus et facilisis auctor eget accumsan dui.</p>

</article>
              
            
!

CSS

              
                :root {
	color-scheme: light dark;

	--black: oklch(18% 0.003 17.5);

	--dark_grey: oklch(24% 0.006 17.6);
	--grey: oklch(36% 0.003 17.3);
	--bright_grey: oklch(47% 0.005 17.3);

	--white: oklch(76% 0.03 55);
	--bright_white: oklch(94.75% 0.04 73);

	--blue: oklch(56.5% 0.13 253);
	--cyan: oklch(71.2% 0.112 198.7);
	--magenta: oklch(61.2% 0.21 5.4);
}

body {
	margin: 3rem;
	font-family: "EB Garamond", serif;
	color: light-dark(var(--black), var(--bright_white));
	background: light-dark(var(--bright_white), var(--black));

	@media (max-width: 700px) {
		margin: 0 0.8rem;
	}
}

article {
	max-width: 80ch;

	* + h2,
	* + h3 {
		margin-top: 2rem;
	}

	> * + * {
		margin-top: 1rem;
	}
}

h1 {
	text-transform: uppercase;
	text-wrap: balance;
	font-weight: 700;
	font-size: 2.5rem;
	line-height: 2.8rem;
}

a {
	color: inherit;
	text-decoration: underline 0.1rem light-dark(var(--cyan), var(--blue));
	-webkit-text-decoration-line: underline;
	-webkit-text-decoration-color: light-dark(var(--cyan), var(--blue));
	text-decoration-skip-ink: none;
	text-underline-offset: 0.2rem;

	&:hover,
	&:active {
		text-decoration-thickness: 0.7rem;
		text-underline-offset: -0.37rem;
	}
}

figure {
	width: 100%;
	margin: 0;
	position: relative;

	img {
		width: 100%;
	}

	figcaption {
		font-size: small;
		font-style: italic;
		text-align: center;
		color: light-dark(var(--grey), var(--white));
	}
}

.left {
	float: left;
	width: 65%;
	margin: 0 1rem 0 -2rem;
}

.right {
	float: right;
	width: 65%;
	margin: 0 -2rem 0 1rem;
}

.figure-content-wrapper {
	position: relative;
	width: 100%;
	height: 100%;
}

.blur {
	position: absolute;
	inset: 0;
	z-index: -1;
	transform: scale(1.05);
	filter: blur(1rem);

	@media (prefers-color-scheme: dark) {
		filter: blur(1rem) brightness(0.5);
	}
}

.lightbox {
	color: inherit;
	overflow-y: auto;
	align-content: center;
	border: none;
	background: none;
	margin: auto;

	&::backdrop {
		background: light-dark(var(--bright_white), var(--black));
		opacity: 0.9;
	}

	img {
		max-width: 100%;
		max-height: calc(90vh - 60px);
		display: block;
		margin: 0 auto;
		position: relative;
		z-index: 1;
	}

	.caption,
	.alt-text {
		margin: 1rem auto;
		text-align: center;
		max-width: 70ch;
	}

	.alt-text {
		padding-top: 1rem;
		border-top: 2px solid var(--bright_grey);
	}

	.close {
		position: fixed;
		top: 0.8rem;
		right: 2rem;
		padding: 0.8rem;
		background: none;
		border: transparent;
		font-size: 2rem;
		color: light-dark(var(--black), var(--bright_white));
		z-index: 1;
	}
}

:root:has(.lightbox[open]) {
	overflow: hidden;
}

@media (max-width: 700px) {
	.left,
	.right {
		float: none;
		margin: 1rem auto;
	}

	.lightbox {
		padding: 0.8rem;

		.close {
			padding: 0.8rem;
			right: 0.8rem;
			top: 0;
		}
	}
}

              
            
!

JS

              
                class FigureGlowLightbox {
	constructor() {
		this.figures = document.querySelectorAll("figure");
		this.init();
	}

	init() {
		if (!this.figures.length) {
			console.warn("No figures found");
			return;
		}
		this.setupFigures();
	}

	createDialog(figure, index) {
		const dialog = document.createElement("dialog");
		dialog.id = `lightbox-${index}`;
		dialog.className = "lightbox";

		const clonedImg = figure.querySelector("img").cloneNode(true);
		const closeButton = this.createCloseButton();

		dialog.appendChild(clonedImg);
		dialog.appendChild(closeButton);

		const caption = this.createCaption(figure);
		if (caption) {
			dialog.appendChild(caption);
		}

		const altText = clonedImg.getAttribute("alt");
		const altElement = this.createAltTextElement(altText);
		if (altElement) {
			dialog.appendChild(altElement);
		}

		return dialog;
	}

	createCaption(figure) {
		const figcaption = figure.querySelector("figcaption");
		if (figcaption) {
			const clonedCaption = figcaption.cloneNode(true);
			clonedCaption.className = "caption";
			return clonedCaption;
		}
		return null;
	}

	createAltTextElement(altText) {
		if (!altText) return null;

		const altElement = document.createElement("p");
		altElement.className = "alt-text";
		altElement.textContent = `Alt Text: ${altText}`;
		return altElement;
	}

	createBlur(img) {
		const blur = document.createElement("div");
		blur.className = "blur";
		blur.style.backgroundImage = `url('${img.src}')`;
		return blur;
	}

	createCloseButton() {
		const closeButton = document.createElement("button");
		closeButton.textContent = "×";
		closeButton.className = "close";
		closeButton.setAttribute("aria-label", "Close lightbox");
		return closeButton;
	}

	addBlurEffect(figure) {
		const wrapper = document.createElement("div");
		wrapper.className = "figure-content-wrapper";
		const originalImg = figure.querySelector("img");
		const blur = this.createBlur(originalImg);
		wrapper.appendChild(blur);
		originalImg.parentNode.insertBefore(wrapper, originalImg);
		wrapper.appendChild(originalImg);
	}

	setupFigure(figure, index) {
		this.addBlurEffect(figure);
		const dialog = this.createDialog(figure, index);
		document.body.appendChild(dialog);
		figure.style.cursor = "zoom-in";
		figure.tabIndex = 0;
		this.setupEventListeners(figure, dialog);
	}

	setupEventListeners(figure, dialog) {
		figure.addEventListener("click", () => {
			dialog.showModal();
		});

		figure.addEventListener("keydown", (e) => {
			if (e.key === "Enter" || e.key === " ") {
				e.preventDefault();
				dialog.showModal();
			}
		});

		dialog.querySelector(".close").addEventListener("click", () => {
			dialog.close();
		});

		dialog.addEventListener("click", (e) => {
			const rect = dialog.getBoundingClientRect();
			if (
				e.clientX < rect.left ||
				e.clientX > rect.right ||
				e.clientY < rect.top ||
				e.clientY > rect.bottom
			) {
				dialog.close();
			}
		});

		dialog.addEventListener("keydown", (e) => {
			if (e.key === "Escape") {
				dialog.close();
			}
		});
	}

	setupFigures() {
		this.figures.forEach((figure, index) => this.setupFigure(figure, index));
	}
}

document.addEventListener("DOMContentLoaded", () => {
	new FigureGlowLightbox();
});

              
            
!
999px

Console