Files
op-packages/luci-theme-footstrap/styles/theme/15-wallpaper.css
T
github-actions[bot] 410d762592
Merge-upstream / merge (push) Canceled after 0s
🎄 Sync 2026-08-27 02:13:09
2026-08-27 02:13:09 +08:00

78 lines
4.2 KiB
CSS

@layer theme {
/* Wallpaper axis, value `pattern`: an SVG the admin uploads, tiled behind the content and
* recoloured by the theme, so the same file reads correctly in light and dark and under any
* palette without being edited.
*
* A dedicated element rather than a `background-image`, because recolouring a rasterised image
* takes `mask-image` — the SVG supplies the alpha, the element the colour — and a mask applies
* to the element's whole rendering, children included, so it can never go on .fs-shell or
* <body>. Hence .fs-pattern, emitted as the first child of <body> by header.ut and sysauth.ut
* (the login page has no .fs-shell), whose only job is to be masked.
*
* z-index: -1 with a transparent body, because inside the root stacking context the paint order
* is html's background, then negative-z children, then every block background: the layer sits
* above the canvas and below the content, but body's own opaque --fs-bg would bury it. The
* canvas therefore moves up to :root for this axis and body goes transparent; .fs-main and the
* footer paint their own --fs-bg and follow for the same reason. The sidebar is deliberately
* not excluded —
* the bar is translucent and the pattern showing behind it is what makes the page read as one
* sheet.
*
* Cards sit on opaque --fs-panel, so the pattern shows through the gaps only. */
.fs-pattern { display: none; }
:root[data-wallpaper="pattern"] { background-color: var(--fs-bg); }
:root[data-wallpaper="pattern"] body,
:root[data-wallpaper="pattern"] .fs-main { background-color: transparent; }
:root[data-wallpaper="pattern"] footer.fs-footer { background: transparent; }
/* `fixed`, so the pattern is one calm backdrop the page scrolls under rather than a strip that
* slides with every table — the same argument the File photo's background-attachment makes.
* --fs-pattern-url is `none` until something is uploaded (head.ut / fs-prefs.js), so the axis
* selected with no file is a bare canvas rather than a broken tile. */
:root[data-wallpaper="pattern"] .fs-pattern {
display: block;
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
opacity: var(--fs-pattern-strength);
}
/* THEME INK (the default). The file's own colours are discarded and only its alpha is used, so
* an opaque background inside the SVG would mask as a solid sheet — which is exactly why the
* admin can switch to the file's own colours below. Line art on transparency is the shape this
* mode is for. */
:root[data-wallpaper="pattern"]:not([data-pattern-ink="original"]) .fs-pattern {
background-color: var(--fs-text);
-webkit-mask-image: var(--fs-pattern-url);
mask-image: var(--fs-pattern-url);
-webkit-mask-repeat: repeat;
mask-repeat: repeat;
-webkit-mask-size: var(--fs-pattern-size) auto;
mask-size: var(--fs-pattern-size) auto;
}
/* THE FILE'S OWN COLOURS: an ordinary tiled background, no mask. For artwork that carries its
* own palette and would be flattened to one colour by the mask. */
:root[data-wallpaper="pattern"][data-pattern-ink="original"] .fs-pattern {
background-image: var(--fs-pattern-url);
background-repeat: repeat;
background-size: var(--fs-pattern-size) auto;
}
/* A CBI form has dozens of .btn/.cbi-button; a backdrop-filter on each is a live
* backdrop-sampling layer over the pattern — costly on weak GPUs, and invisible anyway
* since every button is already opaque. Blur dropped from buttons entirely; closed
* dropdowns keep the frost (few of them, and their body can show the pattern through). */
/* var(--fs-blur), not a literal: one radius for every frosted surface (02-tokens.css), and
* the literal 6px was also invisible to prefers-reduced-transparency, which nulls the token
* (95-a11y-media.css) — the one frost that kept blurring for users who asked for opaque. */
:root[data-wallpaper="pattern"] .cbi-dropdown:not([open]) {
backdrop-filter: var(--fs-blur);
-webkit-backdrop-filter: var(--fs-blur);
}
/* No wash layer behind #view: the pattern shows through the gaps between the cards at
* full strength. Every block that carries text paints an opaque --fs-panel of its own,
* so nothing has to be dimmed globally. */
}