Using Custom CSS with Mastodon
Mastodon has an option for applying custom CSS from within its administration panel. Unfortunately, I couldn’t find any examples of what this CSS should look like, even after asking in the Mastodon Fourms. I did discover how tricky modifying Mastodon CSS can be. I couldn’t figure out why changes to the body
element wouldn’t affect anything, and was informed that Mastodon draws to a component with the .ui
class. Through some careful work with the Firefox development tools, I was able to figure out which CSS selectors controlled what, and have tried to build a list for getting started with creating themes in Mastodon via a custom style sheet.
Here’s a table of all the important CSS selectors I adjusted for my custom theme. There are three main layouts in Mastodon: The Landing Page (for non-logged in users), the User Interface (when logged in) and the Profile Page (public page for a user). Few of the CSS classes are shared across pages.
CSS Selector | Element it Styles | Page |
---|---|---|
.ui | Primary content box for logged in user | UI |
.search__input | Search Input Box | UI |
.search-results | Search Results Box | UI |
.search-results__header | Header for Search Results | UI |
.search-results__section h5 | Section Titles for Search Results | UI |
.account__section-headline | Bar under profile with Toots / Replies / Media | UI |
.status-link | Links within statuses | UI |
.account__header > div | Area for tinting User Profiles | UI |
.account__header .account__header__fields dt | User profile keys | UI |
.account__header .account__header__fields dd | User profile values | UI |
.status__content | Text content within individual status | UI |
.reply-indicator__content | Text for reply indication content | UI |
.column | Individual column (opacity useful for transparency) | UI / Landing |
.column-header | Header for Column | UI |
.column-header__button | Settings/Hamburger Button on Columns | UI |
.column-back-button | Back Button / Timeline heading on Landing | UI / Landing |
.hero-widget__text | Can’t Remember | UI |
.drawer__inner | Top half of the composition column | UI |
.drawer__inner__mastodon | Bottom region with Mastodon logo | UI |
.drawer__inner__mastodon img | Mastodon Send logo image | UI |
.drawer__header | Top Left Control Box | UI |
article | Element for most statuses | UI |
.status-public | Background for public statues (default theme colors public/private the same) | UI |
.status.status-direct:not(.read) | Unread direct messages | UI |
.column > .scrollable | Bar under profile with Toots / Follows / Followers | UI |
.column-link | Links in Getting Started Menu | UI |
.column-link:hover | Hover in Getting Started Menu | UI |
.column-subheading | Getting Started Menu Section Headings | UI |
.column-header__back-button | Local timeline Back Button | UI |
.status-reply | Statuses that are Replies | UI |
.detailed-status | Focused Status Opened in Side Column | UI |
.detailed-status__action-bar | Reply / Boost / Star Bar under Detailed Status | UI |
.getting-started | Getting Started Box | UI |
.landing-page | Primary content box for main site | Landing Page |
.landing-page__information | Center/Lower Info Boxes | Landing Page |
.landing-page__forms | Login/Register Box | Landing Page |
.landing-page__call-to-action | User/Status count box | Landing Page |
.public-layout | Primary content box for profiles | Profile Page |
.activity-stream .entry | Background for statuses on public profile | Profile Page |
.public-layout .public-account-bio | Box under User Profile fields | Profile Page |
.public-layout .header | Header above profile | Profile Page |
.public-layout .footer | Footer below toots | Profile Page |
.public-account-bio .account__header__fields dt | User profile keys | Profile Page |
.public-account-bio .account__header__fields dd | User profile values | Profile Page |
This list may not be exhaustive, as I discovered some of these selectors while finding gaps in my theme. Different color patterns may require additional selectors, but this should still be a good start.
Logos
The easiest way to customize the Mastodon logo under the composition box is to set the display
value of the img
tag to none
and then add in a custom logo as a background image. Setting the background-size
to cover
will allow the image to shrink and expand like the original logo.
.drawer__inner__mastodon { background-image: url("https://example.com/images/logo.png"); background-size: contain; background-color: #0f2a54; opacity: 0.95; } .drawer__inner__mastodon img { display: none; }
Light Themes
I briefly started down the path of a light theme, but then decided on a darker pallet. For a light theme, the text color for most elements needed to be changed from white to black with something like the following:
.ui p, .landing-page p, .public-layout p { color: black !important; } .status__content, .reply-indicator__content { color: black; }
Public Profile Margins
For some reason, the public page layout is pushed down 10 pixels from the top. If you add a custom background image, you do get a black bar. There is no element above the top box, except the html
tag itself, so trying to fix this would affect the two other layouts. I found it easier to just adjust the margins for the .public-layout
element and square off the radii for headers and footers.
.public-layout { margin-top: -10px; } .public-layout .header { background-color: #243d63; border-top-left-radius: 0px; border-top-right-radius: 0px; } .public-layout .footer { background-color: #243d63; padding: 15px; border-top-left-radius: 10px; border-top-right-radius: 10px; }
These modifications are only necessary if using a background image, and can be avoided by using just a background color.
Account Profile
Viewing a user’s profile is another oddity when it comes to themeing. For the background photo in a user’s profile to have the correct color theme, you must apply a style to .account__header > div
and you must use the rgba()
notation as background-color
will colorize the entire bounding region including the account header fields. The final value is the opacity which affects the tint applied to the background image of the profile you are viewing.
.account__header > div { background: rgba(27, 42, 69, 0.9); }
Designing Your Theme
The background should be set against all three page types. This can be split up if you want different background types for the different parts of the site, but if you want something uniform, your code will look like the following:
.ui, .landing-page, .public-layout { background-image: url("https://cdn.example.com/images/background.jpg"); background-size: cover; background-repeat: no-repeat; background-position: center; }
Many of the classes listed in the table above will have a simple background color or a text color. It’s best to pick a color pallet first and then assign elements in groups to those colors, like so:
.account__header .account__header__fields dd, .public-account-bio .account__header__fields dd, .drawer__inner, .drawer__inner__mastodon { background-color: #0f2a54; }
Sapphire Ocean Theme
Here is the Sapphire Ocean v1.0 theme I created for my personal instance, Hitchhiker.Social. The CSS code is public domain, and the background image is available under the Creative Commons BY-NC-SA license. Please copy and host the background yourself if you wish to use this theme. You can easily store the background in Mastodon permanently by keeping it in a pinned toot.
Screenshots
Color Pallet
Source Code
.search__input { background-color: #343f51; } .search-results { background-color: #182a3c; } .landing-page__forms, .public-layout .header, .public-layout .footer { background-color:#243d63; } .landing-page__call-to-action, .detailed-status { background-color:#213759; } .public-layout { margin-top: -10px; } .public-layout .header { border-top-left-radius: 0px; border-top-right-radius: 0px; } .public-layout .footer { padding: 15px; border-top-left-radius: 10px; border-top-right-radius: 10px; } .ui, .landing-page, .public-layout { background-image: url("https://example.org/background.jpg"); background-size: cover; background-repeat: no-repeat; background-position: center; } .account__section-headline, .column-header__back-button { background-color: #1b2a45 !important; } .status-link { color: #73a9d1 !important; } .account__header > div { background: rgba(27, 42, 69, 0.9); } .account__header .account__header__fields dt, .public-account-bio .account__header__fields dt, .column-header, .column-header__button, .column-back-button, .hero-widget__text, .status.status-direct:not(.read) { background-color: #08152b; } .account__header .account__header__fields dd, .public-account-bio .account__header__fields dd, .drawer__inner, .drawer__inner__mastodon { background-color: #0f2a54; } .column { background-color: transparent; opacity: 0.95; } article, .status-public, .activity-stream .entry, .column > .scrollable, .drawer__header, .landing-page__information { background-color: #0b1d3a; } .column-link { color:#8ba9c7; background-color:#1e2a3e; } .column-link:hover { background-color: #21314b; } .status-reply { background-color: #071a3a; } .detailed-status__action-bar { background-color:#1c2d49; } .getting-started, .public-layout .public-account-bio { background-color: #002b55; } .column-subheading, .search-results__header, .search-results__section h5 { background-color: #002549; color: #7398bc; } .drawer__inner, .drawer__inner__mastodon { opacity: 0.95; } .drawer__inner__mastodon { background-image: url("https://example.org/logo.png"); background-size: contain; } .drawer__inner__mastodon img { display: none; }
Final Thoughts
I’ve found it’s easiest to deploy Mastodon using the official Docker containers released by the Mastodon developers. Many of the customization tutorials I’ve found involve building custom containers from those base images and injecting the needed assets. The Custom CSS option that’s now available in the administration console seems to be a much cleaner option than modifying the base application. It’s powerful tool for creating a custom look and feel for Mastodon. I hope this tutorial provides a decent starting point for those seeking to customize Mastodon instances they administer. I’m sure there are ways to simplify the number of classes needing to be themed, and look forward to seeing what other themes people come up with.