Rapid designing with Tailwind CSS

Rapid designing with Tailwind CSS

Component-focused CSS frameworks such as Bootstrap get you up and running quickly, but often lack the tools necessary for designing custom interfaces. For this people usually just use plain (S)CSS, which gets the job done but can become difficult to maintain in the long run.

Enter Tailwind, a utility-first CSS framework that approaches building complex components from a constrained set of primitive utilities. What sets Tailwind apart is the vast range of CSS properties it covers, a powerful PostCSS-backed configuration API and excellent documentation that explains CSS along the way. This talk will show Tailwind's unique approach to various aspects of design (spacing, colors, pseudo-classes, responsive design and more) and compare it with existing solutions.

376e4eb9dc6c2e33d1330262edc4f109?s=128

Janko Marohnić

May 29, 2020
Tweet

Transcript

  1. 2.

    Janko Marohnić • Ruby developer • open source contributor •

    inexperienced in CSS • mainly used Bootstrap
  2. 3.

    Tailwind CSS • utility-first CSS framework • maps closely to

    CSS properties • PostCSS plugin • created by Adam Wathan in 2017
  3. 6.
  4. 7.

    CSS

  5. 8.

    <div class="vacation-card"> <img class="vacation-card-image" src="..."> <div class="vacation-card-info"> <div class="vacation-card-eyebrow"> Private

    Villa </div> <div class="vacation-card-title"> <a href="..." class="vacation-card-link"> Relaxing All-Inclusive Resort in Cancun </a> </div> <div class="vacation-card-price"> $299 USD per night </div> </div> </div>
  6. 9.

    .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; }
  7. 10.
  8. 11.

    <div class="vacation-card mx-auto"> <img class="rounded" src="..."> <div class="mt-2"> <div class="vacation-card-eyebrow

    text-uppercase font-weight-bold"> Private Villa </div> <div class="vacation-card-title font-weight-bold"> <a href="..." class="vacation-card-link"> Relaxing All-Inclusive Resort in Cancun </a> </div> <div class="vacation-card-price mt-2"> $299 USD per night </div> </div> </div>
  9. 12.

    .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; }
  10. 13.

    <div class="w-64 mx-auto"> <img class="rounded" src="..."> <div class="mt-2"> <div class="text-xs

    text-gray-600 uppercase font-bold"> Private Villa </div> <div class="font-bold text-gray-700 leading-snug"> <a href="..." class="hover:underline"> Relaxing All-Inclusive Resort in Cancun </a> </div> <div class="mt-2 text-sm text-gray-600"> $299 USD per night </div> </div> </div>
  11. 14.
  12. 16.

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

    .container-wrapper-container .box-control-outer-container
  13. 21.

    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 ...
  14. 22.

    DRY

  15. 23.

    <div class="card"> <img class="card-img-top" src="/apple"> <div class="card-body"> <div class="card-title">Apple</div> <div

    class="card-text">Apple</div> ... </div> </div> <div class="card"> <img class="card-img-top" src="/kiwi"> <div class="card-body"> <div class="card-title">Kiwi</div> <div class="card-text">Kiwi</div> ... </div> </div> page1.html page2.html
  16. 24.

    <div class="card"> <img class="card-img-top" src={img}> <div class="card-body"> <div class="card-title">{title}</div> <div

    class="card-text">{text}</div> ... </div> </div> <Card img="/apple" title="Apple" text="Apple" /> Card.jsx Card.vue card.erb card.php ... page1.html <Card img="/kiwi" title="Kiwi" text="Kiwi" /> page2.html
  17. 25.

    <div class="flex rounded bg-white shadow-sm"> <img class="rounded-t w-full" src={img}> <div

    class="flex-auto p-4 break-words"> <div class="mb-3">{title}</div> <div class="break-words">{text}</div> ... </div> </div> <Card img="/apple" title="Apple" text="Apple" /> Card.jsx Card.vue card.erb card.php ... page1.html <Card img="/kiwi" title="Kiwi" text="Kiwi" /> page2.html
  18. 26.

    .btn-blue { background-color: #4299e1; color: white; font-weight: 700; padding: 0.5rem

    1rem; border-radius: 0.25rem; } <a href="..." class="btn-blue">Some Link</a> <form ...> ... <button type="submit" class="btn-blue">Save</button> </form>
  19. 27.

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

    <a href="..." class="btn-blue">Some Link</a> <form ...> ... <button type="submit" class="btn-blue">Save</button> </form> PostCSS directive
  20. 30.

    .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
  21. 31.

    .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-*
  22. 33.

    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%
  23. 39.

    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
  24. 40.

    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
  25. 41.
  26. 42.

    #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%) ... ...
  27. 46.
  28. 48.

    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
  29. 49.

    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
  30. 51.

    <button class="btn-blue">Save</button> .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); }
  31. 53.

    .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; }
  32. 54.

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

    { hyphens: manual; } .hyphens-auto { hyphens: auto; } } PostCSS directive
  33. 55.

    .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; }
  34. 58.

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

    ... } @media (min-width: 1024px) { ... } @media (min-width: 1280px) { ... }
  35. 59.

    .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
  36. 62.

    .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
  37. 64.

    @responsive { .hyphens-none { hyphens: none; } .hyphens-manual { hyphens:

    manual; } .hyphens-auto { hyphens: auto; } } PostCSS directive
  38. 65.

    @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; } }
  39. 70.
  40. 71.

    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 ! ✕ <div class="text-{error ? 'red' : 'green'}-600"></div> <div class="{error ? 'text-red-600' : 'text-green-600'}"></div> ✓
  41. 73.

    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
  42. 75.

    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
  43. 76.

    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