Suppose you observe CSS function growth as carefully as we do right here at CSS-Tips. In that case, you could be like me and keen to make use of many of those wonderful instruments however discover browser help generally lagging behind what is likely to be thought of “fashionable” CSS (no matter meaning).
Even when browser distributors all have a sure function launched, customers won’t have the newest variations!
We will definitely plan for this various methods:
- function detection with
@helps
- progressively enhanced designs
- polyfills
For even further assist, we flip to construct instruments. Chances are high, you’re already utilizing some form of construct device in your tasks in the present day. CSS builders are probably aware of CSS pre-processors (equivalent to Sass or Much less), however when you don’t know, these are instruments able to compiling many CSS information into one stylesheet. CSS pre-processors assist make organizing CSS loads simpler, as you possibly can transfer elements of CSS into associated folders and import issues as wanted.
Pre-processors don’t simply present organizational superpowers, although. Sass gave us a loopy record of options to work with, together with:
- extends
- capabilities
- loops
- mixins
- nesting
- variables
- …extra, in all probability!
For some time, this huge function set offered a method of filling gaps lacking from CSS, making Sass (or no matter preprocessor you fancy) really feel like a necessity when beginning a brand new venture. CSS has advanced loads because the launch of Sass — now we have so lots of these options in CSS in the present day — so it doesn’t fairly really feel that manner anymore, particularly now that now we have native CSS nesting and customized properties.
Together with CSS pre-processors, there’s additionally the idea of publish-processing. Any such device often helps rework compiled CSS in several methods, like auto-prefixing properties for various browser distributors, code minification, and extra. PostCSS is the large one right here, providing you with tons of the way to govern and optimize your code, one other step within the construct pipeline.
In lots of implementations I’ve seen, the construct pipeline usually runs roughly like this:
- Generate static property
- Construct utility information
- Bundle for deployment
CSS is often dealt with in that first half, which incorporates operating CSS pre- and post-processors (although post-processing may additionally occur after Step 2). As talked about, the continued evolution of CSS makes it much less obligatory for a device equivalent to Sass, so we’d have a chance to avoid wasting time.
Vite for CSS
Awarded “Most Adopted Expertise” and “Most Liked Library” from the State of JavaScript 2024 survey, Vite definitely appears to be one of many extra common construct instruments accessible. Vite is principally used to construct reactive JavaScript front-end frameworks, equivalent to Angular, React, Svelte, and Vue (made by the identical developer, after all). Because the identify implies, Vite is loopy quick and may be as easy or advanced as you want it, and has develop into considered one of my favourite instruments to work with.
Vite is generally considered a JavaScript device for JavaScript tasks, however you need to use it with out writing any JavaScript in any respect. Vite works with Sass, although you continue to want to put in Sass as a dependency to incorporate it within the construct pipeline. However, Vite additionally routinely helps compiling CSS with no further steps. We will arrange our CSS code how we see match, with no or very minimal configuration obligatory. Let’s verify that out.
We shall be utilizing Node and npm to put in Node packages, like Vite, in addition to instructions to run and construct the venture. When you should not have node
or npm
put in, please try the obtain web page on their web site.
Navigate a terminal to a protected place to create a brand new venture, then run:
npm create vite@newest
The command line interface will ask a couple of questions, you possibly can maintain it so simple as doable by selecting Vanilla
and JavaScript
which is able to give you a starter template together with some no-frameworks-attached HTML, CSS, and JavaScript information to assist get you began.

Earlier than operating different instructions, open the folder in your IDE (built-in growth setting, equivalent to VSCode) of alternative in order that we are able to examine the venture information and folders.
If you want to observe together with me, delete the next information which can be pointless for demonstration:
property/
public/
src/
.gitignore
We must always solely have the next information left in out venture folder:

Let’s additionally exchange the contents of index.html
with an empty HTML template:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta identify="viewport" content material="width=device-width, initial-scale=1.0" />
<title>CSS Solely Vite Challenge</title>
</head>
<physique>
<!-- empty for now -->
</physique>
</html>
One final piece to arrange is Vite’s dependencies, so let’s run the npm set up command:
npm set up

A brief sequence will happen within the terminal. Then we’ll see a brand new folder known as node_modules/
and a package-lock.json
file added in our file viewer.
node_modules
is used to deal with all bundle information put in by means of node bundle supervisor, and permits us to import and use put in packages all through our functions.package-lock.json
is a file often used to verify a growth group is all utilizing the identical variations of packages and dependencies.

We probably received’t want to the touch this stuff, however they’re obligatory for Node and Vite to course of our code in the course of the construct. Contained in the venture’s root folder, we are able to create a types/
folder to include the CSS we’ll write. Let’s create one file to start with, major.css
, which we are able to use to check out Vite.
├── public/
├── types/
| └── major.css
└──index.html
In our index.html
file, contained in the <head>
part, we are able to embody a <hyperlink>
tag pointing to the CSS file:
<head>
<meta charset="UTF-8" />
<hyperlink rel="icon" kind="picture/svg+xml" href="https://css-tricks.com/vite.svg" />
<meta identify="viewport" content material="width=device-width, initial-scale=1.0" />
<title>CSS Solely Vite Challenge</title>
<!-- Primary CSS -->
<hyperlink rel="stylesheet" href="https://css-tricks.com/compiling-css-with-vite-and-lightning-css/types/major.css">
</head>
Let’s add a little bit of CSS to major.css
:
physique {
background: inexperienced;
}
It’s not a lot, however it’s all we’ll want in the meanwhile! In our terminal, we are able to now run the Vite construct command utilizing npm
:
npm run construct
With every thing linked up correctly, Vite will construct issues based mostly on what is out there throughout the index.html
file, together with our linked CSS information. The construct shall be very quick, and also you’ll be returned to your terminal immediate.

The newly generated dist/
folder is Vite’s default output listing, which we are able to open and see our processed information. Trying out property/index.css
(the filename will embody a singular hash for cache busting), and also you’ll see the code we wrote, minified right here.

Now that we all know easy methods to make Vite conscious of our CSS, we’ll in all probability need to begin writing extra CSS for it to compile.
As fast as Vite is with our code, continuously re-running the construct command would nonetheless get very tedious. Fortunately, Vite gives its personal growth server, which features a stay setting with scorching module reloading, making modifications seem immediately within the browser. We will begin the Vite growth server by operating the next terminal command:
npm run dev

Vite makes use of the default community port 5173
for the event server. Opening the http://localhost:5137/
tackle in your browser will show a clean display screen with a inexperienced background.

Including any HTML to the index.html
or CSS to major.css
, Vite will reload the web page to show modifications. To cease the event server, use the keyboard shortcut CTRL+C or shut the terminal to kill the method.
At this level, you just about know all you should learn about easy methods to compile CSS information with Vite. Any CSS file you hyperlink up shall be included within the constructed file.
Organizing CSS into Cascade Layers
One of many objects on my 2025 CSS Wishlist is the power to apply a cascade layer to a hyperlink
tag. To me, this is likely to be useful to prepare CSS in a significant methods, in addition to superb management over the cascade, with the advantages cascade layers present. Sadly, this can be a fairly troublesome ask when contemplating the way in which browsers paint types within the viewport. Any such performance is being mentioned between the CSS Working Group and TAG, however it’s unclear if it’ll transfer ahead.
With Vite as our construct device, we are able to replicate the idea as a method to arrange our constructed CSS. Contained in the major.css
file, let’s add the @layer at-rule to set the cascade order of our layers. I’ll use a few layers right here for this demo, however be at liberty to customise this setup to your wants.
/* types/major.css */
@layer reset, layouts;
That is all we’ll want inside our major.css
, let’s create one other file for our reset. I’m a fan of my buddy Mayank‘s fashionable CSS reset, which is out there as a Node bundle. We will set up the reset by operating the next terminal command:
npm set up @acab/reset.css

Now, we are able to import Mayank’s reset into our newly created reset.css
file, as a cascade layer:
/* types/reset.css */
@import '@acab/reset.css' layer(reset);
If there are some other reset layer stylings we need to embody, we are able to open up one other @layer reset
block inside this file as effectively.
/* types/reset.css */
@import '@acab/reset.css' layer(reset);
@layer reset {
/* customized reset types */
}
This @import
assertion is used to tug packages from the node_modules
folder. This folder just isn’t usually accessible within the constructed, public model of a web site or utility, so referencing this may trigger issues if not dealt with correctly.
Now that now we have two information (major.css
and reset.css
), let’s hyperlink them up in our index.html
file. Contained in the <head>
tag, let’s add them after <title>
:
<head>
<meta charset="UTF-8" />
<hyperlink rel="icon" kind="picture/svg+xml" href="https://css-tricks.com/vite.svg" />
<meta identify="viewport" content material="width=device-width, initial-scale=1.0" />
<title>CSS Solely Vite Challenge</title>
<hyperlink rel="stylesheet" href="https://css-tricks.com/compiling-css-with-vite-and-lightning-css/types/major.css">
<hyperlink rel="stylesheet" href="https://css-tricks.com/compiling-css-with-vite-and-lightning-css/types/reset.css">
</head>
The concept right here is we are able to add every CSS file, within the order we want them parsed. On this case, I’m planning to tug in every file named after the cascade layers setup in the principle.css file. This will not work for each setup, however it’s a useful manner to bear in mind the priority of how cascade layers have an effect on computed types when rendered in a browser, in addition to grouping equally related information.
Since we’re within the index.html
file, we’ll add a 3rd CSS <hyperlink>
for types/layouts.css
.
<head>
<meta charset="UTF-8" />
<hyperlink rel="icon" kind="picture/svg+xml" href="https://css-tricks.com/vite.svg" />
<meta identify="viewport" content material="width=device-width, initial-scale=1.0" />
<title>CSS Solely Vite Challenge</title>
<hyperlink rel="stylesheet" href="https://css-tricks.com/compiling-css-with-vite-and-lightning-css/types/major.css">
<hyperlink rel="stylesheet" href="https://css-tricks.com/compiling-css-with-vite-and-lightning-css/types/reset.css">
<hyperlink rel="stylesheet" href="https://css-tricks.com/compiling-css-with-vite-and-lightning-css/types/layouts.css">
</head>
Create the types/layouts.css
file with the brand new @layer layouts
declaration block, the place we are able to add layout-specific stylings.
/* types/layouts.css */
@layer layouts {
/* layouts types */
}
For some fast, simple, and superior CSS snippets, I are inclined to discuss with Stephanie Eckles‘ SmolCSS venture. Let’s seize the “Smol intrinsic container” code and embody it throughout the layouts
cascade layer:
/* types/layouts.css */
@layer layouts {
.smol-container {
width: min(100% - 3rem, var(--container-max, 60ch));
margin-inline: auto;
}
}
This highly effective little, two-line container makes use of the CSS min()
operate to supply a responsive width, with margin-inline: auto;
set to horizontally heart itself and include its youngster components. We will additionally dynamically alter the width utilizing the --container-max
customized property.
Now if we re-run the construct command npm run construct
and verify the dist/
folder, our compiled CSS file ought to include:
- Our cascade layer declarations from
major.css
- Mayank’s CSS reset absolutely imported from
reset.css
- The
.smol-container
class added fromlayouts.csss
As you possibly can see, we are able to get fairly far with Vite as our construct device with out writing any JavaScript. Nevertheless, if we select to, we are able to prolong our construct’s capabilities even additional by writing only a little bit of JavaScript.
Publish-processing with LightningCSS
Lightning CSS is a CSS parser and post-processing device that has a number of good options baked into it to assist with cross-compatibility amongst browsers and browser variations. Lightning CSS can rework a number of fashionable CSS into backward-compatible types for you.
We will set up Lightning CSS in our venture with npm
:
npm set up --save-dev lightningcss
The --save-dev
flag means the bundle shall be put in as a growth dependency, because it received’t be included with our constructed venture. We will embody it inside our Vite construct course of, however first, we might want to write a tiny little bit of JavaScript, a configuration file for Vite. Create a brand new file known as: vite.config.mjs
and inside add the next code:
// vite.config.mjs
export default {
css: {
transformer: 'lightningcss'
},
construct: {
cssMinify: 'lightningcss'
}
};
Vite will now use LightningCSS to rework and minify CSS information. Now, let’s give it a check run utilizing an oklch
coloration. Inside major.css
let’s add the next code:
/* major.css */
physique {
background-color: oklch(51.98% 0.1768 142.5);
}
Then re-running the Vite construct command, we are able to see the background-color
property added within the compiled CSS:
/* dist/index.css */
physique {
background-color: inexperienced;
background-color: coloration(display-p3 0.216141 0.494224 0.131781);
background-color: lab(46.2829% -47.5413 48.5542);
}
Lightning CSS converts the colour white offering fallbacks accessible for browsers which could not help newer coloration varieties. Following the Lightning CSS documentation for utilizing it with Vite, we are able to additionally specify browser variations to focus on by putting in the browserslist
bundle.
Browserslist will give us a method to specify browsers by matching sure circumstances (attempt it out on-line!)
npm set up -D browserslist
Inside our vite.config.mjs
file, we are able to configure Lightning CSS additional. Let’s import the browserslist
bundle into the Vite configuration, in addition to a module from the Lightning CSS bundle to assist us use browserlist
in our config:
// vite.config.mjs
import browserslist from 'browserslist';
import { browserslistToTargets } from 'lightningcss';
We will add configuration settings for lightningcss
, containing the browser targets based mostly on specified browser variations 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%')),
}
},
construct: {
cssMinify: 'lightningcss'
}
};
There are many methods to increase Lightning CSS with Vite, equivalent to enabling particular options, excluding options we received’t want, or writing our personal customized transforms.
// vite.config.mjs
import browserslist from 'browserslist';
import { browserslistToTargets, Options } from 'lightningcss';
export default {
css: {
transformer: 'lightningcss',
lightningcss: Options.Colours,
},
construct: {
cssMinify: 'lightningcss'
}
};
For a full record of the Lightning CSS options, try their documentation on function flags.
Is any of this obligatory?
Studying by means of all this, you could be asking your self if all of that is actually obligatory. The reply: completely not! However I believe you possibly can see the advantages of getting access to partialized information that we are able to compile into unified stylesheets.
I doubt I’d go to those lengths for smaller tasks, nevertheless, if constructing one thing with extra complexity, equivalent to a design system, I’d attain for these instruments for organizing code, cross-browser compatibility, and totally optimizing compiled CSS.