The content on this website, including videos and code examples, is for educational purposes only. All demonstrations and designs are fictional and created to illustrate coding techniques. Any resemblance to existing websites or brands is purely coincidental.
The creators and administrators of this website do not claim ownership or affiliation with any existing websites or companies. Users are encouraged to use the information responsibly for learning purposes. Liability for any misuse of the content provided is not accepted.
Below is the html code for this video.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Gallery</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<svg display="none">
<symbol id="close" viewBox="0 0 20 20">
<line x1="2" y1="2" x2="18" y2="18" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
<line x1="2" y1="18" x2="18" y2="2" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</symbol>
<symbol id="left" viewBox="0 0 20 20">
<polyline points="11, 7 8, 10 11, 13" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" />
</symbol>
<symbol id="right" viewBox="0 0 20 20">
<polyline points="9, 7 12, 10 9, 13" fill="none" stroke="currentColor" stroke-width="2"
stroke-linecap="round" />
</symbol>
</svg>
<div id="img-grid" class="img-grid">
<div class="detail-pane" data-open="false">
<div class="detail-pane-left">
<img src="https://images.unsplash.com/photo-1530138209850-3b2227d9ff9f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1469&q=80"
alt="Pane Img 1" class="detail-pane-img" width="300" height="255" data-image>
</div>
<div class="detail-pane-right">
<button class="detail-pane-close" type="button" aria-label="Close" data-action="close">
<svg class="detail-pane-close-svg" width="20px" height="20px">
<use xlink:href="#close" />
</svg>
</button>
<div class="detail-pane-info">
<div>
<h5 class="detail-pane-title" data-title>
Title Image 1
</h5>
<p class="detail-pane-subtitle" data-subtitle>
Subtitle Image 1
</p>
</div>
<a href="#" class="detail-pane-btn">
View Image
</a>
</div>
<div class="detail-pane-arrows">
<button class="detail-pane-btn detail-pane-btn-arrow" type="button" aria-label="Previous"
data-action="prev" disabled>
<svg class="detail-pane-arrow-svg" width="20px" height="20px">
<use xlink:href="#left" />
</svg>
</button>
<button class="detail-pane-btn detail-pane-btn-arrow" type="button" aria-label="Next"
data-action="next">
<svg class="detail-pane-arrow-svg" width="20px" height="20px">
<use xlink:href="#right" />
</svg>
</button>
</div>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="0">
<img src="https://images.unsplash.com/photo-1530138209850-3b2227d9ff9f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1469&q=80"
alt="Img 1" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 1</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 1</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="1">
<img src="https://images.unsplash.com/photo-1664142638093-9a78da96c425?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1374&q=80"
alt="Img 2" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 2</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 2</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="2">
<img src="https://images.unsplash.com/photo-1536825250137-962bff445079?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"
alt="Img 3" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 3</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 3</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="3">
<img src="https://images.unsplash.com/photo-1664448010557-cd3c22c21335?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1632&q=80"
alt="Img 4" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 4</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 4</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="4">
<img src="https://images.unsplash.com/photo-1664793228961-1c04f47de728?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1389&q=80"
alt="Img 5" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 5</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 5</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="5">
<img src="https://images.unsplash.com/photo-1664770052936-221f47b78b70?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"
alt="Img 6" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 6</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 6</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="6">
<img src="https://images.unsplash.com/photo-1663644480223-743c030c370e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1475&q=80"
alt="Img 7" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 7</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 7</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="7">
<img src="https://images.unsplash.com/photo-1663104871422-0db075242809?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1471&q=80"
alt="Img 8" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 8</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 8</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="8">
<img src="https://images.unsplash.com/photo-1664473654151-422592d8b753?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"
alt="Img 9" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 9</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 9</span>
</a>
</div>
</div>
<div class="cell">
<button class="cell-img-btn" type="button" data-action="open" data-id="9">
<img src="https://images.unsplash.com/photo-1664737371049-6738d22f1c74?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"
alt="Img 10" class="cell-img" width="300" height="255" data-thumb>
</button>
<div class="cell-caption">
<a href="#" class="cell-caption-link">
<span class="cell-caption-title">Title Image 10</span>
<br />
<span class="cell-caption-subtitle">Subtitle Image 10</span>
</a>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
Below is the css code for this video.
style.css
* {
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
:root {
font-size: calc(20px + (30 - 20) * (100vw - 320px) / (1280 - 320));
}
body, button {
font: 24px/1.5 Arial, Helvetica, sans-serif;
}
body {
background-color: #e3e4e8;
color: #17181c;
overflow: hidden;
scroll-behavior: smooth;
transition: all 0.25s;
}
.img-grid {
width: 100vw;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 16px;
padding: 16px;
}
.cell, .cell-img-btn {
position: relative;
}
.cell {
aspect-ratio: 16 / 12;
}
.cell-img-btn {
height: calc(100% - 24px);
width: 100%;
display: block;
background-color: #d5d7dd;
text-decoration: none;
transition: background-color 0.25s, opacity 0.15s linear;
overflow: hidden;
}
.cell-img-btn-active, .cell-img-btn:focus {
opacity: 0.5;
}
.cell-img-btn:focus {
outline: transparent;
}
.cell-img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: auto;
width: 100%;
display: block;
pointer-events: none;
}
.cell-caption {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 24px;
padding-top: 4px;
}
.cell-caption-link {
color: currentColor;
font-size: 8px;
line-height: 1.25;
text-decoration: none;
}
.cell-caption-link br {
display: none;
}
.cell-caption-link:focus, .cell-caption-link:hover {
text-decoration: underline;
}
.cell-caption-link:focus {
outline: transparent;
}
.cell-caption-title, .cell-caption-subtitle {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.cell-caption-title {
font-weight: bold;
}
.detail-pane {
position: fixed;
display: flex;
flex-direction: column;
background-color: #17181c;
color: #e3e4e8;
padding: 48px 0 0 0;
grid-column: 1 / -1;
inset: 0;
transition: background-color 0.25s;
z-index: 1;
}
.detail-pane[data-open="false"] {
display: none;
}
.detail-pane-left {
margin: auto 0;
}
.detail-pane-right {
display: flex;
flex-direction: column;
flex-shrink: 0;
background-color: #22252a;
justify-content: space-between;
padding: 16px;
}
.detail-pane-img {
display: block;
height: auto;
width: 100%;
margin: auto;
}
.detail-pane-close:focus, .detail-pane-btn:focus {
outline: transparent;
}
.detail-pane-close {
position: absolute;
top: 16px;
right: 16px;
height: 12px;
width: 12px;
background: transparent;
color: #abafba;
align-self: flex-end;
}
.detail-pane-close:focus, .detail-pane-close:hover {
color: #e3e4e8;
}
.detail-pane-arrow-svg, .detail-pane-close-svg {
height: 100%;
width: 100%;
display: block;
pointer-events: none;
}
.detail-pane-info {
display: flex;
justify-content: space-between;
align-items: center;
}
.detail-pane-title {
font-size: 12px;
line-height: 1;
font-weight: 500;
}
.detail-pane-subtitle {
color: #abafba;
font-size: 8px;
}
.detail-pane-btn {
background-color: #393d46;
border-radius: 4px;
color: #e3e4e8;
font-size: 8px;
padding: 6px 8px;
text-decoration: none;
transition: background-color 0.15s linear, opacity 0.15s linear;
}
.detail-pane-btn:disabled {
opacity: 0.25;
}
.detail-pane-btn:focus, .detail-pane-btn:not(:disabled):hover {
background-color: #505562;
}
.detail-pane-btn-arrows {
display: flex;
justify-content: center;
}
.detail-pane-btn-arrow {
display: block;
height: 16px;
width: 16px;
padding: 0;
border-radius: 50%;
}
.detail-pane-btn-arrow+.detail-pane-btn-arrow {
margin-left: 4px;
}
@supports selector(:focus-visible) {
.cell-img-btn:focus-visible {
opacity: 0.5;
}
.detail-pane-close:focus {
color: #abafba;
}
.detail-pane-close:focus-visible, .detail-pane-close:hover {
color: #e3e4e8;
}
.detail-pane-btn:focus {
background-color: #393d46;
}
.detail-pane-btn:focus-visible, .detail-pane-btn:not(:disabled):hover {
background-color: #505562;
}
}
@media (min-width: 768px) {
.img-grid {
grid-template-columns: repeat(3, 1fr);
}
.detail-pane {
position: static;
height: 160px;
flex-direction: row;
margin: 0 -16px;
padding: 16px;
}
.detail-pane-left, .detail-pane-right {
flex: 1;
}
.detail-pane-left {
flex: 2;
margin: 0;
}
.detail-pane-right {
background-color: transparent;
padding: 0 0 0 16px;
}
.detail-pane-img {
height: 100%;
width: auto;
}
.detail-pane-close {
position: static;
}
.detail-pane-info {
display: block;
}
.detail-pane-title, .detail-pane-subtitle {
margin-bottom: 12px;
}
.detail-pane-arrows {
justify-content: flex-end;
}
}
@media (min-width: 1024px) {
.img-grid {
grid-template-columns: repeat(4, 1fr);
}
}
@media (min-width: 1280px) {
.img-grid {
grid-template-columns: repeat(5, 1fr);
}
}
Below is the javascript code for this video.
index.js
window.addEventListener("DOMContentLoaded", () => {
const ig = new ImageGrid("#img-grid");
});
class ImageGrid {
constructor(selector) {
this.el = document.querySelector(selector);
this.detailPaneOpen = true;
this.currentImage = 0;
this.images = 10;
this.updateView();
this.el?.addEventListener("click", this.action.bind(this));
document.addEventListener("keydown", this.action.bind(this));
}
action(e) {
const { key, shiftKey, target } = e;
const action = target.getAttribute("data-action");
const imageID = +target.getAttribute("data-id");
if (key !== "Tab" && !shiftKey) {
if (!key && action === "open") {
if (imageID === this.currentImage && this.detailPaneOpen)
this.closeDetailPane();
else
this.openDetailPane(imageID);
} else if (key === "Escape" || action === "close") {
this.closeDetailPane();
} else if (key === "ArrowLeft" || (!key && action === "prev")) {
this.prev();
} else if (key === "ArrowRight" || (!key && action === "next")) {
this.next();
}
this.updateView();
this.moveFocus(target, action);
}
}
closeDetailPane() {
this.detailPaneOpen = false;
}
openDetailPane(imageID) {
this.detailPaneOpen = true;
this.currentImage = imageID;
}
prev() {
--this.currentImage;
if (this.currentImage < 0)
this.currentImage = 0;
}
next() {
++this.currentImage;
if (this.images < 2)
this.currentImage = 0;
else if (this.currentImage === this.images)
this.currentImage = this.images - 1;
}
moveFocus(target, action) {
const isPrev = action === "prev";
const isNext = action === "next";
if (isPrev || isNext) {
if (target.disabled) {
if (isPrev)
this.el.querySelector(`[data-action="next"]`)?.focus();
else if (isNext)
this.el.querySelector(`[data-action="prev"]`)?.focus();
} else {
target.focus();
}
}
}
updateView() {
const dataID = this.currentImage;
const detailPane = document.querySelector("[data-open]");
detailPane?.setAttribute("data-open", this.detailPaneOpen ? "true" : "false");
const minWidths = [768, 1024, 1280];
const matchedWidths = minWidths.filter(width => {
const mediaQuery = window.matchMedia(`(min-width: ${width}px)`);
return mediaQuery.matches;
});
const imagesPerRow = 2 + matchedWidths.length;
const moveToRow = 1 + Math.ceil((dataID + 1) / imagesPerRow);
detailPane.style.gridRow = moveToRow;
const firstCellInRow = this.el.querySelector(`[data-id="${dataID}"]`);
this.el.insertBefore(detailPane, firstCellInRow?.parentNode.nextSibling);
if (this.detailPaneOpen) {
const firstCellBtn = this.el.querySelector(`[data-id="0"]`);
const firstCell = firstCellBtn?.parentElement;
const { offsetHeight, offsetTop } = firstCell;
const scrollY = detailPane.offsetTop - (offsetHeight + offsetTop * 2);
window.scrollTo({ top: scrollY, behavior: "smooth" });
}
const paneImage = this.el.querySelector(`[data-image]`);
const paneThumbBtns = this.el.querySelectorAll(`[data-id]`);
const paneThumbBtn = this.el.querySelector(`[data-id="${dataID}"]`);
const paneThumb = paneThumbBtn?.querySelector(`[data-thumb]`);
Array.from(paneThumbBtns).forEach((btn, i) => {
const activeClass = "cell-img-btn-active";
if (i === dataID && this.detailPaneOpen)
btn.classList.add(activeClass);
else
btn.classList.remove(activeClass);
});
if (paneImage && paneThumb)
paneImage.src = paneThumb.src;
const paneTitle = this.el.querySelector("[data-title]");
if (paneTitle)
paneTitle.textContent = `Title Image ${dataID + 1}`;
const paneSubtitle = this.el.querySelector("[data-subtitle]");
if (paneSubtitle)
paneSubtitle.textContent = `Subtitle Image ${dataID + 1}`;
const prevButton = this.el.querySelector(`[data-action="prev"]`);
if (prevButton)
prevButton.disabled = dataID === 0;
const nextButton = this.el.querySelector(`[data-action="next"]`);
if (nextButton)
nextButton.disabled = this.images < 2 || dataID === this.images - 1;
}
}
Thanks for visiting