Skip to content

Docs :: Getting Started

mCSS is both a CSS framework and a methodology. You need to first understand the methodology to use the framework correctly. There are 3 main parts to the methodology.

  1. The file structure
  2. The CSS syntax
  3. The component architecture

Once you’ve read through the basics below, have a look at the source code to see how it all comes together, and look at Installation to choose the best option for your project.

mCSS file structure

Two folders

framework/: the core files you should not edit yourself:

  • Settings
  • Base
  • HTML elements
  • Global styles
  • Components (optional)
  • Themes (the default theme, plus optional swappable themes)
  • Helpers

site/: your own CSS. These files do not use CSS layers so understanding and using ITCSS methodology there is key. (The mCSS own /site folder is a good reference.)

  • Custom theme
  • Custom layouts
  • Your components
  • Page specific overrides
  • Patches to vendor plugins, packages, etc.

The layers

mCSS is a modern take on ITCSS. Files are organized in layers going from broad and generic (settings → reset → HTML elements) to specific and local (components → helpers). This methodology addresses all the supposed “shortcomings” of CSS such as specificity wars and cascading conflicts.

While ITCSS used specificity for its layers, mCSS upgrades that with native CSS cascade layers priority. Every framework file is imported into a named @layer, and the layer order (not the import order, and not specificity) dictates the priority. By default, anything you write outside the layers (in the /site folder) has higher priority.

The only exception is helpers which use !important to override everything, by design.

Here are all the mCSS layers, from lowest to highest priority:

Layer Files What lives there
base base.* Reset/normalize.
elements elements.* Default styling of bare HTML elements.
global global.* Grid, wrap, layout scaffolds, prose, a11y.
components component.* Self-contained component styles.
theme.default theme.default.* Default theme files.
theme.user theme.* Custom theme override.
external (your imports) Code from plugins, npm packages, etc.
helpers help.* Tailwind style utility classes, but done right.
(unlayered) your own CSS Beats every layer above, except helpers.

Have a look at framework/mcss.css to see how it’s organized. All layers are defined in this file.

Notes:

  • settings.* files conceptually occupy the top position of the ITCSS “inverted pyramid” with lowest specificity, but since they’re only used at build-time, they don’t need their own @layer.
  • The external layer ships empty. This layer is reserved for third-party CSS (npm packages, plugins, etc.). That way you can use @import url(…) layer(external); to import vendor styles and it becomes trivial to override with your own CSS in a patch.* file (like this site’s patch.astro.css).

The global import

The global import (_global.css for this site) is where it all comes together. You import everything used on your site there:

  • The mCSS framework
  • The mCSS components (optional)
  • The default theme
  • Your theme (optional override)
  • Your custom layouts, components, and page overrides
  • Vendor style patches
global.css
@import url(./framework/mcss.css);
/* Optional: the mCSS component library. */
@import url(./framework/mcss.components.css);
/* The default theme. */
@import url(./framework/theme.default.css);
/* Optional: your own theme, overriding the default */
@import url(./site/theme.starter.css);
/* Your own CSS: it wins over every mCSS layer (except helpers) */
@import url(./site/global.layout.css);
@import url(./site/component.header.css);
@import url(./site/page.blog.css);
/* etc. */

Detailed description of all files

Settings

Two settings.* files sit outside the @layer stack: they’re only used at build time.

  • Media queries include responsive sizes, as well as user preferences like color schemes, reduced motion, etc. See media queries docs.
  • Mixins (optional). It is not used in other parts of mCSS by default but can be useful to streamline your own components’ code. It requires a PostCSS plugin to work.

Base

  • Simple reset/normalize.

HTML Elements

The default styling of all HTML elements, without classes.

  • Sectioning: header, footer, etc.
  • Text: a, p, etc.
  • Quotes: adds the correct quotes depending on language.
  • Media: img,video, etc.
  • Table: table, th, etc.
  • Form: input, button, etc.
  • Interactive: dialog, details.

Global

Global styles included out of the box:

  • A responsive grid system.
  • A full feature wrapper.
  • Common global site layouts.
  • Typography, via the .prose class, for long form text, like articles, etc.
  • Accessibility (A11Y) specific classes.
  • Basic @keyframes animations (e.g., fade in/out)

Components

Self-contained styles for single components. mCSS is designed to let you to create your own components, but a collection of components built on top of mCSS is included. It ships separately to keep mCSS nimble as the component library grows.

Note: Some components are CSS-only. A single class on a single element, with no associated HTML. For example, the .badge class on a <span> is the whole badge, and the .bt class can style a <button> or an <a>.

Theme

Every design value in mCSS lives in the default theme (theme.default.css) composed of 2 parts:

  • tokens: Raw design tokens such as dimensions, fonts, colors, etc.
  • UI tokens: abstraction layer that maps raw tokens to semantic tokens, e.g. --ui-border-color, --input-padding, etc.

Use the starter template to make your own theme (feel free to rename it to anything you’d like but it’s recommended to follow the theme.*.css convention). Anything you add to this file will automatically override what’s in the default theme.

Don’t edit the default theme files: keeping your design in your theme makes framework updates easy.

If you want to make a self contained mCSS theme you can distribute, see how theme.wireframe.css is set up. It basically imports the default theme itself, so you can swap the @import in your global import. More details on that in the theme docs.

Helpers

Helpers provide classes for “one-off” local overrides. They’re similar to utility classes from other frameworks, with a critical difference: they’re meant to be used as a last resort and as sparingly as possible. Helper declarations use !important and override everything on that element, including your own CSS. Read the docs for more info on this.

Your CSS

Your own CSS is unlayered, which means:

  • Your CSS has higher priority than mCSS’ (except helpers)
  • Using the ITCSS methodology is critical.

Your site/ CSS is required to be imported in this order:

  • theme.starter.css overrides the default mCSS theme.
  • global.*.css for site-wide additions to the framework’s globals.
  • component.*.css for your own components (most of your CSS should end up here)
  • page.*.css for the rare page-specific styles
  • patch.*.css for patching CSS you don’t control, i.e. plugins

Note: You can also refer to mCSS own /site’s setup as a reference.

Pages

Page files should be used sparingly, for the rare page-specific overrides.

page.blog.css
.blog-index {
--layout-content-width: 100%;
}

Note: page classes should go on the <body> in the HTML, at the same level as the layout scaffold classes (not on <main>):

<body class="layout layout-centered blog blog-index"></body>

mCSS classes syntax

Classes in mCSS are inspired by BEM, but they’re simpler to use and easier to look at.

You can use standard BEM, the even more verbose BEMIT, or any other syntax you’d like. But the mCSS syntax gets you 90% of the same benefits without any drawbacks, even on large projects involving many devs.

Whatever syntax you pick, one rule stands above all of it: never couple classes across components. A selector may only contain classes from its own block, and every override goes through classes you mix onto the markup, component tokens, or the theme. It’s important enough to have its own article, with plenty of examples.

Blocks, elements, and modifiers

BEM mCSS
Block site-search siteSearch
Element site-search__field siteSearch_field
Modifier site-search--full siteSearch-full

States

Here’s how you implement a state in BEM vs. mCSS.

HTML:

<!-- BEM -->
<form class="form">
<input class="form__input" type="text" />
<input class="form__submit form__submit--disabled" type="submit" />
</form>
<!-- mCSS -->
<form class="form">
<input class="form_input" type="text" />
<input class="form_submit is-disabled" type="submit" />
</form>

CSS:

/* BEM */
.form__submit--disabled {
}
/* mCSS */
.form_submit {
&.is-disabled {
}
}

Note: State selectors have higher specificity than modifier classes (.avatar.is-online = 020 vs. .avatar-xl = 010), so always declare custom properties default values inside the main class and use the properties inside the state.

.avatar {
/* Defaults on the main class */
--status-dot-size: 12px;
&.is-online {
/* ❌ not here: it would override .avatar-xl */
/* states just use the properties */
width: var(--status-dot-size);
}
}
.avatar-xl {
/* modifiers override the default */
--status-dot-size: 20px;
}

Components

Targeting HTML elements within a component

When using mCSS syntax within a component, it’s considered overkill to create a class for every single HTML element you need to target.

For example, this is acceptable (and recommended) CSS for the tags component:

.tags {
li {
[…]
}
a {
[…]
&:hover {
[…]
}
}
}

Modifiers and component variations

When using modifiers to create different variations of a component, it’s recommended to use local custom properties if possible instead of overriding the CSS directly. (See the notice component for an implementation example.)

/* Don't do that */
.component {
color: blue;
}
.component-variation {
color: red;
}
/* Do that instead */
.component {
--color: blue;
color: var(--color);
}
.component-variation {
--color: red;
}

One class per file

For example, the component.card.css should only contain:

  • .card and nested HTML elements.
  • .card_* descendants.
  • .card-* modifiers.
  • State classes
  • Nothing else. See this blog article for more details.