Slide 1

Slide 1 text

@klickreflex • wentsch.me Utility-First CSS with Tailwind

Slide 2

Slide 2 text

@klickreflex • wentsch.me Hi Daniel ⌨ Frontend Code ✏ UX Design # Site Building $ land in sicht & freelance % Living Styleguides & Drupal, Neos, TYPO3, … work ' Structure & Consistency ( Connecting Design & Code focus

Slide 3

Slide 3 text

@klickreflex • wentsch.me Hi Daniel Passionate About ❤ Friends & Family * Books ⛺ Outdoors & Camping , Running - Sustainability Toolbox

Slide 4

Slide 4 text

@klickreflex • wentsch.me Goals & Assumptions Maintainability Flat Hierarchy Speed of Development Consistency Safe-to-Delete CSS Premature Abstraction Deep Nesting Context Switching Magic Numbers Append-only CSS As Safe as possible

Slide 5

Slide 5 text

@klickreflex • wentsch.me

Slide 6

Slide 6 text

@klickreflex • wentsch.me

Slide 7

Slide 7 text

@klickreflex • wentsch.me people hate Change

Slide 8

Slide 8 text

@klickreflex • wentsch.me

Slide 9

Slide 9 text

@klickreflex • wentsch.me

Slide 10

Slide 10 text

@klickreflex • wentsch.me

Slide 11

Slide 11 text

@klickreflex • wentsch.me Before I started doing both performance and user testing I did not like the idea of oocss/atomic css. Adam Morse, Creator of Tachyons CSS and Scalability

Slide 12

Slide 12 text

@klickreflex • wentsch.me I rejected utility-first because it was implying my beloved and familiar approach wasn’t good anymore. Sarah Dayan In Defense of Utility First CSS

Slide 13

Slide 13 text

@klickreflex • wentsch.me Sarah Dayan In Defense of Utility First CSS Since then, I’ve dived a lot deeper into the topic. 
 I studied design patterns and functional programming, and this allowed me to… radically revise my judgment.

Slide 14

Slide 14 text

@klickreflex • wentsch.me people hate Change

Slide 15

Slide 15 text

@klickreflex • wentsch.me Issues with Traditional CSS™

Slide 16

Slide 16 text

@klickreflex • wentsch.me Premature Abstraction .weather-forecast-togglebutton .tb-ui-icon { + .tb-weather-forecast __toggle .tb-ui-icon { font-size: 4em; } }

Slide 17

Slide 17 text

@klickreflex • wentsch.me Premature Abstraction .discount-overview __hint-text { font-weight: $font-weight-light; }

Slide 18

Slide 18 text

@klickreflex • wentsch.me .asset-distribution --single-position-number { font-size: 1.5rem; margin-top: .125em; } Modifier Hell

Slide 19

Slide 19 text

@klickreflex • wentsch.me Modifier Hell .asset-distribution --annex-basis { max-width: 825px; margin-top: .25em; }

Slide 20

Slide 20 text

@klickreflex • wentsch.me Global Scope

Slide 21

Slide 21 text

@klickreflex • wentsch.me Specificity wars & Append-only CSS .favorite { color: red; } .button --secondary.favorite { color: blue; } #product-27 .button --secondary.favorite { color: green; } #product-27 .contact-block .this-is:not(.cool) .button --secondary.favorite { color: red; }

Slide 22

Slide 22 text

@klickreflex • wentsch.me Semantics & Separation of Concerns A Step back

Slide 23

Slide 23 text

@klickreflex • wentsch.me .c-person Semantic

Slide 24

Slide 24 text

@klickreflex • wentsch.me .c-person .c-news-teaser .c-person Not anymore Semantic

Slide 25

Slide 25 text

@klickreflex • wentsch.me .c-person .c-news-teaser .c-person Duplicate All the styles Not anymore Semantic

Slide 26

Slide 26 text

@klickreflex • wentsch.me .c-card - “unsemantic” - Semantics derive from design Refactor Reusable CSS

Slide 27

Slide 27 text

@klickreflex • wentsch.me Separation of Concerns „Separating Concerns“

Slide 28

Slide 28 text

@klickreflex • wentsch.me Separation of Concerns „Mixing Concerns“

Slide 29

Slide 29 text

@klickreflex • wentsch.me Dependency Direction Separation of Concerns

Slide 30

Slide 30 text

@klickreflex • wentsch.me Dependency Direction Separation of Concerns CSS that depends on HTML. HTML that depends on CSS. Mixing Concerns

Only works for „news“ Independent, reusable CLASses HTML is Restyleable With CSS Restyling needs HTML Change

Slide 31

Slide 31 text

@klickreflex • wentsch.me Reusable CSS vs Restyleable HTML

Slide 32

Slide 32 text

@klickreflex • wentsch.me HTML: Local Scope no side effects Here /

Slide 33

Slide 33 text

@klickreflex • wentsch.me CSS: Global Scope Not that sure 0

Slide 34

Slide 34 text

@klickreflex • wentsch.me Less Fear of Change Less Bloated CSS

Slide 35

Slide 35 text

Modifier Replacement Utilities in a BEM world

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

@klickreflex • wentsch.me

Slide 41

Slide 41 text

@klickreflex • wentsch.me Blasphemy!

Slide 42

Slide 42 text

@klickreflex • wentsch.me Gets the job done

Slide 43

Slide 43 text

@klickreflex • wentsch.me wait a second…

Slide 44

Slide 44 text

@klickreflex • wentsch.me Repetition!

Slide 45

Slide 45 text

@klickreflex • wentsch.me The more a component does, or the more specific a component is, the harder it is to reuse. Adam Wathan CSS Utility Classes and "Separation of Concerns"

Slide 46

Slide 46 text

@klickreflex • wentsch.me maximum Reusability

Slide 47

Slide 47 text

@klickreflex • wentsch.me .mt-0 .mt-8

Slide 48

Slide 48 text

@klickreflex • wentsch.me my-8 .my-12 .mt-0 .mt-8

Slide 49

Slide 49 text

@klickreflex • wentsch.me .text-white .text-blue-darkest

Slide 50

Slide 50 text

@klickreflex • wentsch.me When you choose to author HTML and CSS in a way that seeks to reduce the amount of time you spend writing and editing CSS, it involves accepting that you must instead spend more time changing HTML classes on elements if you want to change their styles. This turns out to be fairly practical, both for front-end and back-end developers – anyone can rearrange pre-built “ Lego Blocks ”; it turns out that no one can perform CSS-alchemy. Nicolas Gallagher About HTML semantics and front-end architecture

Slide 51

Slide 51 text

@klickreflex • wentsch.me

Slide 52

Slide 52 text

@klickreflex • wentsch.me An API for Design Tokens

Slide 53

Slide 53 text

@klickreflex • wentsch.me textSizes: { 'xs': '.75rem', // 12px 'sm': '.875rem', // 14px 'base': '1rem', // 16px 'lg': '1.125rem', // 18px 'xl': '1.25rem', // 20px '2xl': '1.5rem', // 24px '3xl': '1.875rem', // 30px '4xl': '2.25rem', // 36px '5xl': '3rem', // 48px },

Slide 54

Slide 54 text

@klickreflex • wentsch.me margin: { 'auto': 'auto', 'px': '1px', '0': '0', '1': '0.25rem', '2': '0.5rem', '3': '0.75rem', '4': '1rem', '5': '1.25rem', '6': '1.5rem', '8': '2rem', '10': '2.5rem', '12': '3rem', '16': '4rem', '20': '5rem', '24': '6rem', '32': '8rem', },

Slide 55

Slide 55 text

@klickreflex • wentsch.me shadows: { default: '0 2px 4px 0 rgba(0,0,0,0.10)', 'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)', 'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)', 'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)', 'outline': '0 0 0 3px rgba(52,144,220,0.5)', 'none': 'none', },

Slide 56

Slide 56 text

@klickreflex • wentsch.me common language

Slide 57

Slide 57 text

@klickreflex • wentsch.me What does it look like?

Slide 58

Slide 58 text

@klickreflex • wentsch.me youtu.be/MqpzAPEoNUU

Slide 59

Slide 59 text

@klickreflex • wentsch.me What does it Feel like?

Slide 60

Slide 60 text

@klickreflex • wentsch.me

Slide 61

Slide 61 text

@klickreflex • wentsch.me Utilities and Components Not mutually exclusive:

Slide 62

Slide 62 text

@klickreflex • wentsch.me 1. Build with Utilities 2. Abstract Repeating Patterns Utility First

Slide 63

Slide 63 text

@klickreflex • wentsch.me Utility First

Slide 64

Slide 64 text

@klickreflex • wentsch.me .c-button { @apply .rounded .tracking-wide .px-4 .py-2; } .c-button --secondary { @apply .text-white .bg-blue; &:hover { @apply .bg-blue-dark; } } Abstraction Second

Slide 65

Slide 65 text

@klickreflex • wentsch.me Components Modular Sign Up context!

Slide 66

Slide 66 text

@klickreflex • wentsch.me Ways of Abstraction 1. HTML 2. CSS

Slide 67

Slide 67 text

@klickreflex • wentsch.me Abstract in HTML
    {% setcontent news = 'news' limit 3 orderby '-datecreated' allowpaging %} {% for post in news %}
  • {{ post.datecreated|date("d.m.Y") }}

    {{ post.title }}

    {{ post.teaser }}
  • {% endfor %} {{ pager('news', 3, 'partials/_sub_pager_news.twig') }}

Slide 68

Slide 68 text

@klickreflex • wentsch.me Abstract in HTML {% if content.field_hero __title %}

{{ content.field_hero __title }}

{% endif %} {% if content.field_hero __text %}
{{ content.field_hero __text }}
{% endif %}

Slide 69

Slide 69 text

@klickreflex • wentsch.me Abstract in CSS .c-main-menu __link { @apply .py-3; @apply .px-1; @apply .text-white; @apply .block; @screen md { @apply .py-4; @apply .px-4; } &:hover, &:focus { @apply .bg-red-dark; @apply: .no-underline; } }

Slide 70

Slide 70 text

@klickreflex • wentsch.me Abstraction Flowchart

Slide 71

Slide 71 text

@klickreflex • wentsch.me Why ?

Slide 72

Slide 72 text

@klickreflex • wentsch.me .some-component { } @apply text-4xl p-4 bg-grey-lightest; Across Utility Classes and CSS Components Shared Values & Names

Hi 1

Slide 73

Slide 73 text

@klickreflex • wentsch.me .some-component { } @apply text-4xl p-4 bg-grey-lightest; Across Utility Classes and CSS Components Shared Values & Names

Hi 1

the same

Slide 74

Slide 74 text

@klickreflex • wentsch.me

Slide 75

Slide 75 text

@klickreflex • wentsch.me Preprocessor Agnostic PostCSS

Slide 76

Slide 76 text

@klickreflex • wentsch.me Sane Defaults Good Naming, nerdcave.com

Slide 77

Slide 77 text

@klickreflex • wentsch.me Configure Customize & textSizes: { 'base': '1rem', 'lg': '1.125rem', 'xl': '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem', }, .text-base { font-size: 1rem; } .text-lg { font-size: 1.125rem; } .text-xl { font-size: 1.25rem; } .text-2xl { font-size: 1.5rem; } .text-3xl { font-size: 1.875rem; } Default textSizes: { 'tiny': '1rem', 'big': '1.125rem', ‘huge': '1.25rem', 'gigantic': '1.5rem', 'enormous': '1.875rem', }, .text-tiny { font-size: 1rem; } .text-big { font-size: 1.125rem; } .text-hug { font-size: 1.25rem; } .text-gigantic { font-size: 1.5rem; } .text-enormous { font-size: 1.875rem; } Go wild

Slide 78

Slide 78 text

@klickreflex • wentsch.me Documentation great

Slide 79

Slide 79 text

@klickreflex • wentsch.me Functions & Plugins ExtenSible @variants create state and responsive variants of your own utilities config() access raw tailwind configuration values Documentation

Slide 80

Slide 80 text

@klickreflex • wentsch.me WHAT ABOUt Css Feature X?

Slide 81

Slide 81 text

@klickreflex • wentsch.me Custom Properties / CSS variables?

Slide 82

Slide 82 text

@klickreflex • wentsch.me DEFINE Custom Properties in HTML… …Use them in TailWind Config

Slide 83

Slide 83 text

@klickreflex • wentsch.me New Properties? And if i Need

Slide 84

Slide 84 text

@klickreflex • wentsch.me @variants responsive, hover, focus { .banana { fruit: 2; } .apple { fruit: 3; } } @variants directive

Slide 85

Slide 85 text

@klickreflex • wentsch.me @variants responsive, hover, focus { .banana { fruit: 2; } .apple { fruit: 3; } } .banana { fruit: 2 } .apple { fruit: 3 } .hover\:banana:hover { fruit: 2 } .hover\:apple:hover { fruit: 3 } .focus\:banana:focus { fruit: 2 } .focus\:apple:focus { fruit: 3 } @media (min-width: 576px) { .sm\:banana { fruit:2 } .sm\:apple { fruit: 3 } .sm\:hover\:banana:hover { fruit: 2 @variants directive

Slide 86

Slide 86 text

@klickreflex • wentsch.me Find a Plugin…

Slide 87

Slide 87 text

@klickreflex • wentsch.me …Or WRITE it!

Slide 88

Slide 88 text

@klickreflex • wentsch.me Simple Tailwind Plugin module.exports = function (variants) { return function({ addUtilities }) { const boxSizing = { '.border-box': { boxSizing: 'border-box' }, '.content-box': { boxSizing: 'content-box' } } addUtilities(boxSizing, variants) } } require(‘tailwindcss-box-sizing’)({ variants: ['responsive', 'hover'], }), tailwind.config.js tailwind-box-sizing/index.js

Slide 89

Slide 89 text

@klickreflex • wentsch.me CompleMenting Tools 4

Slide 90

Slide 90 text

@klickreflex • wentsch.me www.purgecss.com Remove unused CSS const gulp = require('gulp') const purgecss = require('gulp-purgecss') gulp.task('purgecss', () => { return gulp .src('src/**/*.css') .pipe( purgecss({ content: ['src/**/*.html'] }) ) .pipe(gulp.dest('build/css')) })

Slide 91

Slide 91 text

@klickreflex • wentsch.me www.purgecss.com

Slide 92

Slide 92 text

@klickreflex • wentsch.me www.purgecss.com purged

Slide 93

Slide 93 text

@klickreflex • wentsch.me www.purgecss.com purged & gzipPed

Slide 94

Slide 94 text

@klickreflex • wentsch.me https://hihayk.github.io/ Build color scales

Slide 95

Slide 95 text

@klickreflex • wentsch.me Coding Convenience https://github.com/bradlc/vscode-tailwindcss

Slide 96

Slide 96 text

@klickreflex • wentsch.me Frequent Criticism

Slide 97

Slide 97 text

@klickreflex • wentsch.me “Might as well use inline styles” “It violates separation of concerns” “It bloats the HTML” “BEM is enough” “It’s a whole other language to learn on top of CSS” “It’s unmaintainable” “It’s ugly and hard to read” “It’s not how you write CSS” “It makes it hard to know what’s available to use” “Utility classes should be used along with components” “It makes redesigning/theming a nightmare” “You clutter up your markup with styling directives”

Slide 98

Slide 98 text

@klickreflex • wentsch.me „Might as well Use Inline Styles“

Media Queries Pseudo Classes

"

Consistency Central Changes

Slide 99

Slide 99 text

@klickreflex • wentsch.me „You clutter up your DOM with styling directives“ This is true. But I don't have an argument for why that's bad other than that it is stylistically ugly. Which I agree with. But it's fast to render in the browser. And it also has helped me get dev teams to build responsive interfaces more quickly. And those are the things I care about: Adam Morse Creator of Tachyons Dev velocity and application performance.

Slide 100

Slide 100 text

@klickreflex • wentsch.me “It’s a whole other language to learn on top of CSS” You can’t escape having to use a naming interface between your HTML and CSS Sarah Dayan In Defense of Utility-First CSS Ultimately, functional class names are easier to understand because they describe the style. You know what they do without having to lookup the actual styles, while semantic names force you to either look at the rendering or browse code. 


Slide 101

Slide 101 text

@klickreflex • wentsch.me “Utility classes should be used along with components”

Slide 102

Slide 102 text

@klickreflex • wentsch.me Defending Utility-First 5

Slide 103

Slide 103 text

@klickreflex • wentsch.me ❤ Thanks for your time