defuss-shadcn / Website / Media / gallery-item
Built with: CSS
Gallery ItemBLK
Presents one image with a caption and enlarged-view action - the picture opens a large view in a native modal dialog. Part of the Media blocks.
On this page (4)
§Default
The picture is a button with commandfor / command="show-modal": it opens the large view in a native modal <dialog> (focus trap, Escape, backdrop - all built in). The close button sits in a method="dialog" form. Click a picture.
§Overlay
data-variant='overlay': the caption slides over the picture on hover or keyboard focus.
§Framed
data-variant='framed': a white print frame with a shadow, turned a little - it straightens on hover.
§CSS view file
/* -- Gallery Item (website · Media) --------------------------------------- Presents one image with a caption and enlarged-view action - the picture opens a large view in a native modal dialog. */@layer components { /* every box in the block measures border-box - the same on any page */ :where(.mk-gallery-item, .mk-gallery-item *, .mk-gallery-item ::before, .mk-gallery-item ::after) { box-sizing: border-box; } .mk-gallery-item { position: relative; display: grid; gap: 0.625rem; margin: 0; } .mk-gallery-item-open { position: relative; display: block; overflow: hidden; padding: 0; border: 0; border-radius: var(--radius-lg); background: var(--muted); cursor: zoom-in; & img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: scale 400ms ease; } &:hover img { scale: 1.04; } &:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; } } .mk-gallery-item-zoom { position: absolute; top: 0.625rem; right: 0.625rem; display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 999px; background: oklch(0.12 0.02 260 / 0.55); color: #fff; backdrop-filter: blur(6px); opacity: 0; transition: opacity 200ms ease; & svg { width: 1rem; height: 1rem; } } .mk-gallery-item-open:is(:hover, :focus-visible) .mk-gallery-item-zoom { opacity: 1; } .mk-gallery-item-caption { font-size: 0.875rem; font-weight: 500; & span { display: block; color: var(--muted-foreground); font-weight: 400; font-size: 0.8125rem; } } /* the large view */ .mk-gallery-item-viewer { max-width: min(92vw, 72rem); max-height: 92vh; padding: 0; border: 0; background: transparent; color: #fff; overflow: visible; opacity: 1; scale: 1; transition: opacity 250ms ease, scale 250ms ease, display 250ms allow-discrete, overlay 250ms allow-discrete; &::backdrop { background: oklch(0.1 0.01 260 / 0.85); backdrop-filter: blur(6px); } &:not([open]) { opacity: 0; scale: 0.96; } } @starting-style { .mk-gallery-item-viewer[open] { opacity: 0; scale: 0.96; } } .mk-gallery-item-viewer-inner { position: relative; display: grid; gap: 0.75rem; & img { display: block; max-width: 100%; max-height: 80vh; margin-inline: auto; border-radius: var(--radius-lg); object-fit: contain; } & p { margin: 0; text-align: center; font-size: 0.9375rem; } & p span { color: oklch(1 0 0 / 0.65); } & form { position: absolute; top: -0.75rem; right: -0.75rem; } } .mk-gallery-item-close { display: grid; place-items: center; width: 2.25rem; height: 2.25rem; padding: 0; border: 0; border-radius: 999px; background: #fff; color: oklch(0.15 0 0); box-shadow: var(--shadow-lg); cursor: pointer; & svg { width: 1.125rem; height: 1.125rem; } &:focus-visible { outline: 2px solid #fff; outline-offset: 2px; } } .mk-gallery-item[data-variant="overlay"] { & .mk-gallery-item-caption { position: absolute; inset: auto 0 0; z-index: 1; padding: 2rem 1rem 0.875rem; border-radius: 0 0 var(--radius-lg) var(--radius-lg); background: linear-gradient(transparent, oklch(0.12 0.02 260 / 0.85)); color: #fff; opacity: 0; transition: opacity 200ms ease; pointer-events: none; } & .mk-gallery-item-caption span { color: oklch(1 0 0 / 0.75); } &:is(:hover, :focus-within) .mk-gallery-item-caption { opacity: 1; } } .mk-gallery-item[data-variant="framed"] { padding: 0.75rem 0.75rem 1rem; background: #fff; color: oklch(0.2 0 0); box-shadow: var(--shadow-lg); rotate: -1.5deg; transition: rotate 300ms ease; &:nth-child(even) { rotate: 1.5deg; } &:hover { rotate: 0deg; } & .mk-gallery-item-open { border-radius: 2px; } & .mk-gallery-item-caption { font-family: var(--font-serif); text-align: center; } & .mk-gallery-item-caption span { color: oklch(0.45 0 0); } } /* -- Accessibility ------------------------------------------- */ @media (prefers-reduced-motion: reduce) { .mk-gallery-item-open img, .mk-gallery-item-zoom, .mk-gallery-item-viewer, .mk-gallery-item[data-variant="framed"], .mk-gallery-item[data-variant="overlay"] .mk-gallery-item-caption { transition: none; } .mk-gallery-item-open:hover img { scale: none; } } @media (forced-colors: active) { .mk-gallery-item-close { border: 1px solid ButtonText; } }}Comments, ideas or improvements? Edit this page's source on GitHub