Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Taking Flight with Tailwind CSS

Taking Flight with Tailwind CSS

Oliver Davies

May 11, 2024
Tweet

More Decks by Oliver Davies

Other Decks in Technology

Transcript

  1. What is utility-first CSS? • A different way to write

    CSS. • Instead of writing CSS in separate files, you work primarily in HTML. • Small CSS classes with a single responsibility. • Classes are named by what they do, not where they are used. @opdavies
  2. 1 h1 { 2 font-size: 3rem; 3 font-weight: bold; 4

    color: #020617; /* Dark grey */ 5 padding: .5rem 0 2rem; 6 } @opdavies
  3. 1 h1 { 2 font-size: 3rem; 3 font-weight: bold; 4

    color: #020617; /* Dark grey */ 5 padding: .5rem 0 2rem; 6 } 7 8 .card { 9 padding: 2rem; 10 } 11 12 .card p { 13 color: #020617; /* Dark grey */ 14 font-size: 3rem; 15 font-weight: bold; 16 } @opdavies
  4. 1 h1 { 2 font-size: 3rem; 3 font-weight: bold; 4

    color: #020617; /* Dark grey */ 5 padding: .5rem 0 2rem; 6 } 7 8 .card { 9 padding: 2rem; 10 } 11 12 .card p { 13 color: #020617; /* Dark grey */ 14 font-size: 3rem; 15 font-weight: bold; 16 } @opdavies
  5. 1 h1 { 2 font-size: 3rem; 3 font-weight: bold; 4

    color: #020617; /* Dark grey */ 5 padding: .5rem 0 2rem; 6 } 7 8 .card { 9 padding: 2rem; 10 } 11 12 .card p { 13 color: #020617; /* Dark grey */ 14 font-size: 3rem; 15 font-weight: bold; 16 } @opdavies
  6. 1 h1 { 2 font-size: 3rem; 3 font-weight: bold; 4

    color: #020617; /* Dark grey */ 5 padding: .5rem 0 2rem; 6 } 7 8 .card { 9 padding: 2rem; 10 } 11 12 .card p { 13 color: #020617; /* Dark grey */ 14 font-size: 3rem; 15 font-weight: bold; 16 } @opdavies
  7. 1 h1 { 2 font-size: 3rem; 3 font-weight: bold; 4

    color: #020617; /* Dark grey */ 5 padding: .5rem 0 2rem; 6 } 7 8 .card { 9 padding: 2rem; 10 } 11 12 .card p { 13 color: #020617; /* Dark grey */ 14 font-size: 3rem; 15 font-weight: bold; 16 } @opdavies
  8. 1 .font-bold { 2 font-weight: bold; 3 } 4 5

    .text-slate-900 { 6 color: #020617; 7 } 8 9 .text-5xl { 10 text-size: 3rem; 11 } 12 13 .flex { 14 display: flex; 15 } @opdavies
  9. 1 .font-bold { 2 font-weight: bold; 3 } 4 5

    .text-slate-900 { 6 color: #020617; 7 } 8 9 .text-5xl { 10 text-size: 3rem; 11 } 12 13 .flex { 14 display: flex; 15 } @opdavies
  10. 1 .font-bold { 2 font-weight: bold; 3 } 4 5

    .text-slate-900 { 6 color: #020617; 7 } 8 9 .text-5xl { 10 text-size: 3rem; 11 } 12 13 .flex { 14 display: flex; 15 } @opdavies
  11. 1 .font-bold { 2 font-weight: bold; 3 } 4 5

    .text-slate-900 { 6 color: #020617; 7 } 8 9 .text-5xl { 10 text-size: 3rem; 11 } 12 13 .flex { 14 display: flex; 15 } @opdavies
  12. 1 .font-bold { 2 font-weight: bold; 3 } 4 5

    .text-slate-900 { 6 color: #020617; 7 } 8 9 .text-5xl { 10 text-size: 3rem; 11 } 12 13 .flex { 14 display: flex; 15 } @opdavies
  13. What problems does this solve? • You don't waste time

    and energy inventing class names. • No switching between CSS and HTML files. • Your CSS stops growing. • Reusability. • Making changes feels (and is) safer. @opdavies
  14. • Text/border/background colours • Font size/family/weight • Alignment • Padding/margin/negative

    margin • Flexbox • Positioning • Lists • z-index • Opacity @opdavies
  15. • Screenreader visibility • Placeholder colour • first-child, last-child, nth-child

    • CSS Grid • Transition • Transform • Spacing / Divide • Focus ring • Text clamping @opdavies
  16. Interaction states in CSS 1 .text-red-500 { 2 color: #f56565;

    3 } 4 5 .hover\:text-red-500:hover { 6 color: #f56565; 7 } 8 9 .focus\:text-red-500:focus { 10 color: #f56565; 11 } @opdavies
  17. Interaction states in CSS 1 .text-red-500 { 2 color: #f56565;

    3 } 4 5 .hover\:text-red-500:hover { 6 color: #f56565; 7 } 8 9 .focus\:text-red-500:focus { 10 color: #f56565; 11 } @opdavies
  18. Interaction states in CSS 1 .text-red-500 { 2 color: #f56565;

    3 } 4 5 .hover\:text-red-500:hover { 6 color: #f56565; 7 } 8 9 .focus\:text-red-500:focus { 10 color: #f56565; 11 } @opdavies
  19. Interaction states in CSS 1 .text-red-500 { 2 color: #f56565;

    3 } 4 5 .hover\:text-red-500:hover { 6 color: #f56565; 7 } 8 9 .focus\:text-red-500:focus { 10 color: #f56565; 11 } @opdavies
  20. Interaction states in HTML 1 <a 2 href="#" 3 class="text-red-500

    hover:text-red-800" 4 > 5 Read more 6 </a> @opdavies
  21. Interaction states in HTML 1 <a 2 href="#" 3 class="text-red-500

    hover:text-red-800" 4 > 5 Read more 6 </a> @opdavies
  22. Screens (aka breakpoints) 1 // defaultConfig.stub.js 2 3 screens: {

    4 sm: '640px', 5 md: '768px', 6 lg: '1024px', 7 xl: '1280px', 8 }, @opdavies
  23. Responsive classes in CSS 1 .block { 2 display: block;

    3 } 4 5 @media (min-width: 640px) { 6 .sm\:block { 7 display: block; 8 } 9 } @opdavies
  24. Responsive classes in CSS 1 .block { 2 display: block;

    3 } 4 5 @media (min-width: 640px) { 6 .sm\:block { 7 display: block; 8 } 9 } @opdavies
  25. Responsive classes in CSS 1 .block { 2 display: block;

    3 } 4 5 @media (min-width: 640px) { 6 .sm\:block { 7 display: block; 8 } 9 } @opdavies
  26. Responsive classes in HTML 1 <div class="block md:flex"> 2 <div

    class="w-full md:w-1/2"> 3 Column 1 4 </div> 5 6 <div class="w-full md:w-1/2"> 7 Column 2 8 </div> 9 </div> @opdavies
  27. Responsive classes in HTML 1 <div class="block md:flex"> 2 <div

    class="w-full md:w-1/2"> 3 Column 1 4 </div> 5 6 <div class="w-full md:w-1/2"> 7 Column 2 8 </div> 9 </div> @opdavies
  28. Responsive classes in HTML 1 <div class="block md:flex"> 2 <div

    class="w-full md:w-1/2"> 3 Column 1 4 </div> 5 6 <div class="w-full md:w-1/2"> 7 Column 2 8 </div> 9 </div> @opdavies
  29. Loops 1 {% for item in navItems %} 2 <a

    3 class="block py-3 px-4 text-sm text-gray-800" 4 href="{{ item.url }}" 5 > 6 {{ item.title }} 7 </a> 8 {% endfor %} @opdavies
  30. Loops 1 {% for item in navItems %} 2 <a

    3 class="block py-3 px-4 text-sm text-gray-800" 4 href="{{ item.url }}" 5 > 6 {{ item.title }} 7 </a> 8 {% endfor %} @opdavies
  31. Loops 1 {% for item in navItems %} 2 <a

    3 class="block py-3 px-4 text-sm text-gray-800" 4 href="{{ item.url }}" 5 > 6 {{ item.title }} 7 </a> 8 {% endfor %} @opdavies
  32. Loops 1 {navItems.map(item => ( 2 <a 3 class="block py-3

    px-4 text-sm text-gray-800" 4 href={item.url} 5 > 6 {item.title} 7 </a> 8 ))} @opdavies
  33. Loops 1 {navItems.map(item => ( 2 <a 3 class="block py-3

    px-4 text-sm text-gray-800" 4 href={item.url} 5 > 6 {item.title} 7 </a> 8 ))} @opdavies
  34. Loops 1 {navItems.map(item => ( 2 <a 3 class="block py-3

    px-4 text-sm text-gray-800" 4 href={item.url} 5 > 6 {item.title} 7 </a> 8 ))} @opdavies
  35. Includes 1 <h2>Adults</h2> 2 3 {% include 'class-list' with {

    4 classes: page.classes, 5 type: 'adults', 6 } %} 7 8 <h2>Kids</h2> 9 10 {% include 'class-list' with { 11 classes: page.classes, 12 type: 'kids', 13 } %} @opdavies
  36. Includes 1 <h2>Adults</h2> 2 3 <ClassList classes={classes} type="kids" /> 4

    5 <h2>Kids</h2> 6 7 <ClassList classes={classes} type="adults" /> @opdavies
  37. Content Tell Tailwind where it should look for utility classes.

    1 // tailwind.config.js 2 3 module.exports = { 4 content: ['./templates/**/*.twig'], 5 // ... 6 } @opdavies
  38. tailwind.config.js 1 /** @type {import('tailwindcss').Config} */ 2 module.exports = {

    3 content: [], 4 theme: { 5 extend: {}, 6 }, 7 plugins: [], 8 } @opdavies
  39. Overriding configuration 1 /** @type {import('tailwindcss').Config} */ 2 module.exports =

    { 3 content: [], 4 theme: { 5 colors: { 6 inherit: 'inherit' 7 }, 8 extend: {}, 9 }, 10 plugins: [], 11 } @opdavies
  40. Extending configuration 1 /** @type {import('tailwindcss').Config} */ 2 module.exports =

    { 3 content: [], 4 theme: { 5 extend: { 6 colors: { 7 inherit: 'inherit' 8 } 9 }, 10 }, 11 plugins: [], 12 } @opdavies
  41. Including Tailwind 1 /* src/css/tailwind.pcss */ 2 3 @tailwind base;

    4 5 @tailwind components; 6 7 @tailwind utilities; @opdavies
  42. Adding your own classes 1 /* src/css/tailwind.pcss */ 2 3

    @tailwind base; 4 /* Custom base styles */ 5 6 @tailwind components; 7 /* Custom components */ 8 9 @tailwind utilities; 10 /* Custom utilities */ @opdavies
  43. Adding your own classes 1 /* src/css/tailwind.pcss */ 2 3

    @tailwind base; 4 /* Custom base styles */ 5 6 @tailwind components; 7 /* Custom components */ 8 9 @tailwind utilities; 10 /* Custom utilities */ @opdavies
  44. Adding your own classes 1 /* src/css/tailwind.pcss */ 2 3

    @tailwind base; 4 /* Custom base styles */ 5 6 @tailwind components; 7 /* Custom components */ 8 9 @tailwind utilities; 10 /* Custom utilities */ @opdavies
  45. Adding your own classes 1 /* src/css/tailwind.pcss */ 2 3

    @tailwind base; 4 /* Custom base styles */ 5 6 @tailwind components; 7 /* Custom components */ 8 9 @tailwind utilities; 10 /* Custom utilities */ @opdavies
  46. Adding your own classes (with layers) 1 /* src/css/tailwind.pcss */

    2 3 @tailwind base; 4 @tailwind components; 5 @tailwind utilities; 6 7 @layer components { 8 /* Custom components */ 9 } @opdavies
  47. Adding your own classes (with layers) 1 /* src/css/tailwind.pcss */

    2 3 @tailwind base; 4 @tailwind components; 5 @tailwind utilities; 6 7 @layer components { 8 /* Custom components */ 9 } @opdavies
  48. Adding your own classes (with layers) 1 /* src/css/tailwind.pcss */

    2 3 @tailwind base; 4 @tailwind components; 5 @tailwind utilities; 6 7 @layer components { 8 /* Custom components */ 9 } @opdavies
  49. Adding a plugin 1 // tailwind.config.js 2 3 module.exports =

    { 4 theme: { 5 extend: {}, 6 }, 7 plugins: [ 8 require('tailwindcss-list-reset')() 9 ], 10 variants: {}, 11 } @opdavies
  50. Adding a plugin 1 // tailwind.config.js 2 3 module.exports =

    { 4 theme: { 5 extend: {}, 6 }, 7 plugins: [ 8 require('tailwindcss-list-reset')() 9 ], 10 variants: {}, 11 } @opdavies
  51. Writing plugins 1 const plugin = require("tailwindcss/plugin"); 2 3 module.exports

    = plugin(function({ addUtilities }) { 4 5 }) 6 @opdavies
  52. Writing plugins 1 const plugin = require("tailwindcss/plugin"); 2 3 module.exports

    = plugin(function({ addUtilities }) { 4 addUtilities({ 5 '.list-reset': { 6 listStyle: 'none', 7 padding: 0, 8 }, 9 }) 10 }) 11 @opdavies
  53. Writing plugins Adding child and child-hover variants: 1 const plugin

    = require('tailwindcss/plugin'); 2 3 module.exports = plugin(({ addVariant }) => { 4 addVariant('child', '& > *'); 5 addVariant('child-hover', '& > *:hover'); 6 }); @opdavies
  54. Writing plugins Adding a hocus variant: 1 const plugin =

    require('tailwindcss/plugin'); 2 3 module.exports = plugin(({ addVariant }) => { 4 addVariant('hocus', ['&:hover', '&:focus']); 5 }); @opdavies
  55. Disabling the reset styles 1 /** @type {import('tailwindcss').Config} */ 2

    module.exports = { 3 content: [], 4 theme: { 5 extend: {}, 6 }, 7 corePlugins: { 8 preflight: false, 9 }, 10 plugins: [], 11 } @opdavies
  56. Prefixing class names Turn classes like flex into tw-flex. 1

    /** @type {import('tailwindcss').Config} */ 2 module.exports = { 3 prefix: "tw-", 4 content: [], 5 theme: { 6 extend: {}, 7 }, 8 plugins: [], 9 } @opdavies
  57. !important 1 /** @type {import('tailwindcss').Config} */ 2 module.exports = {

    3 important: true, 4 content: [], 5 theme: { 6 extend: {}, 7 }, 8 plugins: [], 9 } @opdavies
  58. !important 1 /** @type {import('tailwindcss').Config} */ 2 module.exports = {

    3 important: "#app", 4 content: [], 5 theme: { 6 extend: {}, 7 }, 8 plugins: [], 9 } @opdavies