Skip to main content
CSS for Joomla
On this page
# Topics

CSS for Joomla

01 July 2026

Look at any Joomla site and ask what makes it look the way it does: the colours, the spacing, the fonts, the way a menu turns into a button on a phone, the shadow under a card. None of that is the content, and none of it is the program logic. It is CSS, the language that decides how every piece of HTML appears on the screen. Joomla builds the page in PHP and brings it to life with JavaScript, but CSS is what makes it look like a finished website instead of a plain wall of text.

This article explains CSS from a Joomla point of view. It covers the basics for site owners and editors, the way Joomla loads and manages stylesheets for administrators, and the developer tools (the Web Asset Manager, the Cassiopeia template, SCSS, CSS custom properties, modern layout, and template overrides) for those who build templates and extensions.

HTML is the content, JavaScript is the behaviour, and CSS is the look.

The goal is simple: help you understand how Joomla uses CSS well enough to change how your site looks, do it in a place that survives updates, and keep your pages fast and accessible.

1. The Basics

1.1 What is CSS?

CSS stands for Cascading Style Sheets. It is the language that tells the browser how HTML should look: which colour a heading is, how much space sits around a paragraph, what font the page uses, and how the layout changes on a small screen. The HTML says what the content is; the CSS says how it should appear.

A style rule has two parts: a selector that picks which elements to style, and a set of declarations that say how. For example, this rule makes every main heading dark blue:

h1 {
  color: #112855;
  margin-bottom: 1rem;
}

The browser reads the CSS, matches each rule against the HTML, and paints the result. Change one line of CSS and the whole site can look different, without touching a single article.

1.2 What "Cascading" Means

The "cascading" part is the rule that decides who wins when two styles target the same element. The browser combines styles from several sources, then resolves conflicts using three things, in order: importance, specificity, and source order.

  • Specificity: a more specific selector beats a less specific one. An ID (#main) beats a class (.box), which beats a tag (div).
  • Source order: when two rules are equally specific, the one that loads later wins.
  • Importance: !important overrides normal rules, which is why it causes so much trouble later.

This matters in Joomla because your styles, the template's styles, Bootstrap's styles, and an extension's styles all load on the same page. Knowing which one wins is half of all CSS troubleshooting.

1.3 Cascade Layers and Nesting

Modern CSS adds two features that make large stylesheets easier to manage, and both work in current browsers. The first is cascade layers (@layer), which let you group rules into named layers and decide their priority on purpose, instead of fighting specificity. Rules in a later layer beat rules in an earlier one, no matter how specific:

@layer base, theme, overrides;

@layer base {
  a { color: #224faa; }
}
@layer overrides {
  a { color: #1b6e3c; }   /* wins: 'overrides' is the last layer */
}

The second is native CSS nesting, which lets you write child rules inside a parent, much like SCSS but with no build step:

.card {
  padding: 1rem;
  & .title { font-weight: 700; }
}

You do not need either to style a Joomla site, but layers are a clean way to keep your own overrides predictable, and nesting makes plain CSS read almost like the SCSS Cassiopeia is built from (section 7).

1.4 Where Joomla Uses CSS

You do not have to write any CSS to benefit from it. A fresh Joomla 6 site already loads a full set of stylesheets:

  • The front-end template (Cassiopeia by default) styles the whole public site.
  • Bootstrap 5 provides the grid, buttons, cards, and other building blocks.
  • Font Awesome provides the icons you see throughout the interface.
  • The administrator template (Atum) styles the entire back end.
  • Components and modules ship their own small stylesheets for their own output.

All of this is loaded and ordered by Joomla. Your job, when you add your own CSS, is to add it in the right place so it loads cleanly on top of the rest rather than fighting it.

Back to top

2. A Short History: From LESS to SCSS and CSS Variables

2.1 The Move to SCSS

Older Joomla templates were styled with hand-written CSS and, in Joomla 3, with LESS, a language that compiles into CSS. From Joomla 4 onward the default template, Cassiopeia, is built with SCSS (also called Sass), the most common CSS pre-processor today. SCSS lets developers use variables, nesting, and reusable pieces, then compiles everything down to ordinary CSS that the browser understands.

2.2 Native CSS Variables Arrived Too

At the same time, browsers gained their own CSS custom properties (often just called CSS variables), written as --name and read with var(--name). Cassiopeia uses these for its colours, so you can re-theme much of the site by changing a few variables, with no build step at all (section 10).

2.3 Bootstrap 5, Without jQuery

Joomla 4, 5, and 6 ship Bootstrap 5 as the underlying CSS framework. This is a big change from Joomla 3, which used Bootstrap 2. Bootstrap 5 dropped jQuery and added its own set of CSS variables, so it fits the modern, framework-light direction of Joomla well.

2.4 Why This Matters to You

The practical result is that you now have three clean ways to change how a Joomla site looks, from easy to advanced: change a CSS variable, add plain CSS in the right file, or rebuild the SCSS. You rarely need to edit the compiled CSS by hand, and you should never edit it inside the core files, because the next update will overwrite your work.

Back to top

3. How the Browser Loads Joomla's CSS

3.1 Stylesheets Collected, Sorted, and De-duplicated

When Joomla renders a page, it gathers every stylesheet that the template, the components, the modules, and the plugins asked for. It removes duplicates, sorts them by their declared dependencies, and writes the <link> tags into the <head> of the page. You never add the same stylesheet twice; Joomla handles that for you.

3.2 The Order Decides the Winner

Because source order is part of the cascade (section 1.2), the order Joomla writes the links in matters. A general rule is that the template loads first and your own custom file should load last, so your styles can override the template without resorting to !important. Joomla's asset system gives each style a weight so the right files end up at the end; Cassiopeia's custom file (user.css) has a high weight on purpose, so it loads after the rest.

3.3 Minified and Pre-compressed Files

On a live site, Joomla loads the minified version of each stylesheet (the .min.css file), which is smaller and faster. Many core files also ship a pre-compressed .min.css.gz version so the server can deliver them with less work. You will see all three side by side in the media folder:

template.css         the readable source (for debugging)
template.min.css     the minified version (smaller, for production)
template.min.css.gz  pre-compressed for faster delivery

The point for you is to edit the readable source (or your own file), not the minified one, because the minified file is generated and will be replaced.

Back to top

4. The Web Asset Manager for Styles

The Web Asset Manager (WAM) is the modern, correct way to add both CSS and JavaScript in Joomla 4, 5, and 6. It replaced the old habit of calling $document->addStyleSheet() with a hard-coded path. The same manager that handles scripts handles styles, with matching method names.

4.1 The Problem It Solves

Before WAM, every extension added its own stylesheets directly, sometimes the same library twice, in the wrong order, with no shared version. WAM fixes this by treating each stylesheet as a named asset with declared dependencies. You ask for an asset by name; Joomla works out the files, the order, and the duplicates.

4.2 The Asset Registry and joomla.asset.json

Styles are declared in a file named joomla.asset.json, the same file used for scripts. (Note: this is JSON, not the old webassets.xml name you may see in outdated guides.) Joomla's core assets live in media/system/joomla.asset.json, and each template or extension can ship its own. Cassiopeia's lives in templates/cassiopeia/joomla.asset.json. Every entry has a name, a type, a file, and its dependencies:

{
  "name": "myextension.site",
  "type": "style",
  "uri": "com_myextension/site.min.css",
  "dependencies": ["fontawesome"]
}

Because the asset declares its dependency on fontawesome, Joomla loads the icon styles first, then yours. You never manage that order yourself.

4.3 Using a Style

From PHP (in a view template, a module, or a plugin) you reach the manager through the document and call useStyle() with the asset name:

use Joomla\CMS\Factory;

$wa = Factory::getApplication()
    ->getDocument()
    ->getWebAssetManager();

// Load a registered style by name:
$wa->useStyle('myextension.site');

If you have a single file that is not worth a full joomla.asset.json entry, you can register and use it in one step:

$wa->registerAndUseStyle(
    'myextension.extra',
    'com_myextension/extra.css',
    [],
    [],
    ['fontawesome']
);

4.4 The Main Methods

MethodWhat it does
useStyle('name') Enable a registered stylesheet (and its dependencies).
registerStyle('name', 'uri', ...) Declare a stylesheet without enabling it yet.
registerAndUseStyle(...) Declare and enable a stylesheet in one call.
addInlineStyle('css') Add a small block of inline CSS.
disableStyle('name') Turn off a stylesheet another extension enabled.

The same method names exist for scripts (useScript, registerScript, and so on). This is the API to learn; with it you rarely need to touch a raw <link> tag again. WAM also adds a version to each asset URL, so when you change a file and bump the media version, browsers fetch the new copy instead of a cached old one.

Back to top

5. Cassiopeia: The Default Template's CSS

Cassiopeia is the front-end template that ships with Joomla. Most of what a visitor sees comes from its stylesheets, and it is built so that you can change a lot without writing any CSS at all. The settings live in the template options, which you reach in the back end.

5.1 Where the Files Live

In Joomla 4 and later, a template's media is not inside the template folder; it lives under media/. Cassiopeia's stylesheets are here:

media/templates/site/cassiopeia/css/    the compiled CSS
media/templates/site/cassiopeia/scss/   the SCSS source
media/templates/site/cassiopeia/css/global/  colour and font presets

The main stylesheet is template.css (with its template.min.css twin). The administrator template, Atum, follows the same layout under media/templates/administrator/atum/.

5.2 Colour and Font Presets, No Code Needed

Open System → Site Templates → Cassiopeia Details and Files → Options and you can change the look without touching CSS:

OptionWhat it changes
Colour (colorName) Picks a colour preset file, such as colors_standard or colors_alternative.
Font Scheme Chooses the body and heading fonts, including local Roboto.
Logo, Site Title, Description The brand area at the top of the page.
Fluid / Static container Whether the layout spans the full width or sits in a fixed-width box.
Sticky header, Back-to-top Common layout behaviours, toggled on or off.

The colour presets are small CSS files in css/global/ that set CSS variables. That is why switching the preset re-colours the whole site instantly: every component reads the same variables.

5.3 The user.css File: Your Easiest Custom CSS

Cassiopeia includes an asset named template.user that points to a file called user.css. It does not exist until you create it, and it is given a high weight so it loads after all the template styles. This makes it the simplest correct place to add your own CSS: anything you put there can override the template without !important.

Create this file and Joomla loads it automatically:
media/templates/site/cassiopeia/css/user.css

There is a matching user.js for JavaScript. Be aware that these files sit under media/ and a careless update could overwrite them, so for serious work a child template (section 6) is safer. For quick fixes, user.css is ideal.

Back to top

6. Where to Put Your Own CSS

As with PHP and JavaScript, the golden rule is to never edit core files. The compiled CSS, Bootstrap, and the template's own files are all replaced on update. Joomla gives you several clean places to add CSS that survive updates; choose by how big and how permanent the change is.

6.1 The Right Places, From Quick to Robust

You want to...Put the CSS in...
Make a quick visual tweak user.css in the active template's media folder.
Maintain a real, update-safe theme A child template with its own stylesheet.
Style one component or module's output A template override, loading the style from there.
Add styles site-wide from code A plugin that calls the Web Asset Manager.
Ship a self-contained feature A component or module with its own assets.

6.2 Child Templates: The Update-safe Way

A child template inherits everything from a parent (such as Cassiopeia) and lets you override only the parts you want. Your custom CSS lives in the child, so a Joomla update to the parent never touches your work. Joomla can create a child template for you from the template manager, after which you add your stylesheet and register it in the child's joomla.asset.json.

6.3 Loading a Style From a Plugin

A system plugin is a tidy way to add a stylesheet to every page without editing the template at all. It listens to a page event and enables the asset:

public function onBeforeCompileHead(): void
{
    $wa = $this->getApplication()
        ->getDocument()
        ->getWebAssetManager();

    $wa->registerAndUseStyle(
        'myplugin.skin',
        'plg_system_myplugin/skin.css'
    );
}

6.4 Avoid Inline Styles in Content

It is tempting to set a colour with a style="..." attribute straight in an article. It works, but it is hard to maintain, impossible to reuse, and it beats your stylesheet on specificity, so it becomes the thing you later have to fight. Keep design in your CSS files and let articles hold only content.

Back to top

7. SCSS and Building CSS

The CSS Cassiopeia ships is not the same as the code its developers write. The source is SCSS, split into many small files; the version sent to browsers is compiled, combined, and minified into plain CSS. Knowing this helps you understand what you see in the media folder.

7.1 Source Versus Built Files

Cassiopeia's SCSS lives in media/templates/site/cassiopeia/scss/, organised into folders such as blocks, global, tools, and vendor. These compile into the css/ folder next to them. You edit the SCSS; the build step produces the CSS. The browser never sees the SCSS.

7.2 The Build Tools

Compiling SCSS uses Node.js and npm, the standard front-end tooling, with a build script in the Joomla project. You only need this if you change the core template's SCSS or build your own template with a SCSS pipeline. For a normal site, the compiled CSS is already in place and you never run a build.

7.3 You Rarely Need a Build for Custom CSS

For your own changes, you usually do not need SCSS at all. Plain CSS in user.css or a child template works everywhere, and CSS variables (plus native nesting from section 1.3) give you much of what people once needed SCSS for. Reach for a SCSS build only when you maintain a large, structured theme, not for a handful of overrides.

Back to top

8. Bootstrap 5 and Joomla's Styling

Joomla bundles Bootstrap 5 in media/vendor/bootstrap/, and Cassiopeia builds on top of it. This means you already have a complete, tested CSS framework on every page: a responsive grid, buttons, cards, alerts, badges, spacing helpers, and more. Using it is usually better than inventing your own.

8.1 Use the Grid and Utilities

Bootstrap's grid lays out columns that stack on small screens, and its utility classes set spacing, colour, and alignment without custom CSS. A two-column layout that becomes one column on a phone needs no CSS of your own:

<div class="row">
  <div class="col-md-8">Main content</div>
  <div class="col-md-4">Sidebar</div>
</div>

Classes such as mt-3 (margin top), p-2 (padding), and text-center cover most small adjustments. Learning a dozen of these saves a lot of custom CSS.

8.2 Load Only What You Need

Like its JavaScript, Bootstrap's CSS is available as named assets, so you load only the part you use rather than the whole framework when you do not need it. Cassiopeia already pulls in what its layout needs; when you add a component, prefer the Bootstrap classes that are already on the page over shipping a second framework.

8.3 Override Bootstrap With Variables, Not Copies

Bootstrap 5 exposes many CSS variables (such as --bs-primary). You can re-colour Bootstrap components by setting these variables in your own CSS, which is far cleaner than copying Bootstrap's rules and editing them. This keeps your overrides small and easy to maintain across Bootstrap updates.

Back to top

9. Modern CSS: Layout, Selectors, and Functions

Bootstrap's grid covers most page layouts, but it is built on top of plain CSS features that you can use directly. For one section, one card, or one module, native CSS is often simpler than adding framework classes to the markup. Everything below works in every current browser, so you can use it in user.css, a child template, or a template override.

Not every modern CSS feature is supported equally across all browsers. Before using a newer property or selector in production, check its browser compatibility on Can I Use (https://caniuse.com/). The site provides up-to-date support tables and helps you decide whether you need a fallback.

9.1 Flexbox for One Direction

Flexbox arranges items in a single row or column and shares the space between them. It is ideal for a navigation bar, a row of buttons, or centring something. Bootstrap's own grid uses it under the hood:

.toolbar {
  display: flex;
  gap: 1rem;
  align-items: center;
  justify-content: space-between;
}

The gap property adds even spacing between items without margins, and align-items and justify-content handle vertical and horizontal alignment.

9.2 CSS Grid for Two Directions

CSS Grid lays out items in rows and columns at the same time, which is perfect for card galleries and dashboards. With auto-fill and minmax you get a responsive grid that needs no media queries: it fits as many columns as will hold the minimum width, then wraps.

.cards {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

This single rule turns a list of article cards into a neat, self-adjusting grid that looks right from a phone to a wide monitor.

9.3 Fluid Sizing With clamp() and aspect-ratio

Two newer functions remove a lot of media-query work. clamp() sets a size that scales with the screen but never goes below a minimum or above a maximum, which is excellent for headings:

h1 {
  font-size: clamp(1.75rem, 4vw, 3rem);
}

And aspect-ratio reserves the correct shape for images and video, so the page does not jump as media loads (which also helps the layout-shift score in section 16):

.media {
  aspect-ratio: 16 / 9;
}

9.4 Container Queries

A media query reacts to the size of the whole screen. A container query reacts to the size of the element's own container, which is exactly what you want for a module that can sit in a wide main area or a narrow sidebar. The same module can lay itself out differently depending on where it is placed:

.module-wrap {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .module-wrap .item { display: flex; }
}

Container queries are a good fit for Joomla, where the same module shows up in many positions. Use them when a component must adapt to its slot, not just to the screen.

9.5 Modern Selectors

Three newer selectors cut down on long, brittle rules and on JavaScript you would otherwise need. The first is :has(), the "parent" selector: it styles an element based on what it contains. For example, give a Joomla article card extra room only when it actually has an image:

.card:has(img) {
  padding-bottom: 1.5rem;
}

The other two, :is() and :where(), group several selectors into one. They read the same, but they differ in specificity: :is() takes the specificity of its strongest argument, while :where() always counts as zero. That makes :where() perfect for low-priority base styles that your own rules can override later without a fight:

/* Easy to override: this adds no specificity. */
:where(h1, h2, h3) {
  margin-top: 0;
}

/* Same target, normal specificity. */
:is(article, .content) p {
  line-height: 1.6;
}

Reaching for :where() in your base styles is a quiet way to avoid the specificity arms race described in section 14.4.

9.6 Modern Functions: clamp() Friends and color-mix()

Alongside clamp() from section 9.3, color-mix() is the function most worth knowing for theming. It blends two colours in the browser, so you can derive a hover or border shade straight from a single brand variable instead of hard-coding a second hex value:

:root {
  --brand: #1b6e3c;
}

.button {
  background: var(--brand);
}
.button:hover {
  /* 85% brand, 15% black: a darker hover, with no extra variable. */
  background: color-mix(in srgb, var(--brand) 85%, black);
}

This pairs naturally with the CSS variables in section 10: define one brand colour, then mix lighter and darker versions from it. One value to change, a whole palette that follows.

Back to top

10. CSS Custom Properties (Variables), Theming, and Dark Mode

CSS custom properties are the single most useful modern CSS feature for theming a Joomla site. They let you define a value once and reuse it everywhere, then change it in one place to update the whole site. Cassiopeia and Bootstrap both rely on them, so you can re-theme much of a site without editing their stylesheets.

10.1 How They Work

A custom property is declared with a double dash and read with var(). The usual home for site-wide values is the :root selector, which means "the whole document":

:root {
  --brand-color: #c0392b;
}

a {
  color: var(--brand-color);
}

Change the one value in :root and every place that uses var(--brand-color) updates at once. This is exactly how Cassiopeia's colour presets work: each preset file simply sets a group of variables.

10.2 Re-theming Cassiopeia

To change Cassiopeia's colours without editing the template, set its variables in your user.css (or child template). Because your file loads last, your values win:

:root {
  --cassiopeia-color-primary: #1b6e3c;
  --cassiopeia-color-link: #1b6e3c;
  --cassiopeia-color-hover: #155030;
}

This re-colours links and accents across the whole site with a few lines and no build step. It is the cleanest way to match a Joomla site to a brand.

10.3 Why Variables Beat Search-and-replace

Before variables, changing a brand colour meant finding every hard-coded hex value across many files and replacing each one, hoping you missed none. With variables, the colour lives in one place. This is safer, faster, and far easier to hand over to whoever maintains the site after you.

10.4 Dark Mode With prefers-color-scheme

Because your theme reads from variables, adding a dark mode is mostly a matter of giving those variables different values when the visitor's device asks for dark. The prefers-color-scheme media query detects that choice:

:root {
  --page-bg: #ffffff;
  --page-text: #1a1a1a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --page-bg: #14171c;
    --page-text: #e8e8e8;
  }
}

body {
  background: var(--page-bg);
  color: var(--page-text);
}

This is another reason to define colours as variables from the start: a dark mode then becomes one extra block, not a second copy of your whole stylesheet. Check the contrast of both light and dark sets (section 15).

Back to top

11. Template Overrides and CSS

Sometimes the problem is not the colour or the spacing but the HTML itself: an extension outputs a wrapper you cannot reach with CSS, or you want to add a class so your styles have something to target. The Joomla answer is a template override, which lets you change the HTML a component or module produces without editing the extension.

11.1 Add a Hook for Your CSS

An override is a copy of an extension's layout file placed inside your template, where Joomla uses it instead of the original. A common reason to make one is purely for styling: you add a class or a wrapper so your CSS has a clean, stable selector to target.

Original layout:
components/com_content/tmpl/article/default.php

Your override (Joomla uses this instead):
templates/yourtemplate/html/com_content/article/default.php

Inside the override you can add a class, then style it in your own CSS file. Because you changed a copy, the next update to the component leaves your override in place (though you should re-check it after big updates).

11.2 Style, Do Not Rebuild

Use an override for styling only when CSS alone cannot reach what you need. If a colour or spacing change is enough, do it in CSS; an override is more to maintain. The two work well together: the override gives your CSS a clean target, and the CSS does the actual styling.

Back to top

12. CSS in the Back End: The Atum Template

The Joomla administrator has its own template, Atum, with its own CSS under media/templates/administrator/atum/. Most site owners never need to touch it, but it helps to know it exists and follows the same rules as the front end.

12.1 The Same System, A Different Template

Atum is built with SCSS, compiled to CSS, and loaded through the Web Asset Manager, exactly like Cassiopeia. If you build a component, its back-end views inherit Atum's styling, so you should use Atum's and Bootstrap's existing classes rather than adding heavy custom CSS to the administrator.

12.2 Styling Your Own Admin Views

When a component needs a little custom CSS in the back end, register it the same way as any other style, from the component's view, with the Web Asset Manager. Keep it light: the administrator should look and behave consistently, so visitors who also manage the site are not confused by a view that ignores the standard look.

Back to top

13. Debugging CSS With Browser Developer Tools

Most CSS problems are solved not by guessing but by looking. Every modern browser has built-in developer tools that show you exactly which rule is winning and why. Open them with F12, or right-click an element and choose "Inspect". Learning a few panels turns "why won't this change?" into a two-minute answer.

13.1 Inspect Element and the Styles Panel

Right-click anything on the page and choose Inspect. The browser highlights the element's HTML and, in the Styles panel, lists every rule that targets it, in order. Rules that are struck through were overridden by something more specific or loaded later. This single view answers most "which CSS applies here?" questions, and it shows which file and line each rule comes from.

13.2 Computed Styles and the Box Model

The Computed tab shows the final value the browser actually used for each property, after the whole cascade is resolved. Next to it, the box model diagram shows the element's content, padding, border, and margin as nested boxes. When spacing looks wrong, this diagram usually shows whether it is margin or padding, and on which side.

13.3 The Grid and Flexbox Inspectors

When you use CSS Grid or Flexbox (section 9), the developer tools add small grid and flex badges next to the element. Click one and the browser draws the grid lines or flex axes over the page, so you can see the tracks, gaps, and alignment instead of imagining them. This makes a misbehaving layout far easier to understand.

13.4 A Quick Troubleshooting Checklist

  • Is the rule even loading? Check the Styles panel; if it is absent, the file did not load or the selector does not match.
  • Is it struck through? Something more specific or later in source order is winning.
  • Did you clear the cache? Joomla and the browser both cache CSS; an old file is a common false alarm.
  • Is an inline style attribute overriding you? Inline styles beat almost everything.
  • Right element? Confirm the selector targets the element you think it does.
Back to top

14. Performance: Keep CSS Fast

CSS is render-blocking: the browser will not paint the page until it has loaded the stylesheets in the <head>. That makes CSS one of the first things to look at when a site feels slow to appear.

14.1 Load Less CSS

  • Do not ship a second CSS framework when Bootstrap is already on the page.
  • Remove stylesheets from extensions you no longer use; an uninstalled-in-name-only extension can still load its CSS.
  • Only enable a stylesheet on the pages that need it, not site-wide by habit.

14.2 Combine, Minify, and Compress

Joomla loads minified core files already. For the rest, a good caching or optimisation extension can combine several small stylesheets into one request and minify them. On the server, enabling Gzip or Brotli compression shrinks the CSS further on the way to the browser. Fewer, smaller, compressed files mean fewer round trips and a faster first paint, especially on HTTP/1.1 hosts.

14.3 Critical CSS and Preload

For the fastest first paint, advanced setups inline the small amount of critical CSS needed for the top of the page and load the rest afterwards, and use <link rel="preload"> to fetch an important stylesheet early. These help, but they add complexity; reach for them once the basics (load less, combine, compress) are done and a measurement still shows render-blocking CSS.

14.4 Avoid the Specificity Arms Race

Every time you reach for !important or a very long selector to force a style, you make the next change harder and the stylesheet heavier to reason about. Loading your CSS last (as user.css and child templates do), or using a cascade layer (section 1.3), lets simple selectors win, which keeps the file small and predictable.

14.5 Measure, Do Not Guess

Use the browser's developer tools to see which stylesheets load and how big they are, and a tool such as Lighthouse to spot render-blocking or unused CSS. Optimise what the measurement shows, not what you assume.

Back to top

15. Accessibility and CSS

CSS decides not only how a site looks but how usable it is for people with low vision, colour blindness, motion sensitivity, or anyone using a keyboard. Good CSS makes a site easier for everyone; careless CSS quietly locks people out. These checks also overlap with the WCAG standards many sites must meet.

15.1 Colour Contrast

Text must stand out clearly from its background. WCAG asks for a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text. Light grey on white may look elegant but fails this test for many readers. Check your colours (the browser's inspector and many free tools show the ratio) before you choose them, and re-check both your light and dark variable sets from section 10.

15.2 Keep a Visible Focus Indicator

When someone moves through a page with the Tab key, the browser shows an outline on the current link or button. A common and harmful mistake is to remove it for looks:

/* Never do this: it strips keyboard navigation cues. */
:focus { outline: none; }

If the default outline does not fit your design, replace it with a clear one of your own, do not delete it:

:focus-visible {
  outline: 3px solid var(--brand-color);
  outline-offset: 2px;
}

15.3 Respect Reduced Motion

Animations and large transitions can cause discomfort or nausea for some people. Browsers expose this preference, and you should honour it by toning movement down:

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

15.4 Readable Typography and Zoom

Set font sizes and line lengths for comfortable reading, and use relative units (rem, em) rather than fixed pixels so the layout still works when a visitor zooms or raises their default font size. Never disable zoom. A site that survives a 200% zoom without breaking is both more accessible and usually better built.

Back to top

16. SEO and Metadata

CSS does not contain content a search engine reads, but it affects ranking in two real ways: speed and usability. Both feed into Core Web Vitals, the page-experience signals search engines use.

  • Render-blocking CSS delays the first paint. Smaller, combined, minified stylesheets help your Largest Contentful Paint score.
  • Layout shift hurts the Cumulative Layout Shift score. Reserve space for images with aspect-ratio (section 9.3) and avoid styles that make content jump as the page loads.
  • Mobile-friendliness is a ranking factor. Use a responsive layout so the site works on every screen size.
  • Hidden content: do not use CSS to hide text you want indexed, and never hide text purely for search engines, which can be treated as a trick.

In short, well-organised CSS that loads fast and lays out cleanly on every device quietly helps your SEO; bloated, render-blocking CSS quietly hurts it.

Back to top

17. Common Mistakes and Pitfalls

17.1 Editing Core or Compiled CSS

Symptom: your styling disappears after a Joomla or template update.

Fix: never edit the template's compiled CSS or core files. Put your CSS in user.css or a child template, which survive updates.

17.2 Overusing !important

Symptom: styles only work with !important, and later you cannot override your own rules.

Fix: load your CSS last and use simple selectors so source order wins, or organise rules with cascade layers. Reserve !important for genuine, rare exceptions.

17.3 Fighting Specificity by Hand

Symptom: a style refuses to apply even though it looks correct.

Fix: open the element in the browser's developer tools (section 13) and read which rule wins and why. A more specific selector or an inline style is usually overriding yours.

17.4 Inline Styles in Articles

Symptom: one article looks different and ignores your stylesheet changes.

Fix: remove style="..." attributes from content and move the design into your CSS, where it is reusable and easy to update.

17.5 Shipping a Second Framework

Symptom: pages are slow and two CSS frameworks load with clashing styles.

Fix: use the Bootstrap 5 that already ships with Joomla instead of adding another framework, and remove extensions that bundle their own.

17.6 Removing the Focus Outline

Symptom: keyboard users cannot tell which link or button they are on.

Fix: never set outline: none without a replacement. Provide a clear :focus-visible style instead (section 15.2).

17.7 Forgetting to Clear the Cache

Symptom: you change the CSS but the site still shows the old look.

Fix: clear Joomla's cache and your browser cache. Joomla also adds a version to asset URLs, so bumping the media version forces browsers to reload changed files.

Back to top

18. Best Practices

If you remember only a few things from this article, remember these:

  • Never edit core or compiled CSS; add your styles in user.css or a child template.
  • Use the Web Asset Manager (useStyle, registerAndUseStyle) for any stylesheet you load from code.
  • Load your CSS last so simple selectors win on source order, and avoid the !important habit; reach for cascade layers when order alone is not enough.
  • Re-theme with CSS variables (Cassiopeia's and Bootstrap's) instead of copying and editing rules, and add dark mode by switching those variables.
  • Use the bundled Bootstrap 5 grid and utilities, and reach for native Flexbox, Grid, and container queries for fine-grained layout.
  • Reach for SCSS only for large themes; plain CSS, variables, and native nesting cover most needs.
  • Use a template override when you need a clean class to target, not as a substitute for CSS.
  • Keep CSS small, combined, minified, and compressed so it does not block the first paint.
  • Build for accessibility: enough colour contrast, a visible focus style, respect for reduced motion, and relative units that survive zoom.
  • Debug with the browser's developer tools, clear the cache after a change, and measure speed instead of guessing.
  • Verify browser compatibility for modern CSS features using Can I Use before deploying changes to production.
Back to top

19. Quick Reference

WHAT IT IS     CSS decides how Joomla's HTML looks (colour, spacing, layout)
CASCADE        importance > specificity > source order decides the winner
LAYERS         @layer name { ... }  later layer wins, regardless of specificity
DEFAULT TPL    Cassiopeia (front end), Atum (administrator)
FRAMEWORK      Bootstrap 5 bundled in media/vendor/bootstrap/
TEMPLATE CSS   media/templates/site/cassiopeia/css/  (scss/ holds the source)
COLOUR PRESET  Template Options → Colour  (colors_standard, colors_alternative)
CUSTOM CSS     media/templates/site/cassiopeia/css/user.css  (loads last)
UPDATE-SAFE    Use a child template for serious, lasting custom CSS
ADD FROM CODE  $wa = $doc->getWebAssetManager(); $wa->useStyle('name');
REGISTER+USE   $wa->registerAndUseStyle('name', 'path.css', [], [], ['fontawesome'])
ASSET FILE     joomla.asset.json  (name, type:style, uri, dependencies, weight)
VARIABLES      :root { --name: value }  read with  var(--name)
RE-THEME       Set --cassiopeia-color-* or --bs-* in user.css
DARK MODE      @media (prefers-color-scheme: dark) { :root { ... } }
LAYOUT         Flexbox (one axis), Grid (two axes), container queries per element
FLUID SIZE     clamp(min, ideal, max);  aspect-ratio: 16 / 9
SELECTORS      :has() (parent), :is() (groups), :where() (zero specificity)
FUNCTIONS      color-mix(in srgb, var(--brand) 85%, black) for shades
OVERRIDE       templates/yourtpl/html/com_xxx/...  to add a class to target
A11Y           contrast 4.5:1; keep :focus-visible; respect reduced motion
DEBUG          F12 / Inspect: Styles, Computed, box model, grid + flex tools
BUILT FILES    *.css source, *.min.css production, *.min.css.gz pre-compressed
PERFORMANCE    Combine, minify, compress, load less; CSS is render-blocking
NO CORE HACKS  user.css, child template, override, or plugin - never core
Back to top

20. Summary

CSS is the layer of Joomla that decides how everything looks. PHP builds the page and JavaScript makes it interactive; CSS turns it into a designed, usable website. Joomla 6 takes a modern, standards-based approach to it:

  • A clear cascade: importance, specificity, and source order decide which style wins, with cascade layers and nesting as modern helpers, and Joomla loads your custom file last so you rarely need !important.
  • The Web Asset Manager: the correct way to add stylesheets, with named assets and declared dependencies, so nothing loads twice or in the wrong order.
  • Cassiopeia and Atum: template options, colour presets, and a user.css file let you restyle a site with little or no code, and child templates make those changes update-safe.
  • SCSS, CSS variables, and modern layout: a build pipeline for large themes, native variables for fast theming and dark mode, and Flexbox, Grid, and container queries for layout.
  • Fast and accessible: combine, minify, and compress CSS so pages paint quickly, and respect contrast, focus, and motion so the site works for everyone.

Most CSS problems on a Joomla site are not deep design challenges. They are styles added in the wrong place and lost on update, an !important war that no one can untangle, a second framework slowing every page, or a colour hard-coded in twenty files instead of one variable. Each one is quick to fix once you know where Joomla expects custom CSS to live and how the cascade decides the winner.

If your site looks slightly off after an update, fights you every time you change a colour, loads slowly because of heavy stylesheets, or fails an accessibility check, the cause and the cure usually sit in how the CSS is organised and loaded. That is exactly the kind of Joomla template and front-end work I help with, so a site stays good-looking, fast, accessible, and easy to maintain for years.

Back to top
CSS for Joomla
Peter Martin
Peter Martin
Joomla Specialist

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.

Frequently Asked Questions

What is CSS in Joomla?

CSS (Cascading Style Sheets) controls the visual appearance of a Joomla website, including colors, fonts, spacing, layouts, and responsive behavior. In Joomla, CSS is typically loaded by the active template, but extensions and custom code can also add their own styles. Understanding how Joomla loads CSS helps you customize your website without breaking updates.

Where should I add custom CSS in Joomla?

The best place to add custom CSS is in your template's custom CSS file or through a template override, depending on your template. Avoid editing the core Joomla or template CSS files directly, as your changes will be lost during updates. Using custom CSS keeps your website maintainable and upgrade-safe.

How do I override CSS in Joomla?

You can override CSS by creating more specific selectors, loading a custom stylesheet after the original CSS, or using template overrides when appropriate. Browser developer tools make it easy to identify which CSS rules are applied and which selectors you need to override.

Why is my CSS not working in Joomla?

CSS may not work because another stylesheet has higher specificity, your custom stylesheet loads before the original CSS, browser caching is serving an old version, or CSS and JavaScript optimization is combining or minifying files. Inspecting the page with your browser's developer tools usually reveals the cause.

How can I make my Joomla website responsive with CSS?

Responsive CSS uses flexible layouts, relative units, and media queries so your Joomla website adapts to desktops, tablets, and smartphones. Modern Joomla templates already include responsive frameworks, but custom CSS can further optimize the user experience across different screen sizes.

What are CSS best practices for Joomla?

The best CSS practices for Joomla include

  • using custom CSS instead of editing core files
  • keeping selectors simple and maintainable
  • minimizing unused CSS
  • organizing styles logically
  • using browser developer tools for debugging
  • and testing changes on multiple devices.

Following these practices improves website performance, simplifies maintenance, and ensures compatibility with future Joomla updates.

How can I check if a CSS feature is supported by browsers?

Before using modern CSS features, it's a good idea to check whether they're supported by the browsers your visitors use. The website Can I Use provides up-to-date compatibility tables for CSS properties, HTML features, and JavaScript APIs across Chrome, Firefox, Safari, Edge, and many other browsers. Checking browser support helps you avoid unexpected layout issues and choose appropriate fallbacks when needed. You can check browser compatibility at https://caniuse.com/.