Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Sunshine And March Vibes (2025 Wallpapers Edition)

      June 3, 2025

      The Case For Minimal WordPress Setups: A Contrarian View On Theme Frameworks

      June 3, 2025

      How To Fix Largest Contentful Paint Issues With Subpart Analysis

      June 3, 2025

      How To Prevent WordPress SQL Injection Attacks

      June 3, 2025

      SteelSeries reveals new Arctis Nova 3 Wireless headset series for Xbox, PlayStation, Nintendo Switch, and PC

      June 3, 2025

      The Witcher 4 looks absolutely amazing in UE5 technical presentation at State of Unreal 2025

      June 3, 2025

      Razer’s having another go at making it so you never have to charge your wireless gaming mouse, and this time it might have nailed it

      June 3, 2025

      Alienware’s rumored laptop could be the first to feature NVIDIA’s revolutionary Arm-based APU

      June 3, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      easy-live2d – About Make your Live2D as easy to control as a pixi sprite! Live2D Web SDK based on Pixi.js.

      June 3, 2025
      Recent

      easy-live2d – About Make your Live2D as easy to control as a pixi sprite! Live2D Web SDK based on Pixi.js.

      June 3, 2025

      From Kitchen To Conversion

      June 3, 2025

      Perficient Included in Forrester’s AI Technical Services Landscape, Q2 2025

      June 3, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      SteelSeries reveals new Arctis Nova 3 Wireless headset series for Xbox, PlayStation, Nintendo Switch, and PC

      June 3, 2025
      Recent

      SteelSeries reveals new Arctis Nova 3 Wireless headset series for Xbox, PlayStation, Nintendo Switch, and PC

      June 3, 2025

      The Witcher 4 looks absolutely amazing in UE5 technical presentation at State of Unreal 2025

      June 3, 2025

      Razer’s having another go at making it so you never have to charge your wireless gaming mouse, and this time it might have nailed it

      June 3, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»Compiling CSS With Vite and Lightning CSS

    Compiling CSS With Vite and Lightning CSS

    February 3, 2025

    Suppose you follow CSS feature development as closely as we do here at CSS-Tricks. In that case, you may be like me and eager to use many of these amazing tools but find browser support sometimes lagging behind what might be considered “modern” CSS (whatever that means).

    Even if browser vendors all have a certain feature released, users might not have the latest versions!

    We can certainly plan for this a number of ways:

    • feature detection with @supports
    • progressively enhanced designs
    • polyfills

    For even extra help, we turn to build tools. Chances are, you’re already using some sort of build tool in your projects today. CSS developers are most likely familiar with CSS pre-processors (such as Sass or Less), but if you don’t know, these are tools capable of compiling many CSS files into one stylesheet. CSS pre-processors help make organizing CSS a lot easier, as you can move parts of CSS into related folders and import things as needed.

    Pre-processors do not just provide organizational superpowers, though. Sass gave us a crazy list of features to work with, including:

    • extends
    • functions
    • loops
    • mixins
    • nesting
    • variables
    • …more, probably!

    For a while, this big feature set provided a means of filling gaps missing from CSS, making Sass (or whatever preprocessor you fancy) feel like a necessity when starting a new project. CSS has evolved a lot since the release of Sass — we have so many of those features in CSS today — so it doesn’t quite feel that way anymore, especially now that we have native CSS nesting and custom properties.

    Along with CSS pre-processors, there’s also the concept of post-processing. This type of tool usually helps transform compiled CSS in different ways, like auto-prefixing properties for different browser vendors, code minification, and more. PostCSS is the big one here, giving you tons of ways to manipulate and optimize your code, another step in the build pipeline.

    In many implementations I’ve seen, the build pipeline typically runs roughly like this:

    1. Generate static assets
    2. Build application files
    3. Bundle for deployment

    CSS is usually handled in that first part, which includes running CSS pre- and post-processors (though post-processing might also happen after Step 2). As mentioned, the continued evolution of CSS makes it less necessary for a tool such as Sass, so we might have an opportunity to save some time.

    Vite for CSS

    Awarded “Most Adopted Technology” and “Most Loved Library” from the State of JavaScript 2024 survey, Vite certainly seems to be one of the more popular build tools available. Vite is mainly used to build reactive JavaScript front-end frameworks, such as Angular, React, Svelte, and Vue (made by the same developer, of course). As the name implies, Vite is crazy fast and can be as simple or complex as you need it, and has become one of my favorite tools to work with.

    Vite is mostly thought of as a JavaScript tool for JavaScript projects, but you can use it without writing any JavaScript at all. Vite works with Sass, though you still need to install Sass as a dependency to include it in the build pipeline. On the other hand, Vite also automatically supports compiling CSS with no extra steps. We can organize our CSS code how we see fit, with no or very minimal configuration necessary. Let’s check that out.

    We will be using Node and npm to install Node packages, like Vite, as well as commands to run and build the project. If you do not have node or npm installed, please check out the download page on their website.

    Navigate a terminal to a safe place to create a new project, then run:

    npm create vite@latest

    The command line interface will ask a few questions, you can keep it as simple as possible by choosing Vanilla and JavaScript which will provide you with a starter template including some no-frameworks-attached HTML, CSS, and JavaScript files to help get you started.

    terminal displaying the output of running the command npm create vite@latest

    Before running other commands, open the folder in your IDE (integrated development environment, such as VSCode) of choice so that we can inspect the project files and folders.

    If you would like to follow along with me, delete the following files that are unnecessary for demonstration:

    • assets/
    • public/
    • src/
    • .gitignore

    We should only have the following files left in out project folder:

    • index.html
    • package.json
    VSCode file browser display two files: index.html and package.json

    Let’s also replace the contents of index.html with an empty HTML template:

    <!doctype html>
    
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    	
        <title>CSS Only Vite Project</title>
      </head>
      <body>
        <!-- empty for now -->
      </body>
    </html>

    One last piece to set up is Vite’s dependencies, so let’s run the npm installation command:

    npm install
    terminal displaying the output of running the command npm install

    A short sequence will occur in the terminal. Then we’ll see a new folder called node_modules/ and a package-lock.json file added in our file viewer.

    • node_modules is used to house all package files installed through node package manager, and allows us to import and use installed packages throughout our applications.
    • package-lock.json is a file usually used to make sure a development team is all using the same versions of packages and dependencies.
    VSCode file browser displaying a node_modules folder, index.html file, package-lock.json file, and a package.json file

    We most likely won’t need to touch these things, but they are necessary for Node and Vite to process our code during the build. Inside the project’s root folder, we can create a styles/ folder to contain the CSS we will write. Let’s create one file to begin with, main.css, which we can use to test out Vite.

    ├── public/
    ├── styles/
    |   └── main.css
    └──index.html

    In our index.html file, inside the <head> section, we can include a <link> tag pointing to the CSS file:

    <head>
      <meta charset="UTF-8" />
      <link rel="icon" type="image/svg+xml" href="/vite.svg" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    	
      <title>CSS Only Vite Project</title>
    
      <!-- Main CSS -->
      <link rel="stylesheet" href="styles/main.css">
    </head>

    Let’s add a bit of CSS to main.css:

    body {
      background: green;
    }

    It’s not much, but it’s all we’ll need at the moment! In our terminal, we can now run the Vite build command using npm:

    npm run build

    With everything linked up properly, Vite will build things based on what is available within the index.html file, including our linked CSS files. The build will be very fast, and you’ll be returned to your terminal prompt.

    Terminal displaying the output of the command npm run build, including the filesizes of compiled files
    Vite will provide a brief report, showcasing the file sizes of the compiled project.

    The newly generated dist/ folder is Vite’s default output directory, which we can open and see our processed files. Checking out assets/index.css (the filename will include a unique hash for cache busting), and you’ll see the code we wrote, minified here.

    VSCode editor displaying a minified CSS file

    Now that we know how to make Vite aware of our CSS, we will probably want to start writing more CSS for it to compile.

    As quick as Vite is with our code, constantly re-running the build command would still get very tedious. Luckily, Vite provides its own development server, which includes a live environment with hot module reloading, making changes appear instantly in the browser. We can start the Vite development server by running the following terminal command:

    npm run dev
    Vite development server running in a terminal

    Vite uses the default network port 5173 for the development server. Opening the http://localhost:5137/ address in your browser will display a blank screen with a green background.

    Arc browser window, navigated to http://localhost:5173, a blank page with a green background

    Adding any HTML to the index.html or CSS to main.css, Vite will reload the page to display changes. To stop the development server, use the keyboard shortcut CTRL+C or close the terminal to kill the process.

    Hostinger

    At this point, you pretty much know all you need to know about how to compile CSS files with Vite. Any CSS file you link up will be included in the built file.

    Organizing CSS into Cascade Layers

    One of the items on my 2025 CSS Wishlist is the ability to apply a cascade layer to a link tag. To me, this might be helpful to organize CSS in a meaningful ways, as well as fine control over the cascade, with the benefits cascade layers provide. Unfortunately, this is a rather difficult ask when considering the way browsers paint styles in the viewport. This type of functionality is being discussed between the CSS Working Group and TAG, but it’s unclear if it’ll move forward.

    With Vite as our build tool, we can replicate the concept as a way to organize our built CSS. Inside the main.css file, let’s add the @layer at-rule to set the cascade order of our layers. I’ll use a couple of layers here for this demo, but feel free to customize this setup to your needs.

    /* styles/main.css */
    @layer reset, layouts;

    This is all we’ll need inside our main.css, let’s create another file for our reset. I’m a fan of my friend Mayank‘s modern CSS reset, which is available as a Node package. We can install the reset by running the following terminal command:

    npm install @acab/reset.css
    Terminal displaying the output of running npm install @acab/reset.css

    Now, we can import Mayank’s reset into our newly created reset.css file, as a cascade layer:

    /* styles/reset.css */
    @import '@acab/reset.css' layer(reset);

    If there are any other reset layer stylings we want to include, we can open up another @layer reset block inside this file as well.

    /* styles/reset.css */
    @import '@acab/reset.css' layer(reset);
    
    @layer reset {
      /* custom reset styles */
    }

    This @import statement is used to pull packages from the node_modules folder. This folder is not generally available in the built, public version of a website or application, so referencing this might cause problems if not handled properly.

    Now that we have two files (main.css and reset.css), let’s link them up in our index.html file. Inside the <head> tag, let’s add them after <title>:

    <head>
      <meta charset="UTF-8" />
      <link rel="icon" type="image/svg+xml" href="/vite.svg" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    	
      <title>CSS Only Vite Project</title>
    	
      <link rel="stylesheet" href="styles/main.css">
      <link rel="stylesheet" href="styles/reset.css">
    </head>

    The idea here is we can add each CSS file, in the order we need them parsed. In this case, I’m planning to pull in each file named after the cascade layers setup in the main.css file. This may not work for every setup, but it is a helpful way to keep in mind the precedence of how cascade layers affect computed styles when rendered in a browser, as well as grouping similarly relevant files.

    Since we’re in the index.html file, we’ll add a third CSS <link> for styles/layouts.css.

    <head>
      <meta charset="UTF-8" />
      <link rel="icon" type="image/svg+xml" href="/vite.svg" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    	
      <title>CSS Only Vite Project</title>
    	
      <link rel="stylesheet" href="styles/main.css">
      <link rel="stylesheet" href="styles/reset.css">
      <link rel="stylesheet" href="styles/layouts.css">
    </head>

    Create the styles/layouts.css file with the new @layer layouts declaration block, where we can add layout-specific stylings.

    /* styles/layouts.css */
    @layer layouts {
      /* layouts styles */
    }

    For some quick, easy, and awesome CSS snippets, I tend to refer to Stephanie Eckles‘ SmolCSS project. Let’s grab the “Smol intrinsic container” code and include it within the layouts cascade layer:

    /* styles/layouts.css */
    @layer layouts {
      .smol-container {
        width: min(100% - 3rem, var(--container-max, 60ch));
        margin-inline: auto;
      }
    }

    This powerful little, two-line container uses the CSS min() function to provide a responsive width, with margin-inline: auto; set to horizontally center itself and contain its child elements. We can also dynamically adjust the width using the --container-max custom property.

    Now if we re-run the build command npm run build and check the dist/ folder, our compiled CSS file should contain:

    • Our cascade layer declarations from main.css
    • Mayank’s CSS reset fully imported from reset.css
    • The .smol-container class added from layouts.csss

    As you can see, we can get quite far with Vite as our build tool without writing any JavaScript. However, if we choose to, we can extend our build’s capabilities even further by writing just a little bit of JavaScript.

    Post-processing with LightningCSS

    Lightning CSS is a CSS parser and post-processing tool that has a lot of nice features baked into it to help with cross-compatibility among browsers and browser versions. Lightning CSS can transform a lot of modern CSS into backward-compatible styles for you.

    We can install Lightning CSS in our project with npm:

    npm install --save-dev lightningcss

    The --save-dev flag means the package will be installed as a development dependency, as it won’t be included with our built project. We can include it within our Vite build process, but first, we will need to write a tiny bit of JavaScript, a configuration file for Vite. Create a new file called: vite.config.mjs and inside add the following code:

    // vite.config.mjs
    export default {
      css: {
        transformer: 'lightningcss'
      },
      build: {
        cssMinify: 'lightningcss'
      }
    };

    Vite will now use LightningCSS to transform and minify CSS files. Now, let’s give it a test run using an oklch color. Inside main.css let’s add the following code:

    /* main.css */
    body {
      background-color: oklch(51.98% 0.1768 142.5);
    }

    Then re-running the Vite build command, we can see the background-color property added in the compiled CSS:

    /* dist/index.css */
    body {
      background-color: green;
      background-color: color(display-p3 0.216141 0.494224 0.131781);
      background-color: lab(46.2829% -47.5413 48.5542);
    }

    Lightning CSS converts the color white providing fallbacks available for browsers which might not support newer color types. Following the Lightning CSS documentation for using it with Vite, we can also specify browser versions to target by installing the browserslist package.

    Browserslist will give us a way to specify browsers by matching certain conditions (try it out online!)

    npm install -D browserslist

    Inside our vite.config.mjs file, we can configure Lightning CSS further. Let’s import the browserslist package into the Vite configuration, as well as a module from the Lightning CSS package to help us use browserlist in our config:

    // vite.config.mjs
    import browserslist from 'browserslist';
    import { browserslistToTargets } from 'lightningcss';

    We can add configuration settings for lightningcss, containing the browser targets based on specified browser versions to Vite’s css configuration:

    // vite.config.mjs
    import browserslist from 'browserslist';
    import { browserslistToTargets } from 'lightningcss';
    
    export default {
      css: {
        transformer: 'lightningcss',
        lightningcss: {
          targets: browserslistToTargets(browserslist('>= 0.25%')),
        }
      },
      build: {
        cssMinify: 'lightningcss'
      }
    };

    There are lots of ways to extend Lightning CSS with Vite, such as enabling specific features, excluding features we won’t need, or writing our own custom transforms.

    // vite.config.mjs
    import browserslist from 'browserslist';
    import { browserslistToTargets, Features } from 'lightningcss';
    
    export default {
      css: {
        transformer: 'lightningcss',
        lightningcss: {
          targets: browserslistToTargets(browserslist('>= 0.25%')),
          // Including `light-dark()` and `colors()` functions
          include: Features.LightDark | Features.Colors,
        }
      },
      build: {
        cssMinify: 'lightningcss'
      }
    };

    For a full list of the Lightning CSS features, check out their documentation on feature flags.

    Is any of this necessary?

    Reading through all this, you may be asking yourself if all of this is really necessary. The answer: absolutely not! But I think you can see the benefits of having access to partialized files that we can compile into unified stylesheets.

    I doubt I’d go to these lengths for smaller projects, however, if building something with more complexity, such as a design system, I might reach for these tools for organizing code, cross-browser compatibility, and thoroughly optimizing compiled CSS.


    Compiling CSS With Vite and Lightning CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleWindows 11 hits a new market share milestone as Windows 10’s death looms on the horizon
    Next Article Rilasciato Mozilla Firefox 135: Novità, Sicurezza e Ottimizzazioni da Conoscere

    Related Posts

    News & Updates

    SteelSeries reveals new Arctis Nova 3 Wireless headset series for Xbox, PlayStation, Nintendo Switch, and PC

    June 3, 2025
    News & Updates

    The Witcher 4 looks absolutely amazing in UE5 technical presentation at State of Unreal 2025

    June 3, 2025
    Leave A Reply Cancel Reply

    Continue Reading

    This premium Lenovo laptop is nearly checks all the boxes for me – including battery life

    News & Updates

    Community News: Latest PECL Releases (08.06.2024)

    Development

    Vahatraker is a live MIDI sequencer

    Linux

    AI’s Greatest Threat? Elon Musk Sounds the Alarm on the ‘Woke Mind Virus’ – Part 3 of the Research Article

    Artificial Intelligence

    Highlights

    The 7 tech gadgets I couldn’t live without in 2024 – and they don’t include AirTags

    December 31, 2024

    I reviewed a slew of handy gadgets this year, but these few became essential parts…

    Frostpunk 2 heats up with a free “major content update” that overhauls the survival city builder’s core gameplay

    May 10, 2025

    ReSi Benchmark: A Comprehensive Evaluation Framework for Neural Network Representational Similarity Across Diverse Domains and Architectures

    August 4, 2024

    OpenAI, Meta, and TikTok Crack Down on Covert Influence Campaigns, Some AI-Powered

    May 31, 2024
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.