Frame
Un marco de proporción fija para que todas las imágenes de un conjunto se alineen, recortadas o contenidas.
Wall clockQ 340
Ceramic cupQ 95
Day backpackQ 520
Instalación
$ pnpm dlx shadcn@latest add @ssntl/frameUso
import { Frame } from "@/components/ui/frame"
<Frame ratio="landscape">
<img src="/taza.webp" srcSet="/taza.webp 1x, /taza@2x.webp 2x" alt="Taza de cerámica" width={640} height={480} />
</Frame>
<Frame fit="contain"><img src="/reloj.webp" alt="" /></Frame>Reglas
Lo que este componente espera de ti, tal como se instala en components/ui/frame.md junto al código. El archivo completo agrega cuándo usarlo, teclado, los fundamentos de UI que aplica y cada regla compartida (en inglés).
## Reglas de Frame
- **Marcos consistentes.** Cada imagen de un conjunto toma la misma proporción (square, portrait, landscape, wide, video) y se recorta para encajar.
- **Calidad de foto.** Sirve el doble del tamaño mostrado (`srcSet` 2x o sizes) y nunca estires una imagen más allá de su original; define width y height para que nada salte.
- `fit="contain"` para objetos recortados sobre fondo transparente: se muestran completos, con espacio alrededor.
- Un contorno de 1px al 10% mantiene el borde de una foto clara sobre cualquier superficie.Código
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
// A fixed-ratio frame for images in a set: products, galleries, covers.
// - Consistent frames: every image in a set takes the same ratio and is
// cropped to fit (object-cover), so a row never goes ragged.
// - Photo quality: give the image twice its displayed size (srcSet 2x, or
// sizes with a width list) and never stretch it past its source.
// - A 1px pure black (white in dark) outline at 10% keeps a light photo's
// edge on any surface.
const frameVariants = cva(
"relative overflow-hidden bg-muted outline -outline-offset-1 outline-black/10 dark:outline-white/10 [&_img]:size-full [&_img]:object-cover",
{
variants: {
ratio: {
square: "aspect-square",
portrait: "aspect-3/4",
landscape: "aspect-4/3",
wide: "aspect-16/10",
video: "aspect-video",
},
fit: {
cover: "",
// Cut-out objects on a transparent ground: shown whole, never cropped.
contain: "[&_img]:object-contain [&_img]:p-4",
},
},
defaultVariants: { ratio: "square", fit: "cover" },
}
)
function Frame({
ratio,
fit,
className,
...props
}: React.ComponentProps<"div"> & VariantProps<typeof frameVariants>) {
return (
<div
data-slot="frame"
className={cn("rounded-md", frameVariants({ ratio, fit, className }))}
{...props}
/>
)
}
export { Frame, frameVariants }