Slide 1

Slide 1 text

You might not need a CSS preprocessor DevDay 2016 Serg Hospodarets @malyw

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No CSS

Slide 4

Slide 4 text

1996 year - CSS invented

Slide 5

Slide 5 text

Content and presentation are separated .page-header { /* shorthand */ border-bottom: 1px solid #eee; } p { font-family: Arial; /* font */ font-size: 14px; /* font */ color: #333; /* color */ margin: 10px 0; /* layout */ } .btn-outline { color: #563d7c; /* color */ border-color: #563d7c; /* color */ }

Slide 6

Slide 6 text

CSS problems Absence of variables Absence of mixins Modules Nested rules are not supported Code duplication as result

Slide 7

Slide 7 text

Preprocessors time

Slide 8

Slide 8 text

Solved by preprocessors

Slide 9

Slide 9 text

Sass: Variables and Operators (+, -, *, /, %) $font-size: 10px; $font-family: Helvetica, sans-serif; body { font: $font-size $font-family; } .mark{ font-size: 1.5 * $font-size; }

Slide 10

Slide 10 text

Mixins @mixin clearfix { &:after { display: block; content: ''; clear: both; } } .sidebar{ @include clearfix; } .main{ @include clearfix; } .sidebar:after { display: block; content: ''; clear: both; } .main:after { display: block; content: ''; clear: both; }

Slide 11

Slide 11 text

Nesting HTML SCSS // menu .nav { > li { > a:hover { background-color: red; } // submenu > ul { background-color: #fff; > li > a:hover { background-color: black; } } } }

Slide 12

Slide 12 text

Modules

Slide 13

Slide 13 text

What we use today

Slide 14

Slide 14 text

Preprocessors problems

Slide 15

Slide 15 text

Additional setup is needed to make a compiler work Any change require recompilation Compilation takes time ⏰

Slide 16

Slide 16 text

Each has own syntax! // Sass $color: #f00; $images: "../img"; @mixin clearfix { &:after { content: " "; display: block; clear: both; } } body { color: $color; background: url("#{img}/1.png"); @include clearfix; } // Less @color: #f00; @images: "../img"; .clearfix() { &:after { content: " "; display: block; clear: both; } } body { color: @color; background: url("@{img}/1.png"); .clearfix; }

Slide 17

Slide 17 text

Source maps are required Debug might be hard (or buggy)

Slide 18

Slide 18 text

We want Variables Mixins Nesting Modules Selector helpers, color functions We don't want Additional setup Compilation Not standardized syntax Hard debug

Slide 19

Slide 19 text

Does CSS have all this today? Let's take a look

Slide 20

Slide 20 text

What we want? Variables

Slide 21

Slide 21 text

First CSS variable currentColor :root { color: red; } i {border: 1px solid currentColor;} :root { color: red; } i {border: 1px solid red;} Other "variables": em, rem html { font-size: 1em; } h1 { font-size: 2.074em; } @media (min-width: 1400px) { html { font-size: 1.25em; } } html { font-size: 16px; } h1 { font-size: 33px; } @media (min-width: 1400px) { html { font-size: 20px; } h1 { font-size: 41px; } }

Slide 22

Slide 22 text

(a.k.a. CSS variables) CSS custom properties

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Good news!

Slide 25

Slide 25 text

Syntax /* declaration */ --VAR_NAME: ; /* usage */ var(--VAR_NAME) /* root element selector (global scope), e.g. */ :root { /* CSS variables declarations */ --main-color: #ff00ff; --main-bg: rgb(200, 255, 255); } body { /* use the variable */ color: var(--main-color); } Didn't expect the "--"? There was . a reason

Slide 26

Slide 26 text

Variable examples :root{ --main-color: #4d4e53; --main-bg: rgb(255, 255, 255); --logo-border-color: rebeccapurple; --header-height: 68px; --content-padding: 10px 20px; --base-line-height: 1.428571429; --transition-duration: .35s; --external-link: "external link"; --margin-top: calc(2vh + 20px); } And even.. :root{ --foo: if(x > 5) this.width = 10; }

Slide 27

Slide 27 text

Variable Defaults If the variable has already been assigned to - it won’t be re-assigned p { --p-margin: 5px; margin: var(--p-margin, 0 0 10px); /* 5px */ } If it doesn’t have a value yet - it will be given one. p { margin: var(--p-margin, 0 0 10px);/* 0 0 10px */ }

Slide 28

Slide 28 text

Reassign vars from others .block { --block-text: 'This is my block'; --block-highlight-text: var(--block-text)' with highlight'; } .block__highlight:before { content: var(--block-highlight-text); /*This is my block with highlight*/ }

Slide 29

Slide 29 text

Reset/inherit values As for any other CSS property, you can apply "initial" and "inherit" values .with-reset { --bgcolor: initial;/* RESETS THE VALUE for the scope */ --color: green;/* CHANGES THE VALUE */ --border: inherit;/* INHERITS THE VALUE for the scope */ }

Slide 30

Slide 30 text

Usage example: emulating non existing CSS rule

Slide 31

Slide 31 text

Scopes
My block is
awesome
Follow usual CSS cascade rules: :root{ --global-var: 1em; /* --global-var is available globally */ } .block { --block-var: 1.5em; /* --global-var and --block-var are available */ } .block__highlight { --block-highlight-var: 2rem; /* --global-var , --block-var and --block-highlight-var */ font-size: var(--block-highlight-font-size); }

Slide 32

Slide 32 text

CSS / preprocessors scopes are different /* SCSS: scope depends on the selectors structure in the code */ $font-size: 20px; .block{ $font-size: 42px; } .block__highlight{ font-size: $font-size; } /* CSS: scope depends on the selectors structure in the DOM */ :root{ --font-size: 20px; } .block{ --font-size: 42px; } .block__highlight{ font-size: var(--font-size); }

Slide 33

Slide 33 text

Scope examples /* Global scope (usually

Slide 34

Slide 34 text

Variables are alive

Slide 35

Slide 35 text

Operators and calculations :root { --block-font-size: 1rem; } .block__highlight { /* DOESN'T WORK */ font-size: var(--block-font-size)*1.5; } CSS calc( ) to the rescue (for values)! :root { --block-font-size: 1rem; } .block__highlight { /* WORKS */ font-size: calc(var(--block-font-size)*1.5); }

Slide 36

Slide 36 text

Generate colors from CSS custom properties

Slide 37

Slide 37 text

CSS to JS: without To pass variables from CSS to JS we used to use to write JSON in CSS workarounds or hacks .breakpoints-data { font-family: '{"phone":"480px","tablet":"800px"}'; }

Slide 38

Slide 38 text

CSS to JS: with .breakpoints-data { --phone: 480px; --tablet: 800px; } JS const breakpointsData = document.querySelector('.breakpoints-data'); // GET const phone = getComputedStyle(breakpointsData) .getPropertyValue('--phone'); // SET breakpointsData.style .setProperty('--phone', 'custom');

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Check if supported CSS @supports ( (--a: 0)) { /* supported */ } @supports ( not (--a: 0)) { /* not supported */ } JS const isSupported = window.CSS && window.CSS.supports && window.CSS.supports('--a', 0); /* e.g. load a CSS file generated by a preprocessor */ if(!isSupported){ removeCss('css-custom-properties.css') loadCss('without-css-custom-properties.css'); }

Slide 41

Slide 41 text

Why else CSS Custom Props are better?

Slide 42

Slide 42 text

Color schema switcher based on CSS custom property values Cannot be done by a preprocessor without generating additional code

Slide 43

Slide 43 text

What do we want? Mixins

Slide 44

Slide 44 text

(a.k.a. CSS mixins) CSS Custom Sets of Properties and @apply rule

Slide 45

Slide 45 text

Custom Property: :root{ /* --property: value; */ --VAR: ; } Custom properties can hold more than just values- they can also be used to hold sets of declarations: :root{ /* --property: { property1: value1; property...: value...; } */ --MIXIN: { /* style declaration 1 */ /* style declaration ... */ }; }

Slide 46

Slide 46 text

Syntax :root { --pink-schema: { color: #6A8759; background-color: #F64778; } } body{ @apply --pink-schema; } @apply rule takes these sets of declarations and inlines them in another style rule

Slide 47

Slide 47 text

Reasons to use Put reusable bunches of styles into separate entities Avoid code duplication Apply changes in a central place Behavior Everything form CSS variables (scopes, usage from JS etc.) is applicable for Custom Sets of Properties

Slide 48

Slide 48 text

Examples :root { --clearfix: { display: table; clear: both; content: ''; }; } .clearfix:after{ @apply --clearfix; } :root { --overflow-ellipsis: { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }; } .overflow-box{ @apply --overflow-ellipsis; }

Slide 49

Slide 49 text

(try in Chrome Canary) CSS Triangle Mixin

Slide 50

Slide 50 text

Problem- variables cannot be passed :root { --triangle-to-bottom-size: 50px; --triangle-to-bottom: { /* STYLES */ border-bottom-width: var(--triangle-to-bottom-size); }; } .triangle-to-bottom { --triangle-to-bottom-size: 8px; @apply --triangle-to-bottom; /* but still 50px size is applied for border-bottom-width */ } Discussion to change this behavior is in progress

Slide 51

Slide 51 text

Mixins for CSS vendor prefixes? Every time you need clip-path: Lea Verou's idea: * {/* has zero specificity */ /* prevents the property inheritance from outer scopes */ --clip-path: initial; -webkit-clip-path: var(--clip-path); clip-path: var(--clip-path); } header {/* any selector like this overrides the "*" */ /* assign the prop value for the scope */ --clip-path: polygon(0% 0%, 100% 0%, 100% 100%%, 0% 100%); }

Slide 52

Slide 52 text

What we need? Nesting

Slide 53

Slide 53 text

What we want to avoid? CSS code duplication in selectors Bad readability of the code table.colortable td { text-align:center; } table.colortable td.upper { text-transform:uppercase; } table.colortable td:first-child, table.colortable td:first-child+td { border:1px solid #000; }

Slide 54

Slide 54 text

Tab Atkins' CSS Nesting spec proposal Syntax is close to preprocessors /* Dropdown menu on hover */ ul { /* direct nesting (& MUST be the first part of selector)*/ & > li { color: #000; & > ul { display: none; } &:hover { color: #f00; & > ul { display: block; } } } }

Slide 55

Slide 55 text

The Nesting At-Rule: '@nest' for complex cases @nest < selector (MUST CONTAIN a nesting selector '&') > .foo { color: black; @nest body.loading & { opacity: 0.5; } @nest :not(&) { color: white; } } .foo { color: black; } body.loading .foo { opacity: 0.5; } :not(.foo) { color: white; }

Slide 56

Slide 56 text

Migration is easy Nesting selector syntax is very close to Sass Complex nesting can be done using @nest at-rule media expression etc. are nested: a { @media (min-width: 30em) { color: yellow; } } @media (min-width: 30em) { a { color: yellow } }

Slide 57

Slide 57 text

What we wish? Modules

Slide 58

Slide 58 text

The @import CSS at-rule is used to import style rules from other style sheets. It is available in all browsers since IE 5.5!

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

Why we didn't use this before? Bugs in old browsers with the order of inclusion Before requests didn't go in parallel For HTTP1x good practice is file concatenation. With coming of HTTP2 rules will be cnanged.

Slide 61

Slide 61 text

You can easily apply media queries for different stylesheets. Advantages for free: Conditional loading /* Formal syntax */ @import [ | ] []?; @import url("print.css") print; @import "mobile.css" (max-width: 728px); The linked resources are loaded only when condition is met.

Slide 62

Slide 62 text

We have Variables, Mixins Nesting and Modules What else we want? Selector helpers for complex cases Color functions

Slide 63

Slide 63 text

pseudo-class :matches /* SYNTAX */ :matches( selector[, selector]* ) A functional pseudo-class taking a selector list as its argument. .nav:matches(.side,.top) .links:matches(:hover, :focus) { color: #BADA55; } /* Same thing as this... */ .nav.side .links:hover, .nav.top .links:hover, .nav.side .links:focus, .nav.top .links:focus { color: #BADA55; }

Slide 64

Slide 64 text

@custom-selector /* SYNTAX */ @custom-selector: ; Example: @custom-selector :--text-inputs input[type="text"], input[type="password"]; :--text-inputs.disabled, :--text-inputs[disabled] { opacity: 0.5 } Same as: input[type="text"].disabled, input[type="password"].disabled, input[type="text"][disabled], input[type="password"][disabled] { opacity: 0.5 }

Slide 65

Slide 65 text

Color functions /* SYNTAX */ color( * ) some adjusters have shortcuts adjusters can be pipped color( red /* from red */ blackness(+25%) /* to 25% more black than red */ blackness(+25%) /* to 50% more black than red */ blackness(-50%) /* to red again */ hue(+ 30deg) /* to orange */ hue(- 30deg) /* to red again */ );

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

Better media queries! Problem The syntax is too long and they cannot be reused easily Need A simple way to set breakpoints and reuse them

Slide 68

Slide 68 text

Media Queries Level 4: Custom media queries /* SYNTAX */ @custom-media --NAME ; How to use: @custom-media --tablet (min-width: 800px) and (max-width: 1024px); @media (--tablet){ .custom-media-queries{ background-color: red; } }

Slide 69

Slide 69 text

Instead of: Use: Media queries ranges @media (min-width: 800px) and (max-width: 1024px) { .media-queries-range{ background-color: red; } } @media (width >= 800px) and (width <= 1024px) { .media-queries-range{ background-color: red; } } With custom media queries: @custom-media --tablet (width >= 800px) and (width <= 1024px); @media (--tablet){ /* STYLES */ }

Slide 70

Slide 70 text

Can we Use it now? Current situation CSS variables are supported in all the modern browsers except EDGE CSS mixins work in Chrome Canary Some of other specs are integrated in various browsers, sometimes it's in beta/dev versions Should we wait for another couple years?

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

PostCSS based Includes other PostCSS plugins (vars, mixins etc.) If you already use Autoprefixer- change is straign forward Build setup: //... postcss: { options: { processors: [ require('autoprefixer')({ browsers: ['last 2 versions'] }) ] }, //... //... postcss: { options: { processors: [ require('postcss-cssnext')({ browsers: ['last 2 versions'] }) ] }, //...

Slide 73

Slide 73 text

How to migrate 1) Preprocessor Add PostCSS and cssnext 2) Preprocessor+PostCSS+ability to use new CSS features Change vars, mixins, media queries, colors and selectors to the CSS ones Disable a preprocessor 3) PostCSS + all the CSS additions power Disable cssnext and PostCss when the browsers support everything 4) You have pure CSS with everything

Slide 74

Slide 74 text

You still can combine preprocessor and all the mentioned CSS additions (or process them via PostCSS) to use the strongest parts of the both.

Slide 75

Slide 75 text

Any live sites which use all these new CSS features? blog.hospodarets.com

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

Conclusions Today we have mostly everything we need from preprocessors in pure CSS variables, mixins modules, nesting complex selectors and color functions We have polyfills to make it work until it's supported in all browsers We have the real examples of migrated applications

Slide 78

Slide 78 text

How can I help / stay tuned? Spec, dra s, proposals CSS Working Group (WG) Editor Dra s Tab Atkins spec proposals Other Subscribe to CSS Working Group mailing list / RSS etc. cssnext issues

Slide 79

Slide 79 text

Thank you! @malyw