Open demo

CSS code

HTML
<div class="full"><span class="lbl">:has() sibling dimming</span>
<div class="mg-gal">
  <a href="#" class="mg-item"><span class="mg-ph"><img src="https://images.unsplash.com/photo-1485955900006-10f4d324d411?auto=format&fit=crop&w=450&h=600&q=70" alt="A spiky succulent in a mint-green pot on a white table" width="450" height="600"></span><b>Aloe in Mint Pot</b><small>$24</small></a>
  <a href="#" class="mg-item"><span class="mg-ph"><img src="https://images.unsplash.com/photo-1463936575829-25148e1db1b8?auto=format&fit=crop&w=450&h=600&q=70" alt="A row of green cacti against a pale sky" width="450" height="600"></span><b>Cactus Trio</b><small>$38</small></a>
  <a href="#" class="mg-item"><span class="mg-ph"><img src="https://images.unsplash.com/photo-1610701596007-11502861dcfa?auto=format&fit=crop&w=450&h=600&q=70" alt="Speckled cream ceramic cups and bowls on a white shelf" width="450" height="600"></span><b>Speckled Cup Set</b><small>$46</small></a>
  <a href="#" class="mg-item"><span class="mg-ph"><img src="https://images.unsplash.com/photo-1565193566173-7a0ee3dbe261?auto=format&fit=crop&w=450&h=600&q=70" alt="Three grey stoneware vases with dried seed heads against a dark wall" width="450" height="600"></span><b>Stoneware Vases</b><small>$58</small></a>
  <a href="#" class="mg-item"><span class="mg-ph"><img src="https://images.unsplash.com/photo-1466692476868-aef1dfb1e735?auto=format&fit=crop&w=450&h=600&q=70" alt="Young seedlings sprouting in a dark seed tray" width="450" height="600"></span><b>Seedling Starter Kit</b><small>$19</small></a>
</div></div>
<div><span class="lbl">@property gradient border</span>
<div class="mg-pair">
  <a href="#" class="mg-ring"><span class="mg-ring-ph"><img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=500&h=500&q=70" alt="A red running shoe on a red background" width="500" height="500"></span><b>Trail Runner 2</b><small>$139 · 6 colours</small></a>
  <a href="#" class="mg-ring"><span class="mg-ring-ph"><img src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?auto=format&fit=crop&w=500&h=500&q=70" alt="Two white smartwatches lying on a light grey surface" width="500" height="500"></span><b>Halo Watch</b><small>$219 · 2 sizes</small></a>
</div></div>
<div><span class="lbl">View-transition-style crossfade</span>
<a href="#" class="mg-xf"><span class="mg-xf-ph"><img src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=900&h=675&q=70" alt="A modern house with large lit windows and a lawn at dusk" width="900" height="675"><img src="https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=900&h=675&q=70" alt="Its open-plan living room with a white sofa and timber wall" width="900" height="675">
  <span class="mg-xf-tag"><span>Outside · 1/2</span><span>Living room · 2/2</span></span></span>
  <span class="mg-xf-body"><b>Cedar Ridge House</b><small>4 bed · 3 bath · 2,480 sq ft</small><strong>$1,185,000</strong></span></a></div>
<div class="full"><span class="lbl">Container-query sized effect (280px and wide container)</span>
<div class="cq-demo">
  <div class="mg-cq-box"><a href="#" class="mg-cq"><img src="https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=600&h=450&q=70" alt="A straight road running between red rock cliffs" width="600" height="450">
    <span class="mg-cq-title" aria-hidden="true">Red Rock Road Trip</span>
    <span class="mg-cq-panel"><i>Road trip · 4 days</i><b>Red Rock Road Trip</b><span>Two canyons, a ghost town and a night under dark skies.</span><strong>From $640</strong></span></a></div>
  <div class="mg-cq-box"><a href="#" class="mg-cq"><img src="https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1200&h=675&q=70" alt="Sunlight breaking over misty green hills and rocky outcrops" width="1200" height="675">
    <span class="mg-cq-title" aria-hidden="true">Highland Mist Weekend</span>
    <span class="mg-cq-panel"><i>Walking · 3 days</i><b>Highland Mist Weekend</b><span>Ridge walks at sunrise, a bothy night and a distillery lunch.</span><strong>From $480</strong></span></a></div>
</div></div>
CSS
/* Hover effects that used to need JavaScript: :has(), @property, a plus-lighter crossfade and container
   queries. Each one degrades to a plain hover where the feature is missing. */
.mg-gal,.mg-pair,.mg-xf,.mg-cq-box{--mg-ink:#0f172a;--mg-muted:#475569;--mg-accent:#047857;--mg-ease:cubic-bezier(.2,.7,.2,1)}

/* 1. :has() sibling dimming: hovering or focusing one item fades the rest */
.mg-gal{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:16px}
.mg-item{display:block;border-radius:14px;color:var(--mg-ink);text-decoration:none;line-height:1.35;
  transition:opacity .35s,filter .35s,transform .35s var(--mg-ease)}
.mg-item:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-ph{display:block;aspect-ratio:3/4;overflow:hidden;border-radius:14px;background:#e2e8f0}
.mg-ph img{display:block;width:100%;height:100%;object-fit:cover}
.mg-item b{display:block;margin-top:10px;font-size:.92rem}
.mg-item small{font-size:.85rem;color:var(--mg-muted)}
.mg-item:is(:hover,:focus-visible){transform:translateY(-4px)}
@media (hover:hover){.mg-gal:has(.mg-item:hover) .mg-item:not(:hover){opacity:.4;filter:grayscale(.8)}}
.mg-gal:has(.mg-item:focus-visible) .mg-item:not(:focus-visible){opacity:.4;filter:grayscale(.8)}

/* 2. @property: a registered angle lets the conic-gradient border spin smoothly */
@property --mg-angle{syntax:"<angle>";inherits:false;initial-value:0deg}
.mg-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.mg-ring{--mg-ring:conic-gradient(from var(--mg-angle),#10b981,#06b6d4,#8b5cf6,#f43f5e,#f59e0b,#10b981);
  display:block;padding:12px 12px 16px;border:2px solid #e2e8f0;border-radius:18px;background:#fff;color:var(--mg-ink);
  text-decoration:none;line-height:1.35;transition:border-color .3s,box-shadow .3s}
.mg-ring:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-ring:is(:hover,:focus-visible){border-color:transparent;background:linear-gradient(#fff,#fff) padding-box,var(--mg-ring) border-box;
  box-shadow:0 14px 30px -14px rgba(139,92,246,.45);animation:mg-spin 3s linear infinite}
@keyframes mg-spin{to{--mg-angle:360deg}}
.mg-ring-ph{display:block;aspect-ratio:1;overflow:hidden;border-radius:10px;background:#f1f5f9}
.mg-ring-ph img{display:block;width:100%;height:100%;object-fit:cover}
.mg-ring b{display:block;margin:12px 4px 2px;font-size:.95rem}
.mg-ring small{display:block;margin:0 4px;font-size:.88rem;color:var(--mg-muted)}

/* 3. Crossfade the way the View Transitions API does it: both photos fade against each other with
   mix-blend-mode: plus-lighter, so the frame never dips in brightness. Without plus-lighter the
   second photo simply fades in over the first. */
.mg-xf{display:block;overflow:hidden;border-radius:18px;background:#fff;color:var(--mg-ink);text-decoration:none;line-height:1.35;
  box-shadow:0 1px 2px rgba(15,23,42,.06),0 16px 36px -22px rgba(15,23,42,.4)}
.mg-xf:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-xf-ph{position:relative;display:block;aspect-ratio:4/3;overflow:hidden;background:#000;isolation:isolate}
.mg-xf-ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:opacity .7s ease,transform .9s var(--mg-ease)}
.mg-xf-ph img+img{opacity:0}
.mg-xf:is(:hover,:focus-visible) .mg-xf-ph img:first-child{transform:scale(1.05)}
.mg-xf:is(:hover,:focus-visible) .mg-xf-ph img+img{opacity:1}
@supports (mix-blend-mode:plus-lighter){
  .mg-xf-ph img{mix-blend-mode:plus-lighter}
  .mg-xf:is(:hover,:focus-visible) .mg-xf-ph img:first-child{opacity:0}
}
.mg-xf-tag{position:absolute;z-index:1;top:12px;left:12px;display:grid;padding:6px 12px;border-radius:999px;background:rgba(255,255,255,.94);
  font-size:.78rem;font-weight:700;color:var(--mg-ink)}
.mg-xf-tag>span{grid-area:1/1;transition:opacity .4s}
.mg-xf-tag>span+span,.mg-xf:is(:hover,:focus-visible) .mg-xf-tag>span:first-child{opacity:0}
.mg-xf:is(:hover,:focus-visible) .mg-xf-tag>span+span{opacity:1}
.mg-xf-body{display:grid;gap:2px;padding:16px 18px 18px}
.mg-xf-body b{font-size:1.1rem}
.mg-xf-body small{font-size:.88rem;color:var(--mg-muted)}
.mg-xf-body strong{margin-top:6px;color:var(--mg-accent)}

/* 4. Container queries: the same card reveals its details from the bottom when narrow
   and from the side when its container is 480px or wider */
.mg-cq-box{container:mgcq/inline-size}
.mg-cq{position:relative;display:block;aspect-ratio:4/3;overflow:hidden;border-radius:16px;background:#1e293b;color:#fff;text-decoration:none}
.mg-cq:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-cq img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .7s var(--mg-ease)}
.mg-cq-title{position:absolute;left:0;right:0;bottom:0;padding:44px 18px 16px;font-size:1.1rem;font-weight:700;line-height:1.25;
  background:linear-gradient(to top,rgba(15,23,42,.9),rgba(15,23,42,0));transition:opacity .3s}
.mg-cq-panel{position:absolute;z-index:1;inset:auto 0 0 0;display:grid;align-content:end;gap:6px;padding:18px;line-height:1.4;
  background:rgba(6,78,59,.95);transform:translateY(101%);transition:transform .45s var(--mg-ease),opacity .3s}
.mg-cq-panel i{font-style:normal;font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#a7f3d0}
.mg-cq-panel b{font-size:1.15rem;line-height:1.2}
.mg-cq-panel span{font-size:.9rem;color:#d1fae5}
.mg-cq-panel strong{font-size:.95rem}
.mg-cq:is(:hover,:focus-visible) .mg-cq-panel{transform:none}
.mg-cq:is(:hover,:focus-visible) .mg-cq-title{opacity:0}
.mg-cq:is(:hover,:focus-visible) img{transform:scale(1.05)}
@container mgcq (min-width:480px){
  .mg-cq{aspect-ratio:16/9}
  .mg-cq-title{padding:60px 24px 20px;font-size:1.35rem}
  .mg-cq-panel{inset:0 0 0 auto;width:min(46%,320px);align-content:center;padding:24px;transform:translateX(101%)}
  .mg-cq:is(:hover,:focus-visible) .mg-cq-title{opacity:1}
}

@media (max-width:767px){.mg-gal{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* Touch: details panels are shown */
@media (hover:none){.mg-cq .mg-cq-panel{transform:none}.mg-cq-title{display:none}}
/* Reduced motion: no lifting, zooming or spinning; dimming, the static gradient ring and fades remain */
@media (prefers-reduced-motion:reduce){
  .mg-item,.mg-xf-ph img,.mg-cq img{transform:none!important}
  .mg-ring:is(:hover,:focus-visible){animation:none}
  .mg-cq-panel{transform:none!important;opacity:0}
  .mg-cq:is(:hover,:focus-visible) .mg-cq-panel{opacity:1}
  @media (hover:none){.mg-cq-panel{opacity:1}}
}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="row gx-4 gy-5">
<div class="col-12"><span class="lbl">:has() sibling dimming</span>
<div class="mg-gal row row-cols-2 row-cols-md-5 g-3">
  <div class="col"><a href="#" class="mg-item"><span class="mg-ph ratio d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1485955900006-10f4d324d411?auto=format&fit=crop&w=450&h=600&q=70" alt="A spiky succulent in a mint-green pot on a white table" width="450" height="600"></span><b>Aloe in Mint Pot</b><small>$24</small></a></div>
  <div class="col"><a href="#" class="mg-item"><span class="mg-ph ratio d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1463936575829-25148e1db1b8?auto=format&fit=crop&w=450&h=600&q=70" alt="A row of green cacti against a pale sky" width="450" height="600"></span><b>Cactus Trio</b><small>$38</small></a></div>
  <div class="col"><a href="#" class="mg-item"><span class="mg-ph ratio d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1610701596007-11502861dcfa?auto=format&fit=crop&w=450&h=600&q=70" alt="Speckled cream ceramic cups and bowls on a white shelf" width="450" height="600"></span><b>Speckled Cup Set</b><small>$46</small></a></div>
  <div class="col"><a href="#" class="mg-item"><span class="mg-ph ratio d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1565193566173-7a0ee3dbe261?auto=format&fit=crop&w=450&h=600&q=70" alt="Three grey stoneware vases with dried seed heads against a dark wall" width="450" height="600"></span><b>Stoneware Vases</b><small>$58</small></a></div>
  <div class="col"><a href="#" class="mg-item"><span class="mg-ph ratio d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1466692476868-aef1dfb1e735?auto=format&fit=crop&w=450&h=600&q=70" alt="Young seedlings sprouting in a dark seed tray" width="450" height="600"></span><b>Seedling Starter Kit</b><small>$19</small></a></div>
</div></div>
<div class="col-md-6"><span class="lbl">@property gradient border</span>
<div class="mg-pair row row-cols-2 g-3">
  <div class="col"><a href="#" class="mg-ring card text-decoration-none"><span class="mg-ring-ph ratio ratio-1x1 d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=500&h=500&q=70" alt="A red running shoe on a red background" width="500" height="500"></span><b>Trail Runner 2</b><small>$139 · 6 colours</small></a></div>
  <div class="col"><a href="#" class="mg-ring card text-decoration-none"><span class="mg-ring-ph ratio ratio-1x1 d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?auto=format&fit=crop&w=500&h=500&q=70" alt="Two white smartwatches lying on a light grey surface" width="500" height="500"></span><b>Halo Watch</b><small>$219 · 2 sizes</small></a></div>
</div></div>
<div class="col-md-6"><span class="lbl">View-transition-style crossfade</span>
<a href="#" class="mg-xf card text-decoration-none"><span class="mg-xf-ph ratio ratio-4x3 d-block"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=900&h=675&q=70" alt="A modern house with large lit windows and a lawn at dusk" width="900" height="675"><img class="object-fit-cover" src="https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=900&h=675&q=70" alt="Its open-plan living room with a white sofa and timber wall" width="900" height="675">
  <span class="mg-xf-tag"><span>Outside · 1/2</span><span>Living room · 2/2</span></span></span>
  <span class="card-body mg-xf-body"><b>Cedar Ridge House</b><small>4 bed · 3 bath · 2,480 sq ft</small><strong>$1,185,000</strong></span></a></div>
<div class="col-12"><span class="lbl">Container-query sized effect (280px and wide container)</span>
<div class="cq-demo">
  <div class="mg-cq-box"><a href="#" class="mg-cq"><img src="https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=600&h=450&q=70" alt="A straight road running between red rock cliffs" width="600" height="450">
    <span class="mg-cq-title" aria-hidden="true">Red Rock Road Trip</span>
    <span class="mg-cq-panel"><i>Road trip · 4 days</i><b>Red Rock Road Trip</b><span>Two canyons, a ghost town and a night under dark skies.</span><strong>From $640</strong></span></a></div>
  <div class="mg-cq-box"><a href="#" class="mg-cq"><img src="https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1200&h=675&q=70" alt="Sunlight breaking over misty green hills and rocky outcrops" width="1200" height="675">
    <span class="mg-cq-title" aria-hidden="true">Highland Mist Weekend</span>
    <span class="mg-cq-panel"><i>Walking · 3 days</i><b>Highland Mist Weekend</b><span>Ridge walks at sunrise, a bothy night and a distillery lunch.</span><strong>From $480</strong></span></a></div>
</div></div>
</div>
CSS
/* Bootstrap .row grids, .card and .ratio, plus the modern CSS Bootstrap has no utility for. Hover effects that used to need JavaScript: :has(), @property, a plus-lighter crossfade and container
   queries. Each one degrades to a plain hover where the feature is missing. */
.mg-gal,.mg-pair,.mg-xf,.mg-cq-box{--mg-ink:#0f172a;--mg-muted:#475569;--mg-accent:#047857;--mg-ease:cubic-bezier(.2,.7,.2,1)}

/* 1. :has() sibling dimming: hovering or focusing one item fades the rest */
.mg-item{display:block;border-radius:14px;color:var(--mg-ink);text-decoration:none;line-height:1.35;
  transition:opacity .35s,filter .35s,transform .35s var(--mg-ease)}
.mg-item:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-ph{--bs-aspect-ratio:133.333%;overflow:hidden;border-radius:14px;background:#e2e8f0}
.mg-item b{display:block;margin-top:10px;font-size:.92rem}
.mg-item small{font-size:.85rem;color:var(--mg-muted)}
.mg-item:is(:hover,:focus-visible){transform:translateY(-4px)}
@media (hover:hover){.mg-gal:has(.mg-item:hover) .mg-item:not(:hover){opacity:.4;filter:grayscale(.8)}}
.mg-gal:has(.mg-item:focus-visible) .mg-item:not(:focus-visible){opacity:.4;filter:grayscale(.8)}

/* 2. @property: a registered angle lets the conic-gradient border spin smoothly */
@property --mg-angle{syntax:"<angle>";inherits:false;initial-value:0deg}
.mg-ring{--mg-ring:conic-gradient(from var(--mg-angle),#10b981,#06b6d4,#8b5cf6,#f43f5e,#f59e0b,#10b981);
  height:100%;padding:12px 12px 16px;border:2px solid #e2e8f0;border-radius:18px;background:#fff;color:var(--mg-ink);
  line-height:1.35;transition:border-color .3s,box-shadow .3s}
.mg-ring:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-ring:is(:hover,:focus-visible){border-color:transparent;background:linear-gradient(#fff,#fff) padding-box,var(--mg-ring) border-box;
  box-shadow:0 14px 30px -14px rgba(139,92,246,.45);animation:mg-spin 3s linear infinite}
@keyframes mg-spin{to{--mg-angle:360deg}}
.mg-ring-ph{overflow:hidden;border-radius:10px;background:#f1f5f9}
.mg-ring b{display:block;margin:12px 4px 2px;font-size:.95rem}
.mg-ring small{display:block;margin:0 4px;font-size:.88rem;color:var(--mg-muted)}

/* 3. Crossfade the way the View Transitions API does it: both photos fade against each other with
   mix-blend-mode: plus-lighter, so the frame never dips in brightness. Without plus-lighter the
   second photo simply fades in over the first. */
.mg-xf{--bs-card-border-width:0;--bs-card-border-radius:18px;overflow:hidden;color:var(--mg-ink);line-height:1.35;
  box-shadow:0 1px 2px rgba(15,23,42,.06),0 16px 36px -22px rgba(15,23,42,.4)}
.mg-xf:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-xf-ph{overflow:hidden;background:#000;isolation:isolate}
.mg-xf-ph img{transition:opacity .7s ease,transform .9s var(--mg-ease)}
.mg-xf-ph img+img{opacity:0}
.mg-xf:is(:hover,:focus-visible) .mg-xf-ph img:first-child{transform:scale(1.05)}
.mg-xf:is(:hover,:focus-visible) .mg-xf-ph img+img{opacity:1}
@supports (mix-blend-mode:plus-lighter){
  .mg-xf-ph img{mix-blend-mode:plus-lighter}
  .mg-xf:is(:hover,:focus-visible) .mg-xf-ph img:first-child{opacity:0}
}
.mg-xf-ph>.mg-xf-tag{z-index:1;top:12px;left:12px;width:auto;height:auto;display:grid;padding:6px 12px;border-radius:999px;background:rgba(255,255,255,.94);
  font-size:.78rem;font-weight:700;color:var(--mg-ink)}
.mg-xf-tag>span{grid-area:1/1;transition:opacity .4s}
.mg-xf-tag>span+span,.mg-xf:is(:hover,:focus-visible) .mg-xf-tag>span:first-child{opacity:0}
.mg-xf:is(:hover,:focus-visible) .mg-xf-tag>span+span{opacity:1}
.mg-xf-body{display:grid;gap:2px;padding:16px 18px 18px;flex:none}
.mg-xf-body b{font-size:1.1rem}
.mg-xf-body small{font-size:.88rem;color:var(--mg-muted)}
.mg-xf-body strong{margin-top:6px;color:var(--mg-accent)}

/* 4. Container queries: the same card reveals its details from the bottom when narrow
   and from the side when its container is 480px or wider */
.mg-cq-box{container:mgcq/inline-size}
.mg-cq{position:relative;display:block;aspect-ratio:4/3;overflow:hidden;border-radius:16px;background:#1e293b;color:#fff;text-decoration:none}
.mg-cq:focus-visible{outline:3px solid var(--mg-accent);outline-offset:4px}
.mg-cq img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:transform .7s var(--mg-ease)}
.mg-cq-title{position:absolute;left:0;right:0;bottom:0;padding:44px 18px 16px;font-size:1.1rem;font-weight:700;line-height:1.25;
  background:linear-gradient(to top,rgba(15,23,42,.9),rgba(15,23,42,0));transition:opacity .3s}
.mg-cq-panel{position:absolute;z-index:1;inset:auto 0 0 0;display:grid;align-content:end;gap:6px;padding:18px;line-height:1.4;
  background:rgba(6,78,59,.95);transform:translateY(101%);transition:transform .45s var(--mg-ease),opacity .3s}
.mg-cq-panel i{font-style:normal;font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#a7f3d0}
.mg-cq-panel b{font-size:1.15rem;line-height:1.2}
.mg-cq-panel span{font-size:.9rem;color:#d1fae5}
.mg-cq-panel strong{font-size:.95rem}
.mg-cq:is(:hover,:focus-visible) .mg-cq-panel{transform:none}
.mg-cq:is(:hover,:focus-visible) .mg-cq-title{opacity:0}
.mg-cq:is(:hover,:focus-visible) img{transform:scale(1.05)}
@container mgcq (min-width:480px){
  .mg-cq{aspect-ratio:16/9}
  .mg-cq-title{padding:60px 24px 20px;font-size:1.35rem}
  .mg-cq-panel{inset:0 0 0 auto;width:min(46%,320px);align-content:center;padding:24px;transform:translateX(101%)}
  .mg-cq:is(:hover,:focus-visible) .mg-cq-title{opacity:1}
}

/* Touch: details panels are shown */
@media (hover:none){.mg-cq .mg-cq-panel{transform:none}.mg-cq-title{display:none}}
/* Reduced motion: no lifting, zooming or spinning; dimming, the static gradient ring and fades remain */
@media (prefers-reduced-motion:reduce){
  .mg-item,.mg-xf-ph img,.mg-cq img{transform:none!important}
  .mg-ring:is(:hover,:focus-visible){animation:none}
  .mg-cq-panel{transform:none!important;opacity:0}
  .mg-cq:is(:hover,:focus-visible) .mg-cq-panel{opacity:1}
  @media (hover:none){.mg-cq-panel{opacity:1}}
}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div class="grid grid-cols-1 gap-x-7 gap-y-[52px] md:grid-cols-2">
<div class="md:col-span-2"><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#56627a] uppercase">:has() sibling dimming</span>
<div class="group/gal grid grid-cols-2 gap-4 md:grid-cols-5">
  <a href="#" class="block rounded-[14px] leading-[1.35] text-ink no-underline transition-[opacity,filter,translate] duration-350 ease-[cubic-bezier(.2,.7,.2,1)] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent motion-safe:hover:-translate-y-1 motion-safe:focus-visible:-translate-y-1 [@media(hover:hover)]:group-has-[a:hover]/gal:opacity-40 [@media(hover:hover)]:group-has-[a:hover]/gal:grayscale-80 hover:opacity-100! hover:filter-none! group-has-[a:focus-visible]/gal:opacity-40 group-has-[a:focus-visible]/gal:grayscale-80 focus-visible:opacity-100! focus-visible:filter-none!"><span class="block aspect-[3/4] overflow-hidden rounded-[14px] bg-[#e2e8f0]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1485955900006-10f4d324d411?auto=format&fit=crop&w=450&h=600&q=70" alt="A spiky succulent in a mint-green pot on a white table" width="450" height="600"></span><b class="mt-2.5 block text-[.92rem]">Aloe in Mint Pot</b><small class="text-[.85rem] text-muted">$24</small></a>
  <a href="#" class="block rounded-[14px] leading-[1.35] text-ink no-underline transition-[opacity,filter,translate] duration-350 ease-[cubic-bezier(.2,.7,.2,1)] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent motion-safe:hover:-translate-y-1 motion-safe:focus-visible:-translate-y-1 [@media(hover:hover)]:group-has-[a:hover]/gal:opacity-40 [@media(hover:hover)]:group-has-[a:hover]/gal:grayscale-80 hover:opacity-100! hover:filter-none! group-has-[a:focus-visible]/gal:opacity-40 group-has-[a:focus-visible]/gal:grayscale-80 focus-visible:opacity-100! focus-visible:filter-none!"><span class="block aspect-[3/4] overflow-hidden rounded-[14px] bg-[#e2e8f0]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1463936575829-25148e1db1b8?auto=format&fit=crop&w=450&h=600&q=70" alt="A row of green cacti against a pale sky" width="450" height="600"></span><b class="mt-2.5 block text-[.92rem]">Cactus Trio</b><small class="text-[.85rem] text-muted">$38</small></a>
  <a href="#" class="block rounded-[14px] leading-[1.35] text-ink no-underline transition-[opacity,filter,translate] duration-350 ease-[cubic-bezier(.2,.7,.2,1)] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent motion-safe:hover:-translate-y-1 motion-safe:focus-visible:-translate-y-1 [@media(hover:hover)]:group-has-[a:hover]/gal:opacity-40 [@media(hover:hover)]:group-has-[a:hover]/gal:grayscale-80 hover:opacity-100! hover:filter-none! group-has-[a:focus-visible]/gal:opacity-40 group-has-[a:focus-visible]/gal:grayscale-80 focus-visible:opacity-100! focus-visible:filter-none!"><span class="block aspect-[3/4] overflow-hidden rounded-[14px] bg-[#e2e8f0]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1610701596007-11502861dcfa?auto=format&fit=crop&w=450&h=600&q=70" alt="Speckled cream ceramic cups and bowls on a white shelf" width="450" height="600"></span><b class="mt-2.5 block text-[.92rem]">Speckled Cup Set</b><small class="text-[.85rem] text-muted">$46</small></a>
  <a href="#" class="block rounded-[14px] leading-[1.35] text-ink no-underline transition-[opacity,filter,translate] duration-350 ease-[cubic-bezier(.2,.7,.2,1)] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent motion-safe:hover:-translate-y-1 motion-safe:focus-visible:-translate-y-1 [@media(hover:hover)]:group-has-[a:hover]/gal:opacity-40 [@media(hover:hover)]:group-has-[a:hover]/gal:grayscale-80 hover:opacity-100! hover:filter-none! group-has-[a:focus-visible]/gal:opacity-40 group-has-[a:focus-visible]/gal:grayscale-80 focus-visible:opacity-100! focus-visible:filter-none!"><span class="block aspect-[3/4] overflow-hidden rounded-[14px] bg-[#e2e8f0]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1565193566173-7a0ee3dbe261?auto=format&fit=crop&w=450&h=600&q=70" alt="Three grey stoneware vases with dried seed heads against a dark wall" width="450" height="600"></span><b class="mt-2.5 block text-[.92rem]">Stoneware Vases</b><small class="text-[.85rem] text-muted">$58</small></a>
  <a href="#" class="block rounded-[14px] leading-[1.35] text-ink no-underline transition-[opacity,filter,translate] duration-350 ease-[cubic-bezier(.2,.7,.2,1)] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent motion-safe:hover:-translate-y-1 motion-safe:focus-visible:-translate-y-1 [@media(hover:hover)]:group-has-[a:hover]/gal:opacity-40 [@media(hover:hover)]:group-has-[a:hover]/gal:grayscale-80 hover:opacity-100! hover:filter-none! group-has-[a:focus-visible]/gal:opacity-40 group-has-[a:focus-visible]/gal:grayscale-80 focus-visible:opacity-100! focus-visible:filter-none!"><span class="block aspect-[3/4] overflow-hidden rounded-[14px] bg-[#e2e8f0]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1466692476868-aef1dfb1e735?auto=format&fit=crop&w=450&h=600&q=70" alt="Young seedlings sprouting in a dark seed tray" width="450" height="600"></span><b class="mt-2.5 block text-[.92rem]">Seedling Starter Kit</b><small class="text-[.85rem] text-muted">$19</small></a>
</div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#56627a] uppercase">@property gradient border</span>
<div class="grid grid-cols-2 gap-4">
  <a href="#" class="block rounded-[18px] border-2 border-[#e2e8f0] bg-white px-3 pt-3 pb-4 leading-[1.35] text-ink no-underline transition-[border-color,box-shadow] duration-300 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent [--mg-ring:conic-gradient(from_var(--mg-angle),#10b981,#06b6d4,#8b5cf6,#f43f5e,#f59e0b,#10b981)] hover:border-transparent focus-visible:border-transparent hover:[background:linear-gradient(#fff,#fff)_padding-box,var(--mg-ring)_border-box] focus-visible:[background:linear-gradient(#fff,#fff)_padding-box,var(--mg-ring)_border-box] hover:shadow-[0_14px_30px_-14px_rgba(139,92,246,.45)] focus-visible:shadow-[0_14px_30px_-14px_rgba(139,92,246,.45)] hover:animate-[mg-spin_3s_linear_infinite] focus-visible:animate-[mg-spin_3s_linear_infinite] motion-reduce:animate-none!"><span class="block aspect-square overflow-hidden rounded-[10px] bg-[#f1f5f9]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=500&h=500&q=70" alt="A red running shoe on a red background" width="500" height="500"></span><b class="mx-1 mt-3 mb-0.5 block text-[.95rem]">Trail Runner 2</b><small class="mx-1 block text-[.88rem] text-muted">$139 · 6 colours</small></a>
  <a href="#" class="block rounded-[18px] border-2 border-[#e2e8f0] bg-white px-3 pt-3 pb-4 leading-[1.35] text-ink no-underline transition-[border-color,box-shadow] duration-300 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent [--mg-ring:conic-gradient(from_var(--mg-angle),#10b981,#06b6d4,#8b5cf6,#f43f5e,#f59e0b,#10b981)] hover:border-transparent focus-visible:border-transparent hover:[background:linear-gradient(#fff,#fff)_padding-box,var(--mg-ring)_border-box] focus-visible:[background:linear-gradient(#fff,#fff)_padding-box,var(--mg-ring)_border-box] hover:shadow-[0_14px_30px_-14px_rgba(139,92,246,.45)] focus-visible:shadow-[0_14px_30px_-14px_rgba(139,92,246,.45)] hover:animate-[mg-spin_3s_linear_infinite] focus-visible:animate-[mg-spin_3s_linear_infinite] motion-reduce:animate-none!"><span class="block aspect-square overflow-hidden rounded-[10px] bg-[#f1f5f9]"><img class="block size-full object-cover" src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?auto=format&fit=crop&w=500&h=500&q=70" alt="Two white smartwatches lying on a light grey surface" width="500" height="500"></span><b class="mx-1 mt-3 mb-0.5 block text-[.95rem]">Halo Watch</b><small class="mx-1 block text-[.88rem] text-muted">$219 · 2 sizes</small></a>
</div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#56627a] uppercase">View-transition-style crossfade</span>
<a href="#" class="group block overflow-hidden rounded-[18px] bg-white leading-[1.35] text-ink no-underline shadow-[0_1px_2px_rgba(15,23,42,.06),0_16px_36px_-22px_rgba(15,23,42,.4)] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent"><span class="relative isolate block aspect-[4/3] overflow-hidden bg-black"><img class="absolute inset-0 size-full object-cover transition-[opacity,scale] duration-[.7s,.9s] ease-[cubic-bezier(.2,.7,.2,1)] supports-[mix-blend-mode:plus-lighter]:mix-blend-plus-lighter motion-safe:group-hover:scale-105 motion-safe:group-focus-visible:scale-105 supports-[mix-blend-mode:plus-lighter]:group-hover:opacity-0 supports-[mix-blend-mode:plus-lighter]:group-focus-visible:opacity-0" src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?auto=format&fit=crop&w=900&h=675&q=70" alt="A modern house with large lit windows and a lawn at dusk" width="900" height="675"><img class="absolute inset-0 size-full object-cover transition-[opacity,scale] duration-[.7s,.9s] ease-[cubic-bezier(.2,.7,.2,1)] supports-[mix-blend-mode:plus-lighter]:mix-blend-plus-lighter opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" src="https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?auto=format&fit=crop&w=900&h=675&q=70" alt="Its open-plan living room with a white sofa and timber wall" width="900" height="675">
  <span class="absolute top-3 left-3 z-1 grid rounded-full bg-white/94 px-3 py-1.5 text-[.78rem] font-bold text-ink"><span class="[grid-area:1/1] transition-opacity duration-400 group-hover:opacity-0 group-focus-visible:opacity-0">Outside · 1/2</span><span class="[grid-area:1/1] opacity-0 transition-opacity duration-400 group-hover:opacity-100 group-focus-visible:opacity-100">Living room · 2/2</span></span></span>
  <span class="grid gap-0.5 px-[18px] pt-4 pb-[18px]"><b class="text-[1.1rem]">Cedar Ridge House</b><small class="text-[.88rem] text-muted">4 bed · 3 bath · 2,480 sq ft</small><strong class="mt-1.5 text-accent">$1,185,000</strong></span></a></div>
<div class="md:col-span-2"><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#56627a] uppercase">Container-query sized effect (280px and wide container)</span>
<div class="grid grid-cols-1 items-start gap-6 md:grid-cols-[280px_minmax(0,1fr)]">
  <div class="@container/mgcq"><a href="#" class="group relative block aspect-[4/3] overflow-hidden rounded-2xl bg-[#1e293b] text-white no-underline @min-[480px]/mgcq:aspect-video focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent"><img class="absolute inset-0 size-full object-cover transition-[scale] duration-700 ease-[cubic-bezier(.2,.7,.2,1)] motion-safe:group-hover:scale-105 motion-safe:group-focus-visible:scale-105" src="https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=600&h=450&q=70" alt="A straight road running between red rock cliffs" width="600" height="450">
    <span class="absolute inset-x-0 bottom-0 bg-[linear-gradient(to_top,rgba(15,23,42,.9),rgba(15,23,42,0))] px-[18px] pt-11 pb-4 text-[1.1rem] leading-[1.25] font-bold transition-opacity duration-300 @max-[480px]/mgcq:group-hover:opacity-0 @max-[480px]/mgcq:group-focus-visible:opacity-0 @min-[480px]/mgcq:px-6 @min-[480px]/mgcq:pt-[60px] @min-[480px]/mgcq:pb-5 @min-[480px]/mgcq:text-[1.35rem] touch:hidden" aria-hidden="true">Red Rock Road Trip</span>
    <span class="absolute inset-x-0 bottom-0 z-1 grid content-end gap-1.5 bg-[rgba(6,78,59,.95)] p-[18px] leading-[1.4] transition-[translate,opacity] duration-450 ease-[cubic-bezier(.2,.7,.2,1)] @max-[480px]/mgcq:translate-y-[101%] @min-[480px]/mgcq:inset-y-0 @min-[480px]/mgcq:left-auto @min-[480px]/mgcq:w-[min(46%,320px)] @min-[480px]/mgcq:content-center @min-[480px]/mgcq:p-6 @min-[480px]/mgcq:translate-x-[101%] group-hover:translate-x-0 group-focus-visible:translate-x-0 group-hover:translate-y-0 group-focus-visible:translate-y-0 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:translate-x-0! motion-reduce:translate-y-0! motion-reduce:opacity-0 touch:translate-x-0! touch:translate-y-0! touch:opacity-100!"><i class="text-[.72rem] font-bold tracking-[.12em] text-[#a7f3d0] uppercase not-italic">Road trip · 4 days</i><b class="text-[1.15rem] leading-[1.2]">Red Rock Road Trip</b><span class="text-[.9rem] text-[#d1fae5]">Two canyons, a ghost town and a night under dark skies.</span><strong class="text-[.95rem]">From $640</strong></span></a></div>
  <div class="@container/mgcq"><a href="#" class="group relative block aspect-[4/3] overflow-hidden rounded-2xl bg-[#1e293b] text-white no-underline @min-[480px]/mgcq:aspect-video focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-accent"><img class="absolute inset-0 size-full object-cover transition-[scale] duration-700 ease-[cubic-bezier(.2,.7,.2,1)] motion-safe:group-hover:scale-105 motion-safe:group-focus-visible:scale-105" src="https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1200&h=675&q=70" alt="Sunlight breaking over misty green hills and rocky outcrops" width="1200" height="675">
    <span class="absolute inset-x-0 bottom-0 bg-[linear-gradient(to_top,rgba(15,23,42,.9),rgba(15,23,42,0))] px-[18px] pt-11 pb-4 text-[1.1rem] leading-[1.25] font-bold transition-opacity duration-300 @max-[480px]/mgcq:group-hover:opacity-0 @max-[480px]/mgcq:group-focus-visible:opacity-0 @min-[480px]/mgcq:px-6 @min-[480px]/mgcq:pt-[60px] @min-[480px]/mgcq:pb-5 @min-[480px]/mgcq:text-[1.35rem] touch:hidden" aria-hidden="true">Highland Mist Weekend</span>
    <span class="absolute inset-x-0 bottom-0 z-1 grid content-end gap-1.5 bg-[rgba(6,78,59,.95)] p-[18px] leading-[1.4] transition-[translate,opacity] duration-450 ease-[cubic-bezier(.2,.7,.2,1)] @max-[480px]/mgcq:translate-y-[101%] @min-[480px]/mgcq:inset-y-0 @min-[480px]/mgcq:left-auto @min-[480px]/mgcq:w-[min(46%,320px)] @min-[480px]/mgcq:content-center @min-[480px]/mgcq:p-6 @min-[480px]/mgcq:translate-x-[101%] group-hover:translate-x-0 group-focus-visible:translate-x-0 group-hover:translate-y-0 group-focus-visible:translate-y-0 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:translate-x-0! motion-reduce:translate-y-0! motion-reduce:opacity-0 touch:translate-x-0! touch:translate-y-0! touch:opacity-100!"><i class="text-[.72rem] font-bold tracking-[.12em] text-[#a7f3d0] uppercase not-italic">Walking · 3 days</i><b class="text-[1.15rem] leading-[1.2]">Highland Mist Weekend</b><span class="text-[.9rem] text-[#d1fae5]">Ridge walks at sunrise, a bothy night and a distillery lunch.</span><strong class="text-[.95rem]">From $480</strong></span></a></div>
</div></div>
</div>
CSS
/* touch: screens without hover show the container-query detail panels */
@custom-variant touch (@media (hover: none));
@theme {
  --color-accent: #047857;
  --color-ink: #0f172a;
  --color-muted: #475569;
}
/* a registered angle can be animated, so the conic-gradient border spins */
@property --mg-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@keyframes mg-spin { to { --mg-angle: 360deg; } }

About this set

Four hover effects that used to need JavaScript, written in current CSS. Sibling dimming is a five-item shop gallery: hovering or focusing one product fades and greys the others, using :has() on the gallery to know that something inside is hovered. The animated gradient border registers an angle with @property, so a conic-gradient ring around two product cards can spin smoothly; without @property the ring still appears, it just does not turn. The crossfade swaps a house listing’s outside photo for its living room the way the View Transitions API does, fading both images against each other with mix-blend-mode: plus-lighter so the frame never dips in brightness, and the label changes from 1/2 to 2/2. The container-query card reveals its details from the bottom when its container is narrow and from the side when it is 480 pixels or wider, shown in a 280 pixel column and a wide one. Each technique falls back to a plain hover where the feature is missing.

What’s included

  • :has() dims every gallery item except the one hovered or focused
  • @property animates a conic-gradient border
  • plus-lighter crossfade between two photos with a fade fallback
  • Container queries switch the reveal direction by card width
  • Static ring and fades kept under reduced motion

Accessibility

Every card is one link with a descriptive name; in the crossfade both photos have their own alt text and the duplicated title is aria-hidden in the container-query card. Keyboard focus shows a 3px outline and triggers the same effect, including the :has() dimming. Under prefers-reduced-motion nothing lifts, zooms or spins and the detail panels fade in instead of sliding.

Customise it

Set --mg-accent, --mg-ink and --mg-muted on each component root, the colours inside --mg-ring for the border, and the 480px breakpoint in the @container rule. In Tailwind change the accent, ink and muted theme colours and the @min-[480px]/mgcq: utilities.