Cassiopeia, Joomla’s powerful built-in template: how to modify the header with css grid
With Joomla's built-in powerhouse template, also known as Cassiopeia, you can do so much more than you’d think. In this tutorial we’ll create a slim and stylish header with just CSS!
Most parts of Cassiopeia’s header are modules, so let's start by looking at the structure. You can check the module positions by switching the setting for showing the module positions to “yes” in the template options (System -> Website Template -> Options in the top right corner) and typing “tp=1” behind the address of the url.
Header structure in Cassiopeia
Topbar and below-top are module positions, where you can insert whatever content you want. Often they are used to show the contact details (address, email, phone number) of a company or other (mostly) one-line information.
Brand is used to display the logo, title (as alternative to logo) and tagline as defined in the template configuration.
Menu and search are again module positions optimized to contain the menu and the search field.
The image below shows the simplified html structure of the header:
Depending on the use of all those elements the header can take up a lot of space and users often ask if it is possible to get the logo and the navigation in the same line. The answer is of course: yes!
Modifying the header
I have tried several ways to modify the header, sometimes with weird outcomes if all positions are used. In this short tutorial I will create a css grid like the one in use for the main part of the website and order the different elements of the header inside the grid. At the end our header will look like this:
And in mobile devices:
We create a custom module with the address of the company for the position topbar and another one with the support time for the position below-top.
The main menu is in the position menu, the search module in the position search and in the configuration of the template we have selected our logo. Then our header looks like this:
The CSS code
.container-header {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: "top below"
"logo logo"
"nav nav";
}
.container-header .container-topbar {
padding: .5em;
}
.container-header .container-topbar {
grid-area: top;
}
.container-header .container-below-top {
grid-area: below;
justify-content: flex-end;
}
.container-header .grid-child:has(.navbar-brand) {
grid-area: logo;
}
.container-header .container-nav {
grid-area: nav;
}
@media (width >= 991.98px) {
.container-header {
grid-template-columns:
[full-start] minmax(0,1fr)
[main-start] repeat(4,minmax(0,19.875rem))
[main-end] minmax(0,1fr)[full-end];
grid-template-areas: ". logo nav nav nav .";
gap: 0 1rem;
}
.container-header:has(.container-below-top, .container-topbar) {
grid-template-areas: ". top top below below ."
". logo nav nav nav .";
}
}
If you're not using a user.css file yet, create one to make sure your css code doesn't get removed upon updating the site.
We start defining the grid for the container-header with display: grid. We set two columns for the grid and give names for the different areas, so it is easier to place the elements later. The container-topbar goes in the area “top” (that is the first column in the first row of our grid), the container-below-top is placed in the area “below” (second column, first row). The logo (.container-header .grid-child:has(.navbar-brand)) gets the area “logo” that spans two columns in the second row of the grid. Finally the menu and the search (there are together inside the container-nav) are placed in the area “nav” that spans two columns in the third row of the grid.
Probably you are thinking: what the heck is .container-header .grid-child:has(.navbar-brand)? As you can see in the simplified html code above, the container that holds the logo only has a generic class, “grid-child” that is also used in other places. So we can’t modify this class without side effects. Fortunately, since 2023 we have the css pseudo-class :has() that allows us to select a parent element using one of its childs. Translated this line means: please select the element with the class “grid-child” that contains an element with the class “navbar-brand”.
In the next block of code we override the definition for viewports wider than 991.98px (below this point we have the mobile version of the menu). In bigger displays we need more columns in our grid, six in total:
grid-template-columns:
[full-start] minmax(0,1fr)
[main-start] repeat(4,minmax(0,19.875rem))
[main-end] minmax(0,1fr)[full-end];
Grids can have named grid lines (normally they are only numbered), similar to grid areas; this makes it easier to place elements in the grid. Our grid lines are named full-start, main-start, main-end and full-end. For this tutorial the named lines are not important, but this grid definition is also used in the main content of a Cassiopeia site and the lines are used to place the content and the sidebar(s) and to create full-width containers. The first and the last column are placeholders, so our elements are centered in the header and aligned with the content of the page. In between we create four equal columns.
Now we need a new definition of the grid areas. If we don’t use topbar and below-top then we will place our logo, menu and search like this:
grid-template-areas: ". logo nav nav nav .";
The dots are our place holders / empty columns, the logo takes a column and the menu/search spans three columns.
If topbar and/or below-top are present we will place them above the logo and menu and each of them will span two columns:
grid-template-areas: ". top top below below ." ". logo nav nav nav .";
In your browser you can get a visualization of the grid using the inspector and clicking the grid symbol. The following image shows the browser inspector from Firefox:
In displays under 992px the grid looks like this:
And in bigger viewports like this:
Using modern CSS it is possible to change a lot of things without re-writing the html code of a template.
Resources
- The :has() pseudo-class: https://developer.mozilla.org/en-US/docs/Web/CSS/:has
- CSS Grid Areas: https://ishadeed.com/article/css-grid-area/
- Examining grid layouts in Firefox: https://firefox-source-docs.mozilla.org/devtools-user/page_inspector/how_to/examine_grid_layouts/index.html
- Inspect CSS grid layouts in Chrome: https://developer.chrome.com/docs/devtools/css/grid
Some articles published on the Joomla Community Magazine represent the personal opinion or experience of the Author on the specific topic and might not be aligned to the official position of the Joomla Project
By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/
Comments 4
Have a nice day!
Sorry if I'm writing in the wrong place, but I can't find the specific contact details of the cassiopeia developers, I hope you can help.
I have discovered a problem in the cassiopeia template, both in J4 and J5, when the menu module is set to "Collapsible Dropdown", in mobile view, if there is a dropdown menu, I open the hamburger menu and drop down a submenu, then close the hamburger menu, leaving the dropdown submenu open. If I do this for a random amount of time, suddenly something fails and the drop-down buttons simply don't respond to being clicked.
What could cause this?
Is there a solution to this?
Thx
Hi Gulyás, we don't have dedicated developers for Cassiopeia. The place to report bugs is github: https://github.com/joomla/joomla-cms/issues
Hi Viviana,
Oooh, nice example of customization txs to CSS Grid
I have added a link to your present article to my https://slides.wolupracticle example http://ofweb.be/cassiopeia/cassiopeia.html#resources
(which is btw the most visited of all my presentations, so there is interest in Cassiopeia )
Technically, you are now cited 9 times in that presentation
Thank you Marc!