What's your Vue?
Senior FED
2010
2014
2008
2015
2010
2014
2002
1991
1995
2005
2008
2011
2015
Component
CSS/SCSS
CSS-in-JS
CSS/SCSS
CSS Modules
Scoped CSS
Component
CSS/SCSS
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
OOCSS & SMACSS
BEM
CSS processors
NOT pure CSS
HARD to migrate
NAMING !
STILL GLOBAL
STILL NOT scalable
(that HUGE CSS file!)
/*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>
/*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]
var()
JavaScript
😰 Performance
😰 Complexity
Scoped CSS
Extendable
Full CSS support
SSR (Static CSS extraction)
Debuggable
Syntax highlighting
Free of dead CSS code
Themes
<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>
/*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>
not really
NOT Full extendable CSS in global scope
NO EASY way for theming
NAMING (not name collisions)
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>
/* ExtendedItem.vue */
import styled from "styled-components";
import Item from './Item'
const ExtendedItem = Item.extend`
background: "blue";
border-color: "blue";
`;
NO more CSS file!
Parse CSS
Inject to Stylesheet
stylesheet.insertRule
HTML Paint
load
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
The Good
The Bad
The Ugly
The Good
The Bad
The Ugly
Styled components
Scoped CSS
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