troccoli's avatar

Two layouts but different sans font

First of all, I'm not sure if this relates to Tailwind, Vite, Laravel, or maybe even Flux. If you think I would be better off asking in one of those project directly please let me know.

I have a new Laravel 12 project. In it I have two separate parts: a public, and am admin part.

The public part uses our brand style, while I want the admin one to use the default Flux style.

One of the difference is the font used for the sans family The public uses Google's Work Sans, so I have the following in my app.css

@theme {
    --font-sans: 'Work Sans', ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    ...
}

How can instead use, for example, Instruments Sans for the admin part?

The public and admin parts use two separate layouts, but as far as I know I cannot have Vite produce two separate CSS files (I did try)

0 likes
5 replies
LaryAI's avatar
Level 58

Certainly! Here’s how you can handle different font families for your public and admin layouts in a Laravel 12 + Vite + Tailwind setup, without needing two separate CSS files.

Solution: Use CSS Variables and Layout-specific Classes

1. Define Both Fonts in Your CSS

In your main CSS (e.g., app.css), define both font families as CSS variables, each under a unique class:

/* app.css */
:root {
    --font-sans-public: 'Work Sans', ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
    --font-sans-admin: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}

/* Optional: fallback for Tailwind's font-sans */
.font-sans-public {
    font-family: var(--font-sans-public);
}
.font-sans-admin {
    font-family: var(--font-sans-admin);
}

2. Use Tailwind’s fontFamily Customization

If you want to use Tailwind’s font-sans utility, you can override it per layout using a custom class:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        'sans-public': ['var(--font-sans-public)'],
        'sans-admin': ['var(--font-sans-admin)'],
      },
    },
  },
}

3. Apply the Class in Your Blade Layouts

Public Layout:

<body class="font-sans-public">
    <!-- Public content -->
</body>

or with Tailwind utility:

<body class="font-sans-public font-sans-public">
    <!-- Public content -->
</body>

Admin Layout:

<body class="font-sans-admin">
    <!-- Admin content -->
</body>

or with Tailwind utility:

<body class="font-sans-admin font-sans-admin">
    <!-- Admin content -->
</body>

4. Load Both Fonts

Make sure both fonts are loaded in your HTML (e.g., via Google Fonts CDN in your layouts):

<!-- In public layout -->
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;700&display=swap" rel="stylesheet">

<!-- In admin layout -->
<link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;700&display=swap" rel="stylesheet">

5. Result

Now, each layout will use its own font, but you’re still using a single CSS file. No need to split your Vite build.


Summary:

  • Define both fonts as CSS variables and/or Tailwind custom font families.
  • Apply the appropriate class at the layout level.
  • Load the correct font in each layout’s <head>.
  • No need for multiple CSS files or Vite configs.

Let me know if you need a more detailed example or help with your tailwind.config.js!

troccoli's avatar

Although @laryai answer would work, it looks and feels a bit clunky.

Does anyone have any other suggestion?

martinbean's avatar

The public and admin parts use two separate layouts, but as far as I know I cannot have Vite produce two separate CSS files (I did try)

@troccoli Why do you think so? Of course you can; you just need to specify the additional entry point in your vite.config.js file:

  export default defineConfig({
      plugins: {
          laravel({
              inputs: [
                  'resources/css/app.css',
+                 'resources/css/admin.css',
              ],
              refresh: true,
          }),
      },
  });
troccoli's avatar

@martinbean

Because I tried it and it doesn't do what you think. It produces only one CSS file

export default defineConfig({
  plugins: [
    laravel({
      input: [
        'resources/css/app.css',
        'resources/css/admin/app.css',
        'resources/js/app.js'
      ],
      refresh: [`resources/views/**/*`],
    }),
    tailwindcss(),
  ],
})

and this is the public/build/manifest.json

{
  "resources/css/admin/app.css": {
    "file": "assets/app-DL4dikLy.css",
    "src": "resources/css/app.css",
    "isEntry": true
  },
  "resources/css/app.css": {
    "file": "assets/app-DL4dikLy.css",
    "src": "resources/css/app.css",
    "isEntry": true
  },
  "resources/js/app.js": {
    "file": "assets/app-eMHK6VFw.js",
    "name": "app",
    "src": "resources/js/app.js",
    "isEntry": true
  }
}
martinbean's avatar

@troccoli Then use different names for the style sheets, as they’re clearly conflicting.

If you’re creating an admin style sheet, call it admin.css and not “app.css”:

  export default defineConfig({
      plugins: [
          laravel({
              input: [
                  'resources/css/app.css',
-                 'resources/css/admin/app.css',
+                 'resources/css/admin.css',
                  'resources/js/app.js',
              ],
              refresh: true,
          }),
          tailwindcss(),
      ],
  });

Please or to participate in this conversation.