Scripting in Style

What's your Vue?

Who?

Senior FED

Back to the past (1991)

1995

2002

2005

2011

2010

2014

2008

2015

2010

2014

2002

1991

1995

2005

2008

2011

2015

2017

Component

CSS/SCSS

CSS-in-JS

CSS/SCSS

CSS Modules

Scoped CSS

Component

CSS/SCSS

2018

The Fear

...of CSS

CSS is awesome

BUT

Scaling

Global namespace

Implicit dependencies

Code Maintenance (DEAD code)

Chris

Chris

Chris


/* style.css */

.chris {
  color:'blue';
}

/* style.css */

.chris {
 color:'gold';
}

/* style.css */

.chris {
 color:'green';
}

<div class="my-awesome-container">
    <button class="chris">
        Chris!
    </button>
</div>

Chris!

😰

!important

Scaling

Minification

Sharing constants

Non deterministic order of source

The (not) old style

OOCSS & SMACSS

BEM

CSS processors

NOT pure CSS

HARD to migrate

NAMING !

STILL GLOBAL

STILL NOT scalable

(that HUGE CSS file!)

Scoped      SS

 

Component.vue

JS

Scoped CSS

/*Item.vue*/

<template>
  <div class="item__container_card item__container">
    <img :src="src" width="200">
    <h3 class="title">{{title}}</h3>
  </div>
</template>
<script>
export default { //...code }
</script>
<style scoped lang="scss">
.item__container {
  /* ..stylings */

  &_card {
    margin-right: 10px;
    margin-bottom: 10px;
    width: 220px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  }
}

.title {
  color: #842803;
  margin: 0;
  padding: 0.8rem 0;
  border-top: 1px solid lightgray;
}
</style>

HTML

/*App.vue*/
<template>
  <div id="app">
    <h1 class="title">The Pokemons</h1>
    <item v-bind="pokemon"/> 
  </div>
</template>
<script>
export default { /*code */ }
</script>
/*App.vue*/
<template>
  <div id="app">
    <h1 class="title">The Pokemons</h1>
    <item v-bind="pokemon"/> 
  </div>
</template>
<script>
export default { /*code */ }
</script>
<style>
  .title {
    color: #111;
  }
</style>
/*App.vue*/
<template>
  <div id="app" class="app">
    <h1 class="title">The Pokemons</h1>
    <item v-bind="pokemon"/> 
  </div>
</template>
<script>
export default { /*code */ }
</script>
<style>
  .app .title {
    color: #111;
  }
</style>

Full CSS support

Pre-processor support

Reusable CSS

Random class generator

/*Item.vue*/

<style lang="scss">
//...
</style>

/* OR */

<style lang="less">
//...
</style>
/* Item.vue */
<template>
//...
	<h3 class="title">{{title}}</h3>
//...
</template>

<style scoped>
.title {
  //...
}
</style>

/* will be compiled to */

<head>
	<style>
    .title[data-v-6b294924] {
    //...
    }
    </style>
</head>
<body>
/*...*/
	<h3 class="title" data-v-6b294924>
/*...*/
</body>

Scoped

Global Extendable

.app .title >>> title[data-v-6b294924]

Real-time CSS modifiers ?

var()

😍

😱

JavaScript

😰 Performance 

😰 Complexity 

CSS has fundamental flaws at scale that can be solved by writing styles in JS .

@VJEUX — NOVEMBER 2014

SS-in-JS

Ideal concepts

Scoped CSS

Extendable

Full CSS support

SSR (Static CSS extraction)

Debuggable

Syntax highlighting

Free of dead CSS code

Themes

2015

<template>
  <div class="item__container_card item__container">
	<img :src="src">
    <h3 class="title">{{title}}</h3>
  </div>
</template>

// Will become

<template>
  <div :class="[this.item.container, this.item.container_card]">
    <img :src="src">
    <h3 :class="description.title">{{title}}</h3>
  </div>
</template>

<style scoped lang="scss">
.item__container {
  /*...*/
}

.title {
  /*...*/
}
</style>

//Will become

<style module="item" lang="scss">
.container {
  /* Same as before */
}
</style>
<style module="description">
.title {
  /* Same as before */
</style>
/*App.vue*/
//...
<style module="theme" lang="scss">
$primary-color: #B4DC47;
$light-orange: #fc9e2d;
$purple: rgb(76, 76, 111);
$dark-purple: #111;
$pink: pink;

:export {
  colors: {
    default: $primary-color;
    lightorange: $light-orange;
    purple: $purple;
    darkpurple: $dark-purple;
    pink: $pink;
  }
}
</style>

/*App.vue*/
<script>
//...
    provide() {
      const theme = {};

      Object.defineProperty(theme, "defaultColor", {
        enumerable: true,
        get: () => this.currentThemeColor
      });

      return {
        theme: theme,
      };
    },
    data() {
      return {
        colors: this.theme,
          currentThemeColor: this.theme.default
      };
	}
//...
</script>

Theming

/*Layout.vue*/

<template>
  <div class="layout__container"
       :style="{ background: theme.defaultColor}">
    /*...*/
    <h4>Current Theme: {{theme.defaultColor}}</h4>
    /*...*/
  </div>
</template>
<script>
export default {
  /*...*/
  inject: ["theme"],
  /*...*/
}
</script>

All SCOPED CSS Benefits

Theming

Dynamic modifiers

<div 
  :class="[this.item.container]">
   //...
</div>

//Will become

<div 
  class="_src_components_ModuledItem__container">
  //...
</div>

BUT

CSS in JS

not really

It's still

NOT Full extendable CSS in global scope

NO EASY way for theming

NAMING (not name collisions)

THE CSS-in-JS

The challenge

List-view

Grid-view

+

Themes

/*App.vue*/
<script>
const colors = {
  default: "#fff",
  lightorange: "#fc9e2d",
  purple: "rgb(76, 76, 111)",
  darkpurple: "#111",
  pink: "pink"
};

export default {
  name: "App",
  components: {
    Layout
  },
  provide() { /*....*/ },
  /*...*/
  data() {
    return {
      colors: colors,
      currentThemeColor: colors.default
    };
  }
};
</script>
/*Item.vue*/
<script>
import yiq from "yiq";
import { darken } from "polished";
import styled, { css } from "vue-styled-components";

const itemProps = {
  isGrid: Boolean,
  themeColor: String
};

const TitleRowStyle = css`/*...*/`;
const StyledItemTitle = styled("h3", itemProps)`
  color: ${props => yiq(props.themeColor)};
  /*...*/
  ${props => (props.isGrid ? null : TitleRowStyle)}
`;
  
const Card = css`/*...*/`;
const Row = css`/*...*/`;
const StyledItem = styled("div", itemProps)`
  /*...*/
  background: ${props => props.themeColor};

  ${props => (props.isGrid ? Card : Row)}

  &:hover {
    background-color: ${props => darken(0.05, props.themeColor)};
    cursor: pointer;
  }
`;

export default {
  inject: ["viewMode", "theme"],
  components: { StyledItem, StyledItemTitle },
  /*...*/
};
</script>
/*Item.vue*/
<template>
  <styled-item
    :is-grid="viewMode.isGrid" 
    :theme-color="theme.defaultColor">
    <img :src="src">
    <styled-item-title 
		:is-grid="viewMode.isGrid"
     	:theme-color="theme.defaultColor">
      	{{title}}
    </styled-item-title>
  </styled-item>
</template>

The GOOD

EASY to theme

NO Dead code

Run-time modifier

Extendable

Scoped (100%)

/* ExtendedItem.vue */
import styled from "styled-components";
import Item from './Item'

const ExtendedItem = Item.extend`
  background: "blue";
  border-color: "blue";
`;

NO more CSS file!

It's awesome!

Or is it really ? 😏

The NOT so good

JS

CSS

Parse CSS

Inject to Stylesheet

stylesheet.insertRule

Browser

HTML Paint

load

 😮 Accessibility?

NO Cache

download

Box

/* Box.vue */

<template>
  <styled-box :size="size"/>
</template>
<script>
import styled from "vue-styled-components";

const boxProps = {
  size: String
};

const StyledBox = styled("div", boxProps)`
  width: ${props => props.size}px;
  height: ${props => props.size}px;
  background: grey;
  margin-left: auto;
  margin-right: auto;
  margin-top: 10px;
`;
export default {
  components: { StyledBox },
  props: boxProps
};
</script>

Input size of box

Interactive Comp

🤯

How about

Security?

Security?

CSS-in-JS means

It's still CSS! (not JS)

Learning CSS is still required! 😆

Should we use CSS-in-JS?

Yes, but with caution

So

Easy to theme

NO Dead code

Extendable

Scoped

Styles on run time

Security

Portability

Context switch

Messy code

CSS-in-JS

The Good

The Bad

The Ugly

Portable

No escapsulation

Bundle size

Dead code (somewhere)

Naming

Private to JS code

Load once

No re-render

Scoped CSS

The Good

The Bad

The Ugly

Theme-able

Basic scope

"Use the right tool for the right job"

And naming is not a good enough reason...

Styled components

Scoped CSS

When?

CSS modules

CSS consistency between projects

Simple and isolated component

Medium size apps / third-party libs

Security is a concern

Full control over component styling

Theme is critical (IE included)

Support dynamic styling via props

Complex and large apps

IE 11 is not a concern

Basic scope

NO dynamic styling via props

Thank you

Scripting in style - What's your Vue?

By Maya Shavin

Scripting in style - What's your Vue?

Code Demo: https://codesandbox.io/embed/style-with-vue-fzzci

  • 2,128