Shadcn

Shadcn

DatePickerWithRange 本地化适配

interface DatePickerWithRangeProps {
  onDateChange?: (start: string, end: string) => void 
}

export function DatePickerWithRange({ 
  onDateChange 
}: DatePickerWithRangeProps) {
  const [date, setDate] = React.useState<DateRange | undefined>({
    // from: new Date(new Date().getFullYear(), 0, 20),
    // to: addDays(new Date(new Date().getFullYear(), 0, 20), 20),
    from: new Date(),
    to: new Date(),
  })

  // 监听内部 date 变化,并触发外部回调
  React.useEffect(() => {
    if (date?.from && date?.to) {
      const startStr = format(date.from, "yyyy-MM-dd")
      const endStr = format(date.to, "yyyy-MM-dd")
      onDateChange?.(startStr, endStr)
    }
  }, [date, onDateChange])

  return (
    <Popover>
      <PopoverTrigger render={<Button variant="outline" id="date-picker-range" className="justify-start px-2.5 font-normal"><CalendarIcon data-icon="inline-start" />{date?.from ? (
        date.to ? (
          <>
            {format(date.from, "yyyy年MM月dd日", { locale: zhCN })} -{" "}
            {format(date.to, "yyyy年MM月dd日", { locale: zhCN })}
          </>
        ) : (
          format(date.from, "yyyy年MM月dd日", { locale: zhCN })
        )
      ) : (
        <span>选择日期范围</span>
      )}</Button>} />
      <PopoverContent className="w-auto p-0" align="start">
        <Calendar
          mode="range"
          defaultMonth={date?.from}
          selected={date}
          onSelect={setDate}
          numberOfMonths={2}
          locale={zhCN}
        />
      </PopoverContent>
    </Popover>
  )
}

Tailwind v4 的适配性问题

Tailwind CSS v4 和最新版的 Shadcn UI 默认全面启用了 oklch 颜色空间。这是一个非常现代的 CSS 特性,在最新的 PC 浏览器(Chrome 111+, Safari 15.4+)上运行完美。

但是,Android 平板自带的内置浏览器(或稍老版本的移动端 Chrome 内核)极大概率还不支持 oklch()
当浏览器不认识 oklch(1 0 0) 时,它会直接忽略这行 CSS,导致所有依赖这些变量的背景、边框颜色全部失效,退化成默认的透明或白色。同时,布局错乱也可能是因为某些现代 CSS 特性(如某些 Flex/Grid 复合属性)在内置浏览器上的降级。

为了在 Android/平板设备上完美运行,你需要做以下三步调整:

第一步:将 oklch 降级为 hsl 格式(最关键)

你需要把 index.css 中的颜色变量替换为所有浏览器都支持的 hsl 格式。

请将你的 :root.dark 部分替换为以下高兼容性的 HSL 版本:

:root {
    --background: hsl(0 0% 100%);
    --foreground: hsl(240 10% 3.9%);
    --card: hsl(0 0% 100%);
    --card-foreground: hsl(240 10% 3.9%);
    --popover: hsl(0 0% 100%);
    --popover-foreground: hsl(240 10% 3.9%);
    --primary: hsl(240 5.9% 10%);
    --primary-foreground: hsl(0 0% 98%);
    --secondary: hsl(240 4.8% 95.9%);
    --secondary-foreground: hsl(240 5.9% 10%);
    --muted: hsl(240 4.8% 95.9%);
    --muted-foreground: hsl(240 3.8% 46.1%);
    --accent: hsl(240 4.8% 95.9%);
    --accent-foreground: hsl(240 5.9% 10%);
    --destructive: hsl(0 84.2% 60.2%);
    --border: hsl(240 5.9% 90%);
    --input: hsl(240 5.9% 90%);
    --ring: hsl(240 100% 50%); /* 你之前的 oklch(0.708 0 0) 类似一个灰色/主色,这里用标准占位 */
    --chart-1: hsl(12 76% 61%);
    --chart-2: hsl(173 58% 39%);
    --chart-3: hsl(197 37% 24%);
    --chart-4: hsl(43 74% 66%);
    --chart-5: hsl(27 87% 67%);
    --radius: 0.5rem;
    --sidebar-background: hsl(0 0% 98%);
    --sidebar-foreground: hsl(240 5.3% 26.1%);
    --sidebar-primary: hsl(240 5.9% 10%);
    --sidebar-primary-foreground: hsl(0 0% 98%);
    --sidebar-accent: hsl(240 4.8% 95.9%);
    --sidebar-accent-foreground: hsl(240 5.9% 10%);
    --sidebar-border: hsl(220 13% 91%);
    --sidebar-ring: hsl(217.2 91.2% 59.8%);
}

.dark {
    --background: hsl(240 10% 3.9%);
    --foreground: hsl(0 0% 98%);
    --card: hsl(240 10% 3.9%);
    --card-foreground: hsl(0 0% 98%);
    --popover: hsl(240 10% 3.9%);
    --popover-foreground: hsl(0 0% 98%);
    --primary: hsl(0 0% 98%);
    --primary-foreground: hsl(240 5.9% 10%);
    --secondary: hsl(240 3.7% 15.9%);
    --secondary-foreground: hsl(0 0% 98%);
    --muted: hsl(240 3.7% 15.9%);
    --muted-foreground: hsl(240 5% 64.9%);
    --accent: hsl(240 3.7% 15.9%);
    --accent-foreground: hsl(0 0% 98%);
    --destructive: hsl(0 62.8% 30.6%);
    --border: hsl(240 3.7% 15.9%);
    --input: hsl(240 3.7% 15.9%);
    --ring: hsl(240 4.9% 83.9%);
    --chart-1: hsl(220 70% 50%);
    --chart-2: hsl(160 60% 45%);
    --chart-3: hsl(30 80% 55%);
    --chart-4: hsl(280 65% 60%);
    --chart-5: hsl(340 75% 55%);
    --sidebar-background: hsl(240 5.9% 10%);
    --sidebar-foreground: hsl(240 4.8% 95.9%);
    --sidebar-primary: hsl(224.3 76.3% 48%);
    --sidebar-primary-foreground: hsl(0 0% 100%);
    --sidebar-accent: hsl(240 3.7% 15.9%);
    --sidebar-accent-foreground: hsl(240 4.8% 95.9%);
    --sidebar-border: hsl(240 3.7% 15.9%);
    --sidebar-ring: hsl(217.2 91.2% 59.8%);
}

(注:如果这里改回 HSL 后颜色有轻微色差,是因为色彩空间不同导致的,但保证能在安卓上正常渲染出颜色。)

第二步:禁止小米浏览器的“强制深色模式”魔改

小米/安卓自带浏览器经常会自作聪明地反转你的网页颜色。
去你的 index.html<head> 标签中,加上这行:

<meta name="color-scheme" content="light dark">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  • color-scheme 告诉浏览器:我已经自己处理了深色和浅色模式,请系统不要强行干预反转我的颜色。
  • viewport 限制最大缩放比例,防止移动端布局被轻易破坏或双击放大。

第三步:验证浏览器内核问题

为了验证是不是小米自带浏览器内核太老的问题:
你可以尝试在小米 Pad 上下载一个最新版的 Google Chrome 或 Edge 浏览器,然后通过 IP:端口 访问你的开发服务器。

  • 如果在 Pad 的最新版 Chrome 里一切正常,而在自带浏览器里错乱,那 100% 是浏览器内核对新 CSS 支持不佳(尤其是 OKLCH 和嵌套语法)。
  • 如果大屏项目最终是在特定的 Android 设备上的 Webview 运行(比如用你之前提到的 Godot Android Plugin 包裹),你必须确保 Android 系统中的 Android System WebView 组件更新到了较新的版本,否则就会遇到一堆不兼容的问题。

总结:oklch 换成 hsl,加上 color-scheme 标签,然后再在 Pad 上刷新看看,大概率颜色就能直接出来了。遇到边框消失的元素,再补一个 border-solid 即可。

参考网站

https://ui.shadcn.com/docs

posted @ 2026-05-17 14:57  tommao9925  阅读(35)  评论(0)    收藏  举报