feat(glass): Liquid Glass эффект через SVG displacement-фильтр (по статье Хабра)

- PNG карта мелкого равномерного шума (public/assets/liquid-glass/displacement.png)
- инлайн SVG feDisplacementMap инъецируется во все страницы сборщиком (build-pages.mjs)
- glass-neutral + шапка/панели/FAB/overflow получают url(#filter) blur в Chromium
- Safari/Firefox: детект через @supports not (hanging-punctuation:first), остаётся чистый blur
- токены --v12-glass-neutral-filter-lg / -elevated-lg для обеих тем
This commit is contained in:
root committed 2026-09-24 15:14:55 +02:00
1 parent e3acfa072c
commit 5fd8324b47
41 files changed
+535 -137

No files matched your search

+13
View File
@@ -11,6 +11,16 @@ const outDir = path.join(rootDir, "public");
const LOCALES = ["ru", "en"];
const DEFAULT_LOCALE = "ru";
// Liquid Glass: инлайн SVG displacement-фильтр, инъецируется во все страницы.
// PNG-карта — мелкий равномерный шум (см. статью Хабра), даёт «живое» стекло в Chromium.
// В Safari/Firefox url()-фильтр в backdrop-filter не рендерится — там остаётся чистый blur.
const LIQUID_GLASS_FILTER = `<svg class="liquid-glass-defs" aria-hidden="true" width="0" height="0" focusable="false" style="position:absolute;width:0;height:0;overflow:hidden;pointer-events:none">
<filter id="liquid-glass-displacement" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
<feImage href="{{LG_ASSET_PREFIX}}assets/liquid-glass/displacement.png" xlink:href="{{LG_ASSET_PREFIX}}assets/liquid-glass/displacement.png" preserveAspectRatio="none" result="lgMap"/>
<feDisplacementMap in="SourceGraphic" in2="lgMap" scale="28" xChannelSelector="R" yChannelSelector="G"/>
</filter>
</svg>`;
// --- SEO ---
const SITE_ORIGIN = "https://mamadaevv.site";
const OG_IMAGE_DEFAULT = `${SITE_ORIGIN}/assets/og/og-default.png`;
@@ -401,6 +411,9 @@ function build() {
if (isCase) {
rendered = stripCurrentCasePortfolioCarouselItem(rendered, omitFile);
}
// Liquid Glass: инъецируем инлайн SVG displacement-фильтр сразу после <body>.
const lgSvg = LIQUID_GLASS_FILTER.replace(/{{LG_ASSET_PREFIX}}/g, vars.assetPrefix);
rendered = rendered.replace(/(<body[^>]*>)/, `$1\n ${lgSvg}\n`);
ensureDir(path.dirname(outPath));
fs.writeFileSync(outPath, rendered, "utf8");
}