HextaUI

Aspect ratio

Medya yüklenmeden önce şeklini koruyan, yüklenirken parıldayan, medyayı yumuşakça görünür kılan ve hata durumunda yedeğe düşen bir kutu.

Sunset over mountains
import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioDemo() {
  return (
    <div className="w-full max-w-md">
      <AspectRatio ratio={16 / 9} className="rounded-xl">
        <img src="/preview/landscape.svg" alt="Sunset over mountains" />
      </AspectRatio>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/aspect-ratio.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import { AspectRatio } from "@/components/ui/aspect-ratio"
<AspectRatio ratio={16 / 9} className="rounded-lg">
  <img src="/photo.jpg" alt="Sunset over mountains" />
</AspectRatio>

Oranlar

ratio bir sayı, bir "w/h" dizesi veya bir "w:h" dizesi alır.

import {
  AspectRatio,
  type AspectRatioValue,
} from "@/components/ui/aspect-ratio"

const ratios: { label: string; ratio: AspectRatioValue }[] = [
  { label: "16 / 9", ratio: 16 / 9 },
  { label: "1", ratio: 1 },
  { label: '"4/3"', ratio: "4/3" },
  { label: '"21:9"', ratio: "21:9" },
]

export function AspectRatioRatios() {
  return (
    <div className="grid w-full max-w-md grid-cols-2 gap-3">
      {ratios.map(({ label, ratio }) => (
        <div key={label} className="flex flex-col gap-1.5">
          <AspectRatio ratio={ratio} className="rounded-lg">
            <img src="/preview/landscape.svg" alt="Sunset over mountains" />
          </AspectRatio>
          <span className="font-mono text-xs text-muted-foreground">
            {label}
          </span>
        </div>
      ))}
    </div>
  )
}

Yavaş yükleme

Kutu, görsel gelene kadar şeklini korur ve parlar; sonra görsel solarak belirir, böylece altındaki hiçbir şey kaymaz. Yeniden izlemek için Reload'a basın.

"use client"

import * as React from "react"

import { AspectRatio } from "@/components/ui/aspect-ratio"
import { Button } from "@/components/ui/button"

export function AspectRatioSlowLoad() {
  const [src, setSrc] = React.useState<string | undefined>(undefined)
  const [attempt, setAttempt] = React.useState(0)

  React.useEffect(() => {
    const timer = setTimeout(
      () => setSrc(`/preview/landscape.svg?v=${attempt}`),
      1500
    )
    return () => clearTimeout(timer)
  }, [attempt])

  return (
    <div className="flex w-full max-w-md flex-col gap-3">
      <AspectRatio ratio={16 / 9} className="rounded-xl">
        <img src={src} alt="Sunset over mountains" />
      </AspectRatio>
      <Button
        variant="outline"
        size="sm"
        className="self-start"
        onClick={() => {
          setSrc(undefined)
          setAttempt(attempt + 1)
        }}
      >
        Reload
      </Button>
    </div>
  )
}

Bozuk görsel

Görsel başarısız olduğunda tarayıcının bozuk görsel simgesi gizlenir ve onun yerine bir fallback simgesi gösterilir. Değiştirmek için fallback geçin, hiçbir şey göstermemek için fallback={null} kullanın.

import { IconMoodSad } from "@tabler/icons-react"

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioBrokenImage() {
  return (
    <div className="grid w-full max-w-md grid-cols-2 gap-3">
      <AspectRatio ratio={4 / 3} className="rounded-lg">
        <img src="/preview/does-not-exist.jpg" alt="Team photo" />
      </AspectRatio>
      <AspectRatio
        ratio={4 / 3}
        className="rounded-lg"
        fallback={
          <span className="flex flex-col items-center gap-1 text-xs">
            <IconMoodSad />
            Couldn’t load
          </span>
        }
      >
        <img src="/preview/does-not-exist.jpg" alt="Team photo" />
      </AspectRatio>
    </div>
  )
}

Bindirme

Mutlak konumlu alt öğeler medyanın üstünde durur. Kutu hiçbir şeyi kırpmaz, bu yüzden bindirme bağlantılarındaki odak halkaları görünür kalır.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioOverlay() {
  return (
    <div className="w-full max-w-md">
      <AspectRatio ratio={16 / 9} className="rounded-xl">
        <img src="/preview/landscape.svg" alt="Sunset over mountains" />
        <div className="absolute inset-x-3 bottom-3 flex items-center justify-between gap-3 rounded-lg bg-background/80 px-3 py-2 text-sm backdrop-blur-sm">
          <span className="truncate font-medium">Dolomites at dusk</span>
          <a
            href="#"
            className="shrink-0 rounded-sm underline underline-offset-4 outline-none focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden"
          >
            View
          </a>
        </div>
      </AspectRatio>
    </div>
  )
}

Placeholder olmadan

placeholder={false} yükleme shimmer'ını, solarak belirmeyi ve fallback'i kapatır; düz shadcn davranışı elde edilir.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioWithoutPlaceholder() {
  return (
    <div className="w-full max-w-md">
      <AspectRatio ratio={16 / 9} placeholder={false} className="rounded-lg">
        <img src="/preview/landscape.svg" alt="Sunset over mountains" />
      </AspectRatio>
    </div>
  )
}

Duyarlı

Oranı bir breakpoint'te bir aspect sınıfıyla geçersiz kılın. Bu örnek küçük ekranlarda kare, md ve üzerinde md:aspect-video olur.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioResponsive() {
  return (
    <div className="w-full max-w-md">
      <AspectRatio ratio={1} className="rounded-lg md:aspect-video">
        <img src="/preview/landscape.svg" alt="Sunset over mountains" />
      </AspectRatio>
    </div>
  )
}

Ortalanmış bir flex sütunu içinde

Kutu varsayılan olarak tam genişliktedir; bu yüzden üst öğe alt öğelerini ortaladığında sıfıra çökmez, sütunu doldurur.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioFlexColumn() {
  return (
    <div className="flex w-full max-w-md flex-col items-center rounded-lg border border-dashed p-3">
      <AspectRatio ratio={16 / 9} className="rounded-lg">
        <img src="/preview/landscape.svg" alt="Sunset over mountains" />
      </AspectRatio>
    </div>
  )
}

Metin içeriği

Medya olmayan alt öğeler yalnızca kutuyu alır, başka bir şey almaz. Konumlandırmayı kendiniz yapın.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioTextContent() {
  return (
    <div className="w-full max-w-md">
      <AspectRatio ratio={3} className="rounded-lg border">
        <div className="absolute inset-0 grid place-items-center p-4 text-center text-sm text-muted-foreground">
          Any content can sit in the box.
        </div>
      </AspectRatio>
    </div>
  )
}

Figure olarak

Oranı değiştirmemeleri için alt yazıları kutunun dışında tutun.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioFigure() {
  return (
    <figure className="flex w-full max-w-md flex-col gap-2">
      <AspectRatio ratio={16 / 9} className="rounded-lg">
        <img src="/preview/landscape.svg" alt="Sunset over mountains" />
      </AspectRatio>
      <figcaption className="text-xs text-muted-foreground">
        Dolomites at dusk, photographed from Seceda.
      </figcaption>
    </figure>
  )
}

Geçersiz oran

0, negatif sayılar ve ayrıştırılamayan dizeler kareye geri döner ve geliştirme sırasında bir uyarı kaydeder.

import {
  AspectRatio,
  type AspectRatioValue,
} from "@/components/ui/aspect-ratio"

export function AspectRatioInvalidRatio() {
  return (
    <div className="grid w-full max-w-md grid-cols-2 gap-3">
      <AspectRatio ratio={0} className="rounded-lg border" />
      <AspectRatio
        ratio={"abc" as AspectRatioValue}
        className="rounded-lg border"
      />
    </div>
  )
}

Sağdan sola

start-3 gibi mantıksal özelliklerle konumlandırılan bindirmeler okuma yönünü izler.

import { AspectRatio } from "@/components/ui/aspect-ratio"

export function AspectRatioRtl() {
  return (
    <div dir="rtl" className="w-full max-w-md">
      <AspectRatio ratio={16 / 9} className="rounded-lg">
        <img src="/preview/landscape.svg" alt="غروب الشمس فوق الجبال" />
        <span className="absolute start-3 top-3 rounded-md bg-background/80 px-2 py-1 text-xs">
          جديد
        </span>
      </AspectRatio>
    </div>
  )
}
  • Medyası yüklenirken kutu aria-busy olur.
  • Fallback dekoratiftir ve yardımcı teknolojilerden gizlenir. Görsel yüklenemediğinde görselin alt metni erişilebilir kalır; bu yüzden her zaman bir tane yazın.
  • Azaltılmış hareket açıkken medya solmadan görünür.

Oluşturduğu öğenin tüm niteliklerini kabul eder. Doğrudan içine yerleştirilen medya (bir <img>, <picture> veya <video>), object-cover ile kutuyu doldurur ve yarıçapını devralır.

PropTürVarsayılan
ratio
number | `${number}/${number}` | `${number}:${number}`1
placeholderMedya yüklenirken bir shimmer, başarısız olduğunda bir fallback gösterir.
booleantrue
fallbackMedya başarısız olduğunda gösterilir. null hiçbir şey göstermez.
ReactNode<IconPhotoOff />
render
ReactElement | (props, state) => ReactElement<div>
ÖznitelikAçıklama
data-slot="aspect-ratio"CSS'te kutuyu hedefleyin.
data-stateloading, loaded veya error. Yalnızca placeholder açıkken ve kutu medya içerirken ayarlanır.
aria-busyMedya yüklenirken bulunur.
--ratioSayı olarak ayrıştırılmış oran.
data-slot="aspect-ratio-placeholder"Yükleme sırasında veya hatadan sonra gösterilen shimmer.
data-slot="aspect-ratio-fallback"Fallback'i saran sarmalayıcı.

parseAspectRatio(ratio) kabul edilen her oranı bir sayıya dönüştürür, olmazsa 1'e geri döner. Diğer öğeleri aynı biçimde boyutlandırmak için kullanın. AspectRatioValue ve AspectRatioProps tipleri de dışa aktarılır.