Verwaltung: das Bild wird zur Buehne statt zum Streifen
Der erste Anlauf hat die Motive kaputtgemacht. Sie standen in einem schmalen Streifen, auf 190 % gezoomt, davon ein Ausschnitt gewaehlt und die linke Haelfte voll zugedeckt -- alles nur, damit Text darauf lesbar bleibt. Von einer Kristallwelt, die ueber das ganze Bild geht, war ein Zipfel uebrig. Der Denkfehler: Bild und Text auf dieselbe Ebene zwingen und dann das Bild opfern. Jetzt liegen sie auf zwei Ebenen. DAS BILD IST DIE BUEHNE. Bildschirmfuellend, fest stehend, ungeschnitten, ungedimmt. Kein Zoom, kein einseitiges Abdunkeln. Beim Bereichswechsel wechselt der ganze Raum. DER INHALT SCHWEBT ALS GLAS DARUEBER. Karten, Reiter, Bedienknoepfe und selbst die Meldung "Wird geladen" bekommen eine Rueckseiten-Unschaerfe. Das Motiv bleibt sichtbar, verliert hinter dem Glas aber jede Struktur -- und genau das macht Text darauf ruhig lesbar. Dadurch muss das Bild nirgends mehr weichen. Die Kacheln tragen eine Leuchtkante in der Leitfarbe des Bereichs. Das bindet Inhalt und Buehne zusammen, statt die Kacheln wie aufgeklebte Zettel wirken zu lassen. Weil der Text jetzt auf Glas steht statt auf dem Bild, konnte auch die Toenung deutlich zurueckgenommen werden: von .42/.58/.72 auf .18/.38/.60. Mehr Bild, gleiche Lesbarkeit -- gemessen 12,4 bis 14,5:1 auf der Kachel, verlangt sind 4,5:1. Die Pruefung ist mitgedreht und misst jetzt das Gegenteil von vorher: - Wird das Bild NICHT gezoomt und NICHT ausgeschnitten? (frueher stand hier "190% auto" und "84% 46%") - Traegt jede Flaeche, auf der gelesen wird, wirklich Glas? - Bleibt der Text lesbar -- gemessen an echten Bildpunkten, nicht am rechnerischen Wert des Stilblatts. Die Kachel ist halbdurchsichtig, ihr Sollwert sagt nichts darueber, was am Ende darunter liegt. Dazu die Vergleichsmessung: Wie unruhig ist der Kachelgrund MIT Buehne gegenueber ohne? Gemessen: minus 1 bis plus 1 in allen sechs Bereichen. Das Glas arbeitet. Was unveraendert gilt: Bewegung aus bei prefers-reduced-motion, aber die Buehne bleibt sichtbar -- abschalten heisst nicht verschwinden. Auf dem Handy die kleine Bildfassung und eine etwas dichtere Toenung, weil dort mehr Inhalt uebereinander liegt. Geprueft: 229 Pruefungen gruen (Verwaltung 31, Portfolio 15, CRYONOVA 53, Blickfang 13, System 5, Abmelden 16, Abbruch 42, Angebot 54). Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+180
-261
@@ -1,14 +1,21 @@
|
||||
/* =====================================================================
|
||||
Prueft den Bildschmuck im Verwaltungsbereich.
|
||||
Prueft die Buehne im Verwaltungsbereich.
|
||||
|
||||
Die eigentliche Frage ist nicht "sieht man das Bild?", sondern:
|
||||
Kostet es Lesbarkeit? Die Verwaltung ist ein Arbeitsplatz -- ein
|
||||
Motiv, das hinter einer Zahlenspalte liegt, ist genau die Art von
|
||||
Schoenheit, die ein Werkzeug unbrauchbar macht.
|
||||
Das Konzept hat sich umgedreht, und damit auch die Pruefung.
|
||||
|
||||
Seit der Bereichs-Signatur kommt eine zweite Frage dazu: Sind die
|
||||
sechs Bereiche wirklich unterscheidbar, oder sieht nur der Code so
|
||||
aus? Deshalb wird jeder Reiter einzeln angeklickt und gemessen.
|
||||
Vorher: ein schmaler Streifen, auf 190 % gezoomt, davon ein Ausschnitt
|
||||
gewaehlt und die linke Haelfte voll zugedeckt -- damit Text darauf
|
||||
lesbar bleibt. Gemessen wurde, ob das Bild leise genug ist. Uebrig
|
||||
blieb ein Zipfel.
|
||||
|
||||
Jetzt: Das Motiv ist die Buehne -- bildschirmfuellend, ungeschnitten,
|
||||
ungedimmt. Der Inhalt schwebt als Milchglas darueber. Text steht nie
|
||||
direkt auf dem Bild.
|
||||
|
||||
Deshalb wird jetzt das Gegenteil geprueft:
|
||||
1. Ist das Bild wirklich GANZ da? (kein Zoom, kein Ausschnitt)
|
||||
2. Traegt jede Flaeche, auf der gelesen wird, auch Glas?
|
||||
3. Bleibt der Text darauf lesbar -- an echten Bildpunkten gemessen?
|
||||
===================================================================== */
|
||||
import { chromium } from "playwright";
|
||||
import http from "http";
|
||||
@@ -54,8 +61,39 @@ function verhaeltnis(a, b) {
|
||||
|
||||
const BEREICHE = ["uebersicht", "anfragen", "projekte", "kunden", "zahlungen", "postfach"];
|
||||
|
||||
/* Misst, wie stark der dunkle Grund in einem Bereich schwankt. Hohe
|
||||
Schwankung heisst: Da liegt ein Bild unter der Schrift. */
|
||||
/* Setzt einen Bereich und legt Beispielinhalt ein. Ohne Inhalt liesse
|
||||
sich nicht messen, ob Text ueber der Buehne lesbar bleibt -- und genau
|
||||
das ist die Frage, an der das ganze Konzept haengt.
|
||||
|
||||
Der Aufbau passiert vor JEDER Messung neu: Der Datenabruf laeuft im
|
||||
Hintergrund weiter und klappt den Arbeitsbereich verzoegert wieder zu
|
||||
(Zugangspruefung, kein Fehler). */
|
||||
async function bereichAufbauen(seite, bereich) {
|
||||
await seite.evaluate((b) => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
const bereichEl = document.querySelector("#vw-bereich");
|
||||
bereichEl.removeAttribute("hidden");
|
||||
document.documentElement.setAttribute("data-vw-bereich", b);
|
||||
document.querySelectorAll("[data-tab]").forEach((x) =>
|
||||
x.classList.toggle("vw-an", x.dataset.tab === b));
|
||||
|
||||
let probe = document.querySelector("#vw-probe");
|
||||
if (!probe) {
|
||||
probe = document.createElement("div");
|
||||
probe.id = "vw-probe";
|
||||
probe.innerHTML =
|
||||
'<div class="wd-karte" style="padding:1.4rem;margin-bottom:1rem">' +
|
||||
'<h2 style="margin-top:0">Vanessa Geske</h2>' +
|
||||
'<p class="wd-klein wd-leise">[email protected]</p>' +
|
||||
'<p id="vw-probe-text">Zwei Projekte, eines davon laufend.</p></div>';
|
||||
bereichEl.appendChild(probe);
|
||||
}
|
||||
}, bereich);
|
||||
await seite.waitForTimeout(700);
|
||||
}
|
||||
|
||||
/* Misst die Schwankung des Untergrunds an echten Bildpunkten. Hohe
|
||||
Schwankung heisst: Da liegt Bildstruktur unter der Schrift. */
|
||||
async function unruheAn(seite, wahl) {
|
||||
const bild = await seite.locator(wahl).first().screenshot();
|
||||
return seite.evaluate(async (daten) => {
|
||||
@@ -68,7 +106,7 @@ async function unruheAn(seite, wahl) {
|
||||
const grund = [];
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
const h = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
||||
if (h < 110) grund.push(h);
|
||||
if (h < 120) grund.push(h);
|
||||
}
|
||||
if (grund.length < 50) return null;
|
||||
const m = grund.reduce((a, b) => a + b, 0) / grund.length;
|
||||
@@ -78,296 +116,177 @@ async function unruheAn(seite, wahl) {
|
||||
|
||||
srv.listen(4404, async () => {
|
||||
const browser = await chromium.launch();
|
||||
|
||||
/* =================================================================
|
||||
TEIL 1 — die Anmeldemaske
|
||||
================================================================= */
|
||||
for (const [gr, vp] of [["Computer", { width: 1440, height: 950 }],
|
||||
["Handy", { width: 390, height: 844 }]]) {
|
||||
console.log(`\n===== ANMELDUNG (${gr}) =====`);
|
||||
const seite = await browser.newPage({ viewport: vp });
|
||||
const seite = await browser.newPage({ viewport: { width: 1440, height: 900 } });
|
||||
const skriptfehler = [];
|
||||
seite.on("pageerror", (e) => skriptfehler.push(String(e).slice(0, 140)));
|
||||
await seite.goto("http://127.0.0.1:4404/webdesign/verwaltung.html");
|
||||
await seite.waitForTimeout(1400);
|
||||
await seite.waitForTimeout(1500);
|
||||
|
||||
const login = await seite.evaluate(() => {
|
||||
const el = document.querySelector("#vw-anmeldung");
|
||||
console.log("===== 1. IST DAS BILD GANZ DA? =====");
|
||||
await bereichAufbauen(seite, "kunden");
|
||||
const buehne = await seite.evaluate(() => {
|
||||
const el = document.querySelector(".vw-buehne");
|
||||
if (!el) return null;
|
||||
el.removeAttribute("hidden");
|
||||
const vor = getComputedStyle(el, "::before");
|
||||
const treffer = vor.backgroundImage.match(/img\/([a-z0-9-]+\.webp)/i);
|
||||
return { datei: treffer ? treffer[1] : "(keins)", deckkraft: parseFloat(vor.opacity) };
|
||||
const st = getComputedStyle(el);
|
||||
const r = el.getBoundingClientRect();
|
||||
const treffer = st.backgroundImage.match(/img\/([a-z0-9-]+\.webp)/i);
|
||||
return {
|
||||
datei: treffer ? treffer[1] : "(keins)",
|
||||
groesse: st.backgroundSize,
|
||||
lage: st.backgroundPosition,
|
||||
haltung: st.position,
|
||||
breite: Math.round(r.width),
|
||||
hoehe: Math.round(r.height),
|
||||
z: parseInt(st.zIndex, 10),
|
||||
klicks: st.pointerEvents,
|
||||
versteckt: el.getAttribute("aria-hidden"),
|
||||
};
|
||||
});
|
||||
pruefe(`${gr}: die Anmeldekarte hat ein Motiv`,
|
||||
login && login.datei.includes("wappen"), login && login.datei);
|
||||
if (!buehne) { pruefe("Buehne vorhanden", false); }
|
||||
else {
|
||||
/* Das ist der Kern der Korrektur. Beim ersten Anlauf stand hier
|
||||
"190% auto" plus ein Ausschnitt wie "84% 46%" -- damit war der
|
||||
groesste Teil des Bildes weggeschnitten. */
|
||||
pruefe("das Bild wird NICHT gezoomt", buehne.groesse === "cover", buehne.groesse);
|
||||
pruefe("und NICHT einseitig ausgeschnitten",
|
||||
/50%\s+50%|center/.test(buehne.lage), buehne.lage);
|
||||
pruefe("die Buehne fuellt den ganzen Bildschirm",
|
||||
buehne.breite >= 1430 && buehne.hoehe >= 890, `${buehne.breite}x${buehne.hoehe}`);
|
||||
pruefe("sie steht fest, der Inhalt scrollt darueber",
|
||||
buehne.haltung === "fixed", buehne.haltung);
|
||||
pruefe("sie liegt hinter allem", buehne.z < 0, "z-index " + buehne.z);
|
||||
pruefe("sie faengt keine Klicks ab", buehne.klicks === "none", buehne.klicks);
|
||||
pruefe("sie ist als Zierde ausgezeichnet", buehne.versteckt === "true");
|
||||
}
|
||||
|
||||
await seite.waitForTimeout(500);
|
||||
const messen = async () => {
|
||||
const bild = await seite.locator("#vw-anmeldung p.wd-klein").first().screenshot();
|
||||
return seite.evaluate(async (daten) => {
|
||||
console.log("\n===== 2. TRAEGT ALLES GLAS, WORAUF GELESEN WIRD? =====");
|
||||
const glas = await seite.evaluate(() => {
|
||||
const pruefen = [".wd-karte", ".vw-filter-knopf", ".vw-wer"];
|
||||
const raus = {};
|
||||
for (const w of pruefen) {
|
||||
const el = document.querySelector("#vw-bereich " + w);
|
||||
if (!el) { raus[w] = "(nicht gefunden)"; continue; }
|
||||
const st = getComputedStyle(el);
|
||||
raus[w] = st.backdropFilter || st.webkitBackdropFilter || "keins";
|
||||
}
|
||||
return raus;
|
||||
});
|
||||
for (const [w, wert] of Object.entries(glas)) {
|
||||
if (wert === "(nicht gefunden)") continue;
|
||||
pruefe(` ${w} hat Rueckseiten-Unschaerfe`, /blur/.test(wert), wert.slice(0, 34));
|
||||
}
|
||||
|
||||
console.log("\n===== 3. BLEIBT DER TEXT LESBAR? =====");
|
||||
for (const bereich of BEREICHE) {
|
||||
await bereichAufbauen(seite, bereich);
|
||||
|
||||
const aufGlas = await unruheAn(seite, "#vw-probe .wd-karte");
|
||||
await seite.evaluate(() => {
|
||||
document.querySelector(".vw-buehne").style.visibility = "hidden";
|
||||
});
|
||||
await seite.waitForTimeout(350);
|
||||
await bereichAufbauen(seite, bereich);
|
||||
const ohneBuehne = await unruheAn(seite, "#vw-probe .wd-karte");
|
||||
await seite.evaluate(() => {
|
||||
document.querySelector(".vw-buehne").style.visibility = "";
|
||||
});
|
||||
await seite.waitForTimeout(250);
|
||||
|
||||
const mehr = (aufGlas ?? 99) - (ohneBuehne ?? 0);
|
||||
/* Etwas Struktur DARF durchkommen -- das ist ja der Reiz. Sie darf
|
||||
nur nicht so stark werden, dass die Schrift darauf flimmert. */
|
||||
pruefe(` ${bereich}: der Kachelgrund bleibt ruhig`,
|
||||
aufGlas !== null && ohneBuehne !== null && mehr <= 8,
|
||||
`mit Buehne ${aufGlas}, ohne ${ohneBuehne} → plus ${mehr}`);
|
||||
|
||||
await bereichAufbauen(seite, bereich);
|
||||
/* Der tatsaechliche Kachelgrund wird aus dem BILD gelesen, nicht aus
|
||||
dem Stilblatt: Die Kachel ist halbdurchsichtig, ihr rechnerischer
|
||||
Wert sagt nichts darueber, was am Ende darunter liegt. */
|
||||
const stelle = await seite.evaluate(() => {
|
||||
const k = document.querySelector("#vw-probe .wd-karte");
|
||||
const r = k.getBoundingClientRect();
|
||||
return { x: Math.round(r.x + r.width * 0.72), y: Math.round(r.y + r.height * 0.62) };
|
||||
});
|
||||
const punkt = await seite.screenshot({
|
||||
clip: { x: stelle.x, y: stelle.y, width: 10, height: 10 } });
|
||||
const grundfarbe = await seite.evaluate(async (daten) => {
|
||||
const bl = await fetch("data:image/png;base64," + daten).then((r) => r.blob());
|
||||
const bm = await createImageBitmap(bl);
|
||||
const c = new OffscreenCanvas(bm.width, bm.height);
|
||||
const x = c.getContext("2d");
|
||||
x.drawImage(bm, 0, 0);
|
||||
const d = x.getImageData(0, 0, bm.width, bm.height).data;
|
||||
const grund = [];
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
const h = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
||||
if (h < 110) grund.push(h);
|
||||
}
|
||||
if (grund.length < 50) return null;
|
||||
const m = grund.reduce((a, b) => a + b, 0) / grund.length;
|
||||
return Math.round(Math.sqrt(grund.reduce((a, b) => a + (b - m) ** 2, 0) / grund.length));
|
||||
}, bild.toString("base64"));
|
||||
};
|
||||
const mitBild = await messen();
|
||||
/* Die Vergleichsmessung ist der Kern. Ein fester Grenzwert waere
|
||||
geraten: Schon die weichgezeichneten Buchstabenkanten allein
|
||||
erzeugen eine Schwankung um 12. Gefragt ist, wie viel Unruhe DAS
|
||||
MOTIV hinzufuegt. */
|
||||
await seite.evaluate(() =>
|
||||
document.querySelector("#vw-anmeldung").classList.remove("wd-motiv", "wd-motiv--wappen"));
|
||||
await seite.waitForTimeout(400);
|
||||
const ohneBild = await messen();
|
||||
await seite.waitForTimeout(200);
|
||||
const zusatz = (mitBild ?? 99) - (ohneBild ?? 0);
|
||||
pruefe(`${gr}: das Motiv macht den Textgrund kaum unruhiger`,
|
||||
mitBild !== null && ohneBild !== null && zusatz <= 5,
|
||||
`mit ${mitBild}, ohne ${ohneBild} → plus ${zusatz}`);
|
||||
let r = 0, g = 0, b = 0, n = 0;
|
||||
for (let i = 0; i < d.length; i += 4) { r += d[i]; g += d[i + 1]; b += d[i + 2]; n++; }
|
||||
return [Math.round(r / n), Math.round(g / n), Math.round(b / n)];
|
||||
}, punkt.toString("base64"));
|
||||
|
||||
await seite.close();
|
||||
const schrift = await seite.evaluate(() =>
|
||||
getComputedStyle(document.querySelector("#vw-probe-text"))
|
||||
.color.match(/[\d.]+/g).slice(0, 3).map(Number));
|
||||
|
||||
const v = verhaeltnis(schrift, grundfarbe);
|
||||
pruefe(` ${bereich}: Text auf der Kachel erfuellt AA (4,5:1)`,
|
||||
v >= 4.5, v.toFixed(2) + ":1");
|
||||
}
|
||||
|
||||
/* =================================================================
|
||||
TEIL 2 — die sechs Bereichs-Signaturen
|
||||
================================================================= */
|
||||
const seite = await browser.newPage({ viewport: { width: 1440, height: 950 } });
|
||||
const skriptfehler = [];
|
||||
seite.on("pageerror", (e) => skriptfehler.push(String(e).slice(0, 140)));
|
||||
await seite.goto("http://127.0.0.1:4404/webdesign/verwaltung.html");
|
||||
await seite.waitForTimeout(1400);
|
||||
await seite.evaluate(() => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
});
|
||||
await seite.waitForTimeout(500);
|
||||
|
||||
/* Erst EINMAL echt klicken, um zu beweisen, dass der Reiter die
|
||||
Signatur ueberhaupt umschaltet. Danach geht das nicht mehr: Beim
|
||||
Klick laedt die Seite Daten, merkt dass niemand angemeldet ist, und
|
||||
klappt den Arbeitsbereich korrekterweise wieder zu. Das ist die
|
||||
Zugangspruefung, kein Fehler -- aber es beendet den Rundgang.
|
||||
|
||||
Deshalb wird der Bereich danach direkt gesetzt, so wie der
|
||||
Klick-Listener es auch tut. Geprueft wird dabei das Stilblatt, und
|
||||
das kennt nur das Kennzeichen am Wurzelelement. */
|
||||
await seite.click('[data-tab="anfragen"]');
|
||||
await seite.waitForTimeout(900);
|
||||
const nachKlick = await seite.evaluate(() =>
|
||||
document.documentElement.getAttribute("data-vw-bereich"));
|
||||
console.log("\n===== SCHALTET DER REITER UM? =====");
|
||||
pruefe("ein echter Reiterklick setzt den Bereich", nachKlick === "anfragen", nachKlick);
|
||||
|
||||
/* Zurueck in den sichtbaren Zustand fuer die Messreihe. */
|
||||
await seite.evaluate(() => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
});
|
||||
await seite.waitForTimeout(300);
|
||||
|
||||
console.log("\n===== 4. WECHSELT DER RAUM WIRKLICH? =====");
|
||||
const gesehen = [];
|
||||
for (const bereich of BEREICHE) {
|
||||
console.log(`\n===== BEREICH: ${bereich} =====`);
|
||||
/* Der Datenabruf laeuft im Hintergrund weiter und klappt den
|
||||
Arbeitsbereich verzoegert wieder zu (Zugangspruefung). Deshalb vor
|
||||
JEDER Messung erneut aufmachen, nicht nur einmal am Anfang. */
|
||||
await seite.evaluate((b) => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
document.documentElement.setAttribute("data-vw-bereich", b);
|
||||
document.querySelectorAll("[data-tab]").forEach((x) =>
|
||||
x.classList.toggle("vw-an", x.dataset.tab === b));
|
||||
}, bereich);
|
||||
await seite.waitForTimeout(500);
|
||||
|
||||
await bereichAufbauen(seite, bereich);
|
||||
const d = await seite.evaluate(() => {
|
||||
const wurzel = document.documentElement.getAttribute("data-vw-bereich");
|
||||
const s = document.querySelector(".vw-schmuck");
|
||||
const st = getComputedStyle(s);
|
||||
const treffer = st.backgroundImage.match(/img\/([a-z0-9-]+\.webp)/i);
|
||||
const reiter = document.querySelector(".vw-filter-knopf.vw-an");
|
||||
const rs = getComputedStyle(reiter);
|
||||
const titel = document.querySelector("#vw-titel");
|
||||
/* Untergrund der Seite suchen -- die Reiterflaeche ist
|
||||
halbdurchsichtig und muss darueber verrechnet werden. */
|
||||
const seitenGrund = getComputedStyle(document.body).backgroundColor
|
||||
.match(/[\d.]+/g).slice(0, 3).map(Number);
|
||||
const st = getComputedStyle(document.querySelector(".vw-buehne"));
|
||||
const t = st.backgroundImage.match(/img\/([a-z0-9-]+\.webp)/i);
|
||||
return {
|
||||
wurzel,
|
||||
datei: treffer ? treffer[1] : "(keins)",
|
||||
deckkraft: parseFloat(st.opacity),
|
||||
blick: st.backgroundPosition,
|
||||
reiterText: reiter.textContent.trim().slice(0, 14),
|
||||
reiterFarbe: rs.color.match(/[\d.]+/g).slice(0, 3).map(Number),
|
||||
reiterFlaeche: rs.backgroundColor.match(/[\d.]+/g),
|
||||
titelFarbe: getComputedStyle(titel).color.match(/[\d.]+/g).slice(0, 3).map(Number),
|
||||
seitenGrund,
|
||||
lumen: getComputedStyle(document.querySelector("#vw-bereich")).getPropertyValue("--vw-farbe").trim(),
|
||||
datei: t ? t[1] : "(keins)",
|
||||
farbe: getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--vw-farbe").trim(),
|
||||
};
|
||||
});
|
||||
|
||||
pruefe(` Kennzeichen steht am Wurzelelement`, d.wurzel === bereich, d.wurzel);
|
||||
gesehen.push({ bereich, datei: d.datei, farbe: d.lumen, blick: d.blick });
|
||||
|
||||
/* Der aktive Reiter muss lesbar bleiben -- auch im Bereich
|
||||
"Kunden", dessen Leitfarbe Prism Indigo als SCHRIFT durchfaellt.
|
||||
Genau deshalb faerbt die Leitfarbe dort nur die Flaeche. */
|
||||
const a = d.reiterFlaeche.length === 4 ? parseFloat(d.reiterFlaeche[3]) : 1;
|
||||
const flaeche = d.seitenGrund.map((u, i) =>
|
||||
Math.round(Number(d.reiterFlaeche[i]) * a + u * (1 - a)));
|
||||
const v = verhaeltnis(d.reiterFarbe, flaeche);
|
||||
pruefe(` der aktive Reiter bleibt lesbar (AA = 4,5:1)`, v >= 4.5, v.toFixed(2) + ":1");
|
||||
|
||||
const vt = verhaeltnis(d.titelFarbe, d.seitenGrund);
|
||||
pruefe(` der Titel bleibt lesbar`, vt >= 4.5, vt.toFixed(2) + ":1");
|
||||
/* Frueher stand hier "Deckkraft unter 20 %". Dieser Massstab ist
|
||||
hinfaellig, seit das Motiv nach rechts gerueckt ist: Es darf jetzt
|
||||
kraeftig sein, WEIL es nicht mehr hinter der Schrift liegt. Eine
|
||||
Zahl allein sagt darueber nichts.
|
||||
|
||||
Geprueft wird stattdessen das, worauf es ankommt -- wie ruhig der
|
||||
Grund unter der Reiterzeile ist, mit Motiv gegen ohne Motiv. */
|
||||
const offen = () => seite.evaluate(() => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
});
|
||||
await offen();
|
||||
const grundMit = await unruheAn(seite, ".vw-tabs");
|
||||
await seite.evaluate(() => {
|
||||
document.querySelector(".vw-schmuck").style.visibility = "hidden";
|
||||
});
|
||||
await offen();
|
||||
await seite.waitForTimeout(350);
|
||||
const grundOhne = await unruheAn(seite, ".vw-tabs");
|
||||
await seite.evaluate(() => {
|
||||
document.querySelector(".vw-schmuck").style.visibility = "";
|
||||
});
|
||||
await seite.waitForTimeout(250);
|
||||
const mehr = (grundMit ?? 99) - (grundOhne ?? 0);
|
||||
pruefe(` der Grund unter den Reitern bleibt ruhig`,
|
||||
grundMit !== null && grundOhne !== null && mehr <= 6,
|
||||
`mit ${grundMit}, ohne ${grundOhne} → plus ${mehr}`);
|
||||
gesehen.push({ bereich, ...d });
|
||||
console.log(` ${bereich.padEnd(11)} ${d.datei.padEnd(22)} ${d.farbe}`);
|
||||
}
|
||||
pruefe("jeder Bereich hat eine eigene Leitfarbe",
|
||||
new Set(gesehen.map((g) => g.farbe)).size === 6,
|
||||
new Set(gesehen.map((g) => g.farbe)).size + " von 6");
|
||||
pruefe("mindestens fuenf verschiedene Motive",
|
||||
new Set(gesehen.map((g) => g.datei)).size >= 5,
|
||||
new Set(gesehen.map((g) => g.datei)).size + " verschiedene");
|
||||
|
||||
/* ---- Die Kernfrage: sind die sechs wirklich unterscheidbar? ---- */
|
||||
console.log("\n===== SIND DIE BEREICHE UNTERSCHEIDBAR? =====");
|
||||
for (const g of gesehen) console.log(` ${g.bereich.padEnd(11)} ${g.datei.padEnd(22)} ${g.farbe}`);
|
||||
|
||||
const farben = new Set(gesehen.map((g) => g.farbe));
|
||||
pruefe("jeder Bereich hat eine eigene Leitfarbe", farben.size === 6,
|
||||
farben.size + " von 6 verschieden");
|
||||
|
||||
/* Motive duerfen sich wiederholen -- es gibt fuenf Bilder fuer sechs
|
||||
Bereiche. Aber dann MUSS der Ausschnitt ein anderer sein, sonst
|
||||
sehen zwei Bereiche gleich aus. */
|
||||
const doppelt = {};
|
||||
for (const g of gesehen) (doppelt[g.datei] ||= []).push(g);
|
||||
let ausschnittOk = true, hinweis = [];
|
||||
for (const [datei, liste] of Object.entries(doppelt)) {
|
||||
if (liste.length < 2) continue;
|
||||
const blicke = new Set(liste.map((l) => l.blick));
|
||||
if (blicke.size !== liste.length) { ausschnittOk = false; hinweis.push(datei); }
|
||||
else hinweis.push(`${datei}: ${liste.length}x, aber je anderer Ausschnitt`);
|
||||
}
|
||||
pruefe("mehrfach genutzte Motive zeigen einen anderen Ausschnitt",
|
||||
ausschnittOk, hinweis.join("; ") || "kein Motiv doppelt");
|
||||
|
||||
/* ---- Und die alte Regel gilt weiter ---- */
|
||||
const stoerung = await seite.evaluate(() => {
|
||||
const schlimm = [];
|
||||
for (const el of document.querySelectorAll("table, .wd-tabelle, .vw-liste")) {
|
||||
let p = el;
|
||||
while (p && p !== document.body) {
|
||||
if (p.classList && (p.classList.contains("wd-motiv") ||
|
||||
p.classList.contains("vw-schmuck"))) {
|
||||
schlimm.push(el.tagName);
|
||||
break;
|
||||
}
|
||||
p = p.parentElement;
|
||||
}
|
||||
}
|
||||
return schlimm;
|
||||
});
|
||||
pruefe("kein Motiv hinter Tabellen oder Listen", stoerung.length === 0,
|
||||
stoerung.join(", ") || "keine");
|
||||
pruefe("kein Skriptfehler", skriptfehler.length === 0, skriptfehler[0] || "");
|
||||
|
||||
await seite.evaluate(() => {
|
||||
document.documentElement.setAttribute("data-vw-bereich", "uebersicht");
|
||||
document.querySelectorAll("[data-tab]").forEach((x) =>
|
||||
x.classList.toggle("vw-an", x.dataset.tab === "uebersicht"));
|
||||
});
|
||||
await seite.waitForTimeout(700);
|
||||
await bereichAufbauen(seite, "kunden");
|
||||
await seite.screenshot({ path: "pruef-vw-schmuck-computer.png" });
|
||||
await seite.close();
|
||||
|
||||
/* ---- Bewegung aus, wenn der Nutzer das so eingestellt hat ---- */
|
||||
console.log("\n===== REDUZIERTE BEWEGUNG =====");
|
||||
console.log("\n===== 5. REDUZIERTE BEWEGUNG =====");
|
||||
const ruhig = await browser.newPage({
|
||||
viewport: { width: 1440, height: 950 }, reducedMotion: "reduce" });
|
||||
viewport: { width: 1440, height: 900 }, reducedMotion: "reduce" });
|
||||
await ruhig.goto("http://127.0.0.1:4404/webdesign/verwaltung.html");
|
||||
await ruhig.waitForTimeout(1200);
|
||||
await ruhig.evaluate(() => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
});
|
||||
await ruhig.click('[data-tab="projekte"]');
|
||||
await ruhig.waitForTimeout(700);
|
||||
/* Der Klick klappt den Bereich zu (Zugangspruefung) -- fuer die
|
||||
Messung wieder aufmachen. Das Kennzeichen hat der Klick gesetzt. */
|
||||
await ruhig.evaluate(() => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
});
|
||||
await ruhig.waitForTimeout(300);
|
||||
await ruhig.waitForTimeout(1300);
|
||||
await bereichAufbauen(ruhig, "projekte");
|
||||
const bewegung = await ruhig.evaluate(() => {
|
||||
const s = document.querySelector(".vw-schmuck");
|
||||
const st = getComputedStyle(s);
|
||||
return {
|
||||
animation: st.animationName,
|
||||
sichtbar: parseFloat(st.opacity),
|
||||
bereich: document.documentElement.getAttribute("data-vw-bereich"),
|
||||
};
|
||||
const st = getComputedStyle(document.querySelector(".vw-buehne"));
|
||||
return { animation: st.animationName, sichtbar: st.visibility };
|
||||
});
|
||||
pruefe("keine Animation bei reduzierter Bewegung",
|
||||
bewegung.animation === "none", bewegung.animation);
|
||||
/* Wichtig: abschalten heisst NICHT verschwinden. Das Motiv muss da
|
||||
sein, nur ohne Bewegung. */
|
||||
pruefe("das Motiv ist trotzdem sichtbar", bewegung.sichtbar > 0.05,
|
||||
Math.round(bewegung.sichtbar * 100) + " %");
|
||||
pruefe("der Bereichswechsel wirkt trotzdem", bewegung.bereich === "projekte",
|
||||
bewegung.bereich);
|
||||
/* Abschalten heisst NICHT verschwinden. */
|
||||
pruefe("die Buehne ist trotzdem da", bewegung.sichtbar === "visible", bewegung.sichtbar);
|
||||
await ruhig.close();
|
||||
|
||||
/* ---- Handy ---- */
|
||||
console.log("\n===== HANDY =====");
|
||||
console.log("\n===== 6. HANDY =====");
|
||||
const handy = await browser.newPage({ viewport: { width: 390, height: 844 } });
|
||||
await handy.goto("http://127.0.0.1:4404/webdesign/verwaltung.html");
|
||||
await handy.waitForTimeout(1200);
|
||||
await handy.evaluate(() => {
|
||||
document.querySelector("#vw-anmeldung").setAttribute("hidden", "");
|
||||
document.querySelector("#vw-bereich").removeAttribute("hidden");
|
||||
});
|
||||
await handy.evaluate(() => {
|
||||
document.documentElement.setAttribute("data-vw-bereich", "kunden");
|
||||
});
|
||||
await handy.waitForTimeout(600);
|
||||
await handy.waitForTimeout(1300);
|
||||
await bereichAufbauen(handy, "zahlungen");
|
||||
const hd = await handy.evaluate(() => {
|
||||
const st = getComputedStyle(document.querySelector(".vw-schmuck"));
|
||||
const st = getComputedStyle(document.querySelector(".vw-buehne"));
|
||||
const t = st.backgroundImage.match(/img\/([a-z0-9-]+\.webp)/i);
|
||||
return { datei: t ? t[1] : "(keins)", deckkraft: parseFloat(st.opacity) };
|
||||
return { datei: t ? t[1] : "(keins)", groesse: st.backgroundSize };
|
||||
});
|
||||
pruefe("Handy: kleine Bildfassung", hd.datei.includes("-klein"), hd.datei);
|
||||
pruefe("Handy: auch hier kein Zoom", hd.groesse === "cover", hd.groesse);
|
||||
const ueberlauf = await handy.evaluate(() =>
|
||||
document.documentElement.scrollWidth - document.documentElement.clientWidth);
|
||||
pruefe("Handy: nichts laeuft seitlich ueber", ueberlauf <= 1, ueberlauf + "px");
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 301 KiB |
+1
-1
@@ -34,7 +34,7 @@
|
||||
Start alle alten Zwischenspeicher weg. Muss bei jeder Änderung an den
|
||||
Dateien unten hochgezählt werden, sonst hängen Nutzer auf einem alten
|
||||
Stand fest. */
|
||||
const CACHE_NAME = "dogfather-webdesign-v36";
|
||||
const CACHE_NAME = "dogfather-webdesign-v37";
|
||||
|
||||
/* Bausteine, die die Oberfläche zum Anzeigen braucht. Bewusst KEINE
|
||||
HTML-Datei in dieser Liste. */
|
||||
|
||||
+114
-108
@@ -133,130 +133,136 @@
|
||||
--vw-blick: 12% 54%;
|
||||
}
|
||||
|
||||
/* Warum 190% statt cover: Bei "cover" skaliert der Browser das Bild
|
||||
auf die Breite des Streifens -- die volle Bildbreite ist dann immer
|
||||
sichtbar, und eine waagerechte Ausschnittsangabe bewirkt schlicht
|
||||
nichts. Genau das ist hier passiert: Alle Werte von 62% bis 84%
|
||||
zeigten dasselbe Bild. Erst mit einem Zoom ueber 100% entsteht
|
||||
ueberhaupt Spielraum, den --vw-blick verschieben kann.
|
||||
/* ---------- DIE BUEHNE ----------
|
||||
|
||||
190% ist so gewaehlt, dass der Streifen auf jeder Bildschirmbreite
|
||||
gefuellt bleibt: Die Bildbreite ist immer 1,9-mal so breit wie der
|
||||
Streifen, die Hoehe waechst proportional mit.
|
||||
Das Motiv fuellt den ganzen Bildschirm. Fest stehend, ungeschnitten,
|
||||
in voller Leuchtkraft. Es wird NICHT gezoomt und NICHT einseitig
|
||||
abgedunkelt.
|
||||
|
||||
Zu den Ausschnitten (--vw-blick): Sie sind so gewaehlt, dass KEIN
|
||||
Logo angeschnitten im Streifen haengt. Ein halber Hundekopf mitten
|
||||
im Bild sieht nach Versehen aus, nicht nach Absicht -- und das Logo
|
||||
steht ohnehin schon oben links in der Kopfleiste. Gezeigt werden
|
||||
stattdessen die Kristallformationen, also das, was an den Motiven
|
||||
tatsaechlich spektakulaer ist. */
|
||||
.vw-schmuck {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
/* Genau die Kopfzone: Titel plus Reiterreihe, mehr nicht. Der
|
||||
Streifen ist zu Ende, BEVOR die erste Kachel anfaengt.
|
||||
Warum das der zweite Anlauf ist: Vorher war es ein schmaler Streifen
|
||||
mit 190 % Zoom, aus dem ein Ausschnitt gewaehlt und dessen linke
|
||||
Haelfte voll zugedeckt wurde -- damit der Text darauf lesbar bleibt.
|
||||
Uebrig blieb ein Zipfel. Von einer Kristallwelt, die ueber das ganze
|
||||
Bild geht, war praktisch nichts mehr zu sehen.
|
||||
|
||||
Vorher war er fast doppelt so hoch und reichte in den
|
||||
Kachelbereich hinein. Dadurch musste er blass bleiben, sonst
|
||||
haette er durch die halbdurchsichtigen Kacheln geschienen. Kurz
|
||||
und kraeftig ist beides besser: mehr Wirkung dort, wo Platz ist,
|
||||
und null Stoerung dort, wo gearbeitet wird. */
|
||||
height: clamp(186px, 25vh, 250px);
|
||||
z-index: -1;
|
||||
Der Denkfehler war, Bild und Text auf dieselbe Ebene zu zwingen und
|
||||
dann das Bild zu opfern. Jetzt liegen sie auf zwei Ebenen: Das Bild
|
||||
ist die Buehne, der Inhalt schwebt als Milchglas darueber. Dadurch
|
||||
steht Text NIE direkt auf dem Bild -- und das Bild muss nirgends
|
||||
mehr weichen. */
|
||||
|
||||
.vw-buehne {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -2;
|
||||
pointer-events: none;
|
||||
|
||||
/* ZWEI Ebenen, und die Reihenfolge ist der ganze Trick:
|
||||
oben eine Deckschicht, darunter das Motiv.
|
||||
|
||||
Die Deckschicht ist LINKS fast undurchsichtig und wird nach
|
||||
rechts hin offen. Links stehen Titel und Reiter -- dort bleibt es
|
||||
ruhig. Rechts ist die Flaeche leer, dort darf das Bild richtig
|
||||
auftreten.
|
||||
|
||||
Der erste Versuch war gleichmaessig bei 17 % Deckkraft. Ergebnis:
|
||||
Das Wappen war ueberall gleich schwach zu ahnen, ein Fleck statt
|
||||
eines Bildes -- und trotzdem lag es hinter der Schrift. Diese
|
||||
Loesung ist beides zugleich staerker und ruhiger, weil Bild und
|
||||
Text sich schlicht nicht mehr denselben Platz teilen. */
|
||||
background:
|
||||
/* Bis 46 % voll deckend -- das ist genau die Zone, in der Titel
|
||||
und Reiterreihe liegen. Der Wert ist gemessen, nicht geschaetzt:
|
||||
Bei 34 % schob das Thron-Motiv seine hellen Kristallfluegel bis
|
||||
unter die Reiter und machte den Grund dort merklich unruhiger
|
||||
als ohne Bild. */
|
||||
linear-gradient(100deg,
|
||||
rgb(3 8 16 / 1) 0%,
|
||||
rgb(3 8 16 / 1) 46%,
|
||||
rgb(3 8 16 / .52) 64%,
|
||||
rgb(3 8 16 / .05) 86%,
|
||||
rgb(3 8 16 / 0) 100%),
|
||||
var(--vw-motiv, url("/assets/img/cryo-wappen.webp"))
|
||||
var(--vw-blick, center top) / 190% auto no-repeat;
|
||||
|
||||
opacity: .82;
|
||||
|
||||
/* Unten ausblenden, damit es keine sichtbare Kante gibt, an der das
|
||||
Bild einfach aufhoert. */
|
||||
-webkit-mask-image:
|
||||
linear-gradient(180deg, #000 0%, #000 55%, rgb(0 0 0 / .45) 82%, transparent 100%);
|
||||
mask-image:
|
||||
linear-gradient(180deg, #000 0%, #000 55%, rgb(0 0 0 / .45) 82%, transparent 100%);
|
||||
background: var(--vw-motiv, url("/assets/img/cryo-wappen.webp"))
|
||||
center center / cover no-repeat;
|
||||
/* Kein Zoom: "cover" zeigt bei einem 16:9-Motiv auf einem
|
||||
ueblichen Bildschirm praktisch das ganze Bild. */
|
||||
}
|
||||
|
||||
/* Die Kristallkante als eigene Ebene: ein sehr schmaler Leuchtsaum in
|
||||
der Leitfarbe, der den Streifen nach unten abschliesst. */
|
||||
.vw-schmuck::after {
|
||||
/* Eine ruhige Toenung darueber. Sie nimmt dem Bild nicht die Zeichnung,
|
||||
sondern legt nur so viel Tiefe darunter, dass die Glasflaechen sich
|
||||
abheben. Oben etwas dichter, weil dort die Kopfleiste sitzt. */
|
||||
.vw-buehne::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0; right: 0; bottom: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
rgb(var(--vw-farbe) / .55) 22%,
|
||||
rgb(var(--vw-farbe) / .18) 50%,
|
||||
rgb(var(--vw-farbe) / .55) 78%,
|
||||
transparent 100%);
|
||||
clip-path: polygon(
|
||||
0% 0%, 6% 100%, 13% 0%, 21% 100%, 29% 0%, 37% 100%, 45% 0%,
|
||||
53% 100%, 61% 0%, 69% 100%, 77% 0%, 85% 100%, 93% 0%, 100% 100%);
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(125% 95% at 50% 8%,
|
||||
rgb(3 8 16 / .18) 0%, rgb(3 8 16 / .38) 52%, rgb(3 8 16 / .60) 100%),
|
||||
linear-gradient(180deg,
|
||||
rgb(3 8 16 / .14) 0%, rgb(6 19 35 / .20) 55%, rgb(3 8 16 / .40) 100%);
|
||||
}
|
||||
|
||||
/* Beim Bereichswechsel blendet die Signatur kurz aus und wieder ein.
|
||||
Ohne das springt das Bild hart um -- mit sieht es aus, als wuerde
|
||||
der Raum wechseln. */
|
||||
@keyframes vw-signatur-ein {
|
||||
from { opacity: 0; transform: scale(1.05); }
|
||||
to { opacity: .82; transform: none; }
|
||||
/* Beim Bereichswechsel wechselt der ganze Raum. */
|
||||
@keyframes vw-buehne-ein {
|
||||
from { opacity: 0; transform: scale(1.06); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
.vw-buehne { animation: vw-buehne-ein .7s cubic-bezier(.16,.8,.3,1) both; }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.vw-buehne { animation: none; }
|
||||
}
|
||||
.vw-schmuck { animation: vw-signatur-ein .55s ease-out both; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
/* Auf dem Handy die kleine Fassung -- ein Bruchteil der Datenmenge
|
||||
fuer ein Bild, das ohnehin nur angedeutet ist. */
|
||||
/* Auf dem Handy ist links kein Platz, den man freihalten koennte --
|
||||
die Reiter laufen ueber die ganze Breite. Deshalb hier eine
|
||||
gleichmaessige Deckschicht und deutlich weniger Bild. */
|
||||
.vw-schmuck {
|
||||
/* Auf dem Handy die kleine Bildfassung. Und "cover" schneidet bei
|
||||
einem hochkant gehaltenen Telefon zwangslaeufig die Seiten weg --
|
||||
deshalb hier der Bildmittelpunkt, wo bei allen Motiven das
|
||||
Hauptgeschehen sitzt. */
|
||||
.vw-buehne {
|
||||
background-image: var(--vw-motiv-klein, url("/assets/img/cryo-wappen-klein.webp"));
|
||||
background-position: center center;
|
||||
}
|
||||
/* Auf kleinen Schirmen liegt mehr Inhalt uebereinander, also etwas
|
||||
mehr Tiefe unter dem Glas. */
|
||||
.vw-buehne::after {
|
||||
background:
|
||||
linear-gradient(180deg,
|
||||
rgb(3 8 16 / .82) 0%,
|
||||
rgb(3 8 16 / .88) 60%,
|
||||
rgb(3 8 16 / .95) 100%),
|
||||
var(--vw-motiv-klein, url("/assets/img/cryo-wappen-klein.webp"))
|
||||
var(--vw-blick, center top) / 190% auto no-repeat;
|
||||
opacity: .62;
|
||||
height: clamp(200px, 30vh, 300px);
|
||||
}
|
||||
@keyframes vw-signatur-ein {
|
||||
from { opacity: 0; transform: scale(1.04); }
|
||||
to { opacity: .62; transform: none; }
|
||||
rgb(3 8 16 / .52) 0%, rgb(6 19 35 / .58) 50%, rgb(3 8 16 / .72) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wer Bewegung reduziert haben will, bekommt den Wechsel ohne
|
||||
Animation -- das Motiv ist trotzdem da. */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.vw-schmuck { animation: none; }
|
||||
/* ---------- GLAS ----------
|
||||
|
||||
Alles, worauf gelesen wird, bekommt eine Rueckseiten-Unschaerfe.
|
||||
Das Bild bleibt sichtbar, verliert hinter dem Glas aber jede
|
||||
Struktur -- und genau das macht Text darauf ruhig lesbar.
|
||||
|
||||
Wo der Browser backdrop-filter nicht kann, traegt die Farbe allein:
|
||||
Deshalb ist der Hintergrund auch ohne Unschaerfe schon dicht genug.
|
||||
Das ist kein Schoenheitsfehler, sondern der Rueckfall. */
|
||||
#vw-bereich .wd-karte,
|
||||
#vw-bereich .vw-liste,
|
||||
#vw-bereich .wd-notiz,
|
||||
#vw-bereich .vw-kachel,
|
||||
#vw-bereich table {
|
||||
-webkit-backdrop-filter: blur(22px) saturate(1.15);
|
||||
backdrop-filter: blur(22px) saturate(1.15);
|
||||
}
|
||||
|
||||
/* Die Reiter und die Bedienknoepfe schweben ebenfalls. */
|
||||
#vw-bereich .vw-filter-knopf,
|
||||
#vw-bereich .vw-wer {
|
||||
-webkit-backdrop-filter: blur(16px) saturate(1.1);
|
||||
backdrop-filter: blur(16px) saturate(1.1);
|
||||
}
|
||||
|
||||
/* Meldungen wie "Wird geladen" oder "Nichts vorhanden" stehen frei
|
||||
zwischen den Kacheln -- also direkt auf der Buehne. Sie bekommen
|
||||
deshalb ihre eigene kleine Glasflaeche statt nur Text zu sein.
|
||||
Sonst haengt ausgerechnet die Zeile, die etwas erklaeren soll,
|
||||
ungeschuetzt vor einer Kristallwand. */
|
||||
#vw-bereich .vw-laedt,
|
||||
#vw-bereich .vw-leer {
|
||||
display: inline-block;
|
||||
padding: .55rem 1.1rem;
|
||||
border-radius: 999px;
|
||||
background: rgb(6 19 35 / .72);
|
||||
border: 1px solid rgb(var(--vw-farbe) / .22);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
/* Die Glaskacheln bekommen eine Leuchtkante in der Leitfarbe. Das
|
||||
bindet Inhalt und Buehne zusammen, statt die Kacheln wie
|
||||
aufgeklebte Zettel wirken zu lassen. */
|
||||
#vw-bereich .wd-karte {
|
||||
border-color: rgb(var(--vw-farbe) / .30);
|
||||
box-shadow:
|
||||
0 24px 60px -30px rgb(0 0 0 / .85),
|
||||
inset 0 1px 0 rgb(var(--vw-farbe) / .16);
|
||||
}
|
||||
|
||||
/* Der Titel steht als einziges frei auf der Buehne. Damit er das
|
||||
aushaelt, bekommt er einen weichen dunklen Hof -- kein Kasten, der
|
||||
die Buehne zerschneiden wuerde. */
|
||||
#vw-bereich .vw-leiste h1 {
|
||||
text-shadow:
|
||||
0 2px 18px rgb(3 8 16 / .95),
|
||||
0 1px 4px rgb(3 8 16 / .9);
|
||||
}
|
||||
|
||||
/* Suchen und Abmelden sitzen oben rechts -- also genau dort, wo das
|
||||
@@ -1397,7 +1403,7 @@
|
||||
<!-- Rein dekorativ, deshalb aria-hidden: Es gibt hier nichts
|
||||
vorzulesen, und ein leeres Element im Vorlesefluss ist nur
|
||||
eine Stolperstelle. -->
|
||||
<div class="vw-schmuck" aria-hidden="true"></div>
|
||||
<div class="vw-buehne" aria-hidden="true"></div>
|
||||
|
||||
<div class="wd-container">
|
||||
|
||||
@@ -3320,7 +3326,7 @@
|
||||
if (!ANSICHTEN[bereich]) return; // unbekannt: lieber nichts tun
|
||||
document.documentElement.setAttribute("data-vw-bereich", bereich);
|
||||
|
||||
var schmuck = document.querySelector(".vw-schmuck");
|
||||
var schmuck = document.querySelector(".vw-buehne");
|
||||
if (!schmuck) return;
|
||||
/* Wer Bewegung reduziert haben will, bekommt keinen Neustart -- die
|
||||
Animation ist fuer ihn ohnehin abgeschaltet. */
|
||||
|
||||
Reference in New Issue
Block a user