Tag: Classes

How to Cycle Through Classes on an HTML Element

Say you have three HTML classes, and a DOM element should only have one of them at a time:

<div class="state-1"></div> <div class="state-2"></div> <div class="state-3"></div>

Now your job is to rotate them. That is, cycle through classes on an HTML element. When some event occurs, if the element has state-1 on it, remove state-1 and add state-2. If it has state-2 on it, remove that and add state-3. On the last state, remove it, and cycle back to state-1.

Example of how to Cycle Through Classes on an HTML Element. Here a large <button> with an <svg> inside cycles through state-1, state-2, and state-3 classes, turning from red to yellow to green.

It’s notable that we’re talking about 3+ classes here. The DOM has a .classList.toggle() function, even one that takes a conditional as a second parameter, but that’s primarily useful in a two-class on/off situation, not cycling through classes.

Why? There is a number of reasons. Changing a class name gives you lots of power to re-style things in the DOM, and state management like that is a cornerstone of modern web development. But to be specific, in my case, I was wanting to do FLIP animations where I’d change a layout and trigger a tween animation between the different states.

Careful about existing classes! I saw some ideas that overwrote .className, which isn’t friendly toward other classes that might be on the DOM element. All these are “safe” choices for cycling through classes in that way.

Because this is programming, there are lots of ways to get this done. Let’s cover a bunch of them — for fun. I tweeted about this issue, so many of these solutions are from people who chimed into that discussion.

A verbose if/else statement to cycle through classes

This is what I did at first to cycle through classes. That’s how my brain works. Just write out very specific instructions for exactly what you want to happen:

if (el.classList.contains("state-1")) {   el.classList.remove("state-1");   el.classList.add("state-2"); } else if (el.classList.contains("state-2")) {   el.classList.remove("state-2");   el.classList.add("state-3"); } else {   el.classList.remove("state-3");   el.classList.add("state-1"); }

I don’t mind the verbosity here, because to me it’s super clear what’s going on and will be easy to return to this code and “reason about it,” as they say. You could consider the verbosity a problem — surely there is a way to cycle through classes with less code. But a bigger issue is that it isn’t very extensible. There is no semblance of configuration (e.g. change the names of the classes easily) or simple way to add classes to the party, or remove them.

We could use constants, at least:

const STATE_1 = "state-1"; const STATE_2 = "state-2"; const STATE_3 = "state-3";  if (el.classList.contains(STATE_1)) {   el.classList.remove(STATE_1);   el.classList.add(STATE_2); } else if (el.classList.contains(STATE_2)) {   el.classList.remove(STATE_2);   el.classList.add(STATE_3); } else {   el.classList.remove(STATE_3);   el.classList.add(STATE_1); }

But that’s not wildly different or better.

RegEx off the old class, increment state, then re-add

This one comes from Tab Atkins. Since we know the format of the class, state-N, we can look for that, pluck off the number, use a little ternary to increment it (but not higher than the highest state), then add/remove the classes as a way of cycling through them:

const oldN = +/bstate-(d+)b/.exec(el.getAttribute('class'))[1]; const newN = oldN >= 3 ? 1 : oldN+1; el.classList.remove(`state-$ {oldN}`); el.classList.add(`state-$ {newN}`);

Find the index of the class, then remove/add

A bunch of techniques to cycle through classes center around setting up an array of classes up front. This acts as configuration for cycling through classes, which I think is a smart way to do it. Once you have that, you can find the relevant classes for adding and removing them. This one is from Christopher Kirk-Nielsen:

const classes = ["state-1", "state-2", "state-3"]; const activeIndex = classes.findIndex((c) => el.classList.contains(c)); const nextIndex = (activeIndex + 1) % classes.length;  el.classList.remove(classes[activeIndex]); el.classList.add(classes[nextIndex]);

Christopher had a nice idea for making the add/remove technique shorter as well. Turns out it’s the same…

el.classList.remove(classes[activeIndex]); el.classList.add(classes[nextIndex]);  // Does the same thing. el.classList.replace(classes[activeIndex], classes[nextIndex]);

Mayank had a similar idea for cycling through classes by finding the class in an array, only rather than using classList.contains(), you check the classes currently on the DOM element with what is in the array.

const states = ["state-1", "state-2", "state-3"]; const current = [...el.classList].find(cls => states.includes(cls)); const next = states[(states.indexOf(current) + 1) % states.length]; el.classList.remove(current); el.classList.add(next);

Variations of this were the most common idea. Here’s Jhey’s and here’s Mike Wagz which sets up functions for moving forward and backward.

Cascading replace statements

Speaking of that replace API, Chris Calo had a clever idea where you chain them with the or operator and rely on the fact that it returns true/false if it works or doesn’t. So you do all three and one of them will work!

 el.classList.replace("state-1", "state-2") ||  el.classList.replace("state-2", "state-3") ||  el.classList.replace("state-3", "state-1");

Nicolò Ribaudo came to the same conclusion.

Just cycle through class numbers

If you pre-configured a 1 upfront, you could cycle through classes 1-3 and add/remove them based on that. This is from Timothy Leverett who lists another similar option in the same tweet.

// Assumes a `let s = 1` upfront el.classList.remove(`state-$ {s + 1}`); s = (s + 1) % 3; el.classList.add(`state-$ {s + 1}`);

Use data-* attributes instead

Data attributes have the same specificity power, so I have no issue with this. They might actually be more clear in terms of state handling, but even better, they have a special API that makes them nice to manipulate. Munawwar Firoz had an idea that gets this down to a one-liner:

el.dataset.state = (+el.dataset.state % 3) + 1

A data attribute state machine

You can count on David Khourshid to be ready with a state machine:

const simpleMachine = {   "1": "2",   "2": "3",   "3": "1" }; el.dataset.state = simpleMachine[el.dataset.state];

You’ll almost surely want a function

Give yourself a little abstraction, right? Many of the ideas wrote code this way, but so far I’ve move it out to focus on the idea itself. Here, I’ll leave the function in. This one is from Andrea Giammarchi in which a unique function for cycling through classes is set up ahead of time, then you call it as needed:

const rotator = (classes) => ({ classList }) => {   const current = classes.findIndex((cls) => classList.contains(cls));   classList.remove(...classes);   classList.add(classes[(current + 1) % classes.length]); };  const rotate = rotator(["state-1", "state-2", "state-3"]); rotate(el);

I heard from Kyle Simpson who had this same idea, almost character for character.

Others?

There were more ideas in the replies to my original tweet, but are, best I can tell, variations on what I’ve already shared above. Apologies if I missed yours! Feel free to share your idea again in the comments here. I see nobody used a switch statements — that could be a possibility!

David Desandro went as far as recording a video, which is wonderful as it slowly abstracts the concepts further and further until it’s succinct but still readable and much more flexible:

And here’s a demo Pen with all the code for each example in there. They are numbered, so to test out another one, comment out the one that is uncommented, and uncomment another example:


How to Cycle Through Classes on an HTML Element originally published on CSS-Tricks. You should get the newsletter and become a supporter.

CSS-Tricks

, , , ,

Inline Styles as Classes (lol)

If you’re abhorred by using inline styles, just move that style to the class attribute! And then make sure you have CSS in place that, ya know, does what it says on the box.

OK lemme dig in and totally ruin the joke.

  • First off, it’s a joke, so don’t actually do this. I don’t even mind the occasional inline style for one-off stuff, but this is not that.
  • To me the weirdest part is that period (.) character. Escaping the more unusual characters with a backslash () feels normal, but what is that period about?
  • The little period trick there doesn’t work when the following character is a number (e.g. .padding:.1rem;).
  • You can avoid the escaping and trickery if you go with an attribute selector like [class*="display: flex;"].
  • This reminds me of Mathias Bynens’ research: CSS character escape sequences. But… that doesn’t seem to work anymore? I wonder if browsers changed or if the tool broke and doesn’t output what it should anymore (e.g. does .color3a #bada55; look right?).

Here’s all that playing around:


The post Inline Styles as Classes (lol) appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, ,
[Top]

Detect Unused Classes in… HTML

Usually, when “unused” comes up in conversation regarding CSS, it’s about removing chunks of CSS that are not used in your site or, at least, the styles not currently in use on a specific page. The minimal amount of CSS is best! I’ve written about how this is a hard problem in the past. In JavaScript-land, the equivalent is tree shaking (removing unusued JavaScript).

But what about the other way around, detecting classes in HTML that aren’t used in your CSS? If you knew this for sure, you could clean up your markup, removing classes that don’t do anything.

I saw Robert Kieffer post a Gist the other day with an interesting solution. The idea is to load up document.styleSheets and find all the rules (the ones that are classes). Then, use a MutationObserver to watch the DOM for all HTML, and check the classList of each node to see if it matches any from any stylesheet. If the HTML has a class not found in a stylesheet, report it.

I gave it a quick whirl and got it working and correctly reporting unused classes:

Your mileage may vary. For one thing, this script is set up as an ES Module. That means if you just import it and run it on a regular ol’ HTML document, it won’t find anything because your <script type="module"> is deferred and the MutationObserver won’t pick anything up. I just un-moduled it and put it in the <head> to make my demo work.

I Netlify Dropped the site online in case you wanna dig into it and check it out. I would have used CodePen, but CodePen doesn’t link up your styles as <link>ed stylesheets (by default, but you could use external resources to do that). I just thought it would be more clear as a deployed site.

Careful now.

Just like unused CSS is a hard problem because of how hard it is to know for sure know if a ruleset is unused, this approach may be an even harder problem. For one thing, classes might be used as a JavaScript hook for things. Styles might get injected onto the page in <style> blocks, which this script wouldn’t check. Heck, you might have integration tests that run in CI that use classes to do testing-related things.

I’d say this kind of thing is a useful tool for havin’ a looksie at classes that you have a hunch might be unused. But I wouldn’t say there’s a permission slip to run this thing and then yank out every reported class without further investigation.


The post Detect Unused Classes in… HTML appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Building a Scalable CSS Architecture With BEM and Utility Classes

Maintaining a large-scale CSS project is hard. Over the years, we’ve witnessed different approaches aimed at easing the process of writing scalable CSS. In the end, we all try to meet the following two goals:

  1. Efficiency: we want to reduce the time spent thinking about how things should be done and increase the time doing things.
  2. Consistency: we want to make sure all developers are on the same page.

For the past year and a half, I’ve been working on a component library and a front-end framework called CodyFrame. We currently have 220+ components. These components are not isolated modules: they’re reusable patterns, often merged into each other to create complex templates.

The challenges of this project have forced our team to develop a way of building scalable CSS architectures. This method relies on CSS globals, BEM, and utility classes.

I’m happy to share it! 👇

CSS Globals in 30 seconds

Globals are CSS files containing rules that apply crosswise to all components (e.g., spacing scale, typography scale, colors, etc.). Globals use tokens to keep the design consistent across all components and reduce the size of their CSS.

Here’s an example of typography global rules:

/* Typography | Global */ :root {   /* body font size */   --text-base-size: 1em; 
   /* type scale */   --text-scale-ratio: 1.2;   --text-xs: calc((1em / var(--text-scale-ratio)) / var(--text-scale-ratio));   --text-sm: calc(var(--text-xs) * var(--text-scale-ratio));   --text-md: calc(var(--text-sm) * var(--text-scale-ratio) * var(--text-scale-ratio));   --text-lg: calc(var(--text-md) * var(--text-scale-ratio));   --text-xl: calc(var(--text-lg) * var(--text-scale-ratio));   --text-xxl: calc(var(--text-xl) * var(--text-scale-ratio)); } 
 @media (min-width: 64rem) { /* responsive decision applied to all text elements */   :root {     --text-base-size: 1.25em;     --text-scale-ratio: 1.25;   } } 
 h1, .text-xxl   { font-size: var(--text-xxl, 2.074em); } h2, .text-xl    { font-size: var(--text-xl, 1.728em); } h3, .text-lg    { font-size: var(--text-lg, 1.44em); } h4, .text-md    { font-size: var(--text-md, 1.2em); } .text-base      { font-size: 1em; } small, .text-sm { font-size: var(--text-sm, 0.833em); } .text-xs        { font-size: var(--text-xs, 0.694em); }

BEM in 30 seconds

BEM (Blocks, Elements, Modifiers) is a naming methodology aimed at creating reusable components.

Here’s an example:

<header class="header">   <a href="#0" class="header__logo"><!-- ... --></a>   <nav class="header__nav">     <ul>       <li><a href="#0" class="header__link header__link--active">Homepage</a></li>       <li><a href="#0" class="header__link">About</a></li>       <li><a href="#0" class="header__link">Contact</a></li>     </ul>   </nav> </header>
  • A block is a reusable component
  • An element is a child of the block (e.g., .block__element)
  • A modifier is a variation of a block/element (e.g., .block--modifier, .block__element--modifier).

Utility classes in 30 seconds

A utility class is a CSS class meant to do only one thing. For example:

<section class="padding-md">   <h1>Title</h1>   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p> </section> 
 <style>   .padding-sm { padding: 0.75em; }   .padding-md { padding: 1.25em; }   .padding-lg { padding: 2em; } </style>

You can potentially build entire components out of utility classes:

<article class="padding-md bg radius-md shadow-md">   <h1 class="text-lg color-contrast-higher">Title</h1>   <p class="text-sm color-contrast-medium">Lorem ipsum dolor sit amet consectetur adipisicing elit.</p> </article>

You can connect utility classes to CSS globals:

/* Spacing | Global */ :root {   --space-unit: 1em;   --space-xs:   calc(0.5 * var(--space-unit));   --space-sm:   calc(0.75 * var(--space-unit));   --space-md:   calc(1.25 * var(--space-unit));   --space-lg:   calc(2 * var(--space-unit));   --space-xl:   calc(3.25 * var(--space-unit)); }  /* responsive rule affecting all spacing variables */ @media (min-width: 64rem) {   :root {     --space-unit:  1.25em; /* 👇 this responsive decision affects all margins and paddings */   } }
 /* margin and padding util classes - apply spacing variables */ .margin-xs { margin: var(--space-xs); } .margin-sm { margin: var(--space-sm); } .margin-md { margin: var(--space-md); } .margin-lg { margin: var(--space-lg); } .margin-xl { margin: var(--space-xl); }  .padding-xs { padding: var(--space-xs); } .padding-sm { padding: var(--space-sm); } .padding-md { padding: var(--space-md); } .padding-lg { padding: var(--space-lg); } .padding-xl { padding: var(--space-xl); }

A real-life example

Explaining a methodology using basic examples doesn’t bring up the real issues nor the advantages of the method itself.

Let’s build something together! 

We’ll create a gallery of card elements. First, we’ll do it using only the BEM approach, and we’ll point out the issues you may face by going BEM only. Next, we’ll see how Globals reduce the size of your CSS. Finally, we’ll make the component customizable introducing utility classes to the mix.

Here’s a look at the final result:

Let’s start this experiment by creating the gallery using only BEM:

<div class="grid">   <article class="card">     <a class="card__link" href="#0">       <figure>         <img class="card__img" src="/image.jpg" alt="Image description">       </figure> 
       <div class="card__content">         <h1 class="card__title-wrapper"><span class="card__title">Title of the card</span></h1> 
         <p class="card__description">Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore, totam?</p>       </div> 
       <div class="card__icon-wrapper" aria-hidden="true">         <svg class="card__icon" viewBox="0 0 24 24"><!-- icon --></svg>       </div>     </a>   </article> 
   <article class="card"><!-- card --></article>   <article class="card"><!-- card --></article>   <article class="card"><!-- card --></article> </div>

In this example, we have two components: .grid and .card. The first one is used to create the gallery layout. The second one is the card component.

First of all, let me point out the main advantages of using BEM: low specificity and scope.

/* without BEM */ .grid {} .card {} .card > a {} .card img {} .card-content {} .card .title {} .card .description {} 
 /* with BEM */ .grid {} .card {} .card__link {} .card__img {} .card__content {} .card__title {} .card__description {}

If you don’t use BEM (or a similar naming method), you end up creating inheritance relationships (.card > a).

/* without BEM */ .card > a.active {} /* high specificity */ 
 /* without BEM, when things go really bad */ div.container main .card.is-featured > a.active {} /* good luck with that 😦 */ 
 /* with BEM */ .card__link--active {} /* low specificity */

Dealing with inheritance and specificity in big projects is painful. That feeling when your CSS doesn’t seem to be working, and you find out it’s been overwritten by another class 😡! BEM, on the other hand, creates some kind of scope for your components and keeps specificity low.

But… there are two main downsides of using only BEM:

  1. Naming too many things is frustrating
  2. Minor customizations are not easy to do or maintain

In our example, to stylize the components, we’ve created the following classes:

.grid {} .card {} .card__link {} .card__img {} .card__content {} .card__title-wrapper {} .card__title {} .card__description {} .card__icon-wrapper {} .card__icon {}

The number of classes is not the issue. The issue is coming up with so many meaningful names (and having all your teammates use the same naming criteria).

For example, imagine you have to modify the card component by including an additional, smaller paragraph:

<div class="card__content">   <h1 class="card__title-wrapper"><span class="card__title">Title of the card</span></h1>   <p class="card__description">Lorem ipsum dolor...</p>   <p class="card__description card__description--small">Lorem ipsum dolor...</p> <!-- 👈 --> </div>

How do you call it? You could consider it a variation of the .card__description element and go for .card__description .card__description--small. Or, you could create a new element, something like .card__small, .card__small-p, or .card__tag. See where I’m going? No one wants to spend time thinking about class names. BEM is great as long as you don’t have to name too many things.

The second issue is dealing with minor customizations. For example, imagine you have to create a variation of the card component where the text is center-aligned.

You’ll probably do something like this:

<div class="card__content card__content--center"> <!-- 👈 -->   <h1 class="card__title-wrapper"><span class="card__title">Title of the card</span></h1>   <p class="card__description">Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore, totam?</p> </div> 
 <style>   .card__content--center { text-align: center; } </style>

One of your teammates, working on another component (.banner), is facing the same problem. They create a variation for their component as well:

<div class="banner banner--text-center"></div> 
 <style>   .banner--text-center { text-align: center; } </style>

Now imagine you have to include the banner component into a page. You need the variation where the text is aligned in the center. Without checking the CSS of the banner component, you may instinctively write something like banner banner--center in your HTML, because you always use --center when you create variations where the text is center-aligned. Not working! Your only option is to open the CSS file of the banner component, inspect the code, and find out what class should be applied to align the text in the center.

How long would it take, 5 minutes? Multiply 5 minutes by all the times this happens in a day, to you and all your teammates, and you realize how much time is wasted. Plus, adding new classes that do the same thing contributes to bloating your CSS.

CSS Globals and utility classes to the rescue

The first advantage of setting global styles is having a set of CSS rules that apply to all the components.

For example, if we set responsive rules in the spacing and typography globals, these rules will affect the grid and card components as well. In CodyFrame, we increase the body font size at a specific breakpoint; because we use “em” units for all margins and paddings, the whole spacing system is updated at once generating a cascade effect.

Spacing and typography responsive rules — no media queries on a component level 

As a consequence, in most cases, you won’t need to use media queries to increase the font size or the values of margins and paddings!

/* without globals */ .card { padding: 1em; } 
 @media (min-width: 48rem) {   .card { padding: 2em; }   .card__content { font-size: 1.25em; } } 
 /* with globals (responsive rules intrinsically applied) */ .card { padding: var(--space-md); }

Not just that! You can use the globals to store behavioral components that can be combined with all other components. For example, in CodyFrame, we define a .text-component class that is used as a “text wrapper.” It takes care of line height, vertical spacing, basic styling, and other things.

If we go back to our card example, the .card__content element could be replaced with the following:

<!-- without globals --> <div class="card__content">   <h1 class="card__title-wrapper"><span class="card__title">Title of the card</span></h1>   <p class="card__description">Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore, totam?</p> </div> 
 <!-- with globals --> <div class="text-component">   <h1 class="text-lg"><span class="card__title">Title of the card</span></h1>   <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore, totam?</p> </div>

The text component will take care of the text formatting, and make it consistent across all the text blocks in your project. Plus, we’ve already eliminated a couple of BEM classes.

Finally, let’s introduce the utility classes to the mix!

Utility classes are particularly useful if you want the ability to customize the component later on without having to check its CSS.

Here’s how the structure of the card component changes if we swap some BEM classes with utility classes:

<article class="card radius-lg">   <a href="#0" class="block color-inherit text-decoration-none">     <figure>       <img class="block width-100%" src="image.jpg" alt="Image description">     </figure> 
     <div class="text-component padding-md">       <h1 class="text-lg"><span class="card__title">Title of the card</span></h1>       <p class="color-contrast-medium">Lorem ipsum dolor sit amet consectetur adipisicing elit. Tempore, totam?</p>     </div> 
     <div class="card__icon-wrapper" aria-hidden="true">       <svg class="icon icon--sm color-white" viewBox="0 0 24 24"><!-- icon --></svg>     </div>   </a> </article>

The number of BEM (component) classes has shrunk from 9 to 3:

.card {} .card__title {} .card__icon-wrapper {}

That means you won’t deal much with naming things. That said, we can’t avoid the naming issue entirely: even if you create Vue/React/SomeOtherFramework components out of utility classes, you still have to name the components.

All the other BEM classes have been replaced by utility classes. What if you have to make a card variation with a bigger title? Replace text-lg with text-xl. What if you want to change the icon color? Replace color-white with color-primary. How about aligning the text in the center? Add text-center to the text-component element. Less time thinking, more time doing!

Why don’t we just use utility classes?

Utility classes speed-up the design process and make it easier to customize things. So why don’t we forget about BEM and use only utility classes? Two main reasons:

By using BEM together with utility classes, the HTML is easier to read and customize.

Use BEM for:

  • DRY-ing the HTML from the CSS you don’t plan on customizing (e.g., behavioral CSS-like transitions, positioning, hover/focus effects),
  • advanced animations/effects.

Use utility classes for:

  • the “frequently-customized” properties, often used to create component variations (like padding, margin, text-alignment, etc.),
  • elements that are hard to identify with a new, meaningful class name (e.g., you need a parent element with a position: relative → create <div class="position-relative"><div class="my-component"></div></div>).

Example: 

<!-- use only Utility classes --> <article class="position-relative overflow-hidden bg radius-lg transition-all duration-300 hover:shadow-md col-6@sm col-4@md">   <!-- card content --> </article> 
 <!-- use BEM + Utility classes --> <article class="card radius-lg col-6@sm col-4@md">   <!-- card content --> </article>

For these reasons, we suggest that you don’t add the !important rule to your utility classes. Using utility classes doesn’t need to be like using a hammer. Do you think it would be beneficial to access and modify a CSS property in the HTML? Use a utility class. Do you need a bunch of rules that won’t need editing? Write them in your CSS. This process doesn’t need to be perfect the first time you do it: you can tweak the component later on if required. It may sound laborious “having to decide” but it’s quite straightforward when you put it to practice.

Utility classes are not your best ally when it comes to creating unique effects/animations.

Think about working with pseudo-elements, or crafting unique motion effects that require custom bezier curves. For those, you still need to open your CSS file.

Consider, for example, the animated background effect of the card we’ve designed. How hard would it be to create such an effect using utility classes?

The same goes for the icon animation, which requires animation keyframes to work:

.card:hover .card__title {   background-size: 100% 100%; } 
 .card:hover .card__icon-wrapper .icon {   animation: card-icon-animation .3s; } 
 .card__title {   background-image: linear-gradient(transparent 50%, alpha(var(--color-primary), 0.2) 50%);   background-repeat: no-repeat;   background-position: left center;   background-size: 0% 100%;   transition: background .3s; } 
 .card__icon-wrapper {   position: absolute;   top: 0;   right: 0;   width: 3em;   height: 3em;   background-color: alpha(var(--color-black), 0.85);   border-bottom-left-radius: var(--radius-lg);   display: flex;   justify-content: center;   align-items: center; } 
 @keyframes card-icon-animation {   0%, 100% {     opacity: 1;     transform: translateX(0%);   }   50% {     opacity: 0;     transform: translateX(100%);   }   51% {     opacity: 0;     transform: translateX(-100%);   } }

Final result

Here’s the final version of the cards gallery. It also includes grid utility classes to customize the layout.

File structure

Here’s how the structure of a project built using the method described in this article would look like:

project/ └── main/     ├── assets/     │   ├── css/     │   │   ├── components/     │   │   │   ├── _card.scss     │   │   │   ├── _footer.scss     │   │   │   └── _header.scss     │   │   ├── globals/     │   │   │   ├── _accessibility.scss     │   │   │   ├── _breakpoints.scss     │   │   │   ├── _buttons.scss     │   │   │   ├── _colors.scss     │   │   │   ├── _forms.scss     │   │   │   ├── _grid-layout.scss     │   │   │   ├── _icons.scss     │   │   │   ├── _reset.scss     │   │   │   ├── _spacing.scss     │   │   │   ├── _typography.scss     │   │   │   ├── _util.scss     │   │   │   ├── _visibility.scss     │   │   │   └── _z-index.scss     │   │   ├── _globals.scss     │   │   ├── style.css     │   │   └── style.scss     │   └── js/     │       ├── components/     │       │   └── _header.js     │       └── util.js     └── index.html

You can store the CSS (or SCSS) of each component into a separate file (and, optionally, use PostCSS plugins to compile each new /component/componentName.css file into style.css). Feel free to organize the globals as you prefer; you could also create a single globals.css file and avoid separating the globals in different files.

Conclusion

Working on large-scale projects requires a solid architecture if you want to open your files months later and don’t get lost. There are many methods out there that tackle this issue (CSS-in-JS, utility-first, atomic design, etc.).

The method I’ve shared with you today relies on creating crosswise rules (globals), using utility classes for rapid development, and BEM for modular (behavioral) classes.

You can learn in more detail about this method on CodyHouse. Any feedback is welcome!

The post Building a Scalable CSS Architecture With BEM and Utility Classes appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

The Order of CSS Classes in HTML Doesn’t Matter

That’s right! And I can prove it, too. Let’s look at some CSS first:

.a {   color: red; }  .b {   color: blue; }

And now let’s look at some markup:

<div class="a b">Here’s some text</div>

The text is going to be blue because .b is defined last in the CSS, right? But what if we go about and switch the order in which those classes are called in HTML:

<div class="b a">Here’s some text</div>

What color do you think the text should be? Red or blue?

This certainly might sound like a silly question but it tends to trip up a lot of folks who happen to be familiar with CSS-in-JS solutions. And this week I’ve spoken to two very senior front end engineers who thought similarly as well!

But the text in the example above will always be blue no matter what order those CSS classes are in. And that’s because the markup is just reading the CSS in the order that it’s written — the cascade wins in this example.

The post The Order of CSS Classes in HTML Doesn’t Matter appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

CSS :not() with Multiple Classes

Say you want to select an element when it doesn’t have a certain class. That’s what the :not() selector is for.

body:not(.home) {    }

But what if there are multiple classes you want to avoid?

There are no logical combinators with :not(), like and or or, but you can chain them, which is effectively like and.

body:not(.home):not(.away):not(.page-50) {    }

The :not() selector doesn’t add any specificy by itself, but what is inside does, so :not(.foo) adds the same weight as .foo does.

The post CSS :not() with Multiple Classes appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

Could Grouping HTML Classes Make Them More Readable?

You can have multiple classes on an HTML element:

<div class="module p-2"></div>

Nothing incorrect or invalid there at all. It has two classes. In CSS, both of these will apply:

.module { } .p-2 { }
const div = document.querySelector("div"); console.log(div.classList.contains("module")); // true console.log(div.classList.contains("p-3"));    // false

But what about grouping them? All we have here is a space-separated string. Maybe that’s fine. But maybe we can make things more clear!

Years ago, Harry Roberts talked about grouping them. He wrapped groups of classes in square brackets:

<div class="[ foo  foo--bar ]  [ baz  baz--foo ]">

The example class names above are totally abstract just to demonstrate the grouping. Imagine they are like primary names and variations as one group, then utility classes as another group:

<header class="[ site-header site-header-large ]  [ mb-10 p-15 ]">

Those square brackets? Meaningless. Those are there to visually represent the groups to us developers. Technically, they are also classes, so if some sadist wrote .[ {}, it would do stuff in your CSS. But that’s so unlikely that, hopefully, the clarity from the groups outweighs it and is more helpful.

That example above groups the primary name and a variation in one group and some example utility classes in another group.

I’m not necessarily recommending that approach. They are simply groups of classes that you might have.

Here’s the same style of grouping, with different groups:

<button class="[ link-button ] [ font-base text-xs color-primary ] [ js-trigger ]" type="button" hidden>

That example has a single primary name, utility classes with different naming styles, and a third group for JavaScript specific selectors.

Harry wound up shunning this approach a few years ago, saying that the look of it was just too weird for the variety of people and teams he worked with. It caused enough confusion that the benefits of grouped classes weren’t worth it. He suggested line breaks instead:

<div class="media  media--large             testimonial  testimonial--main"> 

That seems similarly clear to me. The line breaks in HTML are totally fine. Plus, the browser will have no trouble with that and JSX is generally written with lots of line breaks in HTML anyway because of how much extra stuff is plopped onto elements in there, like event handlers and props.

Perhaps we combine the ideas of line breaks as separators and identified groups… with emojis!

See the Pen
Grouping Classes
by Chris Coyier (@chriscoyier)
on CodePen.

Weird, but fun. Emojis are totally valid there. Like the square brackets, they could also do things if someone wrote a class name for them, but that’s generally unlikely and something for a team to talk about.

Another thing I’ve seen used is data-* attributes for groups instead of classes, like…

<div    class="primary-name"   data-js="js-hook-1 js-hook-2"   data-utilities="padding-large" >

You can still select and style based on attributes in both CSS and JavaScript, so it’s functional, though slightly less convenient because of the awkward selectors like [data-js="js-hook-1"] and lack of convenient APIs like classList.

How about you? Do you have any other clever ideas for class name groups?

The post Could Grouping HTML Classes Make Them More Readable? appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Creating Reusable Base Classes in TypeScript with a Real-Life Example

Hey CSS-Tricksters! Bryan Hughes was kind enough to take a concept from an existing post he published on converting to TypeScript and take it a few couple steps further in this post to elaborate on creating reusable base classes. While this post doesn’t require reading the other one, it’s certainly worth checking it out because it covers the difficult task of rewriting a codebase and writing unit tests to help the process.

Johnny-Five is an IoT and robotics library for Node.js. Johnny-Five makes it easy to interact with hardware by taking a similar approach that jQuery took to the web a decade ago: it normalizes the differences between various hardware platforms. Also like jQuery, Johnny-Five provides higher-level abstractions that make it easier to work with the platform.

Johnny-Five supports a wide array of platforms via IO Plugins, from the Arduino family, to the Tessel, to the Raspberry Pi, and many more. Each IO Plugin implements a standardized interface for interacting with lower-level hardware peripherals. Raspi IO, which I first created five years ago, is the IO plugin that implements support for the Raspberry Pi.

Any time there are multiple implementations that conform to one thing, there is a chance to share code. IO Plugins are no exception, however, we have not shared any code between IO Plugins to date. We recently decided, as a group, that we wanted to change this. The timing was fortuitous since I was planning on rewriting Raspi IO in TypeScript anyways, so I agreed to take on this task.

The goals of a base class

For those who many not be familiar with using class-based inheritance to enable code sharing, let’s do a quick walk-through of what I mean when I say “creating a base class to reuse code.”

A base class provides structure and common code that other classes can extend. Let’s take a look at a simplified TypeScript example base class that we will extend later:

abstract class Automobile {   private _speed: number = 0;   private _direction: number = 0;   public drive(speed: number): void {     this._speed = speed;   }      public turn(direction: number): void {     if (direction > 90 || direction < -90) {       throw new Error(`Invalid direction "$  {direction}"`);     }     this._direction = direction;   }      public abstract getNumDoors(): number; }

Here, we have created a base class that we call Automobile. This provides some basic functionality shared between all types of automobiles, whether it’s a car, a pickup, etc. Notice how this class is marked as abstract, and how there is one abstract method called getNumDoors. This method is dependent on the specific type of automobile. By defining it as an abstract class, we are saying that we require another class to extend this class and implement this method. We can do so with this code:

class Sedan extends Automobile {   public getNumDoors(): number {     return 4;   } }  const myCar = new Sedan(); myCar.getNumDoors(); // prints 4 myCar.drive(35);     // sets _speed to 35 myCar.turn(20);      // sets _direction to 20

We’re extending the Automobile class to create a four-door sedan class. We can now call all methods on both classes, as if it were a single class.

For this project, we’ll create a base class called AbstractIO that any IO plugin author can then extend to implement a platform-specific IO Plugin.

Creating the Abstract IO base class

Abstract IO is the base class I created to implement the IO Plugin spec for use by all IO Plugin authors, and is available today on npm.

Each author has their own unique style, some preferring TypeScript and others preferring vanilla JavaScript. This means that, first and foremost, this base class must conform to the intersection of TypeScript best practices and JavaScript best practices. Finding the intersection of best practices isn’t always obvious though. To illustrate, let’s consider two parts of the IO Plugin spec: the MODES property and the digitalWrite method, both of which are required in IO Plugins.

The MODES property is an object, with each key having a human readable name for a given mode type, such as INPUT, and the value being the numerical constant associated with the mode type, such as 0. These numerical values show up in other places in the API, such as the pinMode method. In TypeScript, we would want to use an enum to represent these values, but JavaScript doesn’t support it. In JavaScript, the best practice is to define a series of constants and put them into an object “container.”

How do we resolve this apparent split between best practices? Create one using the other! We start by defining an enum in TypeScript and define each mode with an explicit initializer for each value:

export enum Mode {  INPUT = 0,  OUTPUT = 1,  ANALOG = 2,  PWM = 3,  SERVO = 4,  STEPPER = 5,  UNKNOWN = 99 }

Each value is carefully chosen to map explicitly to the MODES property as defined by the spec, which is implemented as part of the Abstract IO class with the following code:

public get MODES() {  return {    INPUT: Mode.INPUT,    OUTPUT: Mode.OUTPUT,    ANALOG: Mode.ANALOG,    PWM: Mode.PWM,    SERVO: Mode.SERVO,    UNKNOWN: Mode.UNKNOWN  } }

With this, we have nice enums when we’re in TypeScript-land and can ignore the numerical values entirely. When we’re in pure JavaScript-land, we still have the MODES property we can pass around in typical JavaScript fashion so we don’t have to use numerical values directly.

But what about methods in the base class that derived classes must override? In the TypeScript world, we would use an abstract class, as we did in the example above. Cool! But what about the JavaScript side? Abstract methods are compiled out and don’t even exist in the output JavaScript, so we have nothing to ensure methods are overridden there. Another contradiction!

Unfortunately, I couldn’t come up with a way to respect both languages, so I defaulted to using the JavaScript approach: create a method in the base class that throws an exception:

public digitalWrite(pin: string | number, value: number): void {  throw new Error(`digitalWrite is not supported by $  {this.name}`); }

It’s not ideal because the TypeScript compiler doesn’t warn us if we don’t override the abstract base method. However, it does work in TypeScript (we still get the exception at runtime), as well as being a best practice for JavaScript.

Lessons learned

While working through the best way to design for both TypeScript and vanilla JavaScript, I determined that the best way to solve discrepancies is:

  1. Use a common best practice shared by each language
  2. If that doesn’t work, try to use the TypeScript best practice “internally” and map it to a separate vanilla JavaScript best practice “externally,” like we did for the MODES property.
  3. And if that approach doesn’t work, default to using the vanilla JavaScript best practice, like we did for the digitalWrite method, and ignore the TypeScript best practice.
  4. These steps worked well for creating Abstract IO, but these are simply what I discovered. If you have any better ideas I’d love to hear them in the comments!

    I discovered that abstract classes are not useful in vanilla JavaScript projects since JavaScript doesn’t have such a concept. This means that they are an anti-pattern here, even though abstract classes are a TypeScript best practice. TypeScript also doesn’t provide mechanisms to ensure type-safety when overriding methods, such as the override keyword in C#. The lesson here is that you should pretend that abstract classes don’t exist when targeting vanilla JavaScript users as well.

    I also learned that it’s really important to have a single source of truth for interfaces shared across modules. TypeScript uses duck typing as its core type system pattern, and is very useful inside any given TypeScript project. However, synchronizing types across separate modules using duck typing turned out to be more of a maintenance headache than exporting an interface from one module and importing it into another. I had to keep publishing little changes to modules until I got them aligned on their types, leading to excess version number churn.

    The final lesson I learned isn’t a new one: get feedback throughout the design process from library consumers. Knowing this going in, I set up two primary rounds of feedback. The first round was in person at the Johnny-Five collaborator’s summit where we brainstormed as a group. The second round was a pull request I opened against myself, despite being the only collaborator on Abstract IO with permission to merge pull requests. The pull request proved invaluable as we sifted through the details as a group. The code at the beginning of the PR bared little resemblance to the code when it was merged, which is good!

    Wrapping up

    Producing base classes destined to be consumed by both TypeScript and vanilla JavaScript users is a mostly straightforward process, but there are some gotchas. Since TypeScript is a superset of JavaScript, the two mostly share the same best practices. When differences in best practices do arise, a little creativity is required to find the best compromise.

    I managed to achieve my goals with Abstract IO, and implemented a base class that serves both TypeScript and vanilla JavaScript IO Plugin authors well. Turns out, it’s (mostly) possible to have your cake and eat it too!

    The post Creating Reusable Base Classes in TypeScript with a Real-Life Example appeared first on CSS-Tricks.

    CSS-Tricks

, , , , , ,
[Top]