CodyHouse Framework + Components are featured on Product Hunt! Join the discussion →

Projects

Progress value is 30%

Framework

The CodyHouse's Framework is a lightweight front-end framework for building accessible, bespoke interfaces.

Some of the advantages of working with this framework:

  • ⚡️ lightweight (8KB minified and gzipped)
  • 🙌 no need to override existing CSS rules
  • 📱 mobile-first
  • 🎨 create unique designs with total control
  • 📖 easy to learn

Download the Framework on Github

or install the framework in your Node.js powered apps with the npm package:

npm i codyhouse-framework

If you want to take the framework for a spin, or follow along one of our tutorials, feel free to fork this pen:

🕹 codepen.io/codyhouse/pen/Wqvpmm


🔍 On this page:

  1. Getting started
  2. Files included
  3. Supported browsers
  4. Progressive enhancement
  5. CSS Custom Properties

Getting started #

The framework includes a Gulp file with some basic configurations needed to run a web project based on the framework. For detailed info on how the Framework Gulp file works, please refer to our article on the topic.

To start a web project using this Gulp configuration file, navigate to the framework folder and run the following commands:

npm install
npm run gulp watch

The first command will install the modules the framework requires for compiling SCSS into CSS; the second will launch your project on a development server.

Files included #

The framework is composed of:

  1. _base.scss: essential CSS rules and utility classes (We suggest you don't modify these files).
  2. _custom-style.scss: a CSS template to create your bespoke style (e.g., buttons, forms, and colors).
  3. style.scss: used to import the _base.scss and _custom-style.scss files. It compiles into two separate CSS files: style.css and style-fallback.css. The first one includes the CSS custom properties; in the second one the CSS custom properties are replaced by their fallbacks (generated using a PostCSS plugin). A script in the <head> of the index.html file checks CSS variables support and delivers only one CSS file.
  4. util.js: the utility functions used in the CodyHouse Components. Make sure to import this file before the component script file.
codyhouse-framework/
└── main/
    ├── assets/
    │   ├── css/
    │   │   ├── base/
    │   │   │   ├── _accessibility.scss
    │   │   │   ├── _breakpoints.scss
    │   │   │   ├── _buttons.scss
    │   │   │   ├── _colors.scss
    │   │   │   ├── _forms.scss
    │   │   │   ├── _grid-layout.scss
    │   │   │   ├── _icons.scss
    │   │   │   ├── _mixins.scss
    │   │   │   ├── _reset.scss
    │   │   │   ├── _shared-styles.scss
    │   │   │   ├── _spacing.scss
    │   │   │   ├── _typography.scss
    │   │   │   ├── _util.scss
    │   │   │   ├── _visibility.scss
    │   │   │   └── _z-index.scss
    │   │   │── custom-style/
    │   │   │   ├── _buttons.scss
    │   │   │   ├── _colors.scss
    │   │   │   ├── _forms.scss
    │   │   │   ├── _shared-styles.scss
    │   │   │   ├── _spacing.scss
    │   │   │   └── _typography.scss
    │   │   ├── _base.scss
    │   │   ├── _custom-style.scss
    │   │   ├── style-fallback.css
    │   │   ├── style.css
    │   │   └── style.scss
    │   └── js/
    │       └── util.js
    └── index.html

Supported browsers #

The Framework supports the latest, stable releases of all major browsers. On Windows, we support IE 9+ / Microsoft Edge.

Progressive enhancement #

The Framework and the Components are built following the principle of progressive enhancement. Please make sure to include the following script in the <head> of your document:

<script>document.getElementsByTagName("html")[0].className += " js";</script>

The script is used in CSS to target that JavaScript is enabled and apply additional style accordingly. If you don't include the script, part of the style of the components won't be visible.

Besides checking JavaScript support, we check the support of CSS custom properties. If the browser supports them, the style.css file is downloaded. Otherwise, the browser downloads the style-fallback.css file, where the CSS variables are replaced by their fallbacks (generated using a PostCSS plugin). More info in the CSS Custom Properties chapter on this page.

<script>
  if('CSS' in window && CSS.supports('color', 'var(--color-var)')) {
    document.write('<link rel="stylesheet" href="assets/css/style.css">');
  } else {
    document.write('<link rel="stylesheet" href="assets/css/style-fallback.css">');
  }
</script>
<noscript>
  <link rel="stylesheet" href="assets/css/style-fallback.css">
</noscript>

CSS Custom Properties #

We use CSS variables as opposed to SASS variables because there are cases where we update the variables at specific breakpoints (e.g., to make typography responsive), or to power-up our adaptive color themes. For more information about the advantages of using CSS custom properties, please check our 'Why we prefer CSS Custom Properties to SASS variables' article on the topic.

To provide a fallback for browsers that don't support CSS custom properties, we use a modified version of the postcss-css-variables gulp plugin. When you use a CSS variable in your SCSS, the plugin generates a copy of the property replacing the variable with its value (the fallback).

For example, if in your SCSS you write this:

.max-width-lg {
    max-width: var(--max-width-lg);
}

In your CSS file you have:

.max-width-lg {
    max-width: 80rem;
    max-width: var(--max-width-lg);
}

⚠️ The Gulp configuration file is set to compile the SCSS file into two separate CSS files: style.css includes the CSS custom properties; in the style-fallback.css file, the CSS variables are replaced by their fallbacks (generated by the PostCSS plugin). The script in the <head> of the index.html file is used to deliver only one file, according to whether the browser supports CSS variables or not.

There are some limitations though when working with CSS Variables in combo with this plugin: in some cases (listed below), the plugin can't provide a fallback (or it may throw an undefined value). It's important to be aware of these limitations, to avoid potential issues in your code.

Case 1: Local scope

If you define a CSS variable within a selector and then update it in one of its child elements, the plugin generates proper fallbacks.

SCSS:

.text-component {
    --text-vspace-multiplier: 1;

    hr {
        --text-vspace-multiplier: 2;
        margin: calc(var(--space-lg) * var(--text-vspace-multiplier)) auto;
    }
}

CSS generated:

.text-component {
    --text-vspace-multiplier: 1;
  }

.text-component hr {
    --text-vspace-multiplier: 2;
    margin: calc(2em * 2) auto;
    margin: calc(var(--space-lg) * var(--text-vspace-multiplier)) auto;
}

However, if you create a class modifier and update the variable in the modifier, the plugin does not generate a fallback for the children of the modifier, unless their properties are defined in the modifier too.

For example, if we consider this code:

.text-component {
    --component-body-line-height: calc(var(--body-line-height) * var(--line-height-multiplier));
    --component-heading-line-height: calc(var(--heading-line-height) * var(--line-height-multiplier));
    --line-height-multiplier: 1;

    h1, h2, h3, h4 {
        line-height: var(--component-heading-line-height);
    }

    p, blockquote, ul li, ol li {
        line-height: var(--component-body-line-height);
    }
}

.article.text-component { 
    --line-height-multiplier: 1.13;
}

In this case, in browsers that support CSS Variables the children of .article inherit the new variable value of the modifier, while in old browsers you won't see changes. This approach makes sense if the modifiers are "enhancements" (e.g. a color theme that does not convey a meaning other than aesthetic embellishment).

Important: if you create a scoped variable, you should use it within the scope (selector) where it's defined.

Case 2: Global scope

If you update a global variable at a specific breakpoint, the plugin generates a proper fallback, but that means that it creates a media query for each property where the variable has been used, which could result in a lot of unexpected CSS code. One way around this issue is targeting the <body> element and not the :root.

:root, body {
    --foo: 1em;
}

@include breakpoint(md) {
    body {
        --foo: 2em;
    }
}

By doing so, the plugin won't generate media queries for all the elements where the variable has been used, thus limiting the variable update to the browsers that natively support CSS Variables (where the new value is propagated anyway). Once again, this approach makes sense as long as the variable updates can be considered "progressive enhancements".

Case 3: skip the fallback using @support

If you don't want the plugin to generate a fallback, you have the option to wrap your code using the @supports(--css: variables) rule.

:root {
  --text-base-size: 1em;
  --text-scale-ratio: 1.2;

}

@supports(--css: variables) {
  :root {
    @include breakpoint(md) {
      --text-base-size: 1.25em;
      --text-scale-ratio: 1.25;
    }
  }
}

A good example is our typography system, or our system for generating color themes, where we define the default theme in the global scope, while the new themes include the @supports(--css: variables) feature query.

In doing so, the themes are visible only in browsers that support CSS Variables, and the plugin does not generate any fallback. If you let the plugin run through a theme, the fallback generated is not correct, and it could result in issues in older browsers.

The takeaway being: use the @supports(--css: variables) if you want to prevent the plugin from generating a fallback because the changes you made won't compromise the user experience in older browsers.

Get started with Accessibility 👉

✅ Project duplicated

✅ Project created

There was an error while trying to export your project. Please try again or contact us