Skip to content

Joomla CSS and User.css — Custom Styling and Responsive Design

DodaTech Updated 2026-06-27 12 min read

In this tutorial, you'll learn how to customize Joomla sites with CSS — using user.css for custom styles, writing responsive media queries with Bootstrap 5 breakpoints, and targeting specific pages using Joomla's built-in body classes.

What You'll Learn

  • Where user.css lives and how Joomla loads it automatically
  • How to add CSS files via the template editor
  • The cascade order: user.css loads last, overrides everything
  • Body classes in Joomla and how to use them for page-specific styling
  • How to use the page class suffix from menu items
  • CSS specificity rules for overriding Joomla defaults
  • Bootstrap 5 responsive breakpoints in Cassiopeia
  • How to write media queries for mobile-first design
  • Styling custom module positions
  • Dark mode customization with prefers-color-scheme
  • Using Font Awesome icons in Cassiopeia
  • Compiling Sass with Cassiopeia's Bootstrap source

Why It Matters

Every Joomla site needs visual customization beyond what the style editor provides. Custom CSS lets you fine-tune spacing, add animations, create unique layouts, and fix design issues without changing template files. Understanding how Joomla loads CSS, which classes are available, and how to write responsive rules gives you complete control over your site's appearance.

Real-World Use

An e-commerce site built on Joomla needs the product category page to display items in a four-column grid instead of the default three-column layout. The developer uses the body class com-content-category to target only category pages, writes a CSS rule to change the grid columns, and the rest of the site remains unchanged.

Learning Path

flowchart LR
  A["Child Templates"] --> B["CSS & User.css
You are here"]:::current B --> C["Extension Manager"] C --> D["Components"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px

Where User.css Lives

The user.css file is located at:

templates/cassiopeia/css/user.css

If the file exists, Cassiopeia loads it automatically on every page. You do not need to edit any template file to include it.

If the file does not exist, you can create it:

# Create user.css for Cassiopeia
touch templates/cassiopeia/css/user.css

You can create the file via FTP, the command line, or through Joomla's built-in template editor.

Creating user.css via the Template Editor

  1. Go to Extensions > Templates > Templates
  2. Click Cassiopeia
  3. Open the Stylesheets folder in the file tree
  4. Click New File
  5. Name it user.css
  6. Click Create
  7. Edit the file and click Save
# Steps to create user.css via admin
# Extensions > Templates > Templates > Cassiopeia
# Click "New File" button
# Enter: user.css
# Select: css/ folder
# Create > Edit > Save

How the Cascade Works

CSS stands for Cascading Style Sheets. The cascade determines which rule takes priority when multiple rules apply to the same element. In Cassiopeia, the load order is:

  1. Bootstrap 5 CSS (from media/vendor/bootstrap/)
  2. Cassiopeia's template.css
  3. Any extension CSS loaded by plugins or components
  4. user.css (loads last, highest priority)

Because user.css loads last, your custom rules override everything above, provided you use equal or higher specificity.

<!-- The actual load order in the page head -->
<link href="/media/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/templates/cassiopeia/css/template.css" rel="stylesheet">
<link href="/templates/cassiopeia/css/user.css" rel="stylesheet">

Body Classes in Joomla

Joomla adds several CSS classes to the <body> element on every page. These classes let you target specific pages, components, or menu items.

<!-- Example body tag on an article page -->
<body class="com-content-article itemid-123">

Common body classes:

Class When It Appears
com-content-article Viewing a single article
com-content-category Viewing a category list
com-content-category-blog Viewing a category blog
com-content-featured Viewing featured articles
com-contact-contact Viewing a single contact
com-banners-banner Viewing a banner
com-users-login Viewing the login page
itemid-NUMBER The menu item ID for the current page
option-com_content Always present on com_content pages
view-article View name
layout-default Layout name

Using Body Classes for Page-Specific Styling

/* Target only the blog category page */
.com-content-category-blog .blog-items {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

/* Target only the single article view */
.com-content-article .page-header h2 {
  font-size: 2.5rem;
  color: var(--cassiopeia-color-primary);
}

/* Target a specific page by menu item ID */
.itemid-456 .article-info {
  background-color: #f0f8ff;
  padding: 15px;
  border-radius: 8px;
}

Page Class Suffix

You can add a custom class to the body tag through the menu item settings:

  1. Go to Menus > [Your Menu] > [Your Menu Item]
  2. Find the Options tab (or Advanced tab)
  3. Look for "Page Class" or "Page Class Suffix"
  4. Enter a class name like "landing-page"
  5. Save
<!-- Resulting body tag -->
<body class="com-content-article itemid-123 landing-page">

Now you can target that specific page:

/* Target only the landing page */
.landing-page .hero {
  background-color: #1a365d;
  color: #ffffff;
  padding: 60px 0;
}

.landing-page .hero h1 {
  font-size: 3rem;
  font-weight: 800;
}

.landing-page .hero p {
  font-size: 1.25rem;
  opacity: 0.9;
}

CSS Specificity

When overriding Joomla styles, you need to match or beat the specificity of the original rule. Cassiopeia uses a combination of class selectors and sometimes IDs.

/* Original Cassiopeia rule — high specificity */
.com-content-article .com-content-article__body p {
  line-height: 1.8;
  margin-bottom: 1rem;
}

/* Your override — needs equal or higher specificity */
.com-content-article .com-content-article__body p {
  line-height: 2;
  margin-bottom: 1.5rem;
}

/* If the rule uses !important in template.css, use !important in user.css */
/* Only as a last resort */

CSS specificity hierarchy (highest to lowest):

  1. Inline styles (style="...")
  2. IDs (#my-id)
  3. Classes, attributes, pseudo-classes (.my-class, [type="text"], :hover)
  4. Elements, pseudo-elements (div, p, ::before)

When you cannot override a style, inspect the element in your browser's developer tools to see which rule is winning and why.

Responsive Breakpoints

Cassiopeia uses Bootstrap 5 breakpoints. You use these in your media queries.

Breakpoint Class Infix Min Width Description
Extra small (none) < 576px Mobile phones
Small sm >= 576px Large phones
Medium md >= 768px Tablets
Large lg >= 992px Desktops
Extra large xl >= 1200px Large desktops
Extra extra large xxl >= 1400px Wide screens

Writing Mobile-First CSS

Bootstrap 5 follows a mobile-first approach. Write base styles for small screens, then add media queries for larger screens:

/* Base style — applies to all screens, including mobile */
.blog-items {
  display: grid;
  grid-template-columns: 1fr;
  gap: 15px;
}

/* Tablet and up — 2 columns */
@media (min-width: 768px) {
  .blog-items {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Desktop and up — 3 columns */
@media (min-width: 992px) {
  .blog-items {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Large desktop — 4 columns */
@media (min-width: 1200px) {
  .blog-items {
    grid-template-columns: repeat(4, 1fr);
  }
}

Max-Width Queries for Overriding Specific Ranges

Sometimes you need styles that only apply below a certain width:

/* Mobile only — hide sidebar on small screens */
@media (max-width: 767.98px) {
  .sidebar-right {
    display: none;
  }
}

/* Tablet only — between 768px and 991px */
@media (min-width: 768px) and (max-width: 991.98px) {
  .sidebar-right {
    width: 50%;
  }
}

Styling Custom Module Positions

Each module position in Cassiopeia gets a CSS class based on the position name. You can target positions to apply consistent styling:

/* Target all modules in the sidebar-right position */
.sidebar-right .moduletable {
  margin-bottom: 30px;
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: 8px;
  border: 1px solid #e9ecef;
}

/* Target a specific module by its module class suffix */
.my-custom-class .moduletable h3 {
  color: var(--cassiopeia-color-primary);
  border-bottom: 2px solid var(--cassiopeia-color-primary);
  padding-bottom: 10px;
}

Dark Mode Customization

Cassiopeia supports dark mode through the prefers-color-scheme media query. You can extend or override the default dark mode styles:

/* Override Cassiopeia's dark mode colors */
@media (prefers-color-scheme: dark) {
  :root {
    --cassiopeia-color-primary: #60a5fa;
    --cassiopeia-color-text: #e2e8f0;
    --cassiopeia-color-body-bg: #0f172a;
    --cassiopeia-color-header-bg: #1e293b;
    --cassiopeia-color-sidebar-bg: #1e293b;
    --cassiopeia-color-footer-bg: #020617;
  }

  /* Custom dark mode additions */
  .moduletable {
    background-color: #1e293b;
    border-color: #334155;
  }

  img {
    opacity: 0.9;
  }
}

Font Awesome Icons

Cassiopeia includes Font Awesome 5 (free version). You can use icons in your CSS:

/* Add an icon before external links */
a[target="_blank"]::after {
  content: "\f35d";
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  margin-left: 5px;
  font-size: 0.8em;
}

/* Style module titles with icons */
.sidebar-right .moduletable h3::before {
  content: "\f15c";
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  margin-right: 8px;
  color: var(--cassiopeia-color-primary);
}

Adding Custom CSS Files

If user.css becomes very large, you can split it into multiple files and load them separately:

  1. Create your file at templates/cassiopeia/css/custom-styles.css
  2. Load it in index.php or use Joomla's API

To load via index.php override:

// In templates/cassiopeia/index.php (use child template or override)
$template = $app->getTemplate();
$wa = $app->getDocument()->getWebAssetManager();
$wa->registerAndUseStyle('custom', Uri::root() . 'templates/' . $template . '/css/custom-styles.css');

Compiling Sass

Cassiopeia's CSS is compiled from Sass source files. The source files are in:

# Cassiopeia Sass source (if included with your installation)
templates/cassiopeia/sass/
├── template.scss
├── _variables.scss
└── _cassiopeia.scss

If you know Sass, you can override variables in custom.scss:

// templates/cassiopeia/sass/custom.scss
// Override Bootstrap variables
$primary: #2563eb;
$font-family-sans-serif: "Inter", system-ui, -apple-system, sans-serif;
$border-radius: 0.5rem;

// Import Cassiopeia
@import "template";

Then compile it:

# Compile Sass to CSS (requires Node.js and node-sass or Dart Sass)
sass templates/cassiopeia/sass/custom.scss templates/cassiopeia/css/custom.css

Debugging CSS

Use your browser's developer tools to inspect Joomla's CSS:

  1. Right-click any element on the page
  2. Click Inspect (or Inspect Element)
  3. In the Styles panel, you see all CSS rules affecting the element
  4. Crossed-out rules are overridden by higher-specificity rules
  5. You can toggle rules on and off to test changes

The browser's developer tools also show you the body classes, which makes targeting specific pages much easier.

Common Mistakes

  1. Using user.css without checking specificity: You write p { color: red; } but the paragraph text stays blue. Cassiopeia's rule .com-content-article p { color: blue; } has higher specificity. Use the same selector chain in your user.css.

  2. Not using body classes for page-specific styles: You add a global style that affects every page, when you only wanted to target the home page. Use the body class to scope your styles to specific pages.

  3. Forgetting to account for responsive breakpoints: Your custom layout looks perfect on desktop but breaks on mobile. Always write mobile-first CSS and test at all breakpoints.

  4. Overusing !important: You add !important to override a stubborn rule. Now every future CSS change also needs !important. This creates a maintenance nightmare. Use specificity instead.

  5. Editing template.css instead of user.css: Cassiopeia's template.css is overwritten during updates. Put all custom styles in user.css, which persists across updates.

Practice Questions

  1. What is the load order of stylesheets in Cassiopeia? Answer: Bootstrap 5 loads first, then template.css, then any extension CSS, then user.css last. Because user.css loads last, it overrides all previous styles when specificity is equal.

  2. How can you apply custom CSS to only one page on your Joomla site? Answer: Two ways: use the body class itemid-NUMBER where NUMBER is the menu item ID, or add a Page Class Suffix in the menu item's Options tab and use that class in your CSS.

  3. What are the Bootstrap 5 breakpoints and their minimum widths? Answer: sm >= 576px, md >= 768px, lg >= 992px, xl >= 1200px, xxl >= 1400px. The default (xs) is < 576px.

  4. Challenge: Create a Responsive Design system in user.css for a multi-section Joomla site. The home page should have a full-width hero section with a dark background. Category blog pages should display articles in a 2-column grid on tablet and 3 columns on desktop. Article pages should have a wider content area and styled blockquotes. The submit button on the contact page should use the accent color. Use only body classes for targeting — no IDs, no inline styles.

FAQ

Where does user.css need to be located in Cassiopeia?

The file must be at templates/cassiopeia/css/user.css. If it exists, Cassiopeia loads it automatically on every page. You can create it via FTP, command line, or Joomla's built-in template editor.

Why is my user.css not overriding template.css?

Your CSS rule likely has lower specificity than the template.css rule. Use the browser's developer tools to compare selectors. You need to match or exceed the specificity of the original rule. Alternatively, user.css might not be loading — check that the file exists at the correct path.

What body classes does Joomla add to pages?

Joomla adds classes for the component (com-content-article), option (option-com_content), view (view-article), layout (layout-default), menu item ID (itemid-123), plus any page class suffix you configure in the menu item settings.

Can I use Bootstrap 5 utility classes in Cassiopeia?

Yes. Since Cassiopeia includes Bootstrap 5, all Bootstrap utility classes are available. You can use classes like d-flex, text-center, mt-3, col-md-6, and bg-primary in your HTML modules or overrides.

Does Cassiopeia support dark mode?

Yes. Cassiopeia includes a dark mode stylesheet that activates automatically when the user's operating system is set to dark mode. It uses the prefers-color-scheme media query. You can customize dark mode colors in user.css.

Mini Project

Your task: Redesign a Joomla site's visual appearance using only user.css.

  1. Create or open user.css at templates/cassiopeia/css/user.css.
  2. Change the site's link color to a deep blue (#1e40af).
  3. Add a subtle background pattern to the page body.
  4. Style the footer with a dark background and light text.
  5. Make the blog category page show articles in a responsive grid (1 column mobile, 2 tablet, 3 desktop).
  6. Add a hover animation on article images (slight scale transform).
  7. Style the login page with a centered card layout.
  8. Add a custom bullet style for unordered lists.
  9. Change the blockquote styling with a left border accent.
  10. Add a smooth scroll behavior to the page.
  11. Test all changes at mobile, tablet, and desktop breakpoints.
  12. Verify that the page class suffix targeting works by adding a custom class to one page.

This project gives you complete hands-on experience with Joomla CSS customization — a skill you use on every site you build.

What's Next

Now that you can style your Joomla site with CSS, you are ready to learn about extensions:

Continue to Lesson 20: Extension Manager — Learn how to install, update, and manage Joomla extensions.

Related lessons:

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro