Why You Should Use Modern Style - ModernInc/modern-style GitHub Wiki
Why should I use Modern Style?
CSS, unlike other languages, doesn't have style guidelines. It has no rules what so ever that help to dictate how to write it well, how to help it scale, and how to work with other developers as they write on the same code base. Modern Style was birthed out of my frustrations with CSS and dealing with it's many pitfalls.
1. Properties brought in order.
My writing style used to begin with opening up the element inspector, then type in a bunch of 'property: value' combos until my markup looked like my design from my designer. Afterword I would copy and past those combos into sublime, wait for Sass to compile and then refresh. I think this is the work flow of 90% of front-end developers. Each selector you write has a different order of properties, it's confusing. You have to read through each set of properties and values to discern that selector and how works.
Lets look at some of my old code and see if we can work through this.
.team .curators .curator-name {
font-family: "Gotham SSm A", "Gotham SSm B";
font-weight: 700;
font-style: normal;
font-size: 24px;
color: #542212;
text-align: center;
margin: 40px 0;
}
.team .curators .lead {
font-family: "Gotham SSm A", "Gotham SSm B";
font-weight: 300;
font-style: normal;
font-size: 18px;
line-height: 1.4;
text-align: center;
color: #333332;
}
As you can see on first selector we have the color property 5th, and on the second selector we have it last. Both look very similar, but it's hard when something is slightly off to forget the structure of the old selector and adopt the structure of the new selector. Lets re write these two selectors and see if we can get a better pattern going.
.team .curators .curator-name {
// Font Face
font-family: "Gotham SSm A", "Gotham SSm B";
font-weight: 700;
font-style: normal;
// Modifying Font
font-size: 24px;
color: #542212;
// Modifying Text Behavior
text-align: center;
// Box Model
margin: 40px 0;
}
.team .curators .lead {
// Font Face
font-family: "Gotham SSm A", "Gotham SSm B";
font-weight: 300;
font-style: normal;
// Modifying Font
font-size: 18px;
line-height: 1.4;
color: #333332;
// Modifying Text Behavior
text-align: center;
}
Wow, that looks like code I could read all day! We broke the code up into sections, the main one being typography related code. I have commented each section to give a little bit of detail as to how they are organized. The following list is how I now section out my properties to create very easy to read CSS.
- Background
- Typography
- Font-Face
- Modifying Font
- Int Support
- Modifying Text Behavior
- Modifying Punctuation
- Modifying Lists
- Box Model
- Display
- Flex
- Table
- Float
- Posititon
- Margin
- Border
- Height
- Width
- Padding
- z-index
- Transform
- Transitions
- Animation
2. Simplify selectors.
Lets look back at our css.
.team .curators .curator-name {
...
}
.team .curators .lead {
...
}
Our selectors are overly complex and they don't have very meaningful names either. Enter our hero http://bem.info. BEM stands for Block Element Modifier. If we think of a nav, the first div would be our block element of nav. Blocks are the larger elements in your HTML, other examples of common blocks are sidebars, comment sections, articles, footers, and heroes. Do keep in mind, a block can live in another block. In the case of our CSS above it looks like we have two Blocks, team and curators.
Elements are the next part of BEM. Elements live in their unique block. We have a curator-name and a lead element. Because I know where this code comes from, lead is not actually an element but a modifier which we will cover shortly. BEM has naming rules for CSS selectors, I'm gonna rewrite my CSS with these naming rules so you can see them.
.team .curators .curator__name {
...
}
.team .curators .curator__name--lead {
...
}
As you can see the name of our Block is now in both our Element and our Modifier. BEM dictates two underscores __ between Blocks and Elements, and two dashes -- between Elements and Modifiers. Modifiers are for when you have a Element that needs to be changed slightly.
There are two more principles to BEM. Only style HTML elements by them selves:
Wrong:
.team .curators h1 {
...
}
Right:
h1 {
...
}
If I need to target that h1, and only if it's in .team and .curators, put a class on it.
And the last one gets a ton of hate but is the right way to go. DON'T INDENT YOUR CODE!
.curator__name {
...
}
.curator__name--lead {
...
}
We don't need to tell our css that .curator__name and .curator__name--lead are in .team .curators. Since we follow BEM they are unique. This will massively improve our performance.
Lets look back at properties and values and see if we can slim them down using BEM.
.curator__name {
// Font Face
font-family: "Gotham SSm A", "Gotham SSm B";
font-weight: 700;
font-style: normal;
// Modifying Font
font-size: 24px;
color: #542212;
// Modifying Text Behavior
text-align: center;
// Box Model
margin: 40px 0;
}
.curator__name--lead {
// Font Face
font-weight: 300;
// Modifying Font
font-size: 18px;
line-height: 1.4;
color: #333332;
}
Since .curator__name--lead is a modifier class, we don't need to include the property: value pairs that are not not being overridden. You would include both classes on your HTML element.
#####3. @extend kinda sucks. I love Sass. But it's not perfect, neither is this tool. For a long time I used @extend to get to every deceleration just once. Using that method problems start to arise. @extend doesn't play well in media queries. So you have to make a placeholder for every media query and every unique 'property: value' combo. This is a pain. First lets look at some new example code.
.foo
+color(#fff)
+display(block)
+margin(15px)
+padding(30px)
.bar
+color(#000)
+display(block)
+padding(30px)
.foo and .bar are two different blocks in this example. They are located in different partials in our project. We want them to be able share code, because they have the same attributes. But at the same time we need to easily be able to remove one with out effecting the other. Lets look at the output CSS.
.foo, .bar {
display: block;
}
.foo, .bar {
padding: 30px;
}
.foo {
color: #fff;
margin: 15px;
}
.bar {
color: #000;
}
DID I JUST BLOW YOUR MIND OR WHAT? Let's talk about how this works and then why it's awesome. Each property is a mixin called with a +property(value) syntax. Modern-Map starts to build a map within a map within a map within a map. This contains all the information about the selector you wrote, the media query it's in, and all of it's properties and values. We then take it part at the end. Combining everything that is not unique to a single selector and then output the properties together. Look at .foo. both color: #fff and padding: 15px are unique to it. The output is as almost as optimized as you can get.