-
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!
-
Always use fewer utility classes when possible. For example, use
mx-2instead ofml-2 mr-2and don't be afraid to use the simplerp-4 lg:pt-8instead of the longer, more complicatedpt-4 lg:pt-8 pr-4 pb-4 pl-4. -
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-centerinstead ofblock lg:flex flex-col justify-centerto make it very clear that the flexbox utilities are only applicable at thelg:breakpoint and larger. -
Keep in mind that, by default, all responsive utilities are set to apply at
min-width. That is, thesm:prefix does not apply only to small viewports; it applies to small breakpoints and larger. So for example instead of using the longformblock sm:block md:flex lg:flex xl:flexfor a<div>element you can just writemd:flex. They both have the same behavior. -
Also note that, by default, the
sm:breakpoint does not start atmin-width: 0as you might expect. It starts atmin-width: 640px. So if you want something to apply only to the smallest of viewports (those smaller than640px), you must first set it to apply to all breakpoints and then override it for larger breakpoints. For example, useblock sm:inlineif you want something to appear asblockfor only the smallest of screens. -
Use a consistent pattern of margin classes to make it easier to reason about positioning. For example, consistently use only
mt-*andml-*utilities, which will position the current element, or consistently use onlymb-*andmr-*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. -
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.
-
Do not prematurely use
@applyto 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@applymay be warranted. -
Do not
@applycomponent classes in other components. For example, maintain seperate.btnand.btn-blueclasses rather than using.btn-blue { @apply btn; }
- 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.