유리 표면Liquid glass

LiquidGlass가 그리는 재질, 호스트에 필요한 클래스, 흐림을 쓸 수 없을 때의 대체 채움입니다.The material LiquidGlass draws, the classes a host needs, and the fallback fill when the backdrop cannot be blurred.

재질The material

LiquidGlass는 @horon-ai/tokens의 glass.ts 값을 그대로 씁니다. Flutter의 HoronLiquidGlass도 같은 값을 읽어 web, desktop(WebView2, WKWebView), iOS, Android가 같은 모습이 됩니다.LiquidGlass reads the values in glass.ts from @horon-ai/tokens. Flutter's HoronLiquidGlass reads the same values, so web, desktop (WebView2, WKWebView), iOS and Android look the same.

  • 배경: 뒤 내용을 20px 흐리게 하고 채도를 180%로 올립니다.Backdrop: blurs what is behind by 20px and raises saturation to 180%.
  • 채움: 호스트가 glass-clear, glass-regular, glass-thick 중 하나로 칠합니다. 높은 값일수록 불투명합니다.Fill: the host paints one of glass-clear, glass-regular or glass-thick. The later the tier, the more opaque.
  • 테두리: 가장자리 안쪽 1px 링입니다. 위가 밝고 가운데에서 옅어졌다가 아래에서 조금 다시 밝아집니다. 호스트에는 자기 테두리를 두지 않습니다. 링이 곧 테두리입니다.Edge: a 1px ring inside the border. Bright at the top, faint at the middle, a little brighter again at the bottom. The host keeps no border of its own; the ring is the edge.

호스트 규칙Host rules

LiquidGlass는 prop을 받지 않고 aria-hidden span 하나를 그립니다. 시각 결정은 모두 호스트의 클래스에서 옵니다.LiquidGlass takes no props and renders a single aria-hidden span. Every visual decision comes from the host's class list.

  • 호스트의 첫 자식으로 둡니다. 레이어는 absolute inset-0이고 반경을 호스트에서 물려받습니다.Make it the host's first child. The layer is absolute inset-0 and inherits the host's radius.
  • 호스트에 relative isolate와 반경, 채움 클래스를 답니다. isolate가 레이어의 z 순서를 호스트 안에 가둡니다.Give the host relative isolate, a radius and the fill class. isolate keeps the layer's z order inside the host.
  • 호스트에 [&>.liquid-layers]:-z-10을 두면 레이어가 호스트 채움 위, 본문 아래로 확정됩니다. Card는 이 일을 스스로 합니다.Putting [&>.liquid-layers]:-z-10 on the host fixes the layer above the host fill and under the body. Card does this itself.
  • isolate를 걸 수 없는 호스트는 본문 요소를 relative로 올려 같은 순서를 만듭니다. LiquidGlass의 예제가 이 방식입니다.A host that cannot isolate raises its body to relative instead, which gives the same order. LiquidGlass's own example does that.
  • 레이어에 bg-glass-*를 얹지 않습니다. 폴백 채움을 덮어서 표면을 실제와 다르게 그립니다.Never put bg-glass-* on the layer. It overrides the fallback fill and draws a surface that differs from the real one.
  • 유리 높이를 정하는 tier prop은 없습니다. 예전 코드의 tier="thick" 같은 인자는 지웁니다.There is no tier prop. In older code, remove arguments such as tier="thick".
floating-bar.tsx
import { LiquidGlass } from "@horon-ai/react";

export function FloatingBar() {
  return (
    <div className="relative isolate overflow-clip rounded-xl bg-glass-regular [&>.liquid-layers]:-z-10">
      <LiquidGlass />
      <p className="px-4 py-3 text-body-sm">Floating chrome</p>
    </div>
  );
}

폴백Fallback

투명도 줄이기 설정이 켜져 있거나 엔진이 backdrop-filter를 지원하지 않으면 흐림 대신 glass-fill-frost 채움이 칠해지고 링은 그대로 남습니다. 이 판단은 globals.css가 하므로 컴포넌트마다 따로 처리하지 않습니다.With reduced transparency requested, or an engine without backdrop-filter, the fill turns to glass-fill-frost and the ring stays. globals.css decides this, so no component handles it separately.

카드Card

Card는 surface로 solid, glass, frost를 고릅니다. glass와 frost는 bg-glass-thick을 쓰고 frost는 glass-fill-frost로 덮습니다. Card는 relative isolate와 -z-10을 스스로 답니다.Card picks solid, glass or frost with surface. glass and frost use bg-glass-thick, and frost overrides it with glass-fill-frost. Card sets relative isolate and -z-10 on its own.

cards.tsx
<Card surface="glass" title="Deploy" description="Ship the build." />
<Card surface="frost" title="Today" description="3 runs finished." />

유리가 놓이는 자리Where glass belongs

유리는 배경 위에 떠 있는 크롬에만 씁니다. 헤더, 사이드바, 다이얼로그, 컴포저, 탭 바, 토스트, 메뉴, 툴팁입니다. 읽거나 누르는 내용 표면은 solid 토큰 표면을 씁니다.Glass belongs to chrome floating over a backdrop: headers, the sidebar, dialogs, the composer, tab bars, toasts, menus and tooltips. Content surfaces people read or press use the solid token surfaces.

입력 필드와 오버레이는 veil을 씁니다. glass.ts의 veil은 8px 흐림에 채도 160%이고, 링과 그림자가 있습니다.Fields and overlays use the veil: glass.ts sets an 8px blur at 160% saturation with a ring and a shadow.