HextaUI

Hairline

Rahmen und Ringe, die auf jedem Bildschirm genau ein Geräte-Pixel breit sind, über eine einzige Variable, die das ganze Theme liest.

1px
inset-ring-1
hairline
inset-ring-(length:--hairline)
export function HairlineDemo() {
  return (
    <div className="grid w-full max-w-sm grid-cols-2 gap-4 text-sm">
      <div className="flex flex-col gap-2">
        <div className="flex h-24 items-center justify-center rounded-lg inset-ring-1 inset-ring-foreground/40">
          1px
        </div>
        <span className="text-center text-xs text-muted-foreground">
          inset-ring-1
        </span>
      </div>
      <div className="flex flex-col gap-2">
        <div className="flex h-24 items-center justify-center rounded-lg inset-ring-(length:--hairline) inset-ring-foreground/40">
          hairline
        </div>
        <span className="text-center text-xs text-muted-foreground">
          inset-ring-(length:--hairline)
        </span>
      </div>
    </div>
  )
}

Hairline ist Teil des HextaUI-Themes. Wenn du das Theme oder eine beliebige Komponente hinzugefügt hast, ist es vorhanden.

pnpm dlx shadcn@latest add https://hextaui.com/r/theme.json

Oder füge es von Hand zu deinem globalen CSS hinzu.

app/globals.css
@theme inline {
  --default-border-width: var(--hairline);
}

@utility border-hairline {
  border-width: var(--hairline);
}

:root {
  --hairline: 1px;

  @media (min-resolution: 1.5dppx) {
    --hairline: calc(1px / 1.5);
  }

  @media (min-resolution: 2dppx) {
    --hairline: 0.5px;
  }

  @media (min-resolution: 3dppx) {
    --hairline: calc(1px / 3);
  }

  @media (min-resolution: 4dppx) {
    --hairline: 0.25px;
  }
}
<div className="border" />
<ul className="divide-y" />
<div className="border-2 sm:border-hairline" />
<button className="inset-ring-(length:--hairline) inset-ring-border" />
<hr className="h-(--hairline) border-0 bg-border" />

Du musst selten direkt darauf zugreifen. Das Theme macht es zur Standard-Rahmenbreite, sodass border, border-t und divide-y alle Hairlines zeichnen. Verwende die Variable direkt dort, wo Tailwind keinen Standard hat, etwa bei Ringen, Outlines und mit einem Hintergrund gezeichneten Linien.

Ein CSS-Pixel deckt auf den meisten Bildschirmen zwei oder drei physische Pixel ab, ein 1px-Rahmen ist also in Wirklichkeit zwei oder drei Geräte-Pixel dick. --hairline teilt durch das Pixelverhältnis des Displays, sodass jede Linie genau ein Geräte-Pixel misst, so wie native Apps Trennlinien zeichnen. Auf einem Standarddisplay bleibt es 1px.

PixelverhältnisBeschreibung
1×1px
1.5×0.667px
2×0.5px
3×0.333px
4×0.25px

Listen und Karten

Einfaches border und divide-y. Dünnere Trennlinien gruppieren Zeilen, ohne sie einzusperren.

const rows = [
  ["Plan", "Pro"],
  ["Seats", "12"],
  ["Billing", "Yearly"],
  ["Renews", "Mar 4, 2027"],
]

export function HairlineList() {
  return (
    <dl className="w-full max-w-xs divide-y rounded-xl border text-sm">
      {rows.map(([term, value]) => (
        <div key={term} className="flex justify-between px-4 py-3">
          <dt className="text-muted-foreground">{term}</dt>
          <dd>{value}</dd>
        </div>
      ))}
    </dl>
  )
}
  • HextaUI-Komponenten zeichnen Kanten mit inset-ring-(length:--hairline) statt mit Rahmen. Ein Inset-Ring beansprucht keinen Layoutplatz, sodass ein Zustand, der Farbe oder Breite des Rings ändert, den Inhalt nie verschiebt.
  • Hairlines wirken auf der Seite heller, daher kann eine für 1px-Linien abgestimmte Rahmenfarbe blass aussehen. Das --border des Themes ist auf Hairlines abgestimmt.
  • Verwende border-2 oder breiter zur Betonung, etwa bei einer ausgewählten Karte. Diese bleiben in CSS-Pixeln.
NameBeschreibung
--hairlineEin Geräte-Pixel, in CSS-Pixeln.
border-hairlineSetzt border-width auf --hairline.
--default-border-widthAuf --hairline gesetzt, sodass border und divide es als Standard verwenden.