Feinschliff: Formulare neu, Glas global dunkler, Hero-Fade sauber
Formulare (form-field.php, 3 Form-Wrapper, components.css, form.js): - Floating Labels (Label im Feld, wandert bei Fokus/Inhalt hoch; select/date dauerhaft oben) via :has() + placeholder=" "-Trick. Echtes <label> bleibt im DOM (kein Placeholder-als-Label). - Globale "Pflichtfelder mit *"-Hinweiszeile entfernt; Stern bleibt am Feld, pro Feld als visually-hidden "(Pflichtfeld)" für Screenreader erklärt. - Markenroter Fokus-Ring statt Weiß. - Felder als sanfter Füll-Look: weichere Ränder (eigene --clr-field-*-Tokens), Erkennbarkeit über Fläche + Rand (WCAG 1.4.11 erfüllt). - form.js: Submit-Button-Text wird je Formular korrekt wiederhergestellt. Glas-Look global (tokens.css, components.css): - Frosted Glass zentral: --glass-blur + --glass-shadow (Glow + Top-Sheen), eine Regel statt 28× wiederholt; Leaf-Karten mit Blur, Container nur Glow (kein Doppel-Frost). @supports-Fallback. - Dunkleres Glas (--clr-glass-bg auf Schwarz-Tint), dezenter Card-Rand. Hero-Fade (components.css): - Unterer Auslauf nicht mehr mit grauem --clr-bg zugedeckt, sondern .hero__media per mask-image ausgeblendet → echter dunkler, texturierter Hintergrund scheint durch (schwärzer, durchsichtig, kein graues Band). Abdunklung auf reines Schwarz. Gilt für alle drei Hero-Varianten. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGzc6GhWhmLJt1jC2q1SRZ
This commit is contained in:
@@ -59,8 +59,6 @@ $f = [
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<p class="form__note">Pflichtfelder sind mit <span class="form__required" aria-hidden="true">*</span><span class="visually-hidden">Stern</span> markiert.</p>
|
||||
|
||||
<div class="form__row">
|
||||
<?php component('form-field', ['field' => $f['name']]); ?>
|
||||
<?php component('form-field', ['field' => $f['email']]); ?>
|
||||
|
||||
@@ -27,8 +27,10 @@ $errorId = $id . '-error';
|
||||
$hintId = $id . '-hint';
|
||||
$describedBy = (!empty($field['hint']) ? $hintId . ' ' : '') . $errorId;
|
||||
|
||||
// Sichtbarer roter Stern (aria-hidden) + pro Feld erklärendes Pflicht-Wort für
|
||||
// Screenreader — ersetzt die frühere globale „Pflichtfelder mit *"-Hinweiszeile.
|
||||
$requiredMark = $required
|
||||
? ' <span class="form__required" aria-hidden="true">*</span>'
|
||||
? ' <span class="form__required" aria-hidden="true">*</span><span class="visually-hidden"> (Pflichtfeld)</span>'
|
||||
: '';
|
||||
|
||||
$commonAttrs = 'name="' . e($name) . '" id="' . e($id) . '"'
|
||||
@@ -56,9 +58,9 @@ $commonAttrs = 'name="' . e($name) . '" id="' . e($id) . '"'
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php elseif ($type === 'textarea'): ?>
|
||||
<textarea <?= $commonAttrs ?> rows="<?= e($field['rows'] ?? 6) ?>"></textarea>
|
||||
<textarea <?= $commonAttrs ?> rows="<?= e($field['rows'] ?? 6) ?>" placeholder=" "></textarea>
|
||||
<?php else: ?>
|
||||
<input type="<?= e($type) ?>" <?= $commonAttrs ?>>
|
||||
<input type="<?= e($type) ?>" <?= $commonAttrs ?> placeholder=" ">
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($field['hint'])): ?>
|
||||
<p class="form__hint" id="<?= e($hintId) ?>"><?= e($field['hint']) ?></p>
|
||||
|
||||
@@ -52,8 +52,6 @@ $f = [
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<p class="form__note">Pflichtfelder sind mit <span class="form__required" aria-hidden="true">*</span><span class="visually-hidden">Stern</span> markiert.</p>
|
||||
|
||||
<fieldset class="form__group">
|
||||
<legend class="form__legend">Zur Person</legend>
|
||||
<div class="form__group-body">
|
||||
|
||||
@@ -51,8 +51,6 @@ $f = [
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<p class="form__note">Pflichtfelder sind mit <span class="form__required" aria-hidden="true">*</span><span class="visually-hidden">Stern</span> markiert.</p>
|
||||
|
||||
<div class="form__row">
|
||||
<?php component('form-field', ['field' => $f['name']]); ?>
|
||||
<?php component('form-field', ['field' => $f['email']]); ?>
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
/* Unten ausblenden statt mit grauem BG zudecken: der echte, dunkle
|
||||
texturierte Seiten-Hintergrund scheint durch → transparent & matcht
|
||||
den Grund exakt (kein graues, opakes Band mehr). */
|
||||
-webkit-mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 92%);
|
||||
mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 92%);
|
||||
}
|
||||
|
||||
.hero__img {
|
||||
@@ -44,12 +49,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Dunkler Verlauf wie auf der alten Seite: oben transparent → unten Seitenhintergrund */
|
||||
/* Reine Schwarz-Abdunklung (kein grauer Fill) — der Auslauf zum Grund kommt
|
||||
aus der Mask auf .hero__media, hier wird nur schwärzer getönt. */
|
||||
.hero__media::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(180deg, rgb(20 20 20 / 0.25) 0%, rgb(20 20 20 / 0.55) 55%, var(--clr-bg) 100%);
|
||||
background: linear-gradient(180deg, rgb(0 0 0 / 0.45) 0%, rgb(0 0 0 / 0.15) 45%, rgb(0 0 0 / 0.5) 100%);
|
||||
}
|
||||
|
||||
.hero__content {
|
||||
@@ -110,14 +116,14 @@
|
||||
/* zusätzlicher Verlauf von links für Textlesbarkeit über dem Video */
|
||||
background:
|
||||
linear-gradient(90deg, rgb(10 10 10 / 0.62) 0%, rgb(10 10 10 / 0.25) 45%, transparent 70%),
|
||||
linear-gradient(180deg, rgb(20 20 20 / 0.2) 0%, rgb(20 20 20 / 0.45) 55%, var(--clr-bg) 100%);
|
||||
linear-gradient(180deg, rgb(0 0 0 / 0.42) 0%, rgb(0 0 0 / 0.15) 45%, rgb(0 0 0 / 0.5) 100%);
|
||||
}
|
||||
|
||||
/* Center+Display: kein Seitenverlauf, nur zentrales Abdunkeln für Lesbarkeit */
|
||||
.hero--center.hero--display .hero__media::after {
|
||||
background:
|
||||
radial-gradient(ellipse 80% 60% at 50% 40%, rgb(10 10 10 / 0.5) 0%, transparent 100%),
|
||||
linear-gradient(180deg, rgb(20 20 20 / 0.2) 0%, rgb(20 20 20 / 0.5) 55%, var(--clr-bg) 100%);
|
||||
linear-gradient(180deg, rgb(0 0 0 / 0.4) 0%, rgb(0 0 0 / 0.14) 45%, rgb(0 0 0 / 0.5) 100%);
|
||||
}
|
||||
|
||||
.hero__kicker {
|
||||
@@ -1243,44 +1249,69 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Floating Label: Label liegt im leeren Feld wie ein Platzhalter und wandert bei
|
||||
Fokus oder Inhalt nach oben. Rein visuell — das echte <label for> bleibt im DOM
|
||||
(kein Placeholder-als-Label), darum auch für Screenreader voll nutzbar. */
|
||||
.form__field {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.form__field label {
|
||||
font-size: var(--fs-500);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form__field input,
|
||||
.form__field select,
|
||||
.form__field textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
background: var(--clr-glass-bg);
|
||||
border: 1px solid var(--clr-glass-border-strong);
|
||||
padding: 1.45rem 0.85rem 0.5rem;
|
||||
background: var(--clr-field-bg);
|
||||
border: 1px solid var(--clr-field-border);
|
||||
border-radius: var(--radius-btn);
|
||||
color: var(--clr-text);
|
||||
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
|
||||
}
|
||||
|
||||
/* Label im Ruhezustand — sitzt auf der Eingabezeile (deckt das " "-Placeholder) */
|
||||
.form__field:not(.form__field--checkbox) > label {
|
||||
position: absolute;
|
||||
left: 0.9rem;
|
||||
top: 1.4rem;
|
||||
font-size: var(--fs-500);
|
||||
line-height: 1;
|
||||
color: var(--clr-text-muted);
|
||||
pointer-events: none;
|
||||
transform-origin: left top;
|
||||
transition: transform var(--transition), color var(--transition);
|
||||
}
|
||||
|
||||
/* Geschwebt: bei Fokus, bei vorhandenem Inhalt (placeholder=" "-Trick) sowie
|
||||
dauerhaft für Select und Datumsfelder (haben keinen :placeholder-shown-Zustand). */
|
||||
.form__field:not(.form__field--checkbox):has(input:focus) > label,
|
||||
.form__field:not(.form__field--checkbox):has(textarea:focus) > label,
|
||||
.form__field:not(.form__field--checkbox):has(select:focus) > label,
|
||||
.form__field:not(.form__field--checkbox):has(input:not(:placeholder-shown)) > label,
|
||||
.form__field:not(.form__field--checkbox):has(textarea:not(:placeholder-shown)) > label,
|
||||
.form__field:not(.form__field--checkbox):has(select) > label,
|
||||
.form__field:not(.form__field--checkbox):has(input[type="date"]) > label {
|
||||
transform: translateY(-0.95rem) scale(0.78);
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
.form__field input:hover,
|
||||
.form__field select:hover,
|
||||
.form__field textarea:hover {
|
||||
border-color: rgb(255 255 255 / 0.55);
|
||||
border-color: var(--clr-field-border-hover);
|
||||
}
|
||||
|
||||
/* Eigener, deutlich sichtbarer Fokus-Ring statt des globalen Outlines */
|
||||
/* Markenroter Fokus-Ring (Akzent nur als Rahmen/Glow, nie als Text). */
|
||||
.form__field input:focus-visible,
|
||||
.form__field select:focus-visible,
|
||||
.form__field textarea:focus-visible {
|
||||
outline: none;
|
||||
border-color: rgb(255 255 255 / 0.75);
|
||||
box-shadow: 0 0 0 3px rgb(255 255 255 / 0.18);
|
||||
border-color: var(--clr-accent);
|
||||
box-shadow: 0 0 0 3px rgb(var(--clr-accent-rgb) / 0.3);
|
||||
}
|
||||
|
||||
/* Der " "-Platzhalter aus dem Floating-Trick bleibt unsichtbar */
|
||||
.form__field ::placeholder {
|
||||
color: rgb(255 255 255 / 0.45);
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
/* Fehlerzustand: per JS (aria-invalid) und nativ nach Nutzereingabe (:user-invalid) */
|
||||
@@ -1306,22 +1337,18 @@
|
||||
color: var(--clr-text);
|
||||
}
|
||||
|
||||
.form__note {
|
||||
margin: 0;
|
||||
font-size: var(--fs-400);
|
||||
color: var(--clr-text-muted);
|
||||
}
|
||||
|
||||
.form__required {
|
||||
color: var(--clr-accent);
|
||||
}
|
||||
|
||||
.form__hint {
|
||||
margin-top: 0.4rem;
|
||||
font-size: var(--fs-400);
|
||||
color: var(--clr-text-muted);
|
||||
}
|
||||
|
||||
.form__error-msg {
|
||||
margin-top: 0.4rem;
|
||||
font-size: var(--fs-400);
|
||||
color: var(--clr-error);
|
||||
}
|
||||
@@ -1337,6 +1364,7 @@
|
||||
}
|
||||
|
||||
.form__field--checkbox {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: start;
|
||||
gap: 0.6rem;
|
||||
@@ -4315,3 +4343,67 @@
|
||||
min-height: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
FROSTED GLASS — globaler Look für alle Glas-Oberflächen.
|
||||
EINZIGE Stelle für Blur + Ruhe-Glow (DRY statt 28× wiederholt).
|
||||
Neue Glas-Karte? Hier zur passenden Liste ergänzen:
|
||||
• Leaf = eigenständige Karte → bekommt Blur + Glow
|
||||
• Container = umschließt selbst Glas-Karten → nur Glow
|
||||
(kein Blur, sonst Doppel-Frost bei verschachtelten Karten)
|
||||
Bewusst ausgenommen: Form-Inputs, Wappen-Initialen, Banner-/Slider-Controls.
|
||||
Glas-Bg/-Border kommen weiterhin aus den Komponenten (var(--clr-glass-*)).
|
||||
============================================================ */
|
||||
|
||||
/* Ruhe-Glow + Top-Sheen für ALLE Glas-Flächen (Leaf + Container).
|
||||
Hover-Lift bleibt pro Komponente erhalten (:hover hat höhere Spezifität). */
|
||||
.instagram__fallback,
|
||||
.sponsor-channels__card,
|
||||
.person-card,
|
||||
.position-card,
|
||||
.partners__item,
|
||||
.key-facts__item,
|
||||
.bento__tile,
|
||||
.group-card,
|
||||
.group-tabs__panel,
|
||||
.age-group,
|
||||
.match-card,
|
||||
.match-list,
|
||||
.matchcenter-empty,
|
||||
.roster-card,
|
||||
.team-card,
|
||||
.department-choice__card,
|
||||
.legal__card,
|
||||
.fee-table,
|
||||
.league-table,
|
||||
.membership-card,
|
||||
.sportheim-bento__addr,
|
||||
.form {
|
||||
box-shadow: var(--glass-shadow);
|
||||
}
|
||||
|
||||
/* Echtes Frosted-Glass-Blur nur auf Leaf-Karten — Container (.match-list,
|
||||
.group-tabs__panel, .age-group, Tabellen) bleiben blur-frei, damit darin
|
||||
liegende Glas-Karten nicht doppelt verschwimmen. */
|
||||
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
|
||||
.instagram__fallback,
|
||||
.sponsor-channels__card,
|
||||
.person-card,
|
||||
.position-card,
|
||||
.partners__item,
|
||||
.key-facts__item,
|
||||
.bento__tile,
|
||||
.group-card,
|
||||
.match-card,
|
||||
.matchcenter-empty,
|
||||
.roster-card,
|
||||
.team-card,
|
||||
.department-choice__card,
|
||||
.legal__card,
|
||||
.membership-card,
|
||||
.sportheim-bento__addr,
|
||||
.form {
|
||||
-webkit-backdrop-filter: var(--glass-blur);
|
||||
backdrop-filter: var(--glass-blur);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,12 @@
|
||||
--clr-text-faint: #8c8c8c; /* 4.5:1 auf --clr-bg (AA) */
|
||||
--clr-sepia-bg: #f3efe4; /* Timeline-Museumsrahmen (Foto-Mount) */
|
||||
--clr-sepia-text: #3a372f; /* Timeline-Text auf hellem Sepia-Grund */
|
||||
--clr-glass-bg: rgb(255 255 255 / 0.11);
|
||||
--clr-glass-border: rgb(255 255 255 / 0.22);
|
||||
--clr-glass-border-strong: rgb(255 255 255 / 0.4); /* Formularfelder: ≥3:1 Kontrast (WCAG 1.4.11) */
|
||||
--clr-glass-bg: rgb(0 0 0 / 0.22); /* dunkles Glas (dunkler als der Grund) */
|
||||
--clr-glass-border: rgb(255 255 255 / 0.14); /* sehr dezenter Card-Rand — Glow/Sheen tragen die Kontur */
|
||||
--clr-glass-border-strong: rgb(255 255 255 / 0.45); /* Back-to-Top, position-/group-card etc.: ≥3:1 (WCAG 1.4.11) */
|
||||
--clr-field-bg: rgb(255 255 255 / 0.07); /* Formularfelder: sanfte Füllfläche (etwas heller als das Glas) */
|
||||
--clr-field-border: rgb(255 255 255 / 0.22); /* Feld-Rand weich — Fläche + Rand machen das Feld erkennbar */
|
||||
--clr-field-border-hover: rgb(255 255 255 / 0.4); /* Feld-Hover: dezent */
|
||||
--clr-error: #ff8a8a; /* Formularfehler, lesbar auf dunkel */
|
||||
--clr-success: #8ce99a;
|
||||
|
||||
@@ -53,7 +56,11 @@
|
||||
--radius-btn: 8px;
|
||||
--radius-card: 15px;
|
||||
--shadow: 0 0 14px rgb(0 0 0 / 0.15);
|
||||
--shadow-card: 0 7px 29px rgb(0 0 0 / 0.33);
|
||||
--shadow-card: 0 14px 38px rgb(0 0 0 / 0.42), inset 0 1px 0 rgb(255 255 255 / 0.18); /* Hover-Lift + Top-Sheen */
|
||||
|
||||
/* --- Glas-Oberflächen (Frosted Glass) — siehe „Frosted Glass"-Block in components.css --- */
|
||||
--glass-blur: blur(13px) saturate(1.4);
|
||||
--glass-shadow: 0 6px 22px rgb(0 0 0 / 0.30), inset 0 1px 0 rgb(255 255 255 / 0.15); /* Ruhe-Glow + Top-Sheen */
|
||||
|
||||
/* --- Layout --- */
|
||||
--container-max: 1200px;
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
var buttonLabel = button.textContent;
|
||||
button.disabled = true;
|
||||
button.textContent = 'Wird gesendet …';
|
||||
|
||||
@@ -89,7 +90,7 @@
|
||||
})
|
||||
.finally(function () {
|
||||
button.disabled = false;
|
||||
button.textContent = 'Nachricht senden';
|
||||
button.textContent = buttonLabel;
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user