Skip to content

Instantly share code, notes, and snippets.

@maxhoffmann
Last active December 6, 2022 16:56
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save maxhoffmann/df09f8d27edcfdab1eaa1085671eae16 to your computer and use it in GitHub Desktop.
Save maxhoffmann/df09f8d27edcfdab1eaa1085671eae16 to your computer and use it in GitHub Desktop.
Component based CSS Architecture

Component based CSS Architecture

Rules

  1. A component always consists of CSS and HTML (JS is optional)
  2. HTML and JS of a component are located in ComponentName.js
  3. Styles of a component are located in ComponentName.scss
  4. Each CSS class starts with the unique component name
  5. The HTML of each component only uses its own prefixed classes
  6. Components can use other components, but never overwrite their styles

The following problems are solved by this architecture:

Problem: CSS classes are used with a wrong HTML structure

Examples:

  • .link was styled to be used with <a>, but gets used with <button> instead. This was not intended and therefore does not overwrite the default browser styles
  • HTML structure changes, e.g. nesting an element deeper in the DOM since a div was added. Hence :nth-child don’t work anymore

Solution:

  • components are always a combination of HTML and CSS, which work together
  • e.g. React components which render HTML and use CSS classes designed for this specific HTML

Problem: Compiling the CSS properties in your head

Example:

  • a CSS class uses multiple mixins and additionaly overwrites some properties of those mixins
  • developers now have to look at each mixin and remember, which properties it yields in case any of them get overwritten
  • mixins could overwrite each other
  • updating mixins could unintentionally affect other classes
  • a mixin can consist of other mixins
  • this leads to jumping between files and memorising their output
.button {
  @include button;
  @include font-family;
  @include size;
  color: white;
  background: $color-primary;
}

Solution:

  • no or very few mixins
  • all styles are only written for the specific HTML of the component
  • all classes are prefixed with the unique component name
  • locating styles of a component is easy: the class prefix is the file name
  • files contain all styles of a component, since only very few mixins are used. this keeps jumping between files to a minimum

Problem: Consistent updates to visual elements is tedious and error-prone

Example:

A button is used in different places of the app/site and looks different although the same class is used. The reason for this is other elements overwriting styles of the button class.

If the design of visual element is contextual, updating all instances of an element requies finding all places where this element is used and check if its styles are overwritten.

The amount of effort to makes these kind of changes increases with the size of the code base. This is tedious, error-prone and sometimes impossible to figure out if the rendering logic is complex.

Solution:

  • no component is allowed to overwrite styles of another component
  • unique class prefixes are supposed to prevent overwriting styles
  • deviations can be found easily: a class is not prefixed with the filename
  • variations of components are handled by the component itself, e.g. <Button theme=”border”>

Problem: Import order leads to different css output

Example:

Classes in different files overwrite each others’ properties and the order of imports decides which one of them wins.

<div class=”form box”>
// form.scss
.form { border: 0; }

// box.scss
.box { border: 2px solid black; }

// imports.scss
@importform”;
@importbox”;   // <- changing this order leads to different results

Solution:

  • HTML is always a part of a component, therefore the classes would have the same unique prefix
  • all styles of a component live in the same file which is named after the component:
    • .box is defined in Box.scss
    • .form is defined in Form.scss
    • .form__input is defined in Form.scss
  • .form and .box cannot be used on the same HTML element, since they are not part of the same component

Problem: Dead Code Elimination

Example:

How do I know which styles are redundant?

Solution:

  • unused components can be deleted safely
  • they can be found easily:
    • search for usage of the component, e.g. <Name
    • webpack doesn’t compile if a component in use gets removed
  • deleting component styles is safe, since there are no dependencies between components due to using unique class prefixes

Examples

Button with modifier

// Button.scss

.button {
  border: 2px solid black;
}

.button--borderless {
  border: 0;
  background: gray;
}
// Button.js

const Button = ({ theme = '' }) =>
  <button className=`button ${theme === '' ? '' : `button--${theme}`}`>
    {children}
 </button>

Nesting components

// SearchField.js

const SearchField = ({ value }) =>
  <div className='search-field'>
    <input className='search-field__input' type='search' value={value} />
    <Button>Suchen</Button>
  </div>
// SearchField.scss

.search-field {
  // styles
}

.search-field__input {
  // styles
}

Advice on component variations

In this exmaple, if <Button> in <SearchField> should look different, one would add a new variation to <Button> via a property, e.g. <Button theme='small' icon='magnifier'>. Do not overwrite Button styles in SearchField.scss!

If the design of this button differs too much or if these styles are very specific to SearchField, one doesn’t need to use the generic <Button> component. In these cases it’s valid to style the html tag <button> directly, e.g. <button className='search-field__button'> or create a new specifc component if it’s used in multiple places, e.g. <SearchButton>.

@cnaa97
Copy link

cnaa97 commented Aug 27, 2018

I also looking for a way to write stylesheet conveniently like component based architecture. But I'm curious, How to control the browser's basic style like nomalize.css or reset.css.

@Maxvien
Copy link

Maxvien commented Mar 21, 2019

@cnaa97 If you want to code with component-based architecture absolutely, you should think about Web Components. You can get started with Stencil.

I have just coded a tool here https://github.com/Maxvien/psd2html. It lets a component always consists of HTML, CSS and JavaScript. You guys can take a look at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment