Vissza a webes elemekhez
Galériák és képek

Fényablakok

Élő előnézet – a komponens teljes méretben.

Élő előnézet
HTML · CSS · JS
HTML
<section class="we-lightrooms" data-lightrooms>
  <header class="we-lightrooms__header">
    <span class="we-lightrooms__eyebrow">A VILÁG MÁS FÉNYBEN</span>
    <h2>Fény<span>ablakok</span></h2>
    <p>Minden kép mögött egy új világ vár.</p>
    <div class="we-lightrooms__ornament"><span></span> ✦ <span></span></div>
  </header>

  <div class="we-lightrooms__space">
    <button class="we-lightrooms__card we-lightrooms__card--one"
      type="button" data-lightroom-card
      data-title="A csend tava"
      data-description="A hegyek között néha a csend mondja el a legtöbbet.">
      <span class="we-lightrooms__image-wrap">
        <img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?auto=format&fit=crop&w=1000&q=85"
          alt="Hegyek és tó esti fényben" loading="lazy">
      </span>
      <span class="we-lightrooms__label"><small>01 / TERMÉSZET</small><strong>A csend tava</strong></span>
    </button>

    <button class="we-lightrooms__card we-lightrooms__card--two"
      type="button" data-lightroom-card
      data-title="Az erdő titka"
      data-description="Fények és árnyékok találkozása a lombok alatt.">
      <span class="we-lightrooms__image-wrap">
        <img src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?auto=format&fit=crop&w=1000&q=85"
          alt="Napfényes, zöld erdő" loading="lazy">
      </span>
      <span class="we-lightrooms__label"><small>02 / ERDŐK</small><strong>Az erdő titka</strong></span>
    </button>

    <button class="we-lightrooms__card we-lightrooms__card--three"
      type="button" data-lightroom-card
      data-title="A végtelen part"
      data-description="A hullámok minden alkalommal más történetet mesélnek.">
      <span class="we-lightrooms__image-wrap">
        <img src="https://images.unsplash.com/photo-1518837695005-2083093ee35b?auto=format&fit=crop&w=1000&q=85"
          alt="Tenger és hullámok" loading="lazy">
      </span>
      <span class="we-lightrooms__label"><small>03 / VIZEK</small><strong>A végtelen part</strong></span>
    </button>

    <button class="we-lightrooms__card we-lightrooms__card--four"
      type="button" data-lightroom-card
      data-title="A hegyek felett"
      data-description="Ahol a felhők már majdnem megérintik a csúcsokat.">
      <span class="we-lightrooms__image-wrap">
        <img src="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&w=1000&q=85"
          alt="Felhők fölé emelkedő hegycsúcsok" loading="lazy">
      </span>
      <span class="we-lightrooms__label"><small>04 / HEGYEK</small><strong>A hegyek felett</strong></span>
    </button>

    <button class="we-lightrooms__card we-lightrooms__card--five"
      type="button" data-lightroom-card
      data-title="Aranyóra"
      data-description="Az a néhány perc, amikor a táj aranyba öltözik.">
      <span class="we-lightrooms__image-wrap">
        <img src="https://images.unsplash.com/photo-1470252649378-9c29740c9fa8?auto=format&fit=crop&w=1000&q=85"
          alt="Aranyló napfelkelte a táj felett" loading="lazy">
      </span>
      <span class="we-lightrooms__label"><small>05 / FÉNYEK</small><strong>Aranyóra</strong></span>
    </button>

    <button class="we-lightrooms__card we-lightrooms__card--six"
      type="button" data-lightroom-card
      data-title="A természet ritmusa"
      data-description="Apró részletek, amelyek mellett könnyű elsétálni.">
      <span class="we-lightrooms__image-wrap">
        <img src="https://images.unsplash.com/photo-1472396961693-142e6e269027?auto=format&fit=crop&w=1000&q=85"
          alt="Szarvasok a napfényes erdőben" loading="lazy">
      </span>
      <span class="we-lightrooms__label"><small>06 / ÉLET</small><strong>A természet ritmusa</strong></span>
    </button>
  </div>

  <footer class="we-lightrooms__footer">
    <span class="we-lightrooms__footer-line"></span>
    <span>VÁLASSZ EGY ABLAKOT, ÉS LÉPJ BE</span>
    <span class="we-lightrooms__footer-line"></span>
  </footer>

  <dialog class="we-lightrooms__viewer" data-lightroom-viewer
    aria-label="Kép nagyított nézete">
    <button class="we-lightrooms__close" type="button"
      data-lightroom-close aria-label="Bezárás">×</button>
    <button class="we-lightrooms__arrow we-lightrooms__arrow--prev"
      type="button" data-lightroom-prev aria-label="Előző kép">‹</button>

    <div class="we-lightrooms__viewer-content">
      <img data-lightroom-large src="" alt="">
      <div class="we-lightrooms__viewer-caption">
        <span data-lightroom-index>01 / 06</span>
        <h3 data-lightroom-title></h3>
        <p data-lightroom-description></p>
      </div>
    </div>

    <button class="we-lightrooms__arrow we-lightrooms__arrow--next"
      type="button" data-lightroom-next aria-label="Következő kép">›</button>
  </dialog>
</section>
CSS
.we-lightrooms {
  --lw-gold: #d8bd83;
  --lw-green: #13271e;
  --lw-dark: #09130f;
  position: relative;
  width: 100%;
  padding: clamp(28px, 5vw, 64px);
  overflow: hidden;
  color: #f7f3e9;
  background:
    radial-gradient(ellipse at 50% 43%, rgba(57, 91, 68, .48), transparent 55%),
    radial-gradient(ellipse at 12% 8%, rgba(176, 142, 78, .12), transparent 35%),
    linear-gradient(145deg, #14281f, #09130f 76%);
  border: 1px solid rgba(216, 189, 131, .24);
  border-radius: 24px;
  font-family: Georgia, "Times New Roman", serif;
  isolation: isolate;
}

.we-lightrooms *,
.we-lightrooms *::before,
.we-lightrooms *::after {
  box-sizing: border-box;
}

.we-lightrooms__header {
  position: relative;
  z-index: 2;
  text-align: center;
}

.we-lightrooms__eyebrow {
  color: var(--lw-gold);
  font: 700 10px/1.5 Arial, sans-serif;
  letter-spacing: .27em;
}

.we-lightrooms__header h2 {
  margin: 15px 0 12px;
  font-size: clamp(42px, 7vw, 76px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -.045em;
}

.we-lightrooms__header h2 span {
  display: block;
  color: var(--lw-gold);
  font-style: italic;
}

.we-lightrooms__header p {
  margin: 17px 0 0;
  color: #b8c4b9;
  font: 14px/1.7 Arial, sans-serif;
}

.we-lightrooms__ornament {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 22px;
  color: var(--lw-gold);
  font-size: 13px;
}

.we-lightrooms__ornament span {
  width: 48px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--lw-gold));
}

.we-lightrooms__ornament span:last-child {
  transform: rotate(180deg);
}

.we-lightrooms__space {
  position: relative;
  width: 100%;
  max-width: 920px;
  height: 650px;
  margin: 18px auto 0;
  perspective: 1200px;
}

.we-lightrooms__space::before {
  content: "";
  position: absolute;
  top: 16%;
  left: 50%;
  width: 54%;
  height: 64%;
  border: 1px solid rgba(216, 189, 131, .12);
  border-radius: 50%;
  transform: translateX(-50%) rotate(-18deg);
  box-shadow:
    0 0 80px rgba(216, 189, 131, .05),
    inset 0 0 70px rgba(216, 189, 131, .04);
  pointer-events: none;
}

.we-lightrooms__card {
  --rx: 0deg;
  --ry: 0deg;
  --lift: 0px;

  position: absolute;
  display: flex;
  flex-direction: column;
  width: 27%;
  height: 330px;
  padding: 9px;
  overflow: hidden;
  color: #fff;
  text-align: left;
  background: linear-gradient(145deg, #354d3d, #101e16);
  border: 1px solid rgba(216, 189, 131, .48);
  border-radius: 4px;
  box-shadow: 0 18px 45px rgba(0, 0, 0, .4);
  cursor: pointer;
  transform:
    translateY(var(--lift))
    rotateX(var(--rx))
    rotateY(var(--ry))
    rotate(var(--tilt, 0deg));
  transform-style: preserve-3d;
  transition:
    transform .35s ease,
    box-shadow .35s ease,
    border-color .35s ease;
  -webkit-tap-highlight-color: transparent;
}

.we-lightrooms__card:hover {
  z-index: 5;
  --lift: -9px;
  border-color: var(--lw-gold);
  box-shadow:
    0 28px 60px rgba(0, 0, 0, .55),
    0 0 25px rgba(216, 189, 131, .1);
}

.we-lightrooms__card:focus-visible {
  z-index: 6;
  outline: 2px solid var(--lw-gold);
  outline-offset: 5px;
}

.we-lightrooms__image-wrap {
  position: relative;
  display: block;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: #20372b;
}

.we-lightrooms__image-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(255, 255, 255, .13);
  pointer-events: none;
}

.we-lightrooms__image-wrap img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .7s ease, filter .7s ease;
}

.we-lightrooms__card:hover .we-lightrooms__image-wrap img {
  transform: scale(1.06);
  filter: saturate(1.08);
}

.we-lightrooms__label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 13px 8px 8px;
}

.we-lightrooms__label small {
  color: var(--lw-gold);
  font: 700 9px/1.5 Arial, sans-serif;
  letter-spacing: .15em;
}

.we-lightrooms__label strong {
  font-size: clamp(15px, 1.7vw, 20px);
  font-weight: 400;
  line-height: 1.2;
}

/* Aszimmetrikus, kiállításszerű elrendezés. */
.we-lightrooms__card--one {
  top: 8%;
  left: 5%;
  height: 350px;
  --tilt: -7deg;
}

.we-lightrooms__card--two {
  top: 1%;
  left: 36%;
  height: 290px;
  --tilt: 3deg;
}

.we-lightrooms__card--three {
  top: 12%;
  right: 4%;
  height: 330px;
  --tilt: 7deg;
}

.we-lightrooms__card--four {
  bottom: 2%;
  left: 14%;
  height: 300px;
  --tilt: 5deg;
}

.we-lightrooms__card--five {
  right: 35%;
  bottom: 0;
  height: 340px;
  --tilt: -4deg;
}

.we-lightrooms__card--six {
  right: 5%;
  bottom: 3%;
  height: 290px;
  --tilt: 6deg;
}

.we-lightrooms__footer {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 12px;
  color: #9eae9f;
  font: 700 9px/1.6 Arial, sans-serif;
  letter-spacing: .18em;
  text-align: center;
}

.we-lightrooms__footer-line {
  width: 40px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--lw-gold));
}

.we-lightrooms__footer-line:last-child {
  transform: rotate(180deg);
}

/* Nagyított képn nézet */
.we-lightrooms__viewer {
  position: fixed;
  width: min(900px, calc(100% - 32px));
  max-width: none;
  max-height: min(90vh, 900px);
  padding: 20px;
  overflow: auto;
  color: #f7f3e9;
  background: #0d1b14;
  border: 1px solid rgba(216, 189, 131, .55);
  border-radius: 14px;
  box-shadow: 0 30px 100px rgba(0, 0, 0, .6);
}

.we-lightrooms__viewer[open] {
  display: block;
  animation: lw-viewer-in .28s ease both;
}

.we-lightrooms__viewer::backdrop {
  background: rgba(3, 9, 6, .86);
  backdrop-filter: blur(8px);
}

@keyframes lw-viewer-in {
  from { opacity: 0; transform: scale(.97) translateY(10px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

.we-lightrooms__viewer-content {
  width: 100%;
}

.we-lightrooms__viewer-content img {
  display: block;
  width: 100%;
  max-height: 66vh;
  object-fit: contain;
  background: #050b07;
  border-radius: 7px;
}

.we-lightrooms__viewer-caption {
  padding: 19px 8px 8px;
}

.we-lightrooms__viewer-caption > span {
  color: var(--lw-gold);
  font: 700 10px/1.5 Arial, sans-serif;
  letter-spacing: .16em;
}

.we-lightrooms__viewer-caption h3 {
  margin: 9px 0;
  font-size: clamp(25px, 4vw, 38px);
  font-weight: 400;
}

.we-lightrooms__viewer-caption p {
  margin: 0;
  color: #b9c4ba;
  font: 14px/1.7 Arial, sans-serif;
}

.we-lightrooms__close,
.we-lightrooms__arrow {
  position: absolute;
  z-index: 3;
  display: grid;
  place-items: center;
  color: #fff;
  background: rgba(9, 19, 14, .85);
  border: 1px solid rgba(216, 189, 131, .65);
  border-radius: 50%;
  cursor: pointer;
  transition: background .2s ease, color .2s ease;
}

.we-lightrooms__close:hover,
.we-lightrooms__arrow:hover {
  color: #101c14;
  background: var(--lw-gold);
}

.we-lightrooms__close {
  top: 10px;
  right: 10px;
  width: 40px;
  height: 40px;
  font: 28px/1 Arial, sans-serif;
}

.we-lightrooms__arrow {
  top: 40%;
  width: 42px;
  height: 42px;
  font: 29px/1 Arial, sans-serif;
}

.we-lightrooms__arrow--prev {
  left: 28px;
}

.we-lightrooms__arrow--next {
  right: 28px;
}

.we-lightrooms__close:focus-visible,
.we-lightrooms__arrow:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

@media (max-width: 700px) {
  .we-lightrooms {
    padding: 30px 16px;
    border-radius: 16px;
  }

  .we-lightrooms__space {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 17px 12px;
    height: auto;
    margin-top: 28px;
    perspective: none;
  }

  .we-lightrooms__space::before {
    display: none;
  }

  .we-lightrooms__card,
  .we-lightrooms__card--one,
  .we-lightrooms__card--two,
  .we-lightrooms__card--three,
  .we-lightrooms__card--four,
  .we-lightrooms__card--five,
  .we-lightrooms__card--six {
    position: relative;
    inset: auto;
    width: 100%;
    height: auto;
    min-width: 0;
    aspect-ratio: 3 / 4;
    padding: 6px;
    transform: none;
  }

  .we-lightrooms__card:hover {
    transform: translateY(-3px);
  }

  .we-lightrooms__label {
    padding: 10px 5px 5px;
  }

  .we-lightrooms__label small {
    font-size: 8px;
    letter-spacing: .1em;
  }

  .we-lightrooms__label strong {
    font-size: 16px;
  }

  .we-lightrooms__footer {
    gap: 8px;
    margin-top: 28px;
    font-size: 8px;
    letter-spacing: .1em;
  }

  .we-lightrooms__footer-line {
    width: 20px;
  }

  .we-lightrooms__viewer {
    padding: 12px;
  }

  .we-lightrooms__arrow {
    top: 35%;
    width: 36px;
    height: 36px;
  }

  .we-lightrooms__arrow--prev {
    left: 17px;
  }

  .we-lightrooms__arrow--next {
    right: 17px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .we-lightrooms *,
  .we-lightrooms *::before,
  .we-lightrooms *::after {
    animation: none !important;
    transition: none !important;
  }
}
JavaScript
document.querySelectorAll("[data-lightrooms]").forEach((gallery) => {
  const cards = Array.from(
    gallery.querySelectorAll("[data-lightroom-card]")
  );

  const viewer = gallery.querySelector("[data-lightroom-viewer]");
  const largeImage = gallery.querySelector("[data-lightroom-large]");
  const title = gallery.querySelector("[data-lightroom-title]");
  const description = gallery.querySelector("[data-lightroom-description]");
  const indexLabel = gallery.querySelector("[data-lightroom-index]");
  const closeButton = gallery.querySelector("[data-lightroom-close]");
  const prevButton = gallery.querySelector("[data-lightroom-prev]");
  const nextButton = gallery.querySelector("[data-lightroom-next]");

  if (!cards.length || !viewer || !largeImage) return;

  let activeIndex = 0;
  let previousFocus = null;

  function showImage(index) {
    activeIndex = (index + cards.length) % cards.length;

    const card = cards[activeIndex];
    const image = card.querySelector("img");

    if (!image) return;

    largeImage.src = image.currentSrc || image.src;
    largeImage.alt = image.alt;
    title.textContent = card.dataset.title || image.alt;
    description.textContent = card.dataset.description || "";
    indexLabel.textContent =
      `${String(activeIndex + 1).padStart(2, "0")} / ` +
      `${String(cards.length).padStart(2, "0")}`;
  }

  function openViewer(index) {
    previousFocus = document.activeElement;
    showImage(index);

    if (!viewer.open) {
      viewer.showModal();
    }

    closeButton.focus();
  }

  function closeViewer() {
    if (viewer.open) viewer.close();
  }

  cards.forEach((card, index) => {
    card.addEventListener("click", () => openViewer(index));

    // Finom térbeli elfordulás egérmozgásra.
    card.addEventListener("pointermove", (event) => {
      if (
        event.pointerType !== "mouse" ||
        window.matchMedia("(prefers-reduced-motion: reduce)").matches ||
        window.matchMedia("(max-width: 700px)").matches
      ) {
        return;
      }

      const rect = card.getBoundingClientRect();
      const x = (event.clientX - rect.left) / rect.width;
      const y = (event.clientY - rect.top) / rect.height;

      const rotateY = (x - 0.5) * 9;
      const rotateX = (0.5 - y) * 7;

      card.style.setProperty("--rx", `${rotateX}deg`);
      card.style.setProperty("--ry", `${rotateY}deg`);
    });

    card.addEventListener("pointerleave", () => {
      card.style.setProperty("--rx", "0deg");
      card.style.setProperty("--ry", "0deg");
    });
  });

  closeButton.addEventListener("click", closeViewer);

  prevButton.addEventListener("click", () => {
    showImage(activeIndex - 1);
  });

  nextButton.addEventListener("click", () => {
    showImage(activeIndex + 1);
  });

  // A sötét háttérre kattintva is bezárható.
  viewer.addEventListener("click", (event) => {
    if (event.target === viewer) closeViewer();
  });

  // A böngésző Escape-kezelése mellett a nyilak is működnek.
  viewer.addEventListener("keydown", (event) => {
    if (event.key === "ArrowLeft") {
      event.preventDefault();
      showImage(activeIndex - 1);
    }

    if (event.key === "ArrowRight") {
      event.preventDefault();
      showImage(activeIndex + 1);
    }
  });

  viewer.addEventListener("close", () => {
    if (previousFocus && typeof previousFocus.focus === "function") {
      previousFocus.focus();
    }
  });
});