# mCSS: full reference
> mCSS is a modern CSS framework and component library for websites: real CSS, real markup, zero build step, built on native cascade layers. It is not a dependency; you copy the files into your project and own them. This file concatenates every docs and components page. A per-page index is at /llms.txt.
# Browser Support
> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/browser-support
**mCSS targets [Baseline](https://web.dev/baseline) 2024**.
It uses cascade layers (`@layer`), nesting, `:has()`, and other modern CSS features natively, with no polyfills. In practice that means the versions of Chrome, Edge, Firefox, and Safari that shipped late 2024 and after:
| Browser | Version |
| -------------- | ------- |
| Chrome | 130+ |
| Edge | 130+ |
| Firefox | 132+ |
| Safari (+ iOS) | 18.2+ |
If you install mCSS with the [PostCSS option](/docs/installation#option-3-compiled-via-postcss), it is possible to modify mCSS browser support via the `.browserslistrc` file. Using a different target, `postcss-preset-env` will start polyfilling the newer features. But it's not recommended: it will create file bloat and it's not foolproof. Some features can break in the process. (See [this blog post](/blog/postcss-setup-for-mcss) for details on what can break when changing the default browser support.)
---
# Components
> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/components
Components in a mCSS project come in two kinds:
- **Built-in components**: a [library of ready-made components](/components/start) built on top of mCSS. Like the rest of the framework, you copy the pieces you want into your project and own the code. It ships separately (`mcss.components.css`), so skip it entirely if you don't need it.
- **Your own components**: mCSS is designed for building your own, one `component.*.css` file per block, in your own CSS folder. The [class syntax](/docs/start#mcss-classes-syntax) and [component conventions](/docs/start#components) from Getting Started are all you need.
The two kinds mix freely: this very site's pages are built from library components, site components, and the occasional page override.
## Marketing template
A complete marketing one-pager built with mCSS and its built-in Astro components: no site CSS, no custom components, no JavaScript beyond what the components ship with.
**[Open the live template](/templates/marketing)**, and use the switcher in its bottom corner to swap between the default theme and the [wireframe theme](/docs/default-theme#full-themes).
The page uses the [base layout scaffold](/docs/layout#layouts) and the following components, from top to bottom:
- [Banner](/components/banner)
- [Header](/components/header) (sticky, with mobile menu)
- [Hero](/components/hero) (full variant on a gradient)
- [Section](/components/section) with a [feature grid](/components/featuregrid) ([Tiles](/components/tiles) + FeatureItems), a filled Section of [Testimonials](/components/testimonial) on the grid
- [Pricing](/components/pricing)
- [FAQ](/components/faq) with exclusive-open items
- Closing-CTA [Section](/components/section)
- [Footer](/components/footer)
### Using it
Copy [`marketing.astro`][srcTemplate] into your own `src/pages/` (as `index.astro`, most likely) and definitely swap the copy ;) Everything it needs is listed below. If you copied the whole framework and component library per [Getting started](/docs/start), you should be good to go.
Two blocks in the file exist for the docs demo and are safe to remove:
- The theme switcher at the bottom (marked with a comment) is just for the demo.
- The inline `@layer` statement at the top of `
` sets the cascade-layer order before any stylesheet loads. It's needed when a theme is loaded as a separate ``, which we do here to power the theme switcher.
| What | Files |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The page | `src/pages/templates/marketing.astro` ([source][srcTemplate]) |
| Astro components | `Banner`, `Header`, `Hero`, `Section`, `Tiles`, `FeatureItem`, `Testimonial`, `Avatar` (used by Testimonial), `PricingCard`, `Faq`, `FaqItem`, `Footer` ([source][srcComponents]) |
| mCSS | The framework entries `mcss.css`, `mcss.components.css`, and `theme.default.css` cover every style used ([source][srcFramework]) |
| Icons | `menu`, `x`, `check`, `circle-check`, `moon-star`, `external-link`, `rotate-ccw`, `mail`, `heart` ([source][srcIcons]) |
| Scripts | `src/scripts/utilities.js` (the Header's scroll throttle) ([source][srcScripts]) |
[srcTemplate]: https://github.com/minimaldesign/mCSS/blob/main/src/pages/templates/marketing.astro
[srcComponents]: https://github.com/minimaldesign/mCSS/tree/main/src/components
[srcFramework]: https://github.com/minimaldesign/mCSS/tree/main/src/styles/framework
[srcIcons]: https://github.com/minimaldesign/mCSS/tree/main/src/assets/icons
[srcScripts]: https://github.com/minimaldesign/mCSS/blob/main/src/scripts/utilities.js
### Useful recipes
Even if you don't use the whole page, three patterns in it are useful to know:
- **The closing CTA** is not a component; it is a `Section` with `variant="primary"` and a `.section_actions` row (see the [Section recipes](/components/section)).
- **The pricing row** is three [PricingCards](/components/pricing) on the plain [grid](/docs/layout#grid) (`col="1" col-md="3"`), with `highlighted` on the recommended tier.
- **Exclusive-open FAQ** items share a `name`, so the browser closes one when another opens. Native ``, no JavaScript.
---
# Default HTML
> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/default-html
The mCSS reset is kept to a minimum. It does the following:
- It sets the `box-sizing` to `border-box`
- It removes the default `margin` on all elements
- It sets the document's `min-height` to 100%.
The rest of the defaults that would traditionally be included in a "reset" or "normalize" file are handled by the `elements.*.css` files. Refer to the [mCSS File structure][structure] section of _Getting Started_ for more details.
You can find an example of all HTML elements default styling in the sections [below](#sectioning).
[structure]: /docs/start#mcss-file-structure
[src]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/base.reset.css
## Sectioning
[srcSectioning]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/elements.sectioning.css
Technically, `address` and `h1`–`h6` are [content sectioning elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element#content_sectioning), like `header`, `section`, etc. But mCSS approach is to prioritize intuitiveness and ease of use rather than technical correctness, so they're included here with the rest of the text elements.
## Text
[srcText]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/elements.text.css
### Headings
Heading sizes are fluid via `clamp()` set on `--heading-font-size-h1`—`--heading-font-size-h6` tokens: each interpolates from a minimum size (at 480px viewports and below) to a maximum (from 1024px up), so the type scale tightens on small screens without media queries. The preferred value mixes `rem` with `vw`, which keeps browser text zoom working. The tokens live in `theme.default.ui.css` with the rest of the heading family (`--heading-spacing-*`, `--heading-line-height-*`), mapping each level onto the [type scale](/docs/default-theme#font-size); override any of them in your theme to change how a heading level scales.
A small paragraph of text to show the heading in context.
Heading Two
A small paragraph of text to show the heading in context.
Heading Three
A small paragraph of text to show the heading in context.
Heading Four
A small paragraph of text to show the heading in context.
Heading Five
A small paragraph of text to show the heading in context.
Heading Six
A small paragraph of text to show the heading in context.
Consecutive headings get less margin… H1 followed by a H2
H2 right after a H1
H3 right after a H2
H4 right after a H3
### Inline Elements
| Element | Example |
| ---------- | ---------------------------------------------------------------------------- |
| `` | This is a text link. |
| `` | Abbreviation: HTML in a sentence. |
| `` | The b element is only stylistically different text from normal text. |
| `` | This is a citation. |
| `` | This text is deleted |
| `` | The dfn element indicates a definition. |
| `` | This text has added emphasis. |
| `` | The i element is text that is offset from the normal text. |
| `` | This text is inserted. |
| `` | The mark element indicates a highlight. |
| `` | This is a short inline quotation. |
| `` | This text has a strikethrough. |
| `` | This small text is small for fine print, etc. |
| `` | Strong is used to indicate strong importance. |
| `` | Subscript for things like H2O. |
| `` | Superscript™️. |
| `` | The variable element, such as x = y. |
### Paragraphs
A paragraph (from the Greek paragraphos, “to write beside” or “written beside”) is a self-contained unit of a discourse in writing dealing with a particular point or idea. A paragraph consists of one or more sentences.
Though not required by the syntax of any language, paragraphs are usually an expected part of formal writing, used to organize longer prose.
### Definition list
Definition List description term
This is a definition list description details
Another description
With the related description details
### Ordered List
1. List Item
1. List Item
1. List Item
1. List Item
1. List Item
1. List Item
1. List Item
1. List Item
1. List Item
1. List Item
### Unordered List
- List Item
- List Item
- List Item
- List Item
- List Item
- List Item
- List Item
- List Item
- List Item
- List Item
### Blockquotes
It would be going too far to call our modern offices sensory-deprivation chambers, but they are most certainly sensory-reduction chambers. They may not brainwash, but the elimination of sensory stimuli definitely increases focus on the task at hand, the work to be done, to the exclusion of all else. Modern offices were designed for that very purpose by people who knew what they were doing.
—Jerry Mander, Four arguments for the elimination of television
### Horizontal Rule
The object of life is not to be on the side of the majority, but to escape finding oneself in the ranks of the insane.
You have power over your mind — not outside events. Realize this, and you will find strength.
### code
Keyboard input: Cmd
Inline code: <div>code</div>
Sample output: This is sample output from a computer program.
### Pre-formatted text
P R E F O R M A T T E D T E X T !
" # $ % & ' ( ) * + , - . / 0 1 2
3 4 5 6 7 8 9 : ; < = > ? @ A B C
D E F G H I J K L M N O P Q R S T
U V W X Y Z [ \ ] ^ _ ` a b c d e
f g h i j k l m n o p q r s t u v
w x y z ~
## Form
| File name | Source |
| -------------------- | ---------------- |
| `elements.form.css` | [Github][srcForm] |
[srcForm]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/elements.form.css
See [How to structure a web form](https://developer.mozilla.org/en-US/docs/Learn/Forms/How_to_structure_a_web_form) on MDN.
This is just the bare minimum default styles to make any form look consistent out of the box. See the [field component](/components/field) for more.
The `legend` HTML element is notoriously impractical to style. The example below uses the following workaround:
```html
Example of a fieldset legend
```
```css
fieldset {
> [aria-hidden] {
/* [styling goes her…] */
}
}
legend {
/* Visually hidden */
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
clip-path: inset(50%);
width: 1px;
height: 1px;
white-space: nowrap;
}
```
### Meter
```html
2 out of 10
5 out of 10
8 out of 10
```
2 out of 10
5 out of 10
8 out of 10
### Progress
## Media
| File name | Source |
| -------------------- | ------------------ |
| `elements.media.css` | [Github][srcMedia] |
[srcMedia]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/elements.media.css
Plain `` element
`` element with `` element
`` element with `` and `` elements
Here is a caption for this image.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum, odio! Odio natus ullam ad quaerat, eaque necessitatibus, aliquid distinctio similique voluptatibus dicta consequuntur animi. Quaerat facilis quidem unde eos! Ipsa.
### Dialog
---
# Default Theme
> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/default-theme
| File name | Description | Source |
| -------------------------- | ------------------------------------------- | ---------------------- |
| `theme.default.css` | Default theme entry: imports the next two | [Github][srcDefault] |
| `theme.default.tokens.css` | Raw tokens: colors, type, spacing, etc. | [Github][src] |
| `theme.default.ui.css` | UI tokens: what elements and components use | [Github][srcUi] |
| `theme.starter.css` | Use it as a start for your own theme | [Github][srcStarter] |
| `theme.wireframe.css` | Full swappable theme example | [Github][srcWireframe] |
[srcDefault]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/theme.default.css
[src]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/theme.default.tokens.css
[srcUi]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/theme.default.ui.css
[srcStarter]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/theme.starter.css
[srcWireframe]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/theme.wireframe.css
Every design value in mCSS (colors, fonts, spacing, component styling) lives in the **default theme**. Your own theme should be imported after it and just override what it needs.
**Never edit the default theme files.** Keep your design decisions in your own theme, so updating the framework is easy.
## Activating a theme
Activate the default theme right after the framework, then (optionally) your own theme:
```css
@import url(./framework/mcss.css);
@import url(./framework/mcss.components.css); /* optional */
@import url(./framework/theme.default.css);
@import url(./site/theme.starter.css); /* your theme */
```
Theme files are **self-layered** and your theme goes in the `theme.user` layer:
```css
/* theme.starter.css */
@layer theme.user {
/* […] */
}
```
mCSS is set up so that, regardless of how you load your theme (`@import`, ``, or bundler), it always overrides the default theme.
## Writing your own theme
Copy [`theme.starter.css`][srcStarter] and start overriding:
- **Tokens first.** Most themes never need a selector: raw tokens for the palette and type, UI tokens for general UI changes, and component tokens for details.
- **Style rules only for what tokens can't express**: pseudo-elements, `nth-child` rhythm, font smoothing, `text-wrap`, etc. Your theme file is the one place where overriding framework classes and HTML elements from other files is ok.
- **Check tokens before writing a style rule.** The page is already painted from `--body-background-color`, `--text-color`, and `--text`: set those instead of writing a `body` rule for background, color, or font.
- **No `!important`.** It will break the layer system. And if you need `!important`, it's a sign you're doing something wrong.
## Full themes
A theme can also be a complete, distributable style. mCSS ships with the [`theme.wireframe.css`][srcWireframe] example. (Flip the switcher on the [marketing template](/templates/marketing) to see it live.)
A full theme is an entry that imports the default theme itself and overrides on top, so you activate it INSTEAD of the default:
```css
@import url(./framework/mcss.css);
/* theme.default.css is swapped */
@import url(./framework/theme.wireframe.css);
```
The wireframe file is a good read if you're planning a full theme. Token overrides do most of the work (grayscale palette, handwriting font stack, "paper cutout" shadows), a few style rules cover the rest (wavy underlines, tilted cards), and it's deliberate about what it leaves alone: the focus ring stays crisp, and text stays high-contrast.
## Tokens
Tokens are CSS custom properties, split in two files:
- **Raw tokens** are named for what they **are**: raw values like colors, type sizes, spacing, radii, etc.
- **UI tokens** are named for what they're **for**: they map raw tokens to elements and components.
Because components read `var(--ui-border-color)` instead of a raw hex value, one override can have three levels of blast radius:
```css
@layer theme.user {
:root {
/* Whole palette shifts */
--base-950: #1a1208;
/* Every bordered surface at once */
--ui-border-color: light-dark(var(--base-300), var(--base-600));
/* Single component override */
--bt-border-radius: 0;
}
}
```
That's why small theme files can go far with a handful of token overrides.
## How to use tokens
When you start a new project, put your design's raw token values in your own theme: your `base` and `primary` colors, your font stacks, and whatever else your design calls for. The defaults are sensible and things like spacing might not need to change.
Then continue overriding UI tokens provided by mCSS as you go, and creating your own when needed. Do not add hard-coded "magic numbers" anywhere else but in your theme's tokens.
## UI tokens
UI tokens are named for what they're for: semantic aliases (`--ui-border-color`), element defaults (`--heading-font`, `--input-padding`, etc.), and every component's defaults (`--badge-color`, `--card-spacing`, etc.).
A UI token usually takes another token for value: a UI token when the meaning is shared (`--input-border-color` is `--ui-border-color`), or a raw token when the value should stay in sync with the rest of the design (`--fieldset-padding` is `--sm3`). Hard-coded values are for the few places where that sync would be wrong: content (separator strings, icon URLs), geometry tuned to one control (`--toggle-width`), and element-relative `em` measures.
For your own components, there's no hard and fast rule about which kind of token to use. If the same style comes up in several places with the same meaning, a new UI token is probably the best option.
## Raw tokens
### Color
Check out [tints.dev](https://www.tints.dev) if you want to make your own palettes programmatically.
### Aspect ratio
| Token | Value | Demo |
| --------------- | ------- | ------------------------------------------ |
| `ar-square` | 1 | |
| `ar-landscape` | 4/3 | |
| `ar-portrait` | 3/4 | |
| `ar-widescreen` | 16/9 | |
| `ar-golden` | 1.618/1 | |
### Typography
#### Font stack
There are 3 font stacks set up by default for the `font-family` CSS property.
| Token | Value |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text` | ui-sans-serif, system-ui, sans-serif |
| `display` | Avenir, Montserrat, Corbel, URW Gothic, source-sans-pro, ui-sans-serif, sans-serif |
| `mono` | Dank Mono, Inconsolata, Fira Mono, SF Mono, Monaco, Droid Sans Mono, Source Code Pro, Cascadia Code, Menlo, Consolas, DejaVu Sans Mono, ui-monospace, monospace |
These stacks are optimized for fonts available on device, to maximize for speed and alleviate any layout shifts or flashes. You can find more stacks at [Modern Font Stacks](https://modernfontstacks.com).
If you'd like to bring in your own fonts or [Google fonts](https://fonts.google.com), you can override the `display` and `text` tokens inside your theme file.
In case you're curious, `ui-sans-serif` is the system's sans-serif UI font,
`system-ui` is the system's UI font whether serif or sans-serif, and
`sans-serif` is the browser default.
#### Font size
Check out [typescale.com](https://typescale.com) if you need help creating your own sizes.
The heading font sizes (`--heading-font-size-h1`…`-h6`) build on this scale but are [UI tokens](#ui-tokens); they're documented with [the headings themselves](/docs/default-html#headings).
#### Font weight
| Token | Value | Demo |
| ------------- | ----- | ---------------------------------------------------- |
| `extra-light` | 200 |
### Drop Shadow
It wouldn't be super useful to list the values here. You can look at them [on Github][githubShadows] if you're curious.
[githubShadows]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/theme.default.tokens.css#L217
### Opacity
| Token | Value | Demo |
| ----- | ----- | ---------------------------------------- |
| `o-0` | 0 | Opacity level 0 |
| `o-1` | 0.2 | Opacity level 1 |
| `o-2` | 0.4 | Opacity level 2 |
| `o-3` | 0.6 | Opacity level 3 |
| `o-4` | 0.8 | Opacity level 4 |
| `o-5` | 1 | Opacity level 5 |
### Z-index
| Token | Value |
| ---------- | ----------- |
| `z-bottom` | -1000000000 |
| `z-0` | 0 |
| `z-1` | 10 |
| `z-2` | 20 |
| `z-3` | 30 |
| `z-4` | 40 |
| `z-5` | 50 |
| `z-top` | 1000000000 |
### Transition
| Token | Value |
| ----------------- | ----------------- |
| `transition` | 220ms ease-in-out |
| `transition-fast` | 100ms ease-in-out |
---
# Installation
> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/installation
## Installation options
### Option 1: easy install
Link the [framework file][dist-min] in your `` and optionally the [components styles][dist-components-min] if you want to use mCSS components:
```html
```
(Unminified versions ([framework][dist-css], [components][dist-components]) are available if you want to read the code.)
### Option 2: individual files
The sweet spot between ease of use and customization options: everything is pre-processed, so there is no build step and no PostCSS. But you can pick and choose which file to include depending on what you need.
Every framework and component file is available pre-processed in [`dist/css/`][dist-dir] with the `@import` index at [`dist/css/mcss.css`][dist-index]. The files are not minified so you can read and understand them. (For the smallest size possible, see the third install option.)
```html
```
Add/remove/comment out files in `mcss.css` according to what you need ([more info][mcss-layers]) and override the default styles with your own [theme][themes]. **Don't delete the `@layer` statement.**
```css
/* css/mcss.css */
@layer base, elements, global, components, theme.default, theme.user, external, helpers;
@import url(./base.reset.css) layer(base);
/* […] */
@import url(./theme.default.css);
@import url(./theme.starter.css); /* your theme */
/* […] */
@import url(./help.typography.css) layer(helpers);
```
### Option 3: compiled via PostCSS
If you want the most flexibility and full customization, this is the option for you.
#### PostCSS setup
You'll need three things to get PostCSS working (more details in [this blog article][postcss-post] if needed):
#### `postcss-preset-env`
Install [postcss-preset-env][presetEnv] as a dev dependency.
```shell
npm install -D postcss postcss-preset-env
```
#### `postcss.config.cjs`
Add this `postcss.config.cjs` at the root of your project.
```cjs
// postcss.config.cjs
const postcssPresetEnv = require("postcss-preset-env");
const config = {
plugins: [
// Uncomment if you use mixins (needs `npm install -D postcss-mixins`)
// require("postcss-mixins"),
postcssPresetEnv({
stage: 2,
features: {
"cascade-layers": false,
"random-function": false,
},
}),
],
};
module.exports = config;
```
#### `.browserslistrc`
A [`.browserslistrc`][browserslistrc], at the repo's root. It sets the [compile floor](/docs/browser-support) so preset-env resolves `@custom-media` and leaves other modern features alone.
```ini
# .browserslistrc
baseline 2024
```
If you already use Astro, Vite, Next, or any other bundler, that's it! Otherwise you'll need `postcss-cli` and `postcss-import` to run the build yourself (details in [blog article][postcss-post]).
#### mCSS setup
Once PostCSS is set up, copy [`src/styles/framework/`][framework-src] in your CSS folder. Next to it, add a folder for your own CSS. Finally, add a global import CSS file.
A bare minimum setup will look like this:
```css
/* global.css */
@import url(./framework/mcss.css);
@import url(./framework/theme.default.css);
@import url(./site/theme.starter.css);
```
A more common full featured setup:
```css
/* global.css */
@import url(./framework/mcss.css);
@import url(./framework/mcss.components.css);
@import url(./framework/theme.default.css);
@import url(./site/global.layout.css);
@import url(./site/component.customComponent.css);
/* etc. */
@import url(./site/page.home.css);
/* etc. */
@import url(./site/theme.starter.css);
```
[browserslistrc]: https://github.com/minimaldesign/mCSS/blob/main/.browserslistrc
[components]: /components/start
[dist-components-min]: https://github.com/minimaldesign/mCSS/blob/main/dist/mcss.components.min.css
[dist-components]: https://github.com/minimaldesign/mCSS/blob/main/dist/mcss.components.css
[dist-css]: https://github.com/minimaldesign/mCSS/blob/main/dist/mcss.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
[dist-min]: https://github.com/minimaldesign/mCSS/blob/main/dist/mcss.min.css
[framework-src]: https://github.com/minimaldesign/mCSS/tree/main/src/styles/framework
[mcss-layers]: /docs/start#the-layers
[postcss-post]: /blog/postcss-setup-for-mcss
[presetEnv]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-preset-env
[themes]: /docs/default-theme
---
# Layout
> Part of mCSS (mcss.dev). Rendered page: https://mcss.dev/docs/layout
Everything you need to lay out a page: a [grid](#grid), a content [wrapper](#wrap), full-page [layout scaffolds](#layouts), and the [media queries](#media-queries) they respond to.
## Grid
[srcGrid]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/global.grid.css
A lightweight, flexible grid system. It uses the [CSS grid property](https://developer.mozilla.org/en-US/docs/Web/CSS/grid) under the hood, but you set up your layouts directly in your HTML. (The implementation is heavily inspired by [Raster](https://github.com/rsms/raster).)
### Syntax
It's composed of 2 classes: `.grid` for the container, and `.grid_item` for each grid item.
The default grid gap is defined as a custom property in [`theme.default.ui.css`](/docs/default-theme#ui-tokens) and is responsive: `16px` (`--sm1`) on small screens, stepping up to `24px` (`--sm3`) at the `--md` breakpoint (768px). You can override `--grid-column-gap` and `--grid-row-gap` globally in your own theme, or on a specific `.grid` element. A `grid-flush` modifier is available if you don't want any gap.
Because `.grid` reads its gaps from those two custom properties, overriding a specific grid is just a matter of setting them on the element. Add a class of your own:
```css
.photoWall {
--grid-column-gap: var(--xs2);
--grid-row-gap: var(--xs2);
}
```
```html
...
```
You define the number of columns of your grid with a custom `col` attribute and the position/width of your grid items with the custom `span` attribute.
The `span` property syntax follows these 5 patterns:
- `row`: the grid_item spans a full row.
- `3`: the grid_item starts in the next column and spans 3 columns.
- `3-5`: the grid_item starts in column 3 and ends in column 5.
- `3+5`: the grid_item starts in column 3 and spans 5 columns.
- `3..`: the grid_item starts in column 3 and spans the remainder of the row.
Both the `col` and `span` attributes have responsive versions, which use [the "mobile first" approach][1] of the `--*-n-above` media queries. The available tiers are **`-md`, `-lg`, and `-xl`** (`col-md`, `span-lg`, etc.); other suffixes like `col-sm` or `col-xxl` don't exist and are silently ignored. Grids support up to 24 columns. (The file is generated by `src/tools/generate.global.grid.cjs`; add a tier there if you need one.)
[1]: /docs/layout#recommended-responsive-setup
The custom attribute will not validate. If this is important to you, you'll
need to change the attributes to `data-col` and `data-span` in both the CSS
and HTML. I personally prefer to use shorter, more legible attributes. Check
this thread on Github if you'd like to read more than you've ever wanted to
know about [custom attributes and
validation](https://github.com/whatwg/html/issues/2271).
### Examples
#### Different types of spans
9 column grid, with all types of spans.
2
4-5
6..
2-3
5..
2+3
6+2
row
4+2
```html
2
4-5
6..
2-3
5..
2+3
6+2
row
4+2
```
#### Responsive grid
The grid layout follows a "mobile first" approach using `--*-n-above` media queries.
The following example goes from 1 → 4 → 9 → 12 columns. (Resize window to see it in action.)
[srcWrap]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/global.wrap.css
The `.wrap` global class is a simple content wrapper: it centers your content on the page and adds some left/right padding on small viewports.
The content column comes in three width presets, set with a modifier on the wrapper: `.wrap-sm`, `.wrap-md`, and `.wrap-lg`. A bare `.wrap` uses the `md` width (`minmax(0, 70ch)`). There is also a `.wrap_content-fullBleed` modifier for children that should extend to the full size of the viewport. See [demo](/demos/wrap).
### Syntax
```html
```
### Settings
Three responsive paddings and the content widths, set in `theme.default.ui.css`. Override them in your [theme](/docs/default-theme).
[srcLayout]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/global.layout.css
Page-level scaffolds: the skeleton between your `body` tag and your content. Every variant extends the same `.layout` base, an app shell with a header, a stretching content area, and a sticky footer.
### Syntax
```html
…
…
```
The header and footer are optional: a bare `.layout` with only `.layout_content` still gives you a full-height page (that's what `.layout-cover` relies on).
### The layouts
Each thumbnail links to a full-page demo built from labeled color blocks. Resize the demo window to see the breakpoints, sticky footer, and full-viewport behavior.
| Class | What it's for |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `.layout` | The base class: header / content / footer with a sticky footer. Required by every variant, usable alone. |
| `.layout-centered` | A single centered reading column (articles, blog posts, legal pages). Width capped at `--layout-content-width`. |
| `.layout-sidebar` | Aside + main from the `--md` breakpoint, single column below it (aside follows source order). |
| `.layout-sidebar-end` | Compose with `.layout-sidebar` to move the aside to the opposite side. |
| `.layout-docs` | Documentation: nav aside + main + TOC aside (`.layout_content_aside-toc`). One column below `--md` with the asides hidden, nav + main from `--md`, TOC from `--lg`. |
| `.layout-split` | Two equal full-height panes (the direct children of `.layout_content`), stacked below `--md`. Auth screens, image + content landings. |
| `.layout-cover` | Full-viewport (`100dvh`) cover with content centered both ways. Landing, 404, coming-soon pages. |
`.layout-docs` hides both asides below the `--md` breakpoint. That's
deliberate: docs navigation belongs in your header menu on small screens
(that's how mcss.dev does it). So make sure everything in your asides is also
reachable somewhere else, like the header menu. If it isn't, use
`.layout-sidebar` instead: on small screens it keeps the aside on the page,
stacked on top of the main content, instead of hiding it.
### Container queries
Every layout main column (`.layout_content_main`) is a named [size container](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries) (`container: main / inline-size`). You can use it in your container queries:
```css
@container main (width >= …);
```
### Settings
Column widths come from three tokens in `theme.default.ui.css`. `--layout-toc-width` accepts any grid track size; the `1fr` default lets the TOC resize to whatever space the main column doesn't use.
Override them globally in your [theme](/docs/default-theme), or per-layout with a scoped rule. This very site uses `.layout-docs` and layers its own specifics on top ([source][srcSiteLayout]): a wider `77ch` reading column and sticky side navs.
[srcSiteLayout]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/site/global.layout.css
## Prose
[srcProse]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/global.prose.css
The global `.prose` class can be used anywhere you need basic typography for long form text, like articles, blog posts, etc.
It makes spacing between paragraphs, lists, tables, etc. consistent. This spacing can be modified in your [theme](/docs/default-theme) via the `--prose-spacing` token.
The `.prose` class also adds extra styling for `ol`, `ul`, and `code` elements.
## Accessibility
[srcA11y]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/global.a11y.css
Accessibility specific styles, used across the framework and the [components](/components/start):
- **`:focus-visible`**: a unified keyboard focus ring on everything. Customizable in your theme via the `--focus-ring-color`, `--focus-ring-width`, and `--focus-ring-offset` tokens.
- **`.a11y-skipLink`**: skip-to-content link. It stays off-screen until focused.
- **`.a11y-srOnly`**: hides the element visually, but keeps it accessible to screen readers.
Place the skip link first in your ``, pointing at the id of your main content:
```html
Skip to content……
```
## Animation
[srcAnimation]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/global.animation.css
Basic fade in/out animations with flexible start/end opacity values. Each keyframe only pins one end of the fade; the other end is the element's own `opacity`:
| Keyframes | What it does |
| --------------------- | ------------------------------------- |
| `fadeFromTransparent` | fades from 0 to the element's opacity |
| `fadeFromOpaque` | fades from 1 to the element's opacity |
| `fadeToTransparent` | fades from the element's opacity to 0 |
| `fadeToOpaque` | fades from the element's opacity to 1 |
```css
.element {
opacity: 0.8;
animation: fadeToTransparent 1s forwards;
}
```
(More info about [forwards](/blog/css-animation-fill-modes).)
## Media queries
| File name | Source |
| ---------------------------- | ------------- |
| `settings.media-queries.css` | [Github][src] |
[src]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/settings.media-queries.css
All the breakpoints, user preferences, and device capabilities, as named [custom media queries][custom] you can use anywhere in your CSS.
[Custom media queries][custom] are not yet available without a [PostCSS
plugin][postcss]. If you can't or don't want to add a build step to your
process, you'll have to hard-code your breakpoints. (You can still use nesting
as in the example below though.)
### Viewport size
#### Dimensions
#### Variations
Using the `md` dimension as an example:
| Token variation | Matches |
| --------------- | ---------------------------- |
| `--md-only` | exact range |
| `--md-n-above` | range top and above |
| `--md` | shorthand for `--md-n-above` |
| `--md-n-below` | range top and below |
| `--md-phone` | exact range in portrait only |
The `-phone` variant is available from `xxs` through `lg` (there is no `xl-phone` or `xxl-phone`).
#### Recommended responsive setup
If you search online for the best approach to responsive design and setting up your breakpoints, you'll come across the technically true but useless "it depends" answer.
Unless you have a good reason not to, you should use a mobile-first approach. What that means is your design works great on small screens out of the box, without any media queries, and then you add your tweaks for larger sizes.
This is how the CSS of most responsive components should be set up:
```css
.exampleComponent {
/* default mobile */
@media (--lg) {
/* responsive tweaks for desktop */
}
}
```
Without [PostCSS plugins][postcss]:
```css
.exampleComponent {
/* default mobile */
@media (width >= 1024px) {
/* responsive tweaks for desktop */
}
}
```
### User preferences
These map to the `prefers-*` and related media features, so you can respect user settings without memorizing the syntax:
#### Example
These are used like any other custom media query, and they can be combined with each other or with a dimension token:
```css
.exampleComponent {
@media (--landscape) and (--touch) {
/* a phone or tablet held sideways */
}
}
```
Without [PostCSS plugins][postcss], the same thing spelled out:
```css
.exampleComponent {
@media (orientation: landscape) and ((hover: none) and (pointer: coarse)) {
/* a phone or tablet held sideways */
}
}
```
[custom]: https://drafts.csswg.org/mediaqueries-5/#custom-mq
[postcss]: https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-custom-media
---
# 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, have a look at the [source code][src] to see how it all comes together, and look at [Installation](/docs/installation) to choose the best option for your project.
## mCSS file structure
### Two folders
**[`framework/`][framework-src]**: 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/`][site-src]**: your own CSS. These files do not use CSS [layers][layers] so **understanding and using [ITCSS][1] methodology there is key**. (The [mCSS own][site-src] `/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][1]. Files are organized in [layers][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][3] wars and cascading conflicts.
While ITCSS used specificity for its layers, mCSS upgrades that with native [CSS cascade layers][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][helpers] which use `!important` to override everything, by design.
Here are all the mCSS layers, from lowest to highest priority:
Have a look at [`framework/mcss.css`][mcss-entry] 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`][4] 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
```css
/* 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. */
```
[cascade-layers]: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer
[mcss-entry]: https://github.com/minimaldesign/mCSS/blob/main/src/styles/framework/mcss.css
## Detailed description of all files
### Settings
Two `settings.*` files sit outside the `@layer` stack: they're only used at build time.
- [Media queries][6] include responsive sizes, as well as user preferences like color schemes, reduced motion, etc. See [media queries docs][6].
- **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][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 included 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. mCSS is designed to let you to create your own components, but a [collection of components][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 `` is the whole badge, and the `.bt` class can style a `