Slide 1

Slide 1 text

Tailwind CSS Rapid designing with utility-first approach

Slide 2

Slide 2 text

Janko Marohnić • Ruby developer • open source contributor • inexperienced in CSS • mainly used Bootstrap

Slide 3

Slide 3 text

Tailwind CSS • utility-first CSS framework • maps closely to CSS properties • PostCSS plugin • created by Adam Wathan in 2017

Slide 4

Slide 4 text

Bootstrap 1 CSS 2 Tailwind 3

Slide 5

Slide 5 text

Utility-First

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

CSS

Slide 8

Slide 8 text

Private Villa
$299 USD per night

Slide 9

Slide 9 text

.vacation-card { width: 16rem; margin: 0 auto; } .vacation-card-info { margin-top: .5rem; } .vacation-card-image { border-radius: .25rem; } .vacation-card-title { font-weight: 700; color: #4a5568; line-height: 1.375; } .vacation-card-eyebrow { font-size: .75rem; color: #718096; text-transform: uppercase; font-weight: 700; } .vacation-card-link:hover { text-decoration: underline; } .vacation-card-price { margin-top: .5rem; font-size: .875rem; color: #718096; }

Slide 10

Slide 10 text

Bootstrap

Slide 11

Slide 11 text

Private Villa
$299 USD per night

Slide 12

Slide 12 text

.vacation-card { width: 16rem; } .vacation-card-eyebrow { font-size: .75rem; color: #718096; } .vacation-card-title { color: #4a5568; line-height: 1.375; } .vacation-card-link:hover { text-decoration: underline; } .vacation-card-price { font-size: .875rem; color: #718096; }

Slide 13

Slide 13 text

Private Villa
$299 USD per night

Slide 14

Slide 14 text

Why?

Slide 15

Slide 15 text

Embraces connection between HTML and CSS 1

Slide 16

Slide 16 text

No need to keep inventing new class names 2 .card-inner-outer-wrapper .container-wrapper-container .box-control-outer-container

Slide 17

Slide 17 text

Localized styling makes changes safer 3

Slide 18

Slide 18 text

Your CSS stops growing 4

Slide 19

Slide 19 text

You’re designing with constraints 5 font-size: .875rem .text-sm color: #feb2b2 .text-red-300 height: 100vh .h-screen

Slide 20

Slide 20 text

Documentation teaches CSS

Slide 21

Slide 21 text

Bootstrap Tailwind .d-block .d-inline-block .d-flex ... .block .inline-block .flex ... .justify-content-start .align-items-center .align-self-center ... .justify-start .items-center .self-center ... .text-uppercase .font-italic .font-weight-bold ... .uppercase .italic .font-bold ... .position-absolute .position-relative ... .absolute .relative ...

Slide 22

Slide 22 text

DRY

Slide 23

Slide 23 text

Apple
Apple
...
Kiwi
Kiwi
...
page1.html page2.html

Slide 24

Slide 24 text

{title}
{text}
...
Card.jsx Card.vue card.erb card.php ... page1.html page2.html

Slide 25

Slide 25 text

{title}
{text}
...
Card.jsx Card.vue card.erb card.php ... page1.html page2.html

Slide 26

Slide 26 text

.btn-blue { background-color: #4299e1; color: white; font-weight: 700; padding: 0.5rem 1rem; border-radius: 0.25rem; } Some Link ... Save

Slide 27

Slide 27 text

.btn-blue { @apply bg-blue-500 text-white font-bold py-2 px-4 rounded; } Some Link ... Save PostCSS directive

Slide 28

Slide 28 text

Spacing & Sizing

Slide 29

Slide 29 text

.vacation-card { margin: 15px; padding: 18em; width: 77%; height: 16rem; }

Slide 30

Slide 30 text

.m-* .mt-* .mb-* .ml-* .mr-* .mx-* .my-* Margin Padding .p-* .pt-* .pb-* .pl-* .pr-* .px-* .py-* Suffix Amount *-0 *-1 *-2 *-3 *-4 *-5 0 0.25rem 0.5rem 1rem 1.5rem 3rem

Slide 31

Slide 31 text

.m-* .mt-* .mb-* .ml-* .mr-* .mx-* .my-* Margin Padding .p-* .pt-* .pb-* .pl-* .pr-* .px-* .py-* Suffix Amount *-0 *-1 *-2 *-3 *-4 *-5 *-6 *-8 *-10 *-12 *-16 *-20 ... *-64 0 0.25rem 0.5rem 1.75rem 1rem 1.25rem 1.5rem 2rem 2.5rem 3rem 4rem 5rem ... 16rem Width .w-* Height .h-*

Slide 32

Slide 32 text

Class Property .w-25 .w-50 .w-75 .w-100 width: 25% width: 50% width: 75% width: 100%

Slide 33

Slide 33 text

Class Property .w-1/2 .w-1/3 .w-2/3 .w-1/4 .w-2/4 .w-3/4 .w-1/5 .w-2/5 .w-3/5 ... .w-11/12 .w-full width: 50% width: 33.333333% width: 66.666667% width: 25% width: 50% width: 75% width: 20% width: 40% width: 60% ... width: 91.66667% width: 100%

Slide 34

Slide 34 text

...
...
...

Slide 35

Slide 35 text

...
...
...

Slide 36

Slide 36 text

...
...
...

Slide 37

Slide 37 text

Phone Number

Slide 38

Slide 38 text

Phone Number

Slide 39

Slide 39 text

module.exports = { theme: { extend: { spacing: { '18': '4.5rem', } } } } ... .m-16 .m-18 .m-20 ... ... .p-16 .p-18 .p-20 ... ... .w-16 .w-18 .w-20 ... ... .h-16 .h-18 .h-20 ... ... 4rem 4.5rem 5rem ... tailwind.config.js

Slide 40

Slide 40 text

module.exports = { theme: { spacing: { 'sm': '8px', 'md': '12px', 'lg': '16px', 'xl': '24px', } } } tailwind.config.js m-sm m-md m-lg m-xl p-sm p-md p-lg m-xl w-sm w-md w-lg w-xl h-sm h-md h-lg h-xl

Slide 41

Slide 41 text

Colors

Slide 42

Slide 42 text

#4b0082 indigo rgb(76, 0, 130) rgba(76, 0, 130, 1.0) hsl(275, 100%, 25%) darken(#4b0082, 10%) lighten(#4b0082, 15%) tint(#4b0082, 20%) shade(#4b0082, 30%) ... ...

Slide 43

Slide 43 text

*-primary *-secondary *-success *-danger *-warning *-info *-light *-dark ... .text-* .bg-* .border-*

Slide 44

Slide 44 text

Taken from Refactoring UI

Slide 45

Slide 45 text

Taken from Refactoring UI

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

.text-red-300 .bg-blue-500 .border-green-700 .btn-indigo { background-color: theme('colors.indigo.500'); } PostCSS function

Slide 48

Slide 48 text

module.exports = { theme: { colors: { indigo: { lighter: '#b3bcf5', default: '#5c6ac4', dark: '#202e78', } } } } tailwind.config.js .text-indigo-lighter .text-indigo-default .text-indigo-dark .bg-indigo-lighter .bg-indigo-default .bg-indigo-dark .border-indigo-lighter .border-indigo-default .border-indigo-dark

Slide 49

Slide 49 text

const { colors } = require('tailwindcss/defaultTheme') module.exports = { theme: { colors: { indigo: { lighter: colors.indigo['300'], default: colors.indigo['500'], dark: colors.indigo['700'], }, blue: { ...colors.blue, '900': '#1e3656', } } } } tailwind.config.js

Slide 50

Slide 50 text

Pseudo-Classes

Slide 51

Slide 51 text

Save .btn-blue { ... } .btn-blue:hover { background-color: #2B6CB0; } .btn-blue:focus { background-color: #2B6CB0; box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5); }

Slide 52

Slide 52 text

Slide 53

Slide 53 text

.hover\:bg-blue-500:hover { background-color: #4299e1; } .focus\:shadow-outline:focus { box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5); } .active\:text-indigo-300:active { color: #a3bffa; }

Slide 54

Slide 54 text

@variants hover, focus { .hyphens-none { hyphens: none; } .hyphens-manual { hyphens: manual; } .hyphens-auto { hyphens: auto; } } PostCSS directive

Slide 55

Slide 55 text

.hyphens-none { hyphens: none; } .hover\:hyphens-none:hover { hyphens: none; } .focus\:hyphens-none:focus { hyphens: none; } .hyphens-manual { hyphens: manual; } .hover\:hyphens-manual:hover { hyphens: manual; } .focus\:hyphens-manual:focus { hyphens: manual; } .hyphens-auto { hyphens: auto; } .hover\:hyphens-auto:hover { hyphens: auto; } .focus\:hyphens-auto:focus { hyphens: auto; }

Slide 56

Slide 56 text

Slide 57

Slide 57 text

Responsive Design

Slide 58

Slide 58 text

@media (min-width: 640px) { ... } @media (min-width: 768px) { ... } @media (min-width: 1024px) { ... } @media (min-width: 1280px) { ... }

Slide 59

Slide 59 text

.col-sm-8 .col-md-6 .col-lg-4 .col-xl-2 .d-sm-block .d-md-inline-block .d-lg-flex .d-xl-none .flex-sm-row .justify-content-md-center .align-items-lg-baseline .align-self-xl-end .row-cols-sm-8 .row-cols-md-6 .row-cols-lg-4 .row-cols-xl-2

Slide 60

Slide 60 text

.d-sm-block .d-md-inline-block .d-lg-flex .d-xl-none

Slide 61

Slide 61 text

.sm:block .md:inline-block .lg:flex .xl:hidden

Slide 62

Slide 62 text

.sm:text-red-500 .md:text-center .lg:text-lg .xl:font-bold .sm:mt-0 .md:px-4 .lg:w-40 .xl:h-24 .sm:self-start .md:justify-center .lg:items-baseline .xl:content-around .sm:border-2 .md:border-blue-500 .lg:border-dashed .xl:rounded-full .sm:grid-cols-2 .md:grid-cols-4 .lg:grid-cols-6 .xl:grid-cols-8 .sm:flex-grow .md:flex-shrink .lg:flex-initial .xl:flex-auto .sm:bg-gray-100 .md:bg-fixed .lg:bg-opacity-50 .xl:bg-left .sm:transition .md:duration-100 .lg:scale-50 .xl:translate-100 .sm:block .md:inline-block .lg:flex .xl:hidden

Slide 63

Slide 63 text

  • Foo
  • Bar
  • Baz

Slide 64

Slide 64 text

@responsive { .hyphens-none { hyphens: none; } .hyphens-manual { hyphens: manual; } .hyphens-auto { hyphens: auto; } } PostCSS directive

Slide 65

Slide 65 text

@media (min-width: 640px) { .sm\:hyphens-none { hyphens: none; } .sm\:hyphens-manual { hyphens: manual; } .sm\:hyphens-auto { hyphens: auto; } } @media (min-width: 768px) { .md\:hyphens-none { hyphens: none; } .md\:hyphens-manual { hyphens: manual; } .md\:hyphens-auto { hyphens: auto; } } @media (min-width: 1024px) { .lg\:hyphens-none { hyphens: none; } .lg\:hyphens-manual { hyphens: manual; } .lg\:hyphens-auto { hyphens: auto; } } @media (min-width: 1280px) { .xl\:hyphens-none { hyphens: none; } .xl\:hyphens-manual { hyphens: manual; } .xl\:hyphens-auto { hyphens: auto; } }

Slide 66

Slide 66 text

Slide 67

Slide 67 text

Bundle Size

Slide 68

Slide 68 text

~1.8MB uncompressed ~148KB minified and compressed with Gzip ~44KB compressed with Brotli

Slide 69

Slide 69 text

PurgeCSS 1

Slide 70

Slide 70 text

module.exports = { purge: [ 'src/**/*.html', 'src/**/*.vue', 'src/**/*.jsx', ], theme: {}, variants: {}, plugins: [], } tailwind.config.js

Slide 71

Slide 71 text

You must list all files in your project that reference any of Tailwind class names ! You must not use string concatenation to create class names ! ✕

Slide 72

Slide 72 text

Reducing features 2

Slide 73

Slide 73 text

module.exports = { theme: { borderColor: theme => ({ 'green': theme('colors.green.300') }), divideColor: theme => ({ 'green': theme('colors.green.300') }), translate: { '1': '0.25rem' }, }, corePlugins: [ 'placeholderColor', 'placeholderOpacity', 'textOpacity', 'skew', 'scale', 'rotate', 'gap', 'gridColumn', 'gridColumnStart', 'gridColumnEnd', 'gridRow', 'gridRowStart', 'gridRowEnd', ].reduce((list, plugin) => ({ [plugin]: false, ...list }), {}), variants: { textColor: ['hover', 'focus'], backgroundColor: ['hover', 'focus'], borderRadius: [], borderOpacity: ['hover', 'focus'], transitionDuration: [], transitionDelay: [], }, } tailwind.config.js

Slide 74

Slide 74 text

0 450 900 1350 1800 Uncompressed Gzip Original Reduced 1800K 400K 148KB 56K

Slide 75

Slide 75 text

Recap • maps closely to CSS • naming optimized for writing • generous defaults (colors, spacing) • pseudo-class & responsive variants (for each class) • PostCSS directives & functions • advanced JavaScript-based configuration

Slide 76

Slide 76 text

Resources • https://tailwindcss.com/docs • https://tailwindcss.com/screencasts • https://tailwindcss-custom-forms.netlify.app/ • https://marketplace.visualstudio.com/items?itemName=bradlc.vscode- tailwindcss • https://github.com/aniftyco/awesome-tailwindcss • https://adamwathan.me/css-utility-classes-and-separation-of-concerns/ • Adam Wathan’s YouTube channel • Steve Schoger's design tips