Skip to content

Instantly share code, notes, and snippets.

@sandren
Last active October 12, 2024 17:10
Show Gist options
  • Save sandren/0f22e116f01611beab2b1195ab731b63 to your computer and use it in GitHub Desktop.
Save sandren/0f22e116f01611beab2b1195ab731b63 to your computer and use it in GitHub Desktop.
Tailwind CSS best practices

Tailwind CSS best practices

Utility classes

  1. When writing a string of multiple utility classes, always do so in an order with meaning. The "Concentric CSS" approach works well with utility classes (i.e,. 1. positioning/visibility 2. box model 3. borders 4. backgrounds 5. typography 6. other visual adjustments). Once you establish a familiar pattern of ordering, parsing through long strings of utility classes will become much, much faster so a little more effort up front goes a long way!

  2. Always use fewer utility classes when possible. For example, use mx-2 instead of ml-2 mr-2 and don't be afraid to use the simpler p-4 lg:pt-8 instead of the longer, more complicated pt-4 lg:pt-8 pr-4 pb-4 pl-4.

  3. Prefix all utility classes that will only apply at a certain breakpoint with that breakpoint's prefix. For example, use block lg:flex lg:flex-col lg:justify-center instead of block lg:flex flex-col justify-center to make it very clear that the flexbox utilities are only applicable at the lg: breakpoint and larger.

  4. Keep in mind that, by default, all responsive utilities are set to apply at min-width. That is, the sm: prefix does not apply only to small viewports; it applies to small breakpoints and larger. So for example instead of using the longform block sm:block md:flex lg:flex xl:flex for a <div> element you can just write md:flex. They both have the same behavior.

  5. Also note that, by default, the sm: breakpoint does not start at min-width: 0 as you might expect. It starts at min-width: 640px. So if you want something to apply only to the smallest of viewports (those smaller than 640px), you must first set it to apply to all breakpoints and then override it for larger breakpoints. For example, use block sm:inline if you want something to appear as block for only the smallest of screens.

  6. Use a consistent pattern of margin classes to make it easier to reason about positioning. For example, consistently use only mt-* and ml-* utilities, which will position the current element, or consistently use only mb-* and mr-* utilities, which will position adjacent elements. In general it is easier to reason about positioning when using the former pattern because it is effectively scoped to the styled element, but keep in mind that you may need to make exceptions to your selected pattern for elements which only appear under certain conditions, as you wouldn't want to have to also add conditional margins to elements that are adjacent to the conditional element.

  7. Remember that you can often add a wrapper <div> with padding instead of using margins, which may help avoid potential issues with margin collapsing. By using utility-first CSS, you don't need to invent "semantic" class names for single purpose <div>s so there is no reason to avoid using them when they are helpful.

Component classes

  1. Do not prematurely use @apply to abstract component classes where a proper framework/template-based component is more appropriate. However, if the string of utility classes within that component is also used in other components, then there is true duplication. In this case, the creation of a new shared CSS component class with @apply may be warranted.

  2. Do not @apply component classes in other components. For example, maintain seperate .btn and .btn-blue classes rather than using .btn-blue { @apply btn; }

Dynamic classes

  1. When CSS classes are selected or generated dynamically, do not use string concatination to combine fragments of the full class. Instead switch between the complete strings. For example, use this {% set width = maxPerRow == 2 ? 'sm:w-1/2' : 'sm:w-1/3' %} instead of this {% set width = 'sm:w-1/' ~ maxPerRow %}. You always want the complete string of each utility class present in the markup to make it easier to reason about and to ensure that it survives the PurgeCSS process, if it is a part of your build tools.
@ecklf
Copy link

ecklf commented Aug 26, 2019

@sandren two additions based on watching Adams videos:

  1. Either only use mt / ml or mb / mr. Preferably mt / ml since they only affect the current element instead of the next in LTR layouts
    https://youtu.be/0aTRN9CSCY0?t=4648
  2. Use div containers with padding instead of using collapsing margins

@sandren
Copy link
Author

sandren commented Sep 1, 2019

@sandren two additions based on watching Adams videos:

1. Either only use mt / ml or mb / mr. Preferably mt / ml since they only affect the current element instead of the next in LTR layouts
   https://youtu.be/0aTRN9CSCY0?t=4648

2. Use div containers with padding instead of using collapsing margins

Those are great recommendations! Thank you. 🙂

@vinayakkulkarni
Copy link

Is this from @adamwathan's talk at Laracon?

https://youtu.be/J_7_mnFSLDg

@sandren
Copy link
Author

sandren commented Sep 27, 2019

Is this from @adamwathan's talk at Laracon?

Some of them, namely #2 and #7, I believe. @adamwathan agrees with all of my other recommendations though.

@sreez
Copy link

sreez commented Mar 8, 2020

@tmaier
Copy link

tmaier commented Jan 11, 2021

At https://vimeo.com/393580241/82c6d7c5f6 they explain how they organize the divs and which classes go to which of these divs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment