CSS File Structure
Last modified: 12 February 2025Basic guidelines for how to structure CSS files in a new project.
Basic Website (HTML/CSS/JS)
Create a folder called CSS and add a file called styles.css.
Use this file for general styles applicable across the entire website, such as typography, layout, reusable utilities, or shared elements like the header and footer.
Create a new file for each page on the website such as about.css or contact.css etc.
Add styles on these that are unique to those pages.
In the head tag on each page link the style.css file and the relevant pages CSS file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home Page</title>
<!-- Global Styles -->
<link rel="stylesheet" href="css/style.css">
<!-- Specific CSS -->
<link rel="stylesheet" href="css/about.css">
</head>
</html>
.NET MVC App - Simple
Within the CSS folder located in wwwroot, add a file called main.css Use this file for general styles applicable across the entire website, such as typography, layout, reusable utilities, or shared elements like the header and footer.
Add a new CSS file for each partial or view etc. for the specific styling for those.
In the _Layout.cshtml file, add the following in the head tag:
<head>
<link rel="stylesheet" href="/css/main.css" />
@RenderSection("Styles", required: false)
</head>
Within each partial or view, add the following to include the styling for it:
@section Styles {
<link rel="stylesheet" href="/css/partial-specific.css" />
}
.NET MVC App - WebOptimizer
WebOptimizer will bundle and minify the CSS and JS.
Install the following Nuget package: LigerShark.WebOptimizer.Core
Update the Program.cs file to add the service, and then call it just before UseStaticFiles:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// Add WebOptimizer services
builder.Services.AddWebOptimizer(options =>
{
// Example: Bundle and minify CSS files in /css folder
options.AddCssBundle("/css/bundle.css", "/css/*.css");
// Example: Bundle and minify JavaScript files in /js folder
options.AddJavaScriptBundle("/js/bundle.js", "/js/*.js");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
// Use WebOptimizer middleware before serving static files
app.UseWebOptimizer();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Or if you want to keep the bundle configurations in a separate file:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// Add WebOptimizer services
builder.Services.AddWebOptimizer(options =>
{
WebOptimizerConfig.ConfigureBundles(options);
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
// Use WebOptimizer middleware before serving static files
app.UseWebOptimizer();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Then create a file called WebOptimizerConfig.cs:
using WebOptimizer;
public static class WebOptimizerConfig
{
public static void ConfigureBundles(IAssetPipeline options)
{
// Shared CSS/JS used globally
options.AddCssBundle("/css/shared-bundle.css",
"/css/base/reset.css",
"/css/layout/header.css",
"/css/layout/main-content.css",
"/css/layout/sidebar.css"
);
//options.AddJavaScriptBundle("/js/shared-bundle.js", "/js/shared.js");
// View-specific bundles
//options.AddCssBundle("/css/home-bundle.css", "/css/home.css");
//options.AddJavaScriptBundle("/js/home-bundle.js", "/js/home.js");
//options.AddCssBundle("/css/about-bundle.css", "/css/about.css");
//options.AddJavaScriptBundle("/js/about-bundle.js", "/js/about.js");
}
}
Reference the bundle in the view or partial:
<link rel="stylesheet" href="/css/shared-bundle.css" asp-append-version="true" />
For partials, consider lazy loading scripts using script tags with the defer or async attributes. This ensures scripts load only when needed without blocking rendering:
<script src="/js/specific-partial.js" defer></script>
.NET MVC App - WebOptimizer with SASS
WebOptimizer will bundle and minify the CSS and JS.
Install the following Nuget packages: LigerShark.WebOptimizer.Core LigerShark.WebOptimizer.Sass JavaScriptEngineSwitcher.Extensions.MsDependencyInjection JavaScriptEngineSwitcher.V8 Microsoft.ClearScript.V8.Native.osx-arm64 (if using Mac) Microsoft.ClearScript.V8.Native.win-x64 (if using Windows)
Update the Program.cs file to add the services (JS Engine and WebOptimizer), and then call the WebOptimizer service just before UseStaticFiles:
using JavaScriptEngineSwitcher.Extensions.MsDependencyInjection;
using JavaScriptEngineSwitcher.V8;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// Register JS Engine for WebOptimizer
builder.Services.AddJsEngineSwitcher(options =>
options.DefaultEngineName = V8JsEngine.EngineName
).AddV8(); // Use the V8 engine
// Add WebOptimizer services
builder.Services.AddWebOptimizer(options =>
{
// Example: Bundle and minify CSS files in /css folder
options.AddCssBundle("/css/bundle.css", "/css/*.css");
// Example: Bundle and minify JavaScript files in /js folder
options.AddJavaScriptBundle("/js/bundle.js", "/js/*.js");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
// Use WebOptimizer middleware before serving static files
app.UseWebOptimizer();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Or if you want to keep the bundle configurations in a separate file:
using JavaScriptEngineSwitcher.Extensions.MsDependencyInjection;
using JavaScriptEngineSwitcher.V8;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// Register JS Engine for WebOptimizer
builder.Services.AddJsEngineSwitcher(options =>
options.DefaultEngineName = V8JsEngine.EngineName
).AddV8(); // Use the V8 engine
// Add WebOptimizer services
builder.Services.AddWebOptimizer(options =>
{
WebOptimizerConfig.ConfigureBundles(options);
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
// Use WebOptimizer middleware before serving static files
app.UseWebOptimizer();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Then create a file called WebOptimizerConfig.cs:
using WebOptimizer;
public static class WebOptimizerConfig
{
public static void ConfigureBundles(IAssetPipeline options)
{
// Shared CSS/JS used globally
options.AddScssBundle("/css/shared-bundle.css",
"/css/base/reset.scss",
"/css/layout/header.scss",
"/css/layout/main-content.scss",
"/css/layout/sidebar.scss"
);
//options.AddJavaScriptBundle("/js/shared-bundle.js", "/js/shared.js");
// View-specific bundles
//options.AddScssBundle("/css/home-bundle.css", "/css/home.css");
//options.AddJavaScriptBundle("/js/home-bundle.js", "/js/home.js");
//options.AddScssBundle("/css/about-bundle.css", "/css/about.css");
//options.AddJavaScriptBundle("/js/about-bundle.js", "/js/about.js");
}
}
Reference the bundle in the view or partial:
<link rel="stylesheet" href="/css/shared-bundle.css" asp-append-version="true" />
For partials, consider lazy loading scripts using script tags with the defer or async attributes. This ensures scripts load only when needed without blocking rendering:
<script src="/js/specific-partial.js" defer></script>
VUE App
For a Vue application, it is best to use the scoped CSS styling within each component's file.