{"id":15730,"date":"2026-09-06T11:15:36","date_gmt":"2026-09-06T09:15:36","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/narzedzia\/colour-contrast-palette-auditor\/"},"modified":"2026-09-06T11:20:19","modified_gmt":"2026-09-06T09:20:19","slug":"colour-contrast-palette-auditor","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/","title":{"rendered":"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Paleta prowadzona w dw\u00f3ch motywach ma dwa sposoby na bycie b\u0142\u0119dn\u0105. Pierwszy to para o zbyt ma\u0142ym kontra\u015bcie. Drugi jest cichszy: zmienna zadeklarowana w jednym motywie i zapomniana w drugim, przez co barwa spada tam do warto\u015bci domy\u015blnej. Jedno i drugie staje si\u0119 widoczne, gdy oba bloki stoj\u0105 obok siebie.<\/p>\n<div style=\"display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; margin-bottom: 14px;\">\n<div>\n            <label for=\"ko-hell\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Motyw jasny, zmienne CSS<\/label><br \/>\n            <textarea id=\"ko-hell\" rows=\"10\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace; font-size: 0.82rem;\">:root {<br \/>\n  &#8211;bg-body: #f4f6f9;<br \/>\n  &#8211;bg-panel: #ffffff;<br \/>\n  &#8211;text-primary: #1a1f2b;<br \/>\n  &#8211;text-secondary: #5b6472;<br \/>\n  &#8211;border: #d7dde5;<br \/>\n  &#8211;accent: #0369a1;<br \/>\n  &#8211;on-accent: #ffffff;<br \/>\n}<\/textarea>\n        <\/div>\n<div>\n            <label for=\"ko-dunkel\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Motyw ciemny, zmienne CSS<\/label><br \/>\n            <textarea id=\"ko-dunkel\" rows=\"10\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace; font-size: 0.82rem;\">:root {<br \/>\n  &#8211;bg-body: #14141a;<br \/>\n  &#8211;bg-panel: #1e1e24;<br \/>\n  &#8211;text-primary: #e8e8ee;<br \/>\n  &#8211;text-secondary: #a0a0b0;<br \/>\n  &#8211;border: #2a2a35;<br \/>\n  &#8211;accent: #7ee787;<br \/>\n  &#8211;on-accent: #0b1114;<br \/>\n}<\/textarea>\n        <\/div>\n<\/p><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">Wystarczy dowolny blok CSS \u2014 deklaracje zostaj\u0105 z niego odczytane. Rozumiane s\u0105 hex, rgb() i hsl(); barwa z warto\u015bci\u0105 alfa jest mierzona na w\u0142asnej warto\u015bci i oznaczana, bo wynik zale\u017cy od tego, co le\u017cy pod spodem.<\/p>\n<p>    <button id=\"ko-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Zmierz kontrast<\/button><\/p>\n<div id=\"ko-ausgabe\" style=\"margin-top: 22px;\"><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; margin: 24px 0 0;\">Wszystko liczy si\u0119 w przegl\u0105darce. \u017badna warto\u015b\u0107 nie opuszcza tej strony.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Paleta prowadzona w dw\u00f3ch motywach ma dwa sposoby na bycie b\u0142\u0119dn\u0105. Pierwszy to para o zbyt ma\u0142ym kontra\u015bcie. Drugi jest cichszy: zmienna zadeklarowana w jednym motywie i zapomniana w drugim, przez co barwa spada tam do warto\u015bci domy\u015blnej. Jedno i drugie staje si\u0119 widoczne, gdy oba bloki stoj\u0105 obok siebie.\",\"label_hell\":\"Motyw jasny, zmienne CSS\",\"label_dunkel\":\"Motyw ciemny, zmienne CSS\",\"hinweis\":\"Wystarczy dowolny blok CSS \u2014 deklaracje zostaj\u0105 z niego odczytane. Rozumiane s\u0105 hex, rgb() i hsl(); barwa z warto\u015bci\u0105 alfa jest mierzona na w\u0142asnej warto\u015bci i oznaczana, bo wynik zale\u017cy od tego, co le\u017cy pod spodem.\",\"knopf\":\"Zmierz kontrast\",\"grenze\":\"Wszystko liczy si\u0119 w przegl\u0105darce. \u017badna warto\u015b\u0107 nie opuszcza tej strony.\",\"urteil_gut\":\"Nic nie stoi na przeszkodzie\",\"urteil_warnung\":\"Warte spojrzenia\",\"urteil_kritisch\":\"Wymaga uwagi\",\"grenzen_erklaerung\":\"WCAG 2.2 wymaga 4,5:1 dla tekstu zwyk\u0142ego, 3:1 dla tekstu du\u017cego od 24 px lub pogrubionego od 19 px oraz 3:1 dla obramowa\u0144 i element\u00f3w steruj\u0105cych nios\u0105cych znaczenie. Poziom AAA podnosi tekst zwyk\u0142y do 7:1.\",\"h_thema_hell\":\"Motyw jasny\",\"h_thema_dunkel\":\"Motyw ciemny\",\"thema_kopf\":\"Barw: {farben}, par: {paare}, najs\u0142absza pierwsza.\",\"spalte_vorne\":\"Pierwszy plan\",\"spalte_hinten\":\"T\u0142o\",\"spalte_wert\":\"Wsp\u00f3\u0142czynnik\",\"spalte_normal\":\"Tekst zwyk\u0142y\",\"spalte_gross\":\"Tekst du\u017cy\",\"spalte_hell\":\"Jasny\",\"spalte_dunkel\":\"Ciemny\",\"stufe_aa\":\"AA\",\"stufe_aaa\":\"AAA\",\"stufe_durchgefallen\":\"nie przechodzi\",\"nur_erste\":\"Wymienione s\u0105 pierwsze {gezeigt} z {gesamt} par.\",\"h_abweichung\":\"Pary, co do kt\u00f3rych motywy s\u0105 niezgodne\",\"h_fehlend\":\"Nazwy istniej\u0105ce tylko w jednym motywie\",\"fehlt_in_hell\":\"brak w motywie jasnym\",\"fehlt_in_dunkel\":\"brak w motywie ciemnym\",\"h_befunde\":\"Ustalenia\",\"keine_befunde\":\"Brak ustale\u0144.\",\"stufe_hoch\":\"Wysoki\",\"stufe_mittel\":\"\u015aredni\",\"stufe_niedrig\":\"Niski\",\"stufe_info\":\"Uwaga\",\"stufe_gut\":\"Dobrze\",\"befund_keine_farben\":\"Nie znaleziono deklaracji barw || W \u017cadnym z dw\u00f3ch blok\u00f3w nie sta\u0142a w\u0142asna w\u0142a\u015bciwo\u015b\u0107 z warto\u015bci\u0105 barwy.\",\"befund_namen_ungleich\":\"Nazw istniej\u0105cych tylko w jednym motywie: {anzahl} || Na przyk\u0142ad {namen}. W motywie bez deklaracji barwa spada do warto\u015bci domy\u015blnej regu\u0142y \u2014 a ta warto\u015b\u0107 zosta\u0142a dobrana pod drugi motyw.\",\"befund_unter_drei_hell\":\"Par poni\u017cej 3:1 w motywie jasnym: {anzahl} || Najs\u0142absza to {schlechtestes} z wynikiem {wert}:1. Poni\u017cej 3:1 nie da si\u0119 odr\u00f3\u017cni\u0107 nawet obramowania ani elementu steruj\u0105cego.\",\"befund_unter_drei_dunkel\":\"Par poni\u017cej 3:1 w motywie ciemnym: {anzahl} || Najs\u0142absza to {schlechtestes} z wynikiem {wert}:1. Poni\u017cej 3:1 nie da si\u0119 odr\u00f3\u017cni\u0107 nawet obramowania ani elementu steruj\u0105cego.\",\"befund_unter_aa_hell\":\"Par poni\u017cej 4,5:1 w motywie jasnym: {anzahl} || Najs\u0142absza to {schlechtestes} z wynikiem {wert}:1. Na tekst du\u017cy to wystarczy, na tekst ci\u0105g\u0142y ju\u017c nie.\",\"befund_unter_aa_dunkel\":\"Par poni\u017cej 4,5:1 w motywie ciemnym: {anzahl} || Najs\u0142absza to {schlechtestes} z wynikiem {wert}:1. Na tekst du\u017cy to wystarczy, na tekst ci\u0105g\u0142y ju\u017c nie.\",\"befund_alles_besteht_hell\":\"Wszystkie pary motywu jasnego ({anzahl}) osi\u0105gaj\u0105 4,5:1\",\"befund_alles_besteht_dunkel\":\"Wszystkie pary motywu ciemnego ({anzahl}) osi\u0105gaj\u0105 4,5:1\",\"befund_rolle_unklar\":\"Barw o zgadywanej roli: {anzahl} || Na przyk\u0142ad {namen}. Rola jest odczytywana z nazwy, a barwa nie wie, do czego jest u\u017cywana \u2014 pary oparte na zgadywaniu s\u0105 wskaz\u00f3wk\u0105, nie werdyktem.\",\"befund_mit_alpha\":\"Barw z warto\u015bci\u0105 alfa: {anzahl} || Liczy si\u0119 na samej barwie. Jak wygl\u0105da naprawd\u0119, zale\u017cy od warstwy pod spodem, a tego sama paleta nie zdradza.\",\"befund_themen_uneinig\":\"Par przechodz\u0105cych w jednym motywie i odpadaj\u0105cych w drugim: {anzahl} || Na przyk\u0142ad {beispiel}. To ten b\u0142\u0105d, kt\u00f3ry ujawnia si\u0119 dopiero przy wsp\u00f3lnym odczytaniu obu palet.\",\"dekor_hinweis\":\"Pary oznaczone * to dekoracja \u2014 mi\u0119kkie linie, welony, cienie oraz barwy \u201ena\\u0022 poza w\u0142asn\u0105 barw\u0105 podstawow\u0105. S\u0105 mierzone i wymieniane, ale nie stosuje si\u0119 do nich dolnej granicy, wi\u0119c pozostaj\u0105 poza ustaleniami.\",\"befund_rand_schwach_hell\":\"Par obramowa\u0144 i element\u00f3w steruj\u0105cych poni\u017cej 3:1 w motywie jasnym: {anzahl} || Najs\u0142absza to {schlechtestes} z wynikiem {wert}:1. WCAG 1.4.11 wymaga 3:1 tylko dla obrys\u00f3w, bez kt\u00f3rych element steruj\u0105cy nie by\u0142by rozpoznawalny \u2014 kraw\u0119d\u017a karty czy ramka zdj\u0119cia nie musi do nich nale\u017ce\u0107, jest to wi\u0119c kwestia oceny, a nie usterka.\",\"befund_rand_schwach_dunkel\":\"Par obramowa\u0144 i element\u00f3w steruj\u0105cych poni\u017cej 3:1 w motywie ciemnym: {anzahl} || Najs\u0142absza to {schlechtestes} z wynikiem {wert}:1. WCAG 1.4.11 wymaga 3:1 tylko dla obrys\u00f3w, bez kt\u00f3rych element steruj\u0105cy nie by\u0142by rozpoznawalny \u2014 kraw\u0119d\u017a karty czy ramka zdj\u0119cia nie musi do nich nale\u017ce\u0107, jest to wi\u0119c kwestia oceny, a nie usterka.\"};<\/p>\n<p>    var STUFEN = ['hoch', 'mittel', 'niedrig', 'info', 'gut'];\n    var GRENZEN = { normal_aa: 4.5, normal_aaa: 7, gross_aa: 3, gross_aaa: 4.5, ui: 3 };<\/p>\n<p>    function text(schluessel, daten) {\n        var t = T[schluessel];\n        if (typeof t !== 'string') { return null; }\n        return t.replace(\/\\{([a-z_0-9]+)\\}\/g, function (m, k) {\n            return (daten && daten[k] !== undefined && daten[k] !== null) ? String(daten[k]) : m;\n        });\n    }<\/p>\n<p>    \/\/ --- Farben lesen -----------------------------------------------------\n    function hslZuRgb(h, s, l) {\n        h = ((h % 360) + 360) % 360 \/ 360; s = s \/ 100; l = l \/ 100;\n        if (s === 0) { var g = Math.round(l * 255); return [g, g, g]; }\n        function hue(p, q, t) {\n            if (t < 0) { t += 1; } if (t > 1) { t -= 1; }\n            if (t < 1 \/ 6) { return p + (q - p) * 6 * t; }\n            if (t < 1 \/ 2) { return q; }\n            if (t < 2 \/ 3) { return p + (q - p) * (2 \/ 3 - t) * 6; }\n            return p;\n        }\n        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n        var p = 2 * l - q;\n        return [Math.round(hue(p, q, h + 1 \/ 3) * 255), Math.round(hue(p, q, h) * 255), Math.round(hue(p, q, h - 1 \/ 3) * 255)];\n    }\n\n    \/** Gibt [r,g,b] oder null. Alpha wird gemeldet, aber nicht verrechnet. *\/\n    function farbeLesen(roh) {\n        var s = String(roh || '').trim().toLowerCase();\n        if (s === '') { return null; }\n        var m;\n        if ((m = s.match(\/^#([0-9a-f]{3,8})$\/))) {\n            var h = m[1];\n            if (h.length === 3 || h.length === 4) {\n                return { rgb: [parseInt(h[0] + h[0], 16), parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16)],\n                    alpha: h.length === 4 ? parseInt(h[3] + h[3], 16) \/ 255 : 1 };\n            }\n            if (h.length === 6 || h.length === 8) {\n                return { rgb: [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)],\n                    alpha: h.length === 8 ? parseInt(h.slice(6, 8), 16) \/ 255 : 1 };\n            }\n            return null;\n        }\n        if ((m = s.match(\/^rgba?\\(([^)]+)\\)$\/))) {\n            var t = m[1].split(\/[\\s,\\\/]+\/).filter(function (x) { return x !== ''; });\n            if (t.length < 3) { return null; }\n            function kanal(w) { return w.indexOf('%') !== -1 ? Math.round(parseFloat(w) * 2.55) : parseInt(w, 10); }\n            var a = t.length > 3 ? (t[3].indexOf('%') !== -1 ? parseFloat(t[3]) \/ 100 : parseFloat(t[3])) : 1;\n            var rgb = [kanal(t[0]), kanal(t[1]), kanal(t[2])];\n            if (rgb.some(function (x) { return isNaN(x); })) { return null; }\n            return { rgb: rgb, alpha: isNaN(a) ? 1 : a };\n        }\n        if ((m = s.match(\/^hsla?\\(([^)]+)\\)$\/))) {\n            var u = m[1].split(\/[\\s,\\\/]+\/).filter(function (x) { return x !== ''; });\n            if (u.length < 3) { return null; }\n            var hh = parseFloat(u[0]), ss = parseFloat(u[1]), ll = parseFloat(u[2]);\n            if (isNaN(hh) || isNaN(ss) || isNaN(ll)) { return null; }\n            var aa = u.length > 3 ? (u[3].indexOf('%') !== -1 ? parseFloat(u[3]) \/ 100 : parseFloat(u[3])) : 1;\n            return { rgb: hslZuRgb(hh, ss, ll), alpha: isNaN(aa) ? 1 : aa };\n        }\n        var NAMEN = { white: [255, 255, 255], black: [0, 0, 0], red: [255, 0, 0], transparent: null };\n        if (Object.prototype.hasOwnProperty.call(NAMEN, s)) {\n            return NAMEN[s] ? { rgb: NAMEN[s], alpha: 1 } : null;\n        }\n        return null;\n    }<\/p>\n<p>    function leuchtdichte(rgb) {\n        var k = rgb.map(function (w) {\n            var c = Math.max(0, Math.min(255, w)) \/ 255;\n            return c <= 0.03928 ? c \/ 12.92 : Math.pow((c + 0.055) \/ 1.055, 2.4);\n        });\n        return 0.2126 * k[0] + 0.7152 * k[1] + 0.0722 * k[2];\n    }\n\n    function verhaeltnis(a, b) {\n        var la = leuchtdichte(a), lb = leuchtdichte(b);\n        var hell = Math.max(la, lb), dunkel = Math.min(la, lb);\n        return (hell + 0.05) \/ (dunkel + 0.05);\n    }\n\n    function runden(w) { return Math.round(w * 100) \/ 100; }\n\n    \/\/ --- Variablen lesen --------------------------------------------------\n    \/** Aus einem CSS-Block die eigenen Eigenschaften mit Farbwert holen. *\/\n    function variablenLesen(css) {\n        var raus = [];\n        var rx = \/(--[A-Za-z0-9_\\-]+)\\s*:\\s*([^;{}]+)\/g;\n        var m;\n        while ((m = rx.exec(String(css || ''))) !== null) {\n            var name = m[1];\n            var wert = m[2].trim().replace(\/\\s*!important\\s*$\/, '');\n            var f = farbeLesen(wert);\n            if (f === null) { continue; }\n            if (raus.some(function (x) { return x.name === name; })) { continue; }\n            raus.push({ name: name, wert: wert, rgb: f.rgb, alpha: f.alpha, rolle: rolleRaten(name) });\n        }\n        return raus;\n    }\n\n    \/**\n     * Rolle aus dem Namen raten. Das ist eine Vermutung und wird als solche\n     * ausgewiesen - eine Farbe weiss nicht, wofuer sie verwendet wird.\n     *\n     * Zwei Rollen halten Scheinbefunde heraus:\n     *   auf    - eine --on-*-Farbe gehoert auf ihre eine Grundfarbe und auf\n     *            keine andere Flaeche. Gegen alle Hintergruende gemessen\n     *            liefert sie Werte um 1:1, die nie jemand zu sehen bekommt.\n     *   dekor  - weiche Linien, Schleier und Schatten sind absichtlich kaum\n     *            sichtbar. Sie werden gemessen und gezeigt, zaehlen aber\n     *            nicht in die Befunde, weil eine Untergrenze auf sie nicht\n     *            anzuwenden ist.\n     *\/\n    function rolleRaten(name) {\n        var n = name.toLowerCase();\n        if (\/^--on-\/.test(n)) { return 'auf'; }\n        if (\/(soft|hairline|tint|wash|edge|glow|shadow|overlay|chip|scrim|veil)\/.test(n)) { return 'dekor'; }\n        if (\/(bg|background|panel|surface|body|paper|fond)\/.test(n)) { return 'hintergrund'; }\n        if (\/(text|fg|foreground|ink|label|heading)\/.test(n)) { return 'vordergrund'; }\n        if (\/(border|line|divider|outline|rule)\/.test(n)) { return 'element'; }\n        if (\/(accent|brand|primary|link|action|button|cta)\/.test(n)) { return 'element'; }\n        return 'unbekannt';\n    }\n\n    \/** Zu welcher Grundfarbe gehoert eine --on-*-Farbe? *\/\n    function grundfarbeZu(name) { return name.replace(\/^--on-\/, '--'); }\n\n    \/** Alle sinnvollen Paare eines Themas bilden und bewerten. *\/\n    function paareBilden(vars) {\n        function eintragen(paare, v, h, zaehlt) {\n            if (v.name === h.name) { return; }\n            var w = verhaeltnis(v.rgb, h.rgb);\n            paare.push({\n                vorne: v.name, hinten: h.name, wert: runden(w),\n                rolle: v.rolle, zaehlt: zaehlt,\n                normalAA: w >= GRENZEN.normal_aa, normalAAA: w >= GRENZEN.normal_aaa,\n                grossAA: w >= GRENZEN.gross_aa, ui: w >= GRENZEN.ui,\n                alpha: v.alpha < 1 || h.alpha < 1\n            });\n        }\n\n        var hg = vars.filter(function (v) { return v.rolle === 'hintergrund'; });\n        var vg = vars.filter(function (v) { return v.rolle === 'vordergrund' || v.rolle === 'element' || v.rolle === 'unbekannt'; });\n        var dekor = vars.filter(function (v) { return v.rolle === 'dekor'; });\n        var auf = vars.filter(function (v) { return v.rolle === 'auf'; });\n        \/\/ Ohne erkannte Hintergruende hilft nur: jede gegen jede.\n        if (!hg.length) { hg = vars.slice(); vg = vars.slice(); dekor = []; auf = []; }\n\n        var paare = [];\n        hg.forEach(function (h) {\n            vg.forEach(function (v) { eintragen(paare, v, h, true); });\n            dekor.forEach(function (v) { eintragen(paare, v, h, false); });\n        });\n        \/\/ Eine --on-*-Farbe nur gegen ihre eigene Grundfarbe.\n        auf.forEach(function (v) {\n            var grund = grundfarbeZu(v.name);\n            vars.forEach(function (h) { if (h.name === grund) { eintragen(paare, v, h, true); } });\n        });\n\n        paare.sort(function (a, b) { return a.wert - b.wert; });\n        return paare;\n    }\n\n    function befund(liste, key, stufe, daten) { liste.push({ key: key, stufe: stufe, daten: daten || {} }); }\n\n    \/** Die ganze Auswertung, beide Themen zusammen. *\/\n    function bewerten(cssHell, cssDunkel) {\n        var b = [];\n        var hell = variablenLesen(cssHell);\n        var dunkel = variablenLesen(cssDunkel);\n\n        if (!hell.length &#038;&#038; !dunkel.length) {\n            befund(b, 'keine_farben', 'hoch', {});\n            return { fehler: null, hell: { vars: [], paare: [] }, dunkel: { vars: [], paare: [] },\n                fehlend: [], befunde: b, stufengruppen: gruppieren(b), urteil: 'kritisch' };\n        }\n\n        var themen = {\n            hell: { vars: hell, paare: hell.length ? paareBilden(hell) : [] },\n            dunkel: { vars: dunkel, paare: dunkel.length ? paareBilden(dunkel) : [] }\n        };\n\n        \/\/ Beide Themen muessen dieselben Namen fuehren, sonst faellt im einen\n        \/\/ Thema eine Farbe auf die Vorgabe zurueck.\n        var namenHell = hell.map(function (v) { return v.name; });\n        var namenDunkel = dunkel.map(function (v) { return v.name; });\n        var fehlend = [];\n        if (hell.length &#038;&#038; dunkel.length) {\n            namenHell.forEach(function (n) { if (namenDunkel.indexOf(n) === -1) { fehlend.push({ name: n, fehlt_in: 'dunkel' }); } });\n            namenDunkel.forEach(function (n) { if (namenHell.indexOf(n) === -1) { fehlend.push({ name: n, fehlt_in: 'hell' }); } });\n            if (fehlend.length) {\n                befund(b, 'namen_ungleich', 'mittel', { anzahl: fehlend.length,\n                    namen: fehlend.slice(0, 5).map(function (f) { return f.name; }).join(', ') });\n            }\n        }\n\n        ['hell', 'dunkel'].forEach(function (thema) {\n            var t = themen[thema];\n            if (!t.vars.length) { return; }\n            \/\/ Nur zaehlende Paare gehen in die Befunde. Dekor bleibt sichtbar,\n            \/\/ aber ohne Untergrenze.\n            var zaehlend = t.paare.filter(function (p) { return p.zaehlt !== false; });\n            \/\/ Text unter 3:1 ist unstrittig kaputt. Ein Rand unter 3:1 ist es\n            \/\/ nicht: WCAG 1.4.11 verlangt die Grenze nur fuer Umrisse, die\n            \/\/ ein Bedienelement ueberhaupt erst erkennbar machen - eine\n            \/\/ Kartenkante gehoert nicht zwangslaeufig dazu. Deshalb zwei\n            \/\/ getrennte Befunde statt eines strengen.\n            var textPaare = zaehlend.filter(function (p) { return p.rolle === 'vordergrund' || p.rolle === 'auf'; });\n            var randPaare = zaehlend.filter(function (p) { return p.rolle === 'element' || p.rolle === 'unbekannt'; });\n            var unterUi = textPaare.filter(function (p) { return !p.ui; });\n            var randSchwach = randPaare.filter(function (p) { return !p.ui; });\n            var unterAA = textPaare.filter(function (p) { return p.ui &#038;&#038; !p.normalAA; });\n            var unbekannt = t.vars.filter(function (v) { return v.rolle === 'unbekannt'; });\n            var durchsichtig = t.vars.filter(function (v) { return v.alpha < 1; });\n\n            if (unterUi.length) {\n                befund(b, 'unter_drei_' + thema, 'hoch', { anzahl: unterUi.length,\n                    schlechtestes: unterUi[0].vorne + ' auf ' + unterUi[0].hinten, wert: unterUi[0].wert });\n            }\n            if (randSchwach.length) {\n                befund(b, 'rand_schwach_' + thema, 'mittel', { anzahl: randSchwach.length,\n                    schlechtestes: randSchwach[0].vorne + ' auf ' + randSchwach[0].hinten, wert: randSchwach[0].wert });\n            }\n            if (unterAA.length) {\n                befund(b, 'unter_aa_' + thema, 'mittel', { anzahl: unterAA.length,\n                    schlechtestes: unterAA[0].vorne + ' auf ' + unterAA[0].hinten, wert: unterAA[0].wert });\n            }\n            if (!unterUi.length &#038;&#038; !unterAA.length &#038;&#038; zaehlend.length) {\n                befund(b, 'alles_besteht_' + thema, 'gut', { anzahl: zaehlend.length });\n            }\n            if (unbekannt.length) {\n                befund(b, 'rolle_unklar', 'info', { anzahl: unbekannt.length,\n                    namen: unbekannt.slice(0, 4).map(function (v) { return v.name; }).join(', ') });\n            }\n            if (durchsichtig.length) {\n                befund(b, 'mit_alpha', 'niedrig', { anzahl: durchsichtig.length });\n            }\n        });\n\n        \/\/ Der Vergleich, um den es bei zwei Themen geht: ein Paar, das im\n        \/\/ einen Thema besteht und im anderen nicht.\n        var abweichung = [];\n        if (themen.hell.paare.length &#038;&#038; themen.dunkel.paare.length) {\n            var karte = {};\n            themen.dunkel.paare.forEach(function (p) { karte[p.vorne + '|' + p.hinten] = p; });\n            themen.hell.paare.forEach(function (p) {\n                if (p.zaehlt === false) { return; }\n                var g = karte[p.vorne + '|' + p.hinten];\n                if (!g) { return; }\n                if (p.normalAA !== g.normalAA) {\n                    abweichung.push({ vorne: p.vorne, hinten: p.hinten, hell: p.wert, dunkel: g.wert,\n                        besteht_hell: p.normalAA });\n                }\n            });\n            if (abweichung.length) {\n                befund(b, 'themen_uneinig', 'mittel', { anzahl: abweichung.length,\n                    beispiel: abweichung[0].vorne + ' auf ' + abweichung[0].hinten });\n            }\n        }\n\n        var gruppen = gruppieren(b);\n        var urteil = gruppen.hoch.length ? 'kritisch' : (gruppen.mittel.length ? 'warnung' : 'gut');\n        return { fehler: null, hell: themen.hell, dunkel: themen.dunkel, fehlend: fehlend,\n            abweichung: abweichung, befunde: b, stufengruppen: gruppen, urteil: urteil };\n    }\n\n    function gruppieren(b) {\n        var g = {};\n        STUFEN.forEach(function (s) { g[s] = b.filter(function (f) { return f.stufe === s; }); });\n        return g;\n    }\n\n    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.KO = { farbeLesen: farbeLesen, leuchtdichte: leuchtdichte, verhaeltnis: verhaeltnis,\n        variablenLesen: variablenLesen, rolleRaten: rolleRaten, paareBilden: paareBilden,\n        bewerten: bewerten, darstellen: null, text: text, STUFEN: STUFEN, GRENZEN: GRENZEN, T: T };\n\n    var btn = document.getElementById('ko-btn');\n    var out = document.getElementById('ko-ausgabe');\n    if (!btn || !out) { return; }\n\n    function el(tag, stil, txt) { var e = document.createElement(tag); if (stil) { e.setAttribute('style', stil); } if (txt !== undefined &#038;&#038; txt !== null) { e.textContent = txt; } return e; }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }\n    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 22px 0 8px;';\n    var ZELLE = 'padding: 5px 12px 5px 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem;';\n    var ZELLE_WERT = 'padding: 5px 12px 5px 0; color: var(--text-primary, #e8e8ee); font-size: 0.87rem; font-family: monospace; word-break: break-all;';\n    var KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 14px 16px; margin: 0 0 10px;';\n    var GUT = ' color: #7ee787;', WARN = ' color: #ffa94d;', ROT = ' color: #ff7b72;', GRAU = ' color: #8a8a99;';\n    var FARBEN = { hoch: '#ff7b72', mittel: '#ffa94d', niedrig: '#e3b341', info: '#8a8a99', gut: '#7ee787' };\n    var URTEIL = { gut: GUT, warnung: WARN, kritisch: ROT };\n    function gitter(sp) { return el('div', 'display: grid; grid-template-columns: ' + sp + '; gap: 0 18px; align-items: baseline;'); }\n\n    function themaZeigen(ziel, name, t) {\n        if (!t.vars.length) { return; }\n        ziel.appendChild(el('div', UEBERSCHRIFT, T['h_thema_' + name]));\n        ziel.appendChild(el('p', ZELLE + ' margin: 0 0 8px;', text('thema_kopf', { farben: t.vars.length, paare: t.paare.length })));\n        var huelle = el('div', 'overflow-x: auto;');\n        var g = gitter('auto auto auto auto auto');\n        [T.spalte_vorne, T.spalte_hinten, T.spalte_wert, T.spalte_normal, T.spalte_gross].forEach(function (s) {\n            g.appendChild(el('div', ZELLE + ' font-weight: 700; color: var(--text-primary, #e8e8ee); white-space: nowrap;', s));\n        });\n        t.paare.slice(0, 40).forEach(function (p) {\n            var stil = p.normalAA ? GUT : (p.ui ? WARN : ROT);\n            g.appendChild(el('div', ZELLE_WERT + (p.zaehlt === false ? GRAU : '') + ' white-space: nowrap;', p.vorne + (p.zaehlt === false ? ' *' : '')));\n            g.appendChild(el('div', ZELLE_WERT + GRAU + ' white-space: nowrap;', p.hinten));\n            g.appendChild(el('div', ZELLE_WERT + stil, p.wert.toFixed(2) + ':1'));\n            g.appendChild(el('div', ZELLE_WERT + (p.normalAA ? GUT : ROT), p.normalAAA ? T.stufe_aaa : (p.normalAA ? T.stufe_aa : T.stufe_durchgefallen)));\n            g.appendChild(el('div', ZELLE_WERT + (p.grossAA ? GUT : ROT), p.grossAA ? T.stufe_aa : T.stufe_durchgefallen));\n        });\n        huelle.appendChild(g);\n        ziel.appendChild(huelle);\n        if (t.paare.some(function (p) { return p.zaehlt === false; })) {\n            ziel.appendChild(el('p', ZELLE + GRAU + ' margin: 4px 0 0;', T.dekor_hinweis));\n        }\n        if (t.paare.length > 40) {\n            ziel.appendChild(el('p', ZELLE + GRAU + ' margin: 4px 0 0;', text('nur_erste', { gezeigt: 40, gesamt: t.paare.length })));\n        }\n    }<\/p>\n<p>    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        ziel.appendChild(el('div', 'font-size: 1.05rem; font-weight: 700; margin: 0 0 6px;' + URTEIL[b.urteil], T['urteil_' + b.urteil]));\n        ziel.appendChild(el('p', ZELLE + ' margin: 0 0 4px;', T.grenzen_erklaerung));<\/p>\n<p>        themaZeigen(ziel, 'hell', b.hell);\n        themaZeigen(ziel, 'dunkel', b.dunkel);<\/p>\n<p>        if (b.abweichung && b.abweichung.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_abweichung));\n            var g2 = gitter('auto auto auto auto');\n            [T.spalte_vorne, T.spalte_hinten, T.spalte_hell, T.spalte_dunkel].forEach(function (s) {\n                g2.appendChild(el('div', ZELLE + ' font-weight: 700; color: var(--text-primary, #e8e8ee); white-space: nowrap;', s));\n            });\n            b.abweichung.slice(0, 20).forEach(function (a) {\n                g2.appendChild(el('div', ZELLE_WERT + ' white-space: nowrap;', a.vorne));\n                g2.appendChild(el('div', ZELLE_WERT + GRAU + ' white-space: nowrap;', a.hinten));\n                g2.appendChild(el('div', ZELLE_WERT + (a.besteht_hell ? GUT : ROT), a.hell.toFixed(2) + ':1'));\n                g2.appendChild(el('div', ZELLE_WERT + (a.besteht_hell ? ROT : GUT), a.dunkel.toFixed(2) + ':1'));\n            });\n            ziel.appendChild(g2);\n        }<\/p>\n<p>        if (b.fehlend && b.fehlend.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_fehlend));\n            var g3 = gitter('auto auto');\n            b.fehlend.slice(0, 20).forEach(function (f) {\n                g3.appendChild(el('div', ZELLE_WERT, f.name));\n                g3.appendChild(el('div', ZELLE_WERT + WARN, f.fehlt_in === 'hell' ? T.fehlt_in_hell : T.fehlt_in_dunkel));\n            });\n            ziel.appendChild(g3);\n        }<\/p>\n<p>        ziel.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n        var irgendwas = false;\n        STUFEN.forEach(function (s) {\n            var gr = b.stufengruppen[s];\n            if (!gr.length) { return; }\n            irgendwas = true;\n            ziel.appendChild(el('div', 'font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 6px; color: ' + FARBEN[s] + ';', T['stufe_' + s] + ' (' + gr.length + ')'));\n            gr.forEach(function (f) {\n                var k = el('div', KASTEN + ' border-left: 3px solid ' + FARBEN[s] + ';');\n                var t = text('befund_' + f.key, f.daten) || f.key;\n                var teile = t.split(' || ');\n                k.appendChild(el('div', 'color: var(--text-primary, #e8e8ee); font-size: 0.9rem; font-weight: 700;', teile[0]));\n                if (teile[1]) { k.appendChild(el('div', ZELLE + ' padding: 6px 0 0; line-height: 1.55;', teile[1])); }\n                ziel.appendChild(k);\n            });\n        });\n        if (!irgendwas) { ziel.appendChild(el('p', ZELLE + ' margin: 0;', T.keine_befunde)); }\n    }\n    window.LW_TEST.KO.darstellen = darstellen;<\/p>\n<p>    btn.addEventListener('click', function () {\n        darstellen(bewerten(wert('ko-hell'), wert('ko-dunkel')), out);\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Narz\u0119dzie bierze zmienne CSS jasnej i ciemnej palety, tworzy ka\u017cd\u0105 par\u0119 pierwszego planu i t\u0142a oraz mierzy jej wsp\u00f3\u0142czynnik kontrastu wzgl\u0119dem WCAG 2.2. Sens trzymania obu naraz: para, kt\u00f3ra w jednym motywie przechodzi, a w drugim nie, oraz zmienna, kt\u00f3ra istnieje w jednej palecie, a w drugiej ju\u017c nie.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92762],"class_list":["post-15730","page","type-page","status-publish","hentry","tag-web-development-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Narz\u0119dzie bierze zmienne CSS jasnej i ciemnej palety, tworzy ka\u017cd\u0105 par\u0119 pierwszego planu i t\u0142a oraz mierzy jej wsp\u00f3\u0142czynnik kontrastu wzgl\u0119dem WCAG 2.2. Sens trzymania obu naraz: para, kt\u00f3ra w jednym motywie przechodzi, a w drugim nie, oraz zmienna, kt\u00f3ra istnieje w jednej palecie, a w drugiej ju\u017c nie.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-06T09:20:19+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/colour-contrast-palette-auditor\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/colour-contrast-palette-auditor\\\/\",\"name\":\"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-06T09:15:36+00:00\",\"dateModified\":\"2026-09-06T09:20:19+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/colour-contrast-palette-auditor\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/colour-contrast-palette-auditor\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/colour-contrast-palette-auditor\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/","og_locale":"en_US","og_type":"article","og_title":"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw - Lukas Wojcik - Blog","og_description":"Narz\u0119dzie bierze zmienne CSS jasnej i ciemnej palety, tworzy ka\u017cd\u0105 par\u0119 pierwszego planu i t\u0142a oraz mierzy jej wsp\u00f3\u0142czynnik kontrastu wzgl\u0119dem WCAG 2.2. Sens trzymania obu naraz: para, kt\u00f3ra w jednym motywie przechodzi, a w drugim nie, oraz zmienna, kt\u00f3ra istnieje w jednej palecie, a w drugiej ju\u017c nie.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-09-06T09:20:19+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/","name":"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-06T09:15:36+00:00","dateModified":"2026-09-06T09:20:19+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/colour-contrast-palette-auditor\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-3\/"},{"@type":"ListItem","position":3,"name":"Audytor kontrastu i palety: dwa motywy, jeden zestaw nazw"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15730","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=15730"}],"version-history":[{"count":2,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15730\/revisions"}],"predecessor-version":[{"id":15736,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/15730\/revisions\/15736"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=15730"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=15730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}