Reduce, Reuse, Recycle:
MAINTAINABLE & MODULAR CSS
Kendall Totten
UX Dev Team Lead, redhat.com
bit.ly/BEACSS


Bootstrap
Mock-ups


<!-- panel -->
<section class="spot1 band">
<header>
<div class="container">
<h1>title</h1>
<h2>Headline</h2>
</div>
</header>
<div class="content">
<div class="container">
<article class="parts-2">
<div>
<p>A column of content can go here</p>
</div>
<div>
<p>Another column of content can go here</p>
</div>
<a class="cta-primary">Call to Action</a>
</article>
</div>
</div>
</section>
.spot1 {
.content {
.container {
section {
div {
@include make-sm-column(12);
h3 {
text-transform: uppercase;
@include rem-fallback(margin-bottom, 1);
}
h4 {
font-size: 1.6rem;
margin: 2rem 0 0;
@include rem-fallback(font-size, 1.6);
@include rem-fallback(margin-top, 2);
}
.cta-primary {
@include rem-fallback(margin-left, 0);
}
}
}
}
}
}
The Story
bit.ly/BEACSS
Deadline: yesterday
Photo Credit: mdanys

<insert framework here>

Add client requests
Photo Credit: marioanima

Evolution of design

Photo credit:
Specificity battles

Photo credit: VisualHunt
Code spaghetti

Photo credit: Vigzu
body.editorial .stat1 .content .container > section .group-3.customer .stat-box {
padding: 0px;
display: table !important;
}
Actual code

Give up.

Change our
approach
bit.ly/BEACSS
Spot the patterns, spot the differences




Establish a vocabulary

Components
- Icon Panel
- Header
- Call to Action
- Featured Item
- Footnote
- Generic Text
- Image Embed
- Link Tile
- Option Set
- Promo
- Quote
- Video Embed



Layouts

- Band
- Group
- Card
- Carousel
- Raw
Components + Layouts = Patterns

Components + Layouts = Patterns

.rh-band-header
.rh-icon-panel
.rh-cta
Components + Layouts = Patterns

rh-data-layout="6 6"
Rules to break the cycle
bit.ly/BEACSS
The Road Runner Rules
A layout never imposes padding or styles on its children. It is only concerned with their horizontal or vertical alignment and spacing.

A layout never imposes padding or styles on its children. It is only concerned with their horizontal or vertical alignment and spacing.

rh-data-layout="4 4 4"
rh-band-container
bit.ly/layout-styles
The Road Runner Rules
Themes and other data attributes never force changes in appearance; they are always a context that layouts, components and elements can subscribe to.

<div class="rh-card--layout"
data-rh-theme="dark">
<div class="rh-card-content">
<!-- Default Component -->
<div class="rh-default--component"
data-rh-align="left">
<h3>Lorem title</h3>
<p>Lorem ipsum dolor sit amet.</p>
</div>...
Themes and other data attributes never force changes in appearance, they are only a context that layouts, components and elements can subscribe to.

%title {
font-size: 22px;
font-family: $base-font-family;
color: blue;
[data-rh-theme="dark"] & {
color: white;
}
}
The Road Runner Rules
A component always touches all four sides of its parent container . No element within a component will have top or left margins and all last children (of a row or column) will have their margins cleared.





<div class="rh-band" data-rh-band-background="gray" data-rh-background-fixed="">
<div class="rh-band-container">
<header class="rh-band-header" data-rh-theme="light">
<div class="rh-band-header--component">
<h2 class="rh-band-header-title">CERTIFICATION TOOLKIT</h2>
<h3 class="rh-band-header-headline">The information you need...</h3>
<p class="rh-band-header-summary">It shouldn't be a chore to ...</p>
</div>
</header>
</div>
</div>
The Road Runner Rules
The component container never has backgrounds, widths, floats, padding or margins. Component styles only target the elements inside.

The Road Runner Rules
Every element has a single, unique, component-scoped class. All styles are applied directly to that selector modified only by contexts and themes.

<div class="rh-band-header--component" data-rh-align="left">
<h2 class="rh-band-header-title">Band title</h2>
<h3 class="rh-band-header-headline">Band headline</h3>
<p class="rh-band-header-summary">Lorem ipsum.</p>
</div>
Every element has a single, unique, component-scoped class, modified only by contextual data attributes.
The Road Runner Rules
Elements never use top margins. The first element touches the top of its component.

Elements are just the pieces inside of components.

The Road Runner Rules
Javascript is never bound to any element class. Functionality is "opted in" via data attributes.

rh.webrh.themeToggle = function(target, selector) {
var $target = $(target),
currentTheme = $target.attr('data-rh-theme'),
newTheme = $target.attr(selector);
$target.attr('data-rh-theme', newTheme);
$target.attr(selector, currentTheme);
};
$('[data-rh-theme-hover]').hover(function() {
rh.webrh.themeToggle(this, 'data-rh-theme-hover');
});
$('[data-rh-theme-click]', context).on('click', function() {
rh.webrh.themeToggle(this, 'data-rh-theme-click');
});
Javascript is never bound to any element class. Functionality is "opted in" via data attributes.
Less work for us later

BEACSS
Block, Element, Attribute CSS

bit.ly/BEACSS
Playing nice with Sass
- Keep an eye on the CSS
- Stay DRY
- Use semantic placeholders

<div class="rh-cta--component" // Block Component >
<a class="rh-cta-link" // Element
data-rh-cta-type="primary" // Attribute
href="http://www.redhat.com"
>Learn more
</a>
</div>
Rule #0
Styles are only applied to classes, never IDs or
HTML elements.*
*except when a WYSIWYG is used.
Rule #0: Don't style elements or IDs
Why?
- Avoid specificity battles!
- Tell your SEO buddy that you can modify the mark-up at any time without breaking styles.
<h2 class=”rh-band-headline”>Eat your veggies.</h2>
<div class="ux-default--component">
<h1>Lorem ipsum</h1>
<p>Sed semper non risus ac placerat.</p>
</div>
Rule #0: Don't style elements or IDs
library/component.html
library/component.scss
.ux-default--component {
p {
@extend %default-paragraph;
}
h1 {
@extend %default-h1;
}
}
Scenario:
What if certain fields get content from a WYSIWYG where it renders without classes?
Okay...
Rule #1
Every element should have a single source of truth from which it derives all of its styles.
<div class="ux-component">
<h2 class="ux-component-headline">...</h2>
</div>
Rule #1: Single Source of Truth
library/component.html
library/component.scss
.ux-component-headline {
color: red;
font-size: 18px;
}
.ux-component-headline {
text-transform: uppercase;
}
custom-page.scss
Scenario:
I want to use an existing component, but I want to add one style (all caps) on a element within that component.
Add additional styles to the existing element class?
No!
<div class="ux-component">
<h2 class="ux-component-headline
ux-component-headline-unicorn">
...</h2>
</div>
Rule #1: Single Source of Truth
library/component.html
library/component.scss
.ux-component-headline {
color: red;
font-size: 18px;
}
.ux-component-headline-unicorn {
text-transform: uppercase;
}
custom-page.scss
Scenario:
I want to use an existing component, but I want to add one style (all caps) on a element within that component.
Create a new class, and add both classes to the element?
No!
<div class="ux-component">
<h2 class="ux-component-headline-foo">…</h2>
</div>
Rule #1: Single Source of Truth
library/component.html OR
custom-page.html
.ux-component-headline-foo {
font-size: 24px;
color: red;
text-transform: uppercase;
}
custom-page.scss
Scenario:
I want to use an existing component, but I want to add one style (all caps) on a element within that component.
Create a new custom element / component?
Yes!
Rule #1: Single Source of Truth
%primary-headline {
color: red;
font-size: 18px;
}
%secondary-headline {
@extend %primary-headline;
text-transform: uppercase;
}
_headline_extends.scss
Scenario:
I want to use an existing component, but I want to add one style (all caps) on a element within that component.
Create a new placeholder that extends the original?
Sure!
.ux-component {
&-headline-foo {
@extend %secondary-headline;
}
}
component-foo.scss
Rule #2
When styling elements, use the &- to append the element name to the parent selector name.
<div class="ux-component-A">
<div class="ux-headline">…</div>
</div>
Rule #2: Namespace Elements with &-
library/component-A.html
library/component-B.html
<div class="ux-component-B">
<div class="ux-headline">…</div>
</div>
.ux-headline {
font-size: 24px;
color: gray;
}
.component-B .ux-headline {
color: red;
}
library/headlines.scss
Scenario:
I want to reuse my generic headline style in a few components.
Create a generic headline style that can be placed into any component?
No!
.ux-component {
background: gray;
}
.ux-component-headline {
color: red;
font-size: 18px;
}
}
.ux-component {
background: gray;
.ux-component-headline {
color: red;
font-size: 18px;
}
}
Rule #2: Namespace Elements with &-
library/component.scss
Scenario:
I'm writing styles for a headline that corresponds with a specific component.
List the full element class separately?
Nest it inside the parent?
No!
%snazzy-headline {
font-size: 22px;
line-height: 1.4;
color: gray;
}
Rule #2: Namespace Elements with &-
library/component-A.scss
Scenario:
I want to reuse my generic headline style in a few components.
Create a placeholder from which multiple components may extend?
Yes!
.ux-component-A {
&-headline {
@extend %snazzy-headline;
}
}
library/component-B.scss
.ux-component-B {
&-headline {
@extend %snazzy-headline;
}
}
library/_headline_extends.scss
body.editorial {
.stat1 {
.content .container > section {
.group-3 {
.stat-box {
display:table !important;
This is why people say "Don't use Sass."
.rh-stats
&-box {
display:table;
}
}
.rh-stats-box {
display:table;
}
Nest the right way and prosper!
body.editorial .stat1 .content .container > section .group-3 .stat-box {
display:table !important;
}
Rule #3
Use extends OR write custom style properties
(not both).
.ux-unicorn-headline {
@extend %fancy-headline;
color: pink;
}
}
Rule #3: Extends OR custom styles
library/custom-page.scss
Scenario:
I want to extend a placeholder because I’m using all the same styles, but I need to override one thing!
Create a custom selector, and extend a placeholder style and then add custom styles beneath it?
No!
%fancy-headline {
font-size: 24px;
line-height: 1.5;
}
%snazzy-headline {
@extend fancy-headline;
color: pink;
}
Rule #3: Extends OR custom styles
library/extends/headlines.scss
Scenario:
I want to extend a placeholder because I’m using all the same styles, but I need to override one thing!
Create a new placeholder that extends another placeholder and add custom styles?
Yes!
.ux-unicorn-headline {
@extend %fancy-headline;
}
.ux-abominable-snowman-title {
@extend %snazzy-headline;
}
library/custom-page.scss
Resources & Plan of Attack

bit.ly/BEACSS
Plan of attack
- Remove any element
<H1> <H2> styles and replace with classes - Refactor in chunks
- Use prefixes to avoid namespace collisions

Resources - bit.ly/BEACSS
- Patternlab.io
- micah.codes/a-new-design-system-architecture
- bit.ly/layout-styles (sassmeister layout examples)
- http://bit.ly/mixin-layouts (sassmeister layout mixin)
- Pattern Kit on Github
- Pattern Builder Drupal module on Github
- Thanks to @micahgodbolt for building much of this amazing system, and to @castastrophee for her contributions to
these slides!

Demo Time!
THANK YOU!
BADcamp - Modular CSS
By Kendall Totten
BADcamp - Modular CSS
CSS bloat is a challenge for every enterprise website. As design elements grow and change, code gets added but rarely deleted and our CSS files get larger and harder to maintain. What was that class name that makes the font color black and 22px? Where is the pattern that gives me the right layout and color scheme for this design? Modular design encourages us to look beyond classes and begin styling on the component level using data attributes. Separate content from design and your code base becomes reusable and more compact.
- 1,813