I'm trying to make my NextJS 14 app router application scale down on any device less than 500px width, as I'm making my app responsive down to 500px wide and anything below that I want it to scale down, previously I've used min-width: 500px; in the body CSS and used this tag inside the <head> tag:
<meta name="viewport" content="width=500, shrink-to-fit=yes, maximum-scale=1, user-scalable=0" />
And that would work on Chrome and Safari mobile apps and everywhere else, however now with NextJS 14, I can't set this tag directly in the <head> tag inside the layout.tsx file as there's an already defined viewport tag and this new one will be a duplicate and won't take effect, the new way of setting and changing this default viewport tag is changed to this way instead:
import type { Viewport } from 'next'
export const viewport: Viewport = {
width: 500,
maximumScale: 1,
userScalable: false,
}
Reference: https://nextjs.org/docs/app/api-reference/functions/generate-viewport
But this doesn't support shrink-to-fit=yes and without adding it, the app would be zoomed in on Safari browser and some other browsers with some horizontal scroll.
Is there a way to set the metatag with shrink-to-fit=yes or another way to fix this issue of being zoomed in on Safari Mobile view when loading the page?
For the ViewportLayout, NextJS 14 have the following:
export type ViewportLayout = {
width?: string | number;
height?: string | number;
initialScale?: number;
minimumScale?: number;
maximumScale?: number;
userScalable?: boolean;
viewportFit?: 'auto' | 'cover' | 'contain';
interactiveWidget?: 'resizes-visual' | 'resizes-content' | 'overlays-content';
};
Would any of these combinations solve the issue mentioned in the Safari mobile browser? or is it possible to extend this layout to include shrink-to-fit?
Otherwise, how do developers usually approach this case where they want to scale down their websites for smaller screens on different browsers in NextJS 14 with app router?
That means... a custom solution: manually injecting the viewport meta tag to include the necessary properties.
Next.js 13.3 and before: You would need to a custom Document (
_document.jsor_document.tsxif you are using TypeScript) where you can define the<meta>tag directly in the HTML<head>.For Next.js 13.4 and after (since you are using NextJS 14), with App Router / Migrating from pages to app, the traditional
pages/_document.jsandpages/_app.jsfiles are replaced by a single root layout file located atapp/layout.js(orlayout.tsxif using TypeScript).In this new structure, the root layout must explicitly define
<html>and<body>tags, as Next.js no longer automatically generates them for pages within theappdirectory.To manage elements in the
<head>, such as setting meta tags including the viewport settings, Next.js now recommends using the built-in SEO support with theMetadataexport in your root layout file.The static
viewportexport or the dynamicgenerateViewportfunction allows you to configure viewport settings directly from your layout or page files, offering a more integrated and type-safe way to manage these settings in Next.js applications.But...
shrink-to-fitis not listed among the documented properties:Since the direct inclusion of
shrink-to-fitis not supported in theviewportobject's type definition, one potential workaround would be to inject custom HTML into the head using a different method, such as a custom hook withnext/headfor dynamic cases, though this approach has its limitations and might not provide the type safety and integration benefits of the newviewportAPI.Based on "How to use the meta viewport tag in NextJS 14 app router?", and the documentation "
generateViewport":Create the custom hook (
useCustomViewport.jsoruseCustomViewport.ts):In your page or layout component, import and use the
useCustomViewporthook to make sure the custom viewport settings are applied.By using this hook in your page or layout component, you dynamically inject the required viewport settings into your document. That makes sure your custom viewport settings, including properties like
shrink-to-fit=yes, are respected across your Next.js application.Ideally, you would need a solution that works within the server-side or static generation capabilities of Next.js, provided the viewport settings are correctly set before the page is rendered to the client to avoid the zoom-in and zoom-out issue.
But, since the direct setting of
shrink-to-fit=yesis not supported in the Next.js 14viewportAPI, and considering the limitations of using a client-side JavaScript approach, a server-side solution seems out of reach without native support for these specific viewport attributes.A possible alternative to using
shrink-to-fit=yesis to enhance the responsive design of the application to handle viewports narrower than 500px, without the need to scale the content.Consider using CSS media queries and flexible layouts that adapt to various screen sizes, even those smaller than 500px. That would eliminate the need for the page to scale down on smaller devices, and... bypass the initial problem.
A CSS flexbox or grid is used to create layouts that can adapt to various screen sizes without specifying a fixed width that would require scaling. Media queries apply different styles based on the viewport width, making sure that content remains accessible and legible on smaller screens. Use relative units (e.g.,
em,rem,%,vw,vh) for widths, font sizes, and spacing, rather than fixed pixels, to allow for more fluid scaling across devices. Make sure images and embedded media are responsive, using CSS techniques or HTML attributes (width="100%",height="auto") to make them scale appropriately.That should provide a way to make sure your application is accessible and usable across all device sizes, including those narrower than 500px, without the adverse effects of manual scaling or client-side dynamic adjustments.