This is a draft document. There are lots of broken links, notes to myself to add or update things, and probably some bullet points that make no sense to the surrounding content. Welcome to my brain. This is also an , so please reach out to me with comments, questions, and suggestions.

Introduction to the P -M CSS methodology

One constant will always remain true: designs change. Whether it’s the whims of fashion, the needs of users, or the desire for design to just be “new”, change is constant. The P -M methodology understands this, and is based around naming components and elements based on their function and purpose, instead of how they look. See Appendix A for a deeper dive into why purpose instead of appearance is the best solution to future-proof a design system. P -M is also designed to help reduce specificity on base styles to make it easier to override them if needed. The two basic principles are:
  1. Element and component classes are named by their purpose
  2. Variations on the base style are made using modifier classes

Elements and components are named for their purpose.

If a component such as a Radio Button will only ever be a radio button, then there is no need to create an additional class called radio. However, the styles for a <button> are also often assigned to an <a href> link, so in this case it makes sense to create a button class. The button class has all the defaults for every aspect of the button: background color, text color, border radius, border color, drop-shadow. Additional default styles for :hover and :active states are also defined.

Variations on the base style are made using modifiers.

Modifiers start with a - dash. In the case of the button class, the modifiers might be -cta, -primary, -ghost, -link, etc. A CTA button would be button -cta see Appendix B for a comparison between P -M and BEM naming conventions. While modifiers can be local to an element or component, they can also be global. For instance, the design system states that disabled elements are 60% opacity, interactivity is disabled, and the “no” cursor shows when hovered. This can be set globally, with a -disabled modifier (for better coverage, the selector would actually be [disabled], .-disabeled {}). Another possibility for a global modifier would be -primary. For elements such as buttons, checkboxes, radio buttons, and badges, they should all have the same attributes for their primary variation: the background color of the button would be the same as the color for the checkboxes, radio buttons, and badges. And the text color of the button would be the same as the text on the badge, the check in the checkbox, or the border of the radio button. By setting these properties globally, they all carry through to the elements as needed. And because they’re on the global scope, which has a very low specificity, then they are easy to override in the component’s CSS scope. More on scope and overrides in the CSS Cascading Layers section

Document and folder structure

  • colors are defined in their own document
  • metrics, such as spacing and corner radius, are in another document
  • theme is in yet another document
  • components are in individual files in a components directory
I’m using Sass to help with functions and mixins. In the future, these will be able to be handled natively in CSS, but for now a lot of the utilities are still in Sass. The folder structure for the files is as follows:
css/
 | icons/
 |   | (all custom svg icons)
 | studs-styles.css

sass/
 | components/
 |   | (individual component styles)
 | utilities/
 |   | (all utility files)
 | base.scss
 | overrides.scss
 | theme.scss
  1. Icons contains any custom icons that are in addiiton to the icon set we are using. Currently, that is the Material icon set
  2. studs-styles.css is where cascading layers and order is being defined (see CSS Cascading Layers for more details). This file must be outside of the Sass compiler, as Sass interprets the @import rules incorrectly, and changes the order of imports. This is a known bug with the Sass-dart compiler.
  3. Components directory contains individual files for each component, e,g, button.scss, badge.scss, dropdown.scss, etc.
  4. Utilities directory contains the majority of the files that make this system work. colorRamps, fonts, metrics, mixins, and the normalize.css files are here.
  5. base.scss is where all the basic page styles are. Elements that aren’t components and aren’t considered “styled elements” are styled here. e.g. <p>, <em>, <strong>, <abbr>, etc.
  6. overrides.scss is where devs can put any style overrides, extended styles, or addition styles.
  7. themes.scss is where all color tokens are defined and used.

Theming Capabilities

F -M is ready for light and dark themes in addition to other custom themes. For instance, the marketing site might want to have a modified color palette for a spring sale, or perhaps a winter theme for the holidays. Or perhaps each web app is to have a different base color palette corresponding to areas of relevance. Apps related to Fasteners and Supports might be blue, but Outdoor Structures might be a purple color palette. In addition to the base color palette, there are accessibility considerations in each theme for higher contrast color combinations. For instance, if a color combination such as a very pale gray background and a medium gray text would fail WCAG contrast tests, this doesn’t mean it can’t be used in the color system. It just means we also need a higher contrast alternative for when a user has selected “use high contrast themes” in their browser or in their system. When this is the case, the high contrast options will be used instead. If the user has turned off motion and transitions in the system or browser, then all animations in the CSS will be reduced to 0 seconds in length. Tokens are also named by their purpose: surface, action, control, feedback.
  • surface: the basic application properties, such as page background color, text color, border colors, etc.
  • action: elements such as buttons that perform actions
  • control: checkboxes, radio buttons, and sliders are examples of controls
  • feedback: alerts, warnings, success and info elements are all considered feedback
Each type has background, foreground, border, and other tokens relevant to their purpose. For instance --surface-backgroud or --action-selected-foreground In addition to colors, other display properties such as elevation (usually shown with varying levels of drop shadows), corner radius, border thickness, and spacing (used for padding and margins) are also defined.

CSS Cascading Layers

F -M relies heavily on CSS Cascading Layers (see also: MDN docs and Getting Started). Once the loading order has been established, we can load additional styles to any layer without having to worry about css load order. Of course, the cascade order is still important within each layer, but this makes it easier to make sure all base styles are loaded first, before modifying or customizing those styles for a specific application. More importantly, CSS Cascading Layers makes it much easier for end users to override styles without the need for !important. CSS Layers helps return !important to it’s original purpose. The layer loading order is reset, utilities, fonts, themes, base, components, layout, overrides
  • reset: a simple browser reset using normalize.css
  • utilities: includes all the basics such as colors, metrics, tokens, and more
  • fonts: where font faces are defined
  • themes: foundational colors and tokens. see Theming Capabilities for more details
    • everything here is a CSS custom property to make theming and accessibility options easier.
    • tokens are also named by their purpose to make updates easier and more logical.
    • other themes are also possible. For example, an app that needs to follow the basic rules of the design system, but with different colors to match a co-branded partner’s colors (dark blue instead of SST orange). Or perhaps a “spring-sale” or “winter-holiday” themed temporary takeover for the marketing site.
  • base: basic page styles: line height, fonts, and all simple HTML elements that aren’t considered a component, such as <p>,<em>, <h1>, <h2>, <h3> etc.
  • components loads all the individual components styles. The components file is another cascading layer within the main layer. While it shouldn’t be necessary, if needed a new component can be added to the components layer with @layer components.my_new_component{ }.
  • layout will contain some layout helpers and utilities. Currently, these are still being designed, but the plan is to make responsive multi-grid layouts, app shells, and other utilities to help end-users with page layout.
  • overrides is a blank file. This is where the end user can put whatever styles they need to override or extend any of the other styles. Since this layer has been named, devs are also welcome to use their own files, and add them to the overrides using @layer overrides.class-name-to-modify{}
In addition to the overrides file, any styles that come after the styles in the CSS layers will naturally have higher importance and specificity. This makes it trivial for end-users to add any additional styles they need. These will even override any styles in the “overrides” file above, providing additional control levels to the end-user. Be sure to read the article linked above for more information and a much deeper dive into cascading layers, specificity, and levels of importance.

Examples

Tokens are named for their purpose. --action-background, -secondary-foreground, --focus-color, and --disabled are all examples of purpose-based tokens. See Theming Capabilities for more about this, including light and dark themes, as well as app-based overrides.

Simple Component

A good example to start with are buttons because there are so many different styles and functions of a button. But under it all, they are still just a button that’s been styled differently. The pieces of a button’s styles are:
- background color
- foreground color (text or icon)
- border color
- border thickness
- border radius
Because buttons are interactive, we also need to give feedback to the user that the buttons does something when clicked or tapped. Usually, that’s just the background color. But it can also be a change in text color, and often a change to the perceived elevation of the button using drop-shadow.
- :hover background color
- :hover foreground color
- :hover dropshadow

- :active background color
- :active foreground color
- :active dropshadow
We have created global tokens for interactive elements. The ones we’ll be using here are:
--action-default-background
--action-default-foreground

--action-default-hover-background
--action-default-hover-foreground

--action-default-active-background
--action-default-active-foreground--corner-radius-75
To help make the code cleaner and easier to read, and also to fully leverage the power of CSS custom properties, we’ll make some local CSS variables for the buttons. Here’s the basic button code so far.
button,
.button {
  --bg: var(--action-default-background);
  --fg: var(--action-default-foreground);
  --hover-bg: var(--action-default-hover-background);
  --hover-fg: var(--action-default-hover-foreground);
  --active-bg: var(--action-default-active-background);
  --active-fg: var(--action-default-active-foreground);
  --border-color: transparent;
  --shadow: var(--shadow-default)

  background: var(--bg);
  color: var(--fg);
  border: 2px solid var(--border-color);
  border-radius: var(--corner-radius-75);
  box-shadow: var(--shadow);

  transition: var(--tx-m);

  &:hover {
    --bg: var(--hover-bg);
    --fg: var(--hover-fg);
  }

  &:active {
    --bg: var(--active-bg);
    --fg: var(--active-fg);
    --shadow: var(--shadow-sm);
  }
}
notes: We’re using CSS vars for transition speed to make it easier to disable transitions if a user has set “reduce motion” in their OS or browser preferences. See Appendix D for more about accessibility. The above will give us this type of basic button:
@TODO: example image and functioning button
Variations on the above button are: secondary, outline, destructive, ghost, link. Each of those variations are considered a modifier, so the class name for them is -secondary, -outline, -destructive, -ghost, -link. For secondary there aren’t a lot of changes from default, so we just need to add this after the &:active selector.
  &.-secondary {
    --bg: var(--action-secondary-background);
    --fg: var(--action-secondary-foreground);
    --hover-bg: var(--action-secondary-hover-background);
    --hover-fg: var(--action-secondary-hover-foreground);
    --active-bg: var(--action-secondary-active-background);
    --active-fg: var(--action-secondary-active-foreground);
  }
And outline is similar, but with a border.
  &.-outline {
    --bg: var(--action-outline-background);
    --fg: var(--action-outline-foreground);
    --hover-bg: var(--action-outline-hover-background);
    --hover-fg: var(--action-outline-hover-foreground);
    --active-bg: var(--action-outline-active-background);
    --active-fg: var(--action-outline-active-foreground);

    --border-color: var(--action-outline-border);
  }
the link button has a few extra styles.
  &.-link {
    --bg: transparent;
    --fg: var(--action-link-foreground);
    --hover-bg: transparent;
    --hover-fg: var(--action-link-hover-foreground);
    --active-bg: transparent;
    --active-fg: var(--action-link-active-foreground);

    --shadow: none;

    &:hover {
      text-decoration: underline;
      text-decoration-color: var(--fg);
      text-underline-offset: .25em;
      text-decoration-thickness: 2px;
    }

    &:active {
      --shadow: none;
    }
  }
@TODO examples of all buttons
THIS HAS NOT BEEN IMPLEMENTED
As part of the metrics, there are some relative t-shirt sizing which can be applied to most elements.
--sm: 0.75em;
--md: 0.875em;
--lg: 1.25em;
--xl: 2em;

.-sm {--font-size: var(--sm)}
.-md {--font-size: var(--md)}
.-lg {--font-size: var(--lg)}
.-xl {--font-size: var(--xl)}
note Why define both variables and utility classes? consistency. To make sure that medium -md is the same no matter where it’s used, and that a -md class is available when needed.
Because they’re based on the font size of the element, they can be applied as a utility class. So <button class="button -secondary -md"> is all you need to make a slightly smaller button. That being said, utility classes are generally avoided, because they are describing what an element looks like, instead of it’s function or purpose. However, the t-shirt sizing is here as a fallback. In most cases, the sizes would be changed on the component’s style overrides instead of assigning the class. For instance, if this was a button in a table header and it should be slightly smaller than the default, then styles for the button might be
th {
	--font-size: 1em;
	.button {
		--font-size: var(--md)
	}
}
END OF NOT IMPLEMENTED
Currently, STUDS only has a light theme implemented. However, the framework is there to add a dark theme once it’s been fully designed. Right now, we are forcing a light theme even if a user has chosen dark theme in their OS or browser settings.

Complex Component

Here’s a simple example card component:
<div class='card'>
  <header></header>
  <div class='content'></div>
  <footer></footer>
</div>
In this case, card components will be elements on a css grid, and the header, .content, and footer will be subgrid items for a clean layout.
@TODO: selector for card wrapper and card subgrid
For an employee page, we want to use cards for each employee to show their name, title, an avatar of who they are, some details about them, and how to contact them through email and phone. The card component will now have these additions:
<div class='card -employee'>
  <header>
    <img src='' alt='employee name' class='avatar'>
    <h1>Employee Name</h1>
    <h2>Employee Title</h2>
  </header>

  <div class='content'>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
    <p>Odio quasi deleniti repudiandae animi.</p>
  </div>

  <footer>
    <a href='mailto:employee@company.com'>email</a>
    <a href='tel:1234567890'>telephone</a>
  </footer>
</div>
To show managers and team leads, the design calls for an orange border around the header section, so we add another modifier to the card div: <div class='card -employee -lead'>. Since and employee card has only a couple changes or additions to the base card styles, using modifiers makes this easier to code. And then the -lead styles are just a couple overrides that works with the -employee and card selectors. See AppendixB. Why not BEM?* for an example of what BEM-style naming would be for this card component.

Appendix