Skip to content

thoughtbot/roux

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Roux

Scaffold projects efficiently with a base set of CSS variables, default styles, and structure. You may have used Bitters in the past -- move on over to a fully native setup with Roux.

Why Roux?

This project is meant as a guide to build up your own CSS architecture. This isn't a UI library, style guide, or a framework like Tailwind. This is to help you (as a designer, developer, anyone) feel empowered to set up your very own styles successfully.

Take what you need

You can cherry pick styles and pull them into your project, just use it for setup inspiration, or you can use the whole thing.

Installation

Installation is very hands-off:

  • npx github:thoughtbot/roux init
    
    • This will copy all files from src/css into a css folder at the root of your project. Feel free to move or rename depending on your needs, OR
  • Copy and paste from the source code, OR
  • Clone this project: https://github.com/thoughtbot/roux.

To compile

  • npm i
  • npm run build (will output into a dist folder)

This project uses lightning CSS to minify and compile the CSS into one file. There are lots of options for CSS compiliation, depending on your project setup and your own preferences. Use whatever you like to compile all the CSS into one file. If you're using Dart Sass, you'll need to use @use instead of @import in your main app.css file (you'll also need to switch your file types from css to scss).

Compilation is purely to show you what the final file might be. You don't need it to use Roux.

Demo

A WIP demo of the styles in action with HTML lives in Codepen right now.

Using Roux

How do I start?

Roux is a guidance tool so you feel more confident about setting up your own CSS styles. The opinions laid out here are to provide a solid baseline for you to create and riff on your own styling and structure.

Everything is imported into app.css. Which should be compiled into one CSS file with whatever compilation method you choose.

  1. reset/_normalize.css comes first in our imports as that overrides some of our browser defaults. We're working on top of the reset. You can add in any more browser resets into that folder and import it. More on reset

  2. base/_variables.css is one of the outliers of our base files as it stores all of our custom properties. This comes before all of the other base files since it's a dependency. You don't have to change any of these values if you don't want to. However, you'll likely want to at least adjust the colors. More on variables

  3. base/_fonts.css is the other outlier as files like _typography.css may rely on it. It's commented out for now since it needs an actual font file to work and you may want to remove it if importing a font in a different way. More on fonts

  4. The rest of the base files make use of many of the custom properties and are not dependent on each other. They're currently in ABC order. More on base files

  5. The components folder is empty. This is where you'll put your component-based styles (e.g. components/_card.css). Ensure the import list is in ABC order for readability.

  6. Utilities are last! Right now there's only one utility. Add in any other global utilities you might have that can be applied as a class. You can prepend them with .u-[utility-name] and give them their own CSS file. More on utilities

Base

Base styles are meant to be more globally applied in your project. Generally (with a few exceptions like buttons), the styles target HTML elements and not class names.

Animation

Any global animations can go here. Roux's only animation defines smooth scrolling behavior, only if a user hasn't set their motion preference. If a user has reduced motion set on their machine, they should not experience smooth scrolling.

Buttons

Roux uses a classname for a "button" style since it can be applied to both button elements and a elements that want to appear as a button. We've defined a few variants (primary and secondary) to work from. When applying it to an element, use both button and button--{variant}. See the demo codepen for structuring. For example:

<button
  type="button"
  class="button button--primary"
 >
  A primary button
</button>
<a
  href="#"
  class="button button--secondary"
>
  A secondary button link
</a>

Disclosures

Basic styling for the details and summary elements with a custom details marker caret.

Fonts

If you have custom fonts you're using, you'll need to import them in some manner. This is a dependency file since other base files may need it to render a font. Currently it's commented out since it's all based on your font files you want to use, but the structure is there. You may declare multiple font files in here. The example in there shows a variable font file with a range of weights so you don't have to define each individual weight.

Generally, font-display: swap is a solid default for most fonts so you always fallback to the other fonts defined in your stack while your custom font is loading.

When you define a font in this file, you'll want to add it to a custom property with a stack in your _variables.css file. For example:

/* base/_fonts.css */

@font-face {
  font-display: swap;
  font-family: "WorkSans";
  font-style: normal;
  font-weight: 100 900;
  src: url("./fonts/work-sans.woff2") format("woff2");
}

@font-face {
  font-display: swap;
  font-family: "Quincy";
  font-style: normal;
  font-weight: normal;
  src: url("./fonts/quincy.woff2") format("woff2");
}
/* base/_variables.css */

:root {
  --font-family--body: "WorkSans", system-ui, Arial, sans-serif;
  --font-family--display: "Quincy", Times, serif;
}
/* base/_typography.css */

body {
  font-family: var(--font-family--body);
  font-weight: var(--font-weight--normal);
}

h1,
h2,
h3 {
  font-family: var(--font-family--display);
  font-weight: var(--font-weight--bold);
}

Forms

Most form styling relies on how you structure the HTML. In Roux's styling, you should be nesting an input within a label. See the demo codepen for structuring. For example:

<label for="email">
  <span>Your email</span>
  <input
    id="email"
    type="email"
    name="email"
    autocapitalize="off"
    autocorrect="off"
    spellcheck="false"
    required
    autocomplete="email"
    />
</label>
label:has(
    input:not([type]),
    select,
    textarea,
    [type="color"],
    [type="date"],
    [type="datetime"],
    [type="datetime-local"],
    [type="email"]
    /* other selectors */
  ) {
  display: flex;
  flex-direction: column;
  gap: var(--space--x-small);
}

If you prefer to keep those elements separate, you can adjust the CSS in the forms to use the next-sibling combinator (or any other selector of your choice). You'll likely have to make some other declarations or use another element to wrap the label and input.

<label for="email">
  Your email
</label>
<input
  id="email"
  type="email"
  name="email"
  autocapitalize="off"
  autocorrect="off"
  spellcheck="false"
  required
  autocomplete="email"
/>
label + :where(
    input:not([type]),
    select,
    textarea,
    [type="color"],
    [type="date"],
    [type="datetime"],
    [type="datetime-local"],
    [type="email"]
    /* other selectors */
  ) {
  display: flex;
  flex-direction: column;
  gap: var(--space--x-small);
}

Lists

Removes list styling (margin, padding, list style) from ordered and unordered lists if there is a class applied. If no class is applied, ols and uls will take on the default browser style. Oftentimes you may find yourself creating a list of components that are highly styled. Semantically, it might make sense to put them in an ordered or unordered list, but you'd have to remove those default styles -- thus this opinion.

This also includes some typographic and spacing opinions for definition lists.

Media

Defines pictures, videos, etc. as block elements that should size responsively with your container. Uses :where so you can override specific instances later if needed.

Modal

Default setup and some base styles for dialog elements. This includes some transition declarations as well as ::backdrop styling.

The .slide-in class can be added for a smooth slide-from-bottom transition when opening a modal (and a slide out on close). See the codepen demo for setup in HTML and Javascript.

Tables

Rounded border and striped row styling for tables. This also includes classes to make an overflow scroll table for data sets that are wider than the viewport. See the codepen demo for structure.

Typography

A fairly unopinionated typographical setup. This isn't a type scale, but some basic defaults such as ensuring headings are bolded and using a pretty text wrap on h1s. This also leverages the base typographic custom properties in body. You can use the --font-size--[variant] custom properties in _variables.css to be more specific about type size.

Variables

This is where your custom properties live. There's some basic setup for colors, spacing, type size, etc. Go in and edit this for your project's needs. Colors may be the only one you need to edit since the other properties are fairly agnostic.

You can change the primitive colors (e.g. --color--blue-100) to your project colors (and names). And then change out where they are in the semantic-ly named colors (e.g. --color--primary-base: var(--color--blue-500)). I'd recommend you still use the same pattern of defining primitives with their ranges (blue-500, blue-900, etc.).

You also might want to follow the same naming conventions, such as --color--[colorname], --font-size--[size], or --space--[size]. This keeps variable names predictable throughout the project. You can extend this naming pattern to any other properties you'd like to add to the :root.

Another fun thing you can add to in :root is defining dark mode (or light mode) styles with the same conventions. For example:

:root {
  --color--beige-100: #f1f1eb;
  --color--beige-900: #b2b2a7;
  
  --color--blue-100: #57929e;
  --color--blue-900: #164650;
  
  --color--pink-100: #efaf98;

  --color--background-base: var(--color--beige-100);
  --color--text: var(--color--blue-900);
  --color--accent: var(--color--pink-100);
  --color--border: var(--color--beige-900);

  @media (prefers-color-scheme: dark) {
    --color--background-base: var(--color--blue-900);
    --color--text: var(--color--beige-100);
    --color--border: var(--color--blue-100);
  }
}

Components

This folder is empty! But this is where you'd put any component-based CSS files.

Reset

The reset in this uses Normalize.

Utilities

This holds an utility-based helpers that can be used globally. The only utility present is .hide-visually which will hide an element visually but still be accessible to a screen reader. It comes with a companion class, .u-hide-visually--focus-unhide which will show an element if focused (by a keyboard for example).

About

A boilerplate of pre-defined native CSS styling

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published