You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让shadcn/Radix导航菜单居中且避免浏览器窗口溢出

解决Shadcn导航菜单居中后溢出窗口的问题

核心问题

你给NavigationMenuViewport套了flex justify-center容器强制菜单居中,但未处理内容过宽时的溢出情况。以下是两种可行解决方案:

方案一:利用Radix内置自动定位(推荐)

Radix UI的NavigationMenuPrimitive.Content支持自动检测视口边界并调整位置,只需调整组件属性即可实现居中+避溢出效果:

修改NavigationMenuContent组件

const NavigationMenuContent = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
  <NavigationMenuPrimitive.Content
    ref={ref}
    align="center" // 开启居中对齐逻辑
    sideOffset={8} // 调整菜单与触发器的间距
    className={cn(
      'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto',
      className
    )}
    {...props}
  />
));

修改NavigationMenuViewport组件

移除外层强制居中的容器,让Radix自行处理定位:

const NavigationMenuViewport = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
  <NavigationMenuPrimitive.Viewport
    ref={ref}
    className={cn(
      'filter-card box-shadow-card origin-top-center absolute top-full mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
      className
    )}
    forceMount
    {...props}
  />
));

方案二:自定义溢出检测逻辑

若需保留自定义居中容器,可添加动态计算逻辑,实时检测菜单是否溢出视口并调整偏移:

修改NavigationMenuViewport组件

const NavigationMenuViewport = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => {
  const viewportRef = React.useRef<HTMLDivElement>(null);
  const [offset, setOffset] = React.useState(0);

  React.useEffect(() => {
    const updateOffset = () => {
      if (!viewportRef.current) return;
      
      const viewport = viewportRef.current;
      const windowWidth = window.innerWidth;
      const viewportWidth = viewport.offsetWidth;
      const viewportLeft = viewport.getBoundingClientRect().left;

      // 计算左右侧溢出量
      const overflowRight = viewportLeft + viewportWidth - windowWidth;
      const overflowLeft = -viewportLeft;

      if (overflowRight > 0) {
        // 向右偏移避免右侧溢出
        setOffset(-overflowRight);
      } else if (overflowLeft > 0) {
        // 向左偏移避免左侧溢出
        setOffset(overflowLeft);
      } else {
        // 无溢出时保持居中
        setOffset(0);
      }
    };

    updateOffset();
    window.addEventListener('resize', updateOffset);
    return () => window.removeEventListener('resize', updateOffset);
  }, []);

  return (
    <div className={cn('absolute top-full flex justify-center')}>
      <NavigationMenuPrimitive.Viewport
        ref={(el) => {
          viewportRef.current = el;
          if (typeof ref === 'function') ref(el);
          else if (ref) ref.current = el;
        }}
        style={{ transform: `translateX(${offset}px)` }}
        className={cn(
          'filter-card box-shadow-card origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
          className
        )}
        forceMount
        {...props}
      />
    </div>
  );
});

方案说明

  • 方案一利用Radix内置能力,代码简洁、兼容性好,优先推荐使用
  • 方案二适合需自定义布局的场景,通过监听窗口尺寸变化动态调整菜单位置

内容的提问来源于stack exchange,提问作者Korer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 17:42:42