shadcn-ui / ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
https://ui.shadcn.com
MIT License
62.96k stars 3.54k forks source link

[BUG] Blurry Content on Low-Resolution Screens with Overflow-Auto in AlertDialog/Dialog Components #2363

Open hqw567 opened 5 months ago

hqw567 commented 5 months ago

Description

The content within AlertDialog/Dialog components becomes blurry on low-resolution screens when the overflow-auto property is in effect. This issue appears to be related to the use of translate on DialogContent. The blurring effect is noticeable when the content exceeds the container size, suggesting that the issue may be linked to subpixel rendering and the rasterization process on low-resolution displays.

Environment

Steps to Reproduce

  1. Create an AlertDialog/Dialog component with overflow-auto on DialogContent.
  2. Add enough content inside the DialogContent to cause overflow.
  3. Observe the content on a low-resolution screen.

Expected Behavior

Content should remain crisp and clear, without any blurring, regardless of screen resolution.

Actual Behavior

Content becomes blurry on low-resolution screens when overflow-auto is applied to DialogContent with a translate transform.

Additional Information

Possible Solutions

I am looking forward to any suggestions or workarounds for this issue. Thank you for your assistance!

AkshayCloudAnalogy commented 4 months ago

Any update on this?

artemshchirov commented 3 months ago

Any update on this?

rugys commented 2 months ago

Changing translate-y-[-50%] to translate-y-[-53%] in dialog.tsx component file removed the blurriness in most cases. it still happens when i change focus on a TinyMCE input I have within the dialog.


  React.ElementRef<typeof DialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <DialogPortal>
    <DialogOverlay />
    <DialogPrimitive.Content
      ref={ref}
      className={cn(
        "[&>div]:p-6 overflow-hidden !p-0 pt-[4.5rem] fixed left-[50%] top-[50%] z-20 grid w-full max-w-2xl translate-x-[-50%] translate-y-[-53%] border border-slate-200 bg-white shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-md md:w-full dark:border-slate-800 dark:bg-slate-950",
        className
      )}
    data-test="dialog-content"
      {...props}
    >
    {children}

    </DialogPrimitive.Content>
  </DialogPortal>
))```
Goodosky commented 2 months ago

Changing translate-y-[-50%] to translate-y-[-53%] in dialog.tsx component file removed the blurriness in most cases. it still happens when i change focus on a TinyMCE input I have within the dialog.

  React.ElementRef<typeof DialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <DialogPortal>
    <DialogOverlay />
    <DialogPrimitive.Content
      ref={ref}
      className={cn(
        "[&>div]:p-6 overflow-hidden !p-0 pt-[4.5rem] fixed left-[50%] top-[50%] z-20 grid w-full max-w-2xl translate-x-[-50%] translate-y-[-53%] border border-slate-200 bg-white shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-md md:w-full dark:border-slate-800 dark:bg-slate-950",
        className
      )}
    data-test="dialog-content"
      {...props}
    >
    {children}

    </DialogPrimitive.Content>
  </DialogPortal>
))```

This works (also for the Command component https://github.com/shadcn-ui/ui/issues/1465).

But my question is: why does this work? How did you come up with this? Is there a specific reason, or was it just trial and error?

slinso commented 2 months ago

I am a user of shadcn/svelte which is currently using the same CSS for dialogs. Here is the issue for the svelte version https://github.com/huntabyte/shadcn-svelte/issues/534 I analyzed it and wrote a lengthy comment in that issue.

IMHO it is best to make the DialogPrimitive.Content a child of DialogOverlay and then use "flex" to center the dialog. This way we would rid of the translate function which is the root of the problem.

MorelSerge commented 2 weeks ago

For those in need, here's the updated original component to use flexbox for centering, instead of translating, which removes the bluriness. The open animation has also been adjusted, so it's the same as before.

const DialogContent = React.forwardRef<
  React.ElementRef<typeof DialogPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <DialogPortal>
    <DialogOverlay />
    <div className="fixed z-50 inset-0 flex items-center justify-center">
      <DialogPrimitive.Content
        ref={ref}
        className={cn(
          "relative grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[-2%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[-2%] sm:rounded-lg",
          className
        )}
        {...props}
      >
        {children}
        <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
          <X className="h-4 w-4" />
          <span className="sr-only">Close</span>
        </DialogPrimitive.Close>
      </DialogPrimitive.Content>
    </div>
  </DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;