Skip to content

Instantly share code, notes, and snippets.

@james-jlo-long
Last active May 31, 2017 13:20
Show Gist options
  • Save james-jlo-long/3c6fe0d7db595de29385ac2f44aa4790 to your computer and use it in GitHub Desktop.
Save james-jlo-long/3c6fe0d7db595de29385ac2f44aa4790 to your computer and use it in GitHub Desktop.
I'm working on a very basic CSS methodology. I'm saving it here to make it easier to find and modify.

OSCAR

OSCAR stands for "Only Style Classes, AlRight?". It's a CSS methodology that is designed to be very simple and lead into other mentalities such as OOCSS, SMACSS or ITCSS. The idea is to take the most basic parts of the other methodologies and create some simple rules that can be quickly taught to a new-comer without weighing them down with complexities. This is the starting point for better CSS.

Two Simple Rules

1. Only add styles to class selectors

No IDs, no elements. Only classes. You can have up to 1 class, 1 pseudo-element and 1 state or pseudo-class.

/* Only style classes, alright? */
.element { }

/* You can use pseudo-elements */
.element::before { }
.element::after { }

/* You can use states */
.element:hover { }
.element.is-something { }

/* You can use both */
.element:hover::before { }

You can also nest elements within states. Try to avoid doing this, but it's within the rules.

:hover .element { }
.is-something > .element { }

It's better to use a modifier class, but you can use pseudo-classes as well. Think of the pseudo-class as occupying the "state" slot in the allowed parts.

/* ALLOWED */
.element:nth-child(even) { }
.element:first-child { }

/* Technically better */
.element-variant { }

Try to limit the specificity strength to a maximum of 3 classes.

Don't style IDs, don't style elements.

/* NOT ALLOWED - ID selector */
#id { }

/* NOT ALLOWED - element selector */
div { }
.element div { }

One thing that will seem wrong at the start is input elements because a lot of developers are used to writing input[type="text"], input[type="number"], input[type="date"] ... to style text elements and avoid styling radio button. The problem is that element selectors aren't allowed but the solution is to just add a class to the element you want to style. As well as being considerably tidier than declaring all the types and less generic than styling anything with a type attribute, it allows other elements to have the same styling should you need it.

/* NOT ALLOWED - element and class selector */
input[type="text"] { }

/* Not recommended - too generic */
[type="text"] /* ... */ { }
[type] { }

/* Much better ^_^ */
.input { }

2. Add a class to any element you want to style

Quite simply, if you want to style an element, give it a class.

<p>Default styling</p>
<p class="element">Magic styling</p>

This counts for all elements and can scare newcomers as it's easy to jump to the conclusion that every single element needs a class.

<ul class="list">
    <li class="item">Alpha</li>
    <li class="item">Bravo</li>
    <li class="item">Charlie</li>
    <!-- ... -->
</ul>

Although this can be beneficial (and even necessary) in some circumstances, styles cascade so adding a font style to .list will automatically apply the styles to .item. The same is true of table headings and cells, especially if the style value for key properties is inherit in the CSS reset.

(adding a class makes it easier to find than a nested selector. also helpful when styling similar things link inputs)

NOTE: expand these out into their own headings and offer examples

Summary

Advantages

  • By keeping the selector strength low, it's easier to avoid the specificity wars. The other thing that will help avoid those wars is ordering your CSS correctly - SMACSS or ITCSS will do that.
  • By preventing 2 classes being used in the same selector, we automatically separate content from container - one of the key components of OOCSS.
  • By only styling classes, we automatically separate style from structure - the other key component of OOCSS."

Disadvantages

  • Because of the additional number of classes, a concern can be HTML bloat. However, this will help get around CSS bloat, so there's always a trade-off. You can test your resulting webpage to see if it's an issue.
  • Adding a class to every element to style requires extra typing. This is largely mitageted with copy-and-paste or generated code.
  • There's always some resistence when asking a developer to change the way they work. Explaining the advantages can make them see reason.

Exceptions

  • CSS resets or normalisers require element selectors. You won't be doing much work on those styles and most people use a standard reset or normaliser so this isn't much of an issue.
  • If you're styling a site that allows a client the ability to create content using a CMS, you may need to include element selectors since a client can rarely be expected to modify the markup.

Naming conventions

You may have noticed that we can't nest classes which can seem to hinder what you can write.

/* NOT ALLOWED - two classes */
.element .child { }

Working with BEM

The solution is to use a naming convention for your classes. For example, here's BEM.

/* Only styling a class ^_^ */
.element__child { }

Disallowed naming conventions

Avoid solutions that require a second class to work correctly. For example, here's the markup for Skeleton's grid

<div class="container">
    <div class="row">
        <div class="one column">One</div>
        <div class="eleven columns">Eleven</div>
    </div>
</div>

The framework CSS files has selectors such as the one below.

/* NOT ALLOWED - two classes */
.eleven.columns {
    width: 91.33333333%;
}

It could easily be re-factored to follow the OSCAR rules. For example, .eleven could simply contain the width and .columns could contain the remaining rules. Although I prefer using modifiers like BEM, there's no rule that enforces them.

.column,
.columns {
    box-sizing: border-box;
    float: left;
    margin-left: 4%;
    width: 100%;
}

.eleven {
    width: 91.33333333%;
}

Preprocessors and nesting

OSCAR attempts to limit the strength of selectors. Since only one class and one state is allowed and neither pesudo-elements nor media queries can be nested, the Inception rule is maintained by default.

// Layer 0
.element {

    // Layer 1
    @media (min-width: 400px) {

        // Layer 2
        &:hover {

            // Layer 3 - Inception rule
            &::before {
            }

        }

    }

}

data-state attributes

Some developers have started putting the state in a dedicated attribute such as data-state. I first saw this in David Boureau's blog although he admits that he didn't create the idea. By having a dedicated attribute, the markup automatically enforces limits the component to only having a single state active at a time. There's anecdotal evidence that this is easier to work with when it comes to Sass.

<!-- Compare this: -->
<button class="button is-active"></button>

<!-- to this: -->
<button class="button" data-state="active"></button>

Since an attribute selector, even with a value, is the same selector strength as a class, the data-state attribute can occupy the "state" slot while keeping to the rules.

.button {
    background-color: #999;
}

.button[data-state="active"] {
    background-color: #CCC;
}

Note: CSS-Tricks article

Examples

Taming tables

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