7 Commits

Author SHA1 Message Date
Claw AI
9e146ac1eb 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-13 23:13:47 +00:00
88780c300a Merge pull request 'Fix #15: Kontaktformular – mailto:-Integration für echte Anfragen' (#20) from feature/issue-15-kontaktformular-backend into main
Reviewed-on: #20
2026-05-14 00:45:55 +02:00
Claw
cc7b2d8d70 fix(kontakt): replace simulated form submit with mailto: link
- Generate mailto: link with all form data on submit
- Opens user's email client with pre-filled email to mki@kies-media.de
- Subject includes interest type, body contains all form fields
- Update success message to reflect email client behavior
- Remove fake setTimeout simulation

Fix #15
2026-05-13 22:39:42 +00:00
ea85280cde Merge pull request 'Fix #11: Kontakt-Section mit Email hinzufügen' (#14) from feature/issue-11 into main
Reviewed-on: #14
2026-05-11 12:50:05 +02:00
958f52fd5d Fix #11: Kontakt-Section mit Email hinzufügen
- Email mki@kies-media.de als direkter Kontaktlink unter dem Formular
- Neues .contact-details CSS passend zum bestehenden Design
- Minimaler Eingriff: bestehendes Design bleibt erhalten
2026-05-11 06:38:28 +00:00
9c68365ab8 Merge pull request 'Fix #4: Impressum-Link im Footer hinzufügen' (#5) from feature/issue-4 into main
Reviewed-on: #5
2026-05-10 23:00:47 +02:00
5b304730fa feat: update Impressum-Link im Footer (Issue #4) 2026-05-10 21:22:14 +02:00
3 changed files with 227 additions and 65 deletions

View File

@@ -1,7 +1,55 @@
/* SKIP LINK */
.skip-link {
position: absolute;
left: -9999px;
top: 0;
background: var(--accent);
color: var(--white);
padding: 0.75rem 1.5rem;
font-size: 0.85rem;
font-weight: 500;
z-index: 200;
text-decoration: none;
transition: none;
}
.skip-link:focus {
left: 0;
outline: 2px solid var(--white);
outline-offset: 2px;
}
/* FOCUS VISIBLE */
*:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.lightbox-close:focus-visible {
outline: 2px solid var(--white);
outline-offset: 2px;
}
button:focus-visible,
a:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.grid-item:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.floor-header:focus-visible {
outline: 2px solid var(--accent);
outline-offset: -2px;
}
:root { :root {
--cream: #f5f0e8; --cream: #f5f0e8;
--warm: #e8dfd0; --warm: #e8dfd0;
--stone: #9e9485; --stone: #7a7062;
--dark: #1c1a17; --dark: #1c1a17;
--charcoal: #2e2b26; --charcoal: #2e2b26;
--accent: #8b6914; --accent: #8b6914;
@@ -928,6 +976,29 @@ nav.scrolled .nav-links a:hover {
color: var(--stone); color: var(--stone);
} }
.contact-details {
text-align: center;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid var(--warm);
}
.contact-details p {
font-size: 0.95rem;
color: var(--stone);
}
.contact-details a {
color: var(--accent);
text-decoration: none;
font-weight: 600;
transition: color 0.2s;
}
.contact-details a:hover {
color: var(--accent-light);
}
/* FOOTER */ /* FOOTER */
footer { footer {
background: var(--dark); background: var(--dark);

View File

@@ -9,7 +9,8 @@
<link rel="stylesheet" href="css/haus-schleusingen.css" /> <link rel="stylesheet" href="css/haus-schleusingen.css" />
</head> </head>
<body> <body>
<nav id="navbar"> <a href="#main-content" class="skip-link">Zum Inhalt springen</a>
<nav id="navbar" role="navigation" aria-label="Hauptnavigation">
<div class="nav-logo">Bahnhofstraße 10</div> <div class="nav-logo">Bahnhofstraße 10</div>
<ul class="nav-links"> <ul class="nav-links">
<li><a href="#galerie">Galerie</a></li> <li><a href="#galerie">Galerie</a></li>
@@ -54,6 +55,7 @@
</div> </div>
</section> </section>
<main id="main-content">
<div class="facts-strip"> <div class="facts-strip">
<div class="fact"> <div class="fact">
<div class="fact-val">227</div> <div class="fact-val">227</div>
@@ -107,7 +109,7 @@
</div> </div>
</section> </section>
<section id="galerie" class="gallery-section"> <section id="galerie" class="gallery-section" aria-label="Fotogalerie">
<div class="gallery-header"> <div class="gallery-header">
<div> <div>
<div class="section-eyebrow">Fotogalerie</div> <div class="section-eyebrow">Fotogalerie</div>
@@ -117,54 +119,54 @@
<div class="masonry-grid"> <div class="masonry-grid">
<div class="grid-sizer"></div> <div class="grid-sizer"></div>
<div class="grid-item" data-img="bilder/Außenansicht-2.png"> <div class="grid-item" data-img="bilder/Außenansicht-2.png" role="button" tabindex="0" aria-label="Außenansicht Großansicht öffnen">
<img src="bilder/Außenansicht-2-small.png" alt="Außenansicht" /> <img src="bilder/Außenansicht-2-small.png" alt="Außenansicht des Einfamilienhauses" />
<span class="grid-item-label">Außenansicht</span> <span class="grid-item-label">Außenansicht</span>
</div> </div>
<div class="grid-item" data-img="bilder/wohnzimmer2.png"> <div class="grid-item" data-img="bilder/wohnzimmer2.png" role="button" tabindex="0" aria-label="Wohnzimmer Großansicht öffnen">
<img src="bilder/wohnzimmer2-small.png" alt="Wohnzimmer" /> <img src="bilder/wohnzimmer2-small.png" alt="Wohnzimmer mit 42,6 m² Wohnfläche" />
<span class="grid-item-label">Wohnzimmer · 42,6 m²</span> <span class="grid-item-label">Wohnzimmer · 42,6 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/Küche 1.jpg"> <div class="grid-item" data-img="bilder/Küche 1.jpg" role="button" tabindex="0" aria-label="Küche Großansicht öffnen">
<img src="bilder/Küche 1.jpg" alt="Küche" /> <img src="bilder/Küche 1.jpg" alt="Küche mit 18,4 m²" />
<span class="grid-item-label">Küche · 18,4 m²</span> <span class="grid-item-label">Küche · 18,4 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/schlafzimmer.png"> <div class="grid-item" data-img="bilder/schlafzimmer.png" role="button" tabindex="0" aria-label="Schlafzimmer Großansicht öffnen">
<img src="bilder/schlafzimmer-small.png" alt="Schlafzimmer" /> <img src="bilder/schlafzimmer-small.png" alt="Schlafzimmer mit 18 m²" />
<span class="grid-item-label">Schlafzimmer · 18 m²</span> <span class="grid-item-label">Schlafzimmer · 18 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/Bad.jpg"> <div class="grid-item" data-img="bilder/Bad.jpg" role="button" tabindex="0" aria-label="Badezimmer Großansicht öffnen">
<img src="bilder/Bad.jpg" alt="Badezimmer" /> <img src="bilder/Bad.jpg" alt="Badezimmer mit 9,8 m²" />
<span class="grid-item-label">Badezimmer · 9,8 m²</span> <span class="grid-item-label">Badezimmer · 9,8 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/Kinderzimmer.png"> <div class="grid-item" data-img="bilder/Kinderzimmer.png" role="button" tabindex="0" aria-label="Kinderzimmer 1 Großansicht öffnen">
<img src="bilder/Kinderzimmer-small.png" alt="Kinderzimmer 1" /> <img src="bilder/Kinderzimmer-small.png" alt="Kinderzimmer 1 mit 21,7 m²" />
<span class="grid-item-label">Kinderzimmer 1 · 21,7 m²</span> <span class="grid-item-label">Kinderzimmer 1 · 21,7 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/Kinderzimmer 2.jpg"> <div class="grid-item" data-img="bilder/Kinderzimmer 2.jpg" role="button" tabindex="0" aria-label="Kinderzimmer 2 Großansicht öffnen">
<img src="bilder/Kinderzimmer 2-small.png" alt="Kinderzimmer 2" /> <img src="bilder/Kinderzimmer 2-small.png" alt="Kinderzimmer 2 mit 15,7 m²" />
<span class="grid-item-label">Kinderzimmer 2 · 15,7 m²</span> <span class="grid-item-label">Kinderzimmer 2 · 15,7 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/kinderzimmer 2 2.jpeg"> <div class="grid-item" data-img="bilder/kinderzimmer 2 2.jpeg" role="button" tabindex="0" aria-label="Kinderzimmer Detail Großansicht öffnen">
<img src="bilder/kinderzimmer 2 2-small.png" alt="Kinderzimmer Detail" /> <img src="bilder/kinderzimmer 2 2-small.png" alt="Detailansicht Kinderzimmer" />
<span class="grid-item-label">Kinderzimmer Detail</span> <span class="grid-item-label">Kinderzimmer Detail</span>
</div> </div>
<div class="grid-item" data-img="bilder/Kinderzimmer 3.jpg"> <div class="grid-item" data-img="bilder/Kinderzimmer 3.jpg" role="button" tabindex="0" aria-label="Gästezimmer Großansicht öffnen">
<img src="bilder/Kinderzimmer 3-small.png" alt="Kinderzimmer 3" /> <img src="bilder/Kinderzimmer 3-small.png" alt="Gästezimmer mit 11,5 m²" />
<span class="grid-item-label">Gästezimmer · 11,5 m²</span> <span class="grid-item-label">Gästezimmer · 11,5 m²</span>
</div> </div>
<div class="grid-item" data-img="bilder/Bad-2.jpg"> <div class="grid-item" data-img="bilder/Bad-2.jpg" role="button" tabindex="0" aria-label="Zweites Bad Großansicht öffnen">
<img src="bilder/Bad-2-small.jpg" alt="Wohnbereich Detail 1" /> <img src="bilder/Bad-2-small.jpg" alt="Zweites Badezimmer im Haus" />
<span class="grid-item-label">Wohnbereich</span> <span class="grid-item-label">Wohnbereich</span>
</div> </div>
<div class="grid-item" data-img="bilder/bad3.jpg"> <div class="grid-item" data-img="bilder/bad3.jpg" role="button" tabindex="0" aria-label="Drittes Bad Großansicht öffnen">
<img src="bilder/Bad-3-small.jpg" alt="Wohnbereich Detail 2" /> <img src="bilder/Bad-3-small.jpg" alt="Drittes Badezimmer im Haus" />
<span class="grid-item-label">Wohnbereich Detail</span> <span class="grid-item-label">Wohnbereich Detail</span>
</div> </div>
<div class="grid-item" data-img="bilder/WhatsApp Image 2026-03-30 at 07.50.42 (2).jpeg"> <div class="grid-item" data-img="bilder/WhatsApp Image 2026-03-30 at 07.50.42 (2).jpeg" role="button" tabindex="0" aria-label="Hausansicht Großansicht öffnen">
<img <img
src="bilder/WhatsApp Image 2026-03-30 at 07.50.42 (2).jpeg" src="bilder/WhatsApp Image 2026-03-30 at 07.50.42 (2).jpeg"
alt="Wohnbereich Detail 3" alt="Weitere Außenansicht des Einfamilienhauses"
/> />
<span class="grid-item-label">Hausansicht</span> <span class="grid-item-label">Hausansicht</span>
</div> </div>
@@ -176,14 +178,14 @@
<h2>Großzügig auf allen Etagen</h2> <h2>Großzügig auf allen Etagen</h2>
<div class="floor-accordion"> <div class="floor-accordion">
<div class="floor-item"> <div class="floor-item">
<div class="floor-header"> <div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-0" id="floor-title-0">
<span class="floor-title">Erdgeschoss</span> <span class="floor-title">Erdgeschoss</span>
<div class="floor-size"> <div class="floor-size">
<span>99,5 m²</span> <span>99,5 m²</span>
<div class="floor-icon">+</div> <div class="floor-icon">+</div>
</div> </div>
</div> </div>
<div class="floor-body"> <div class="floor-body" id="floor-body-0" role="region" aria-labelledby="floor-title-0">
<div class="floor-rooms-grid"> <div class="floor-rooms-grid">
<div class="room-chip"> <div class="room-chip">
Flur Flur
@@ -225,14 +227,14 @@
</div> </div>
</div> </div>
<div class="floor-item"> <div class="floor-item">
<div class="floor-header"> <div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-1" id="floor-title-1">
<span class="floor-title">1. Obergeschoss</span> <span class="floor-title">1. Obergeschoss</span>
<div class="floor-size"> <div class="floor-size">
<span>120,4 m²</span> <span>120,4 m²</span>
<div class="floor-icon">+</div> <div class="floor-icon">+</div>
</div> </div>
</div> </div>
<div class="floor-body"> <div class="floor-body" id="floor-body-1" role="region" aria-labelledby="floor-title-1">
<div class="floor-rooms-grid"> <div class="floor-rooms-grid">
<div class="room-chip"> <div class="room-chip">
Flur Flur
@@ -274,14 +276,14 @@
</div> </div>
</div> </div>
<div class="floor-item"> <div class="floor-item">
<div class="floor-header"> <div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-2" id="floor-title-2">
<span class="floor-title">2. Obergeschoss</span> <span class="floor-title">2. Obergeschoss</span>
<div class="floor-size"> <div class="floor-size">
<span>68 m²</span> <span>68 m²</span>
<div class="floor-icon">+</div> <div class="floor-icon">+</div>
</div> </div>
</div> </div>
<div class="floor-body"> <div class="floor-body" id="floor-body-2" role="region" aria-labelledby="floor-title-2">
<div class="floor-rooms-grid"> <div class="floor-rooms-grid">
<div class="room-chip"> <div class="room-chip">
Flur Flur
@@ -323,14 +325,14 @@
</div> </div>
</div> </div>
<div class="floor-item"> <div class="floor-item">
<div class="floor-header"> <div class="floor-header" role="button" tabindex="0" aria-expanded="false" aria-controls="floor-body-3" id="floor-title-3">
<span class="floor-title">Dachboden</span> <span class="floor-title">Dachboden</span>
<div class="floor-size"> <div class="floor-size">
<span>94 m² Nutzfläche</span> <span>94 m² Nutzfläche</span>
<div class="floor-icon">+</div> <div class="floor-icon">+</div>
</div> </div>
</div> </div>
<div class="floor-body"> <div class="floor-body" id="floor-body-3" role="region" aria-labelledby="floor-title-3">
<div class="floor-rooms-grid"> <div class="floor-rooms-grid">
<div class="room-chip"> <div class="room-chip">
Dachboden unten (ungeheizt) Dachboden unten (ungeheizt)
@@ -362,7 +364,7 @@
</div> </div>
</section> </section>
<section class="pricing-section" id="miete"> <section class="pricing-section" id="miete" aria-label="Mietkonditionen">
<div class="pricing-inner"> <div class="pricing-inner">
<div class="section-eyebrow">Mietkonditionen</div> <div class="section-eyebrow">Mietkonditionen</div>
<h2>Transparente Preisgestaltung</h2> <h2>Transparente Preisgestaltung</h2>
@@ -460,7 +462,7 @@
</div> </div>
</section> </section>
<section class="contact-section" id="kontakt"> <section class="contact-section" id="kontakt" aria-label="Kontaktformular">
<div class="contact-inner"> <div class="contact-inner">
<div class="section-eyebrow">Kontakt</div> <div class="section-eyebrow">Kontakt</div>
<h2> <h2>
@@ -527,23 +529,27 @@
<div class="form-success" id="formSuccess"> <div class="form-success" id="formSuccess">
<p>Vielen Dank für Ihre Anfrage!</p> <p>Vielen Dank für Ihre Anfrage!</p>
<br /> <br />
<small>Wir melden uns schnellstmöglich bei Ihnen.</small> <small>Ihr E-Mail-Programm wurde geöffnet. Bitte senden Sie die E-Mail ab, damit Ihre Anfrage bei uns eingeht.</small>
</div> </div>
</div> </div>
<div class="contact-details">
<p>Oder schreiben Sie uns direkt: <a href="mailto:mki@kies-media.de">mki@kies-media.de</a></p>
</div>
</div> </div>
</section> </section>
<footer> </main>
<footer role="contentinfo">
<div class="footer-logo">Bahnhofstraße 10 · Schleusingen</div> <div class="footer-logo">Bahnhofstraße 10 · Schleusingen</div>
<div class="footer-links"> <div class="footer-links">
<a href="#">Impressum</a> <a href="/impressum" target="_blank">Impressum</a>
<a href="#">Datenschutz</a> <a href="#">Datenschutz</a>
</div> </div>
</footer> </footer>
<div class="lightbox" id="lightbox"> <div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-label="Bildansicht">
<button class="lightbox-close" id="lightboxClose">&times;</button> <button class="lightbox-close" id="lightboxClose" aria-label="Bildansicht schließen">&times;</button>
<img src="" id="lightboxImg" alt="Vollbild" /> <img src="" id="lightboxImg" alt="" />
</div> </div>
<script src="js/haus-schleusingen.js"></script> <script src="js/haus-schleusingen.js"></script>

View File

@@ -36,49 +36,134 @@ $(function () {
var item = $(this).closest(".floor-item"); var item = $(this).closest(".floor-item");
var isOpen = item.hasClass("open"); var isOpen = item.hasClass("open");
$(".floor-item").removeClass("open"); $(".floor-item").removeClass("open");
$(".floor-header").attr("aria-expanded", "false");
$(".floor-body").slideUp(300); $(".floor-body").slideUp(300);
if (!isOpen) { if (!isOpen) {
item.addClass("open"); item.addClass("open");
$(this).attr("aria-expanded", "true");
item.find(".floor-body").slideDown(300); item.find(".floor-body").slideDown(300);
} }
}); });
// Accordion keyboard handler (Enter/Space)
$(".floor-header").on("keydown", function (e) {
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).on("click", ".grid-item", function () { $(document).on("click", ".grid-item", function () {
var src = $(this).data("img") || $(this).find("img").attr("src"); var src = $(this).data("img") || $(this).find("img").attr("src");
$("#lightboxImg").attr("src", src); openLightbox(src);
$("#lightbox").addClass("open");
$("body").css("overflow", "hidden");
}); });
// Lightbox floor plan images in Raumaufteilung // Lightbox floor plan images in Raumaufteilung
$(document).on("click", ".floor-plan img[data-img]", function () { $(document).on("click", ".floor-plan img[data-img]", function () {
var src = $(this).data("img"); var src = $(this).data("img");
$("#lightboxImg").attr("src", src); openLightbox(src);
$("#lightbox").addClass("open");
$("body").css("overflow", "hidden");
}); });
$("#lightboxClose, #lightbox").on("click", function (e) {
// Lightbox close handlers
$("#lightboxClose").on("click", function () {
closeLightbox();
});
$("#lightbox").on("click", function (e) {
if (e.target === this) { if (e.target === this) {
$("#lightbox").removeClass("open"); closeLightbox();
$("body").css("overflow", "");
}
});
$(document).on("keydown", function (e) {
if (e.key === "Escape") {
$("#lightbox").removeClass("open");
$("body").css("overflow", "");
} }
}); });
// Form submit // Escape key to close lightbox
$(document).on("keydown", function (e) {
if (e.key === "Escape" && $("#lightbox").hasClass("open")) {
closeLightbox();
}
});
// Focus trap for lightbox
$("#lightbox").on("keydown", function (e) {
if (e.key !== "Tab") return;
var focusable = $(this).find("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])").filter(":visible");
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();
}
}
});
// Gallery keyboard handler (Enter/Space)
$(document).on("keydown", ".grid-item", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
$(this).trigger("click");
}
});
// Form submit opens email client with pre-filled mailto: link
$("#contactForm").on("submit", function (e) { $("#contactForm").on("submit", function (e) {
e.preventDefault(); e.preventDefault();
var btn = $(this).find(".btn-submit");
btn.text("Wird gesendet...").prop("disabled", true); var fname = $("#fname").val().trim();
setTimeout(function () { var lname = $("#lname").val().trim();
$("#contactForm").hide(); var email = $("#email").val().trim();
$("#formSuccess").fadeIn(400); var phone = $("#phone").val().trim();
}, 1200); var interest = $("#interest").val();
var message = $("#message").val().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
$("#contactForm").hide();
$("#formSuccess").fadeIn(400);
}); });
}); });