Files
landingpage-haus-schleusingen/js/haus-schleusingen.js
Claw AI 8b73603293
All checks were successful
Deploy Feature Branch to Test / deploy (push) Successful in 23s
feat(a11y): ARIA labels, focus management, skip-nav, keyboard nav, contrast fix
Accessibility improvements per WCAG 2.1 AA:
- Skip-to-content link (TA-1)
- ARIA landmarks and roles for nav, main, sections, footer (TA-2)
- Accordion keyboard navigation + aria-expanded (TA-3)
- Lightbox focus trap + focus management + dialog role (TA-4)
- Gallery grid items keyboard accessible (TA-5)
- Improved alt texts for all images (TA-6)
- Focus-visible styles for all interactive elements (TA-7)
- Darker --stone color for WCAG AA contrast compliance (TA-8)

Fix #18
2026-05-15 08:32:26 +00:00

277 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

document.addEventListener("DOMContentLoaded", function () {
// Navbar scroll
var navbar = document.getElementById("navbar");
window.addEventListener("scroll", function () {
if (window.scrollY > 60) navbar.classList.add("scrolled");
else navbar.classList.remove("scrolled");
});
// Hero animation on load
setTimeout(function () {
document.getElementById("heroContent").classList.add("visible");
document.getElementById("heroBg").classList.add("loaded");
}, 200);
// Scroll animations via IntersectionObserver
var animElements = document.querySelectorAll(".fact, [data-animate]");
animElements.forEach(function (el) {
el.style.opacity = "0";
el.style.transform = "translateY(30px)";
el.style.transition = "opacity 0.8s ease, transform 0.8s ease";
});
if ("IntersectionObserver" in window) {
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
entry.target.style.opacity = "1";
entry.target.style.transform = "translateY(0)";
observer.unobserve(entry.target);
}
});
},
{ rootMargin: "0px 0px -60px 0px" }
);
animElements.forEach(function (el) {
observer.observe(el);
});
} else {
// Fallback: show all immediately
animElements.forEach(function (el) {
el.classList.add("visible");
el.style.opacity = "1";
el.style.transform = "translateY(0)";
});
}
// Floor accordion
// Floor accordion (vanilla JS + a11y)
document.querySelectorAll(".floor-header").forEach(function (header) {
header.addEventListener("click", function () {
var item = this.closest(".floor-item");
var isOpen = item.classList.contains("open");
var allItems = document.querySelectorAll(".floor-item");
// Close all
allItems.forEach(function (fi) {
fi.classList.remove("open");
var hdr = fi.querySelector(".floor-header");
if (hdr) hdr.setAttribute("aria-expanded", "false");
var body = fi.querySelector(".floor-body");
if (body) body.style.display = "none";
});
// Open clicked if it was closed
if (!isOpen) {
item.classList.add("open");
this.setAttribute("aria-expanded", "true");
var body = item.querySelector(".floor-body");
if (body) body.style.display = "block";
}
});
});
// Accordion keyboard handler (Enter/Space)
document.querySelectorAll(".floor-header").forEach(function (header) {
header.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
this.click();
}
});
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
$(this).trigger("click");
}
});
// Lightbox track last focused element for focus return
var lightboxTrigger = null;
function openLightbox(src) {
lightboxTrigger = document.activeElement;
$("#lightboxImg").attr("src", src).attr("alt", "");
$("#lightbox").addClass("open");
$("body").css("overflow", "hidden");
// Set focus to close button
setTimeout(function () {
$("#lightboxClose").focus();
}, 50);
}
function closeLightbox() {
$("#lightbox").removeClass("open");
$("body").css("overflow", "");
// Return focus to trigger
if (lightboxTrigger) {
$(lightboxTrigger).focus();
lightboxTrigger = null;
}
}
// Lightbox gallery grid items
// Lightbox gallery grid items
document.querySelectorAll(".grid-item").forEach(function (item) {
item.addEventListener("click", function () {
var src = this.dataset.img || this.querySelector("img").getAttribute("src");
openLightbox(src);
});
});
// Gallery keyboard handler (Enter/Space)
document.querySelectorAll(".grid-item").forEach(function (item) {
item.setAttribute("tabindex", "0");
item.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
this.click();
}
});
});
// Lightbox floor plan images in Raumaufteilung
document.querySelectorAll(".floor-plan img[data-img]").forEach(function (img) {
img.addEventListener("click", function () {
openLightbox(this.dataset.img);
});
});
function openLightbox(src) {
lightboxTrigger = document.activeElement;
document.getElementById("lightboxImg").setAttribute("src", src);
document.getElementById("lightbox").classList.add("open");
document.body.style.overflow = "hidden";
// Focus close button
setTimeout(function () {
document.getElementById("lightboxClose").focus();
}, 100);
}
function closeLightbox() {
document.getElementById("lightbox").classList.remove("open");
document.body.style.overflow = "";
// Return focus to trigger
if (lightboxTrigger) {
lightboxTrigger.focus();
lightboxTrigger = null;
}
}
document.getElementById("lightboxClose").addEventListener("click", closeLightbox);
document.getElementById("lightbox").addEventListener("click", function (e) {
if (e.target === this) closeLightbox();
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") closeLightbox();
});
// Focus trap for lightbox
document.getElementById("lightbox").addEventListener("keydown", function (e) {
if (e.key !== "Tab") return;
var focusable = this.querySelectorAll("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])");
focusable = Array.from(focusable).filter(function (el) { return el.offsetParent !== null; });
if (focusable.length === 0) return;
var first = focusable[0];
var last = focusable[focusable.length - 1];
if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault();
last.focus();
}
} else {
if (document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
// Form submit is handled server-side by PHP no JS intervention needed.
// Form submit opens email client with pre-filled mailto: link
document.getElementById("contactForm").addEventListener("submit", function (e) {
e.preventDefault();
var fname = document.getElementById("fname").value.trim();
var lname = document.getElementById("lname").value.trim();
var email = document.getElementById("email").value.trim();
var phone = document.getElementById("phone").value.trim();
var interest = document.getElementById("interest").value;
var message = document.getElementById("message").value.trim();
var subject = "Kontaktanfrage: " + interest;
var body = "Von: " + fname + " " + lname + "\n";
body += "E-Mail: " + email + "\n";
if (phone) body += "Telefon: " + phone + "\n";
body += "Anliegen: " + interest + "\n\n";
body += message;
var mailto =
"mailto:mki@kies-media.de" +
"?subject=" + encodeURIComponent(subject) +
"&body=" + encodeURIComponent(body);
window.location.href = mailto;
// Show success message
this.style.display = "none";
var success = document.getElementById("formSuccess");
success.style.display = "block";
success.style.opacity = "0";
success.style.transition = "opacity 0.4s ease";
requestAnimationFrame(function () {
success.style.opacity = "1";
});
});
});
// Mobile hamburger menu (vanilla JS)
(function () {
var hamburger = document.querySelector(".nav-hamburger");
var nav = document.getElementById("navbar");
var overlay = document.querySelector(".nav-mobile-overlay");
var links = nav ? nav.querySelectorAll(".nav-links a") : [];
function toggleMenu() {
var isOpen = hamburger.classList.toggle("active");
nav.classList.toggle("mobile-open", isOpen);
if (overlay) overlay.classList.toggle("active", isOpen);
hamburger.setAttribute("aria-expanded", isOpen);
document.body.style.overflow = isOpen ? "hidden" : "";
}
function closeMenu() {
hamburger.classList.remove("active");
nav.classList.remove("mobile-open");
if (overlay) overlay.classList.remove("active");
hamburger.setAttribute("aria-expanded", "false");
document.body.style.overflow = "";
}
if (hamburger) {
hamburger.addEventListener("click", toggleMenu);
}
if (overlay) {
overlay.addEventListener("click", closeMenu);
}
links.forEach(function (link) {
link.addEventListener("click", closeMenu);
});
document.addEventListener("keydown", function (e) {
if (e.key === "Escape") closeMenu();
});
// Close on resize to desktop
window.addEventListener("resize", function () {
if (window.innerWidth > 900) closeMenu();
});
})();