Attribute Driven Styles: The Good, the Bad, and the Unknown (SassConf 2015 Discussion)

71
@JCutrell @DeveloperTea @whiteboardis Attribute Driven Styles: The good, the bad, and the unknown

Transcript of Attribute Driven Styles: The Good, the Bad, and the Unknown (SassConf 2015 Discussion)

@JCutrell @DeveloperTea @whiteboardis

Attribute Driven Styles: The good, the bad, and the unknown

SassConf Austin 2015!!!

Hi! I’m Jonathan.

@JCutrell @DeveloperTea @whiteboardis

@JCutrell @DeveloperTea @whiteboardis

Enjoy your tea.

@JCutrell @DeveloperTea @whiteboardis

@JCutrell @DeveloperTea @whiteboardis

Where I learn.

@JCutrell @DeveloperTea @whiteboardis

@JCutrell @DeveloperTea @whiteboardis

Today’s talk is inspired by:

@JCutrell @DeveloperTea @whiteboardis

Today’s talk is inspired by:

@glenmaddern

@JCutrell @DeveloperTea @whiteboardis

Today’s talk is inspired by:

@JCutrell @DeveloperTea @whiteboardis

This discussion is actually about

change.

@JCutrell @DeveloperTea @whiteboardis

This discussion is actually about

learning how to change.

@JCutrell @DeveloperTea @whiteboardis

@JCutrell @DeveloperTea @whiteboardis

@JCutrell @DeveloperTea @whiteboardis

@JCutrell @DeveloperTea @whiteboardis

Humans are allergic to change. They

love to say, 'We've always done it this way.' I try to fight that. That's why I

have a clock on my wall that runs

counter-clockwise.

@JCutrell @DeveloperTea @whiteboardis

The most damaging

phrase in the language is

“We’ve always done it this

way”Admiral Grace Murray Hopper

@JCutrell @DeveloperTea @whiteboardis

How we do it (right now)

.col-xs-3 {}

.content-section {} ul li.active {} .slider .slide {}

@JCutrell @DeveloperTea @whiteboardis

How we do it (right now)

.template-blog { a {} .primary-section {} }

@JCutrell @DeveloperTea @whiteboardis

Why?

How we do it (right now)

.template-blog { a {} .primary-section {} }

@JCutrell @DeveloperTea @whiteboardis

Discuss: Do you primarily

use classes?

If not, what do you use, and why?

@JCutrell @DeveloperTea @whiteboardis

Why?

- They work fine.

- "That's how I learned"

- That's what everyone I work with knows how to use

- I work quickly with them

@JCutrell @DeveloperTea @whiteboardis

Why?

- That's what [some framework] uses

- Some of my toolset relies on CSS classes for

processing

- They provide adequate flexibility for my use-case

@JCutrell @DeveloperTea @whiteboardis

What’s the problem with classes?

1. Classes are global

2. Imbalance between classes - One class can (and often does) have incredible variance of effect in comparison to another class

@JCutrell @DeveloperTea @whiteboardis

What’s the problem with classes?

3. Often constructed with redundant strings

4. Ambiguity of intention, requiring extra supporting documentation

5. Often abused and overridden in semantically confusing ways

@JCutrell @DeveloperTea @whiteboardis

What About The Spec?

Basically it just says classes exist and can be used.

“For general purpose processing by user agents”

@JCutrell @DeveloperTea @whiteboardis

“For general purpose processing by user agents”

@JCutrell @DeveloperTea @whiteboardis

general purpose

@JCutrell @DeveloperTea @whiteboardis

In essence, classes are global variables that can be used

however the author chooses.

general purpose

@JCutrell @DeveloperTea @whiteboardis

Recommended Watching: Chris Chedeau’s Problems

with CSS at Scale

@JCutrell @DeveloperTea @whiteboardis

Would you do this?

<script> counter = 0; main = $("main"); styles = { color: "blue" } </script>

@JCutrell @DeveloperTea @whiteboardis

Would you do this?<script> counter = 0; main = $("main"); styles = { color: "blue" } </script>

<script> counter = "nope." main = $(".not-the-main"); </script>

<script> // now what if I depend on "counter" here, and expect it to be 0? counter++; // NaN </script>

@JCutrell @DeveloperTea @whiteboardis

<script> counter = 0; main = $("main"); styles = { color: "blue" } </script>

<script> counter = "nope." main = $(".not-the-main"); </script>

<script> // now what if I depend on "counter" here, and expect it to be 0? counter++; // NaN </script>

Would you do this?

@JCutrell @DeveloperTea @whiteboardis

Would you do this?

<script> (function(){ // Scope. It's not just a mouthwash. var counter = 0; var main = $("main"); var styles = { color: "blue" } // Scope. It's not just for hunting rifles. }()); </script>

@JCutrell @DeveloperTea @whiteboardis

<script> (function(){ // Scope. It's not just a mouthwash. var counter = 0; var main = $("main"); var styles = { color: "blue" } // Scope. It's not just for hunting rifles. }()); </script>

Would you do this?

@JCutrell @DeveloperTea @whiteboardis

Then why do this?.container { width: 600px; }

/* more code... */

.container { margin: 0 auto; }

@JCutrell @DeveloperTea @whiteboardis

How do we scope our CSS?.primary-content { .section-right { a { color: orange; &.is-active { color: white; &:hover { opacity: .8; } } } .col-md-4 {

width: $colwidth * 4; @media only screen and (min-width: 578px){ width: 100% !important; } &.js-slide-down.is-closed { min-height: 0; } &.js-slide-down.is-open { min-height: 30vh; } } } }

@JCutrell @DeveloperTea @whiteboardis

How do we scope our CSS?should

.primary-content { .section-right { a { color: orange; &.is-active { color: white; &:hover { opacity: .8; } } } .col-md-4 {

width: $colwidth * 4; @media only screen and (min-width: 578px){ width: 100% !important; } &.js-slide-down.is-closed { min-height: 0; } &.js-slide-down.is-open { min-height: 30vh; } } } }

@JCutrell @DeveloperTea @whiteboardis

This isn’t uncommon.

<div class="col-xs-4 col-xs-offset-6 col-sm-6 col-sm-offset-3 clearfix pad-top article-content article-content-template-php center-text font-serif white-bg no-headline"> <!-- what is happening to our brains --> </div>

@JCutrell @DeveloperTea @whiteboardis

<div class="col-xs-4 col-xs-offset-6 col-sm-6 col-sm-offset-3 clearfix pad-top article-content article-content-template-php center-text font-serif white-bg no-headline"> <!-- what is happening to our brains --> </div>

@JCutrell @DeveloperTea @whiteboardis

This isn’t uncommon.

<div class="col-xs-4 col-xs-offset-6 col-sm-6 col-sm-offset-3 clearfix pad-top article-content article-content-template-php center-text font-serif white-bg no-headline"> <!-- what is happening to our brains --> </div>

Can’t we do better?

@JCutrell @DeveloperTea @whiteboardis

Have you experienced issues of global scope that caused nesting nightmares or latent

bugs? What were they?

Discuss

@JCutrell @DeveloperTea @whiteboardis

“But what’s the alternative?”

I can hear your brain turning.

We've relied on classes for so long, it can feel like there’s no alternative. But there is.

@JCutrell @DeveloperTea @whiteboardis

If it's a good idea, go ahead and do it. It's

much easier to apologize than

it is to get permission.

@JCutrell @DeveloperTea @whiteboardis

“But what’s the alternative?”

We haven’t figured that out yet, but let’s look at some good ideas together.

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: Grids

<div grid="md4 xs12 lg2 o-md4 o-lg5 o-xs0"></div>

<div grid-cols="xs12 md4 lg" grid-offsets="xs0 md4 lg5"></div>

<div grid="xs1/1 md1/2 lg1/3 xl1/4"></div>

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: Separation of Concerns

<div text-utils="align-right bold primary" spacing="pad-top-2 offset-1" module="banana stand"></div>

@JCutrell @DeveloperTea @whiteboardis

<div template="chat-master text-center"> <menu organism="chat-menu"> <div molecule="user-selection">jcutrell</div> <div molecule="user-selection">lauren</div> </menu> <main organism="chat-list"> <div molecule="chat-message" from="lauren"> <div atom="message-avatar"><img src="laur.jpg"></div> <div atom="message-text">Hey friend. How are things going?</div> </div> <div molecule="chat-message" from="jcutrell"> <div atom="message-avatar"><img src="jcut.jpg"></div> <div atom="message-text">Great! How are you???</div> </div> </main> </div>

Source: http://bradfrost.com/blog/post/atomic-web-design/

Your Future, with Attributes: Atomic Design

@JCutrell @DeveloperTea @whiteboardis

<div molecule="chat-message" from="jcutrell"> <div atom="message-avatar"><img src="jcut.jpg"></div> <div atom=“message-text">Great! How are you???</div> </div>

Your Future, with Attributes: Atomic Design

Source: http://bradfrost.com/blog/post/atomic-web-design/

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: BEM

<div class="widget"> <div class="widget__gear" /> <div class="widget__gear--metal widget__gear--solid" /> </div>

.widget {} /* block */

.widget__gear {} /* element */

.widget__gear--metal {} /* modifier */

.widget__gear--solid {} /* modifier */

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: BEM

<div amWidget> <div amWidget-Gear /> <div amWidget-Gear="metal solid" /> </div>

[amWidget]{} [amWidget-Gear]{} [amWidget-Gear~="metal"]{} [amWidget-Gear~="solid"]{}

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: SMACSS

‣ Defaults (Base elements) - a, h1, section, div

‣ Layout (Page sections) - .l-fixed, .l-fixed-wide

‣ Module (Reusable modules) - .widget, .widget-modified

‣ State (Changing state, JS hooks): .is-open, .is-closed, .is-inactive

‣ Theme (Typography, Colors, etc) - .h1, .text-center

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: SMACSS

.l-homepage {} /* layout */ nav {} /* defaults */ .primary-nav { /* module */ a.is-active {} /* base + state, nested in a module */ } .text-primary {} /* theme */

<div class="l-homepage"> <nav class="primary-nav"> <a href="" class="is-active text-primary"></a> </nav> </div>

@JCutrell @DeveloperTea @whiteboardis

Your Future, with Attributes: SMACSS

<div amLayout="homepage"> <nav amModule="primary-nav"> <a href="" amState="active" amTextUtils="primary"></a> </nav> </div>

[amLayout="homepage"] {} nav {} [amModule="primary-nav"] { [amState~="is:active"] {} } [amTextUtils~="primary"] {}

@JCutrell @DeveloperTea @whiteboardis

The Good

‣ Fewer character restrictions, more flexibility

[grid-columns~="1/3"]

@JCutrell @DeveloperTea @whiteboardis

‣ More powerful selection matchers

The Good

~=^=$=Ends with Space-separatedStarts with

<div whizbang="foosball soccer"></div>

[whizbang^="foo"] [whizbang$="er"] [whizbang~="soccer"]

@JCutrell @DeveloperTea @whiteboardis

‣ More powerful selection matchers

The Good

Dash separated matcher

*=|=Contains

<div amCharacter="George-Michael Bluth Jr."></div>

[amCharacter *= "Jr."] [amCharacter |= "George"]

@JCutrell @DeveloperTea @whiteboardis

‣ Selection by Attribute presence (binary)

[row] [slider] [container]

The Good

<div row></div> <div slider></div> <div container></div>

@JCutrell @DeveloperTea @whiteboardis

‣ Separation / isolation

<div class="text-align-right text-bold text-primary pad-top-2 offset-1 banana-stand-module bet-you-wont-see-this"></div>

<div text-utils="align-right bold primary" spacing="pad-top-2 offset-1" module="banana stand"></div>

VS

The Good

@JCutrell @DeveloperTea @whiteboardis

‣ Separation / isolation

VS

The Good

<div class="text-align-right text-bold text-primary pad-top-2 offset-1 banana-stand-module bet-you-wont-see-this"></div>

<div text-utils="align-right bold primary" spacing="pad-top-2 offset-1" module="banana stand"></div>

@JCutrell @DeveloperTea @whiteboardis

The Bad‣The real secret of software: Attributes don’t fix

the problem. Humans fix the problem.

<div module="text-piece" text-u="center red bold xl serif serif-variant-1 primary” my-super-special-attribute="proprietary things" data-template="some-weird-template2.PHP"> Here's some stuff with lots of not-so-great attributes. </div>

Attributes can bring new baggage if we don’t do our jobs.

@JCutrell @DeveloperTea @whiteboardis

The Bad

‣ JavaScript selection via attributes is significantly slower than class-based selection. (In most cases, at least by 3x)

http://jsperf.com/testing-attribute-selectors/6

@JCutrell @DeveloperTea @whiteboardis

The Bad‣ JavaScript selection via attributes is significantly

slower than class-based selection. (In most cases, at least by 3x)

http://jsperf.com/testing-attribute-selectors/6

@JCutrell @DeveloperTea @whiteboardis

‣ No specific standard, so convention is still necessary

‣ Less cohesion amongst disparate projects by different authors

The Bad

@JCutrell @DeveloperTea @whiteboardis

‣ Possibly (marginally) larger CSS files

The Bad

[module="primary-nav"] {} [module="primary-nav"] [state="active"] {}

VS

.primary-nav {}

.primary-nav .is-active {}

@JCutrell @DeveloperTea @whiteboardis

‣ Possibly (marginally) larger CSS files

The Bad

14k 12.1k

@JCutrell @DeveloperTea @whiteboardis

‣ Possibly (marginally) larger CSS files

The Bad

@JCutrell @DeveloperTea @whiteboardis

‣ Compliance with w3c would require all attributes have an added prefix of “data-*“. (This is not functionally required, however.)

The Bad

@JCutrell @DeveloperTea @whiteboardis

‣ Change is hard. Adapting thinking patterns, adopting new tools, and convincing others to do the same

The Bad

@JCutrell @DeveloperTea @whiteboardis

The most important thing I've accomplished, other than building the compiler, is training young people. They come to me, you know, and say, “Do you think we can do this?” I say, “Try it.” And I

back 'em up. They need that. I keep track of them as they get older and I stir 'em up at intervals so

they don't forget to take chances.

One last piece of wisdom from Admiral Hopper:

@JCutrell @DeveloperTea @whiteboardis

The Unknown: Question Time!

@JCutrell @DeveloperTea @whiteboardis

‣ Do you see this potentially

benefitting your processes?

‣ How would you go about attribute-

driven styles in your day-to-day work?

‣ What features of attributes seem the

most compelling? The least?

Discuss:

@JCutrell @DeveloperTea @whiteboardis

Thank you! Questions?