# Getting Started

> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/start

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
1. The CSS syntax
1. The component architecture

Once you've read through the basics below, the best way to understand how it all comes together is to have a look at the [source code][src]. (Video tutorial coming soon!)

## mCSS file structure

<section class="docs_section prose">

The file structure is based on [ITCSS][1], but with important differences detailed below. The basic idea is to organize your files in different [layers][layers] so that your CSS [rulesets][2] are organized from global low [specificity][3] to local high specificity. When done right, it takes care of all the common "shortcomings" of CSS such as specificity wars and cascading conflicts.

mCSS implements this with **native [CSS cascade layers][cascade-layers]**: every framework file is imported into a named `@layer`, and the layer order (not the import order, and not specificity) decides who wins. Anything you write *outside* the layers beats the framework by default, so mCSS always gets out of your way. The only exception is [helper classes][helpers], which use `!important` so they can override anything, including your own CSS. Below is an overview of each layer. The full documentation of most layers is available from the sidebar.

This is how mCSS is organized. ([Github source][4].)

```css
@layer settings, base, elements, global, components, theme, helpers;

/* Build-time only (media queries + mixins definitions) */
@import url(./settings.media-queries.css);
@import url(./settings.mixins.css);

@import url(./settings.tokens.css) layer(settings);
@import url(./settings.ui.css) layer(settings);

@import url(./base.reset.css) layer(base);

@import url(./elements.sectioning.css) layer(elements);
@import url(./elements.text.css) layer(elements);
/* etc. */

@import url(./global.grid.css) layer(global);
@import url(./global.wrap.css) layer(global);
/* etc. */

@import url(./component.button.css) layer(components);
@import url(./component.notice.css) layer(components);
/* etc. */

@import url(./help.spacing.css) layer(helpers);
/* etc. */

/* Optional: activate ONE theme, a swappable skin. Theme files are
   self-layered (@layer theme), so no layer() annotation is needed.
   None imported = the default look. */
@import url(./theme.wireframe.css);

/* Your site's own CSS imports UNLAYERED, after the framework.
   Its normal declarations win over every mCSS layer without fighting
   specificity. One exception: helpers are !important and beat
   unlayered CSS too. */
@import url(./site/myComponent.css);
```

[cascade-layers]: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer

The easiest ways to use mCSS in your own project:

- **Drop-in file**: grab [`dist/mcss.css`][dist-css] (or [`dist/mcss.min.css`][dist-min]), the whole framework in one file, no build step needed.
- **Individual files**: every framework file is also available pre-processed in [`dist/css/`][dist-dir] (with [`dist/css/mcss.css`][dist-index] as an `@import` index), so you can copy just the layers you need.
- **Source files**: copy [`src/styles/framework/`][framework-src] if you run PostCSS yourself (the source uses `@custom-media`, which needs [postcss-preset-env][7]).

Run `npm run build:css` in the repo to produce `dist/` from source.

[dist-css]: https://github.com/minimaldesign/mCSS/blob/main/dist/mcss.css
[dist-min]: https://github.com/minimaldesign/mCSS/blob/main/dist/mcss.min.css
[dist-dir]: https://github.com/minimaldesign/mCSS/tree/main/dist/css
[dist-index]: https://github.com/minimaldesign/mCSS/blob/main/dist/css/mcss.css
[framework-src]: https://github.com/minimaldesign/mCSS/tree/main/src/styles/framework

### Settings

Settings are where all custom properties are set.

- [Tokens][5] is where you set default values for sizes, font stacks, colors, transitions, etc. See [the docs][5] for all the values available by default.
- [Interface tokens][interfaceTokens] are an abstraction level to standardize common values across elements and components. For instance, components use `--ui-border-color` instead of the lower level token `--base-200`, so one override restyles every bordered surface.
- [Media queries][6] include responsive sizes, as well as user preferences like color schemes, reduced motion, etc. See [media queries docs][6].
- **Mixins** is 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][7] 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 inlcluded out of the box:

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

### Components

Self-contained styles for single components, one block per file. The mCSS framework is designed to be used on its own, allowing you to create your own components, but a [collection of components][components] built on top of mCSS is included.

Some components are **CSS-only**: a single class on a single element, with no Astro component because there is no markup structure to encapsulate. For example, the `.badge` class on a `<span>` is the whole badge, and the `.bt` class can style a `<button>` or an `<a>` (styling that has to be opt-in, since not all links are buttons). Their docs live in the [components section][components] like everything else, marked "CSS-only".

### Theme

A [theme][themes] is a swappable skin: one `theme.*.css` file of token overrides plus optional skin rules, wrapped in its own `@layer theme` block. mCSS imports no theme by default (the default look IS the empty theme layer); you activate at most one from your own entry point, and swapping that import restyles the whole site.

### Helpers

[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 important declarations inside a layer beat unlayered CSS, so a helper class overrides everything on that element, including your own CSS. Read [the docs][helpers] for more info on this.

### Your CSS (unlayered)

Everything you write outside the mCSS layers (your components, page styles, and any third-party CSS you don't control) simply imports after the framework, unlayered. Unlayered CSS wins over all layered CSS for normal declarations, so you never fight the framework's specificity. The one exception is helper classes: their `!important` declarations win even over unlayered CSS, by design.

## mCSS classes syntax

<section class="docs_section prose">

Classes in mCSS are inspired by [BEM][bem], but they're simpler to use and easier to look at.

You can use standard BEM, the even more verbose [BEMIT][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.

### Blocks, elements, and modifiers

<div class="docs_oversizedTable">

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

</div>

### States

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

HTML:

```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="formInput" type="text" />
  <input class="formSubmit is-disabled" type="submit" />
</form>
```

CSS:

```css
/* BEM */
.form__submit--disabled {
}

/* mCSS */
.formSubmit {
  &.is-disabled {
  }
}
```

**One gotcha to keep in mind:** nesting a state inside its block compiles to a two-class selector (`.formSubmit.is-disabled`), which beats single-class modifiers like `.formSubmit-lg`. That's usually what you want: states describe what's happening *right now*, so they should win. But it means a state block is the wrong place to declare default values for custom properties. Declare defaults on the block itself, let modifiers override them, and only *use* the properties inside the state. Otherwise your size and color modifiers will mysteriously stop working the moment the state class shows up.

```css
.avatar {
  /* ✅ defaults live on the block… */
  --status-dot-size: 12px;

  &.is-online {
    /* ❌ …not here: this would override .avatar-xl's dot size */
    &::after {
      /* ✅ states just consume the properties */
      width: var(--status-dot-size);
    }
  }
}

.avatar-xl {
  /* modifiers can now override the default */
  --status-dot-size: 20px;
}
```

## Components

<section class="docs_section prose">

### Targetting 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 (`component.tags.css`):

```css
.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 propertie if possible instead of overriding the CSS directly.

```css
/* Don't do that */
.component {
  color: blue;
}

.component-variation {
  color: red;
}

/* Do that instead */
.component {
  --color: blue;
  color: var(--color);
}

.component-variation {
  --color: red;
}
```

See the [implementation][github] of the [notice component](/components/notice) for a real life example.

Any questions or feedback? Head over to the [Github discussions][discussions]!

## Browser support

<section class="docs_section prose">

mCSS targets **[Baseline](https://web.dev/baseline) 2024**: it freely uses cascade layers (`@layer`), nesting, `:has()`, `light-dark()`, `@scope`, `text-wrap: balance`, and relative color syntax, all natively, with no polyfills. In practice that means the current versions of Chrome, Edge, Firefox, and Safari, going back roughly two years.

How things degrade in older browsers:

- **Cascade layers, nesting, `:has()`** (2022–2023): load-bearing. Browsers without them are not supported.
- **`light-dark()`** (mid-2024): colors fall back to the light palette.
- **`@scope`** (mid-2024): only affects `.prose` internals; spacing between prose blocks and headings loses one refinement.
- **Scroll-driven animations**: the [ReadProgressBar](/components/readprogressbar) component detects support and falls back to JavaScript automatically.
- **`sibling-index()`, CSS `random()`, SVG displacement filters**: used only by the [wireframe theme](/docs/themes) for per-element sketch variation; without them the theme keeps its fixed hand-drawn look.

The exact compile floor lives in `.browserslistrc` (`defaults and supports css-cascade-layers`).

[1]: /blog/what-is-itcss
[2]: https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax#css_rulesets
[3]: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
[4]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/_global.css
[5]: /docs/tokens
[6]: /docs/media-queries
[7]: https://github.com/postcss/postcss-mixins
[grid]: /docs/global#grid
[wrap]: /docs/global#wrap
[layout]: /docs/global#layouts
[prose]: /docs/global#prose
[a11y]: /docs/global#accessibility
[components]: /components/start
[helpers]: /docs/helpers
[interfaceTokens]: /docs/tokens#interface-tokens
[themes]: /docs/themes
[layers]: /blog/what-is-itcss#the-layers-of-itcss
[bem]: /blog/what-is-bem
[bemit]: https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/
[github]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/component.notice.css
[src]: https://github.com/minimaldesign/mCSS/tree/main/src/styles
[discussions]: https://github.com/minimaldesign/mCSS/discussions
