bem – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Mon, 28 Nov 2022 21:49:21 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 bem – CSS-Tricks https://css-tricks.com 32 32 45537868 Taming the Cascade With BEM and Modern CSS Selectors https://css-tricks.com/taming-the-cascade-with-bem-and-modern-css-selectors/ https://css-tricks.com/taming-the-cascade-with-bem-and-modern-css-selectors/#comments Mon, 21 Nov 2022 13:59:15 +0000 https://css-tricks.com/?p=375144 BEM. Like seemingly all techniques in the world of front-end development, writing CSS in a BEM format can be polarizing. But it is – at least in my Twitter bubble – one of the better-liked CSS methodologies.

Personally, I think …


Taming the Cascade With BEM and Modern CSS Selectors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
BEM. Like seemingly all techniques in the world of front-end development, writing CSS in a BEM format can be polarizing. But it is – at least in my Twitter bubble – one of the better-liked CSS methodologies.

Personally, I think BEM is good, and I think you should use it. But I also get why you might not.

Regardless of your opinion on BEM, it offers several benefits, the biggest being that it helps avoid specificity clashes in the CSS Cascade. That’s because, if used properly, any selectors written in a BEM format should have the same specificity score (0,1,0). I’ve architected the CSS for plenty of large-scale websites over the years (think government, universities, and banks), and it’s on these larger projects where I’ve found that BEM really shines. Writing CSS is much more fun when you have confidence that the styles you’re writing or editing aren’t affecting some other part of the site.

There are actually exceptions where it is deemed totally acceptable to add specificity. For instance: the :hover and :focus pseudo classes. Those have a specificity score of 0,2,0. Another is pseudo elements — like ::before and ::after — which have a specificity score of 0,1,1. For the rest of this article though, let’s assume we don’t want any other specificity creep. 🤓

But I’m not really here to sell you on BEM. Instead, I want to talk about how we can use it alongside modern CSS selectors — think :is(), :has(), :where(), etc. — to gain even more control of the Cascade.

What’s this about modern CSS selectors?

The CSS Selectors Level 4 spec gives us some powerful new(ish) ways to select elements. Some of my favorites include :is(), :where(), and :not(), each of which is supported by all modern browsers and is safe to use on almost any project nowadays.

:is() and :where() are basically the same thing except for how they impact specificity. Specifically, :where() always has a specificity score of 0,0,0. Yep, even :where(button#widget.some-class) has no specificity. Meanwhile, the specificity of :is() is the element in its argument list with the highest specificity. So, already we have a Cascade-wrangling distinction between two modern selectors that we can work with.

The incredibly powerful :has() relational pseudo-class is also rapidly gaining browser support (and is the biggest new feature of CSS since Grid, in my humble opinion). However, at time of writing, browser support for :has() isn’t quite good enough for use in production just yet.

Lemme stick one of those pseudo-classes in my BEM and…

/* ❌ specificity score: 0,2,0 */
.something:not(.something--special) {
  /* styles for all somethings, except for the special somethings */
}

Whoops! See that specificity score? Remember, with BEM we ideally want our selectors to all have a specificity score of 0,1,0. Why is 0,2,0 bad? Consider a similar example, expanded:

.something:not(a) {
  color: red;
}
.something--special {
  color: blue;
}

Even though the second selector is last in the source order, the first selector’s higher specificity (0,1,1) wins, and the color of .something--special elements will be set to red. That is, assuming your BEM is written properly and the selected element has both the .something base class and .something--special modifier class applied to it in the HTML.

Used carelessly, these pseudo-classes can impact the Cascade in unexpected ways. And it’s these sorts of inconsistencies that can create headaches down the line, especially on larger and more complex codebases.

Dang. So now what?

Remember what I was saying about :where() and the fact that its specificity is zero? We can use that to our advantage:

/* ✅ specificity score: 0,1,0 */
.something:where(:not(.something--special)) {
  /* etc. */
}

The first part of this selector (.something) gets its usual specificity score of 0,1,0. But :where() — and everything inside it — has a specificity of 0, which does not increase the specificity of the selector any further.

:where() allows us to nest

Folks who don’t care as much as me about specificity (and that’s probably a lot of people, to be fair) have had it pretty good when it comes to nesting. With some carefree keyboard strokes, we may wind up with CSS like this (note that I’m using Sass for brevity):

.card { ... }

.card--featured {
  /* etc. */  
  .card__title { ... }
  .card__title { ... }
}

.card__title { ... }
.card__img { ... }

In this example, we have a .card component. When it’s a “featured” card (using the .card--featured class), the card’s title and image needs to be styled differently. But, as we now know, the code above results in a specificity score that is inconsistent with the rest of our system.

A die-hard specificity nerd might have done this instead:

.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }

That’s not so bad, right? Frankly, this is beautiful CSS.

There is a downside in the HTML though. Seasoned BEM authors are probably painfully aware of the clunky template logic that’s required to conditionally apply modifier classes to multiple elements. In this example, the HTML template needs to conditionally add the --featured modifier class to three elements (.card, .card__title, and .card__img) though probably even more in a real-world example. That’s a lot of if statements.

The :where() selector can help us write a lot less template logic — and fewer BEM classes to boot — without adding to the level of specificity.

.card { ... }
.card--featured { ... }

.card__title { ... }
:where(.card--featured) .card__title { ... }

.card__img { ... }
:where(.card--featured) .card__img { ... }

Here’s same thing but in Sass (note the trailing ampersands):

.card { ... }
.card--featured { ... }
.card__title { 
  /* etc. */ 
  :where(.card--featured) & { ... }
}
.card__img { 
  /* etc. */ 
  :where(.card--featured) & { ... }
}

Whether or not you should opt for this approach over applying modifier classes to the various child elements is a matter of personal preference. But at least :where() gives us the choice now!

What about non-BEM HTML?

We don’t live in a perfect world. Sometimes you need to deal with HTML that is outside of your control. For instance, a third-party script that injects HTML that you need to style. That markup often isn’t written with BEM class names. In some cases those styles don’t use classes at all but IDs!

Once again, :where() has our back. This solution is slightly hacky, as we need to reference the class of an element somewhere further up the DOM tree that we know exists.

/* ❌ specificity score: 1,0,0 */
#widget {
  /* etc. */
}

/* ✅ specificity score: 0,1,0 */
.page-wrapper :where(#widget) {
  /* etc. */
}

Referencing a parent element feels a little risky and restrictive though. What if that parent class changes or isn’t there for some reason? A better (but perhaps equally hacky) solution would be to use :is() instead. Remember, the specificity of :is() is equal to the most specific selector in its selector list.

So, instead of referencing a class we know (or hope!) exists with :where(), as in the above example, we could reference a made up class and the <body> tag.

/* ✅ specificity score: 0,1,0 */
:is(.dummy-class, body) :where(#widget) {
  /* etc. */
}

The ever-present body will help us select our #widget element, and the presence of the .dummy-class class inside the same :is() gives the body selector the same specificity score as a class (0,1,0)… and the use of :where() ensures the selector doesn’t get any more specific than that.

That’s it!

That’s how we can leverage the modern specificity-managing features of the :is() and :where() pseudo-classes alongside the specificity collision prevention that we get when writing CSS in a BEM format. And in the not too distant future, once :has() gains Firefox support (it’s currently supported behind a flag at the time of writing) we’ll likely want to pair it with :where() to undo its specificity.

Whether you go all-in on BEM naming or not, I hope we can agree that having consistency in selector specificity is a good thing!


Taming the Cascade With BEM and Modern CSS Selectors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/taming-the-cascade-with-bem-and-modern-css-selectors/feed/ 18 375144
Tailwind versus BEM https://css-tricks.com/tailwind-versus-bem/ https://css-tricks.com/tailwind-versus-bem/#comments Wed, 25 Nov 2020 21:40:03 +0000 https://css-tricks.com/?p=326169 Some really refreshing technological comparison writing from Eric Bailey. Like, ya know, everything in life, we don’t have to hate or love everything. Baby bear thinking, I like to say. There are benefits and drawbacks. Every single bullet point here …


Tailwind versus BEM originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Some really refreshing technological comparison writing from Eric Bailey. Like, ya know, everything in life, we don’t have to hate or love everything. Baby bear thinking, I like to say. There are benefits and drawbacks. Every single bullet point here is well-considered and valid. I really like the first in each section, so I’ll quote those as a taste here:

Tailwind Benefit: “The utility CSS approach creates an API-style approach to thinking about CSS, which helps many developers work with it.”

Tailwind Drawback: “You need to learn Tailwind class names in addition to learning CSS property names to figure out the visual styling you want. Tailwind is reliant on, and will be outlived by CSS, so it is more long-term beneficial to focus on CSS’ capabilities directly.”

BEM Benefit: “BEM will allow you to describe any user interface component you can dream up in a flexible, extensible way. As it is an approach to encapsulate the full range of CSS properties, it will allow you to style things Tailwind simply does not have classes for—think highly art directed experiences.”

BEM Drawback: “BEM runs full-tilt into one of the hardest problems in computer science—naming things. You need to not only describe your component, but also all its constituent parts and their states.”


And remember, these certainly aren’t the only two choices on the block. I covered my thoughts on some other approaches here.

To Shared LinkPermalink on CSS-Tricks


Tailwind versus BEM originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/tailwind-versus-bem/feed/ 1 326169
Tradeoffs and Shifting Complexity https://css-tricks.com/tradeoffs-and-shifting-complexity/ Wed, 15 Jul 2020 23:37:49 +0000 https://css-tricks.com/?p=317165 This is a masterclass from Dave:

After you hit the wall of unremovable complexity, any “advances” are a shell game, making tradeoffs that get passed down to the user … you get “advances” by shifting where the complexity lives.

You …


Tradeoffs and Shifting Complexity originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
This is a masterclass from Dave:

After you hit the wall of unremovable complexity, any “advances” are a shell game, making tradeoffs that get passed down to the user … you get “advances” by shifting where the complexity lives.

You don’t get free reductions in complexity. In CSS land, you don’t get to pick some styling strategy and have all your troubles go away. This is plenty of nuance here, but largely whatever technologies you pick, you’re just placing the complexity in different buckets.

The best we can hope for is picking buckets that feel the most comfortable and productive for us and our teams.

To Shared LinkPermalink on CSS-Tricks


Tradeoffs and Shifting Complexity originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
317165
Building a Scalable CSS Architecture With BEM and Utility Classes https://css-tricks.com/building-a-scalable-css-architecture-with-bem-and-utility-classes/ https://css-tricks.com/building-a-scalable-css-architecture-with-bem-and-utility-classes/#comments Tue, 21 Apr 2020 14:43:29 +0000 https://css-tricks.com/?p=306134 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


Building a Scalable CSS Architecture With BEM and Utility Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
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((--text-base-size / 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: --text-base-size; }
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!


Building a Scalable CSS Architecture With BEM and Utility Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/building-a-scalable-css-architecture-with-bem-and-utility-classes/feed/ 13 306134
What I Like About Writing Styles with Svelte https://css-tricks.com/what-i-like-about-writing-styles-with-svelte/ https://css-tricks.com/what-i-like-about-writing-styles-with-svelte/#comments Wed, 23 Oct 2019 14:22:14 +0000 https://css-tricks.com/?p=297067 There’s been a lot of well-deserved hype around Svelte recently, with the project accumulating over 24,000 GitHub stars. Arguably the simplest JavaScript framework out there, Svelte was written by Rich Harris, the developer behind Rollup. There’s a lot …


What I Like About Writing Styles with Svelte originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
There’s been a lot of well-deserved hype around Svelte recently, with the project accumulating over 24,000 GitHub stars. Arguably the simplest JavaScript framework out there, Svelte was written by Rich Harris, the developer behind Rollup. There’s a lot to like about Svelte (performance, built-in state management, writing proper markup rather than JSX), but the big draw for me has been its approach to CSS.

Single file components

​​

React does not have an opinion about how styles are defined
—React Documentation

​​​​

A UI framework that doesn’t have a built-in way to add styles to your components is unfinished.
—Rich Harris, creator of Svelte

In Svelte, you can write CSS in a stylesheet like you normally would on a typical project. You can also use CSS-in-JS solutions, like styled-components and Emotion, if you’d like. It’s become increasingly common to divide code into components, rather than by file type. React, for example, allows for the collocation of a components markup and JavaScript. In Svelte, this is taken one logical step further: the Javascript, markup and styling for a component can all exist together in a single `.svelte`​ file. If you’ve ever used single file components in Vue, then Svelte will look familiar.

// button.svelte
<style>
  button {
    border-radius: 0;
    background-color: aqua;
  }
</style>

<button>
  <slot/>
</button>

Styles are scoped by default

By default, styles defined within a Svelte file are scoped. Like CSS-in-JS libraries or CSS Modules, Svelte generates unique class names when it compiles to make sure the styles for one element never conflict with styles from another.

That means you can use simple element selectors like div and button in a Svelte component file without needing to work with class names. If we go back to the button styles in our earlier example, we know that a ruleset for <button> will only be applied to our <Button> component — not to any other HTML button elements within the page. If you were to have multiple buttons within a component and wanted to style them differently, you’d still need classes. Classes will also be scoped by Svelte.

The classes that Svelte generates look like gibberish because they are based on a hash of the component styles (e.g. svelte-433xyz). This is far easier than a naming convention like BEM. Admittedly though, the experience of looking at styles in DevTools is slightly worse as the class names lack meaning.

The markup of a Svelte component in DevTools.

It’s not an either/or situation. You can use Svelte’s scoped styling along with a regular stylesheet. I personally write component specific styles within .svelte files, but make use of utility classes defined in a stylesheet. For global styles to be available across an entire app — CSS custom properties, reusable CSS animations, utility classes, any ‘reset’ styles, or a CSS framework like Bootstrap — I suggest putting them in a stylesheet linked in the head of your HTML document.

It lets us create global styles

As we’ve just seen, you can use a regular stylesheet to define global styles. Should you need to define any global styles from within a Svelte component, you can do that too by using :global. This is essentially a way to opt out of scoping when and where you need to.

For example, a modal component may want to toggle a class to style the body element:

<style>
:global(.noscroll) {
  overflow: hidden;
}
</style>

Unused styles are flagged

Another benefit of Svelte is that it will alert you about any unused styles during compilation. In other words, it searches for places where styles are defined but never used in the markup.

Conditional classes are terse and effortless

If the JavaScript variable name and the class name is the same, the syntax is incredibly terse. In this example, I’m creating modifier props for a full-width button and a ghost button.

<script>
  export let big = false;
  export let ghost = false;
</script>

<style>
  .big {
    font-size: 20px;
    display: block;
    width: 100%;
  }
  
  .ghost {
    background-color: transparent;
    border: solid currentColor 2px;
  }
</style>    
    
<button class:big class:ghost>
  <slot/>
</button>

A class of ghost will be applied to the element when a ghost prop is used, and a class of big is applied when a big prop is used.

<script>
  import Button from './Button.svelte';
</script>

<Button big ghost>Click Me</Button>

Svelte doesn’t require class names and prop names to be identical.

<script>
  export let primary = false;
  export let secondary = false;
</script>

<button
  class:c-btn--primary={primary}
  class:c-btn--secondary={secondary}
  class="c-btn">
  <slot></slot>
</button>

The above button component will always have a c-btn class but will include modifier classes only when the relevant prop is passed in, like this:

<Button primary>Click Me</Button>

That will generate this markup:

<button class="c-btn c-btn--primary">Click Me</button>

Any number of arbitrary classes can be passed to a component with a single prop:

<script>
let class_name = '';
export { class_name as class };
</script>

<button class="c-btn {class_name}">
  <slot />
</button>

Then, classes can be used much the same way you would with HTML markup:

<Button class="mt40">Click Me</Button>

From BEM to Svelte

Let’s see how much easier Svelte makes writing styles compared to a standard CSS naming convention. Here’s a simple component coded up using BEM.

.c-card {
  border-radius: 3px;
  border: solid 2px;
}

.c-card__title {
  text-transform: uppercase;
}

.c-card__text {
  color: gray;
}

.c-card--featured {
  border-color: gold;
}

Using BEM, classes get long and ugly. In Svelte, things are a lot simpler.

<style>
div {
  border-radius: 3px;
  border: solid 2px;
}

h2 {
  text-transform: uppercase;
}

p {
  color: gray;
}

.featured {
  border-color: gold;
}
</style>

<div class:featured>
  <h2>{title}</h2>
  <p>
    <slot />
  </p>
</div>

It plays well with preprocessors

CSS preprocessors feels a lot less necessary when working with Svelte, but they can work perfectly alongside one another by making use of a package called Svelte Preprocess. Support is available for Less, Stylus and PostCSS, but here we’ll look at Sass. The first thing we need to do is to install some dependencies:

npm install -D svelte-preprocess node-sass

Then we need to import autoPreprocess in rollup.config.js at the top of the file.

import autoPreprocess from 'svelte-preprocess';

Next, let’s find the plugins array and add preprocess: autoPreprocess() to Svelte:

export default {
  plugins: [
    svelte({
      preprocess: autoPreprocess(),
      ...other stuff

Then all we need to do is specify that we’re using Sass when we’re working in a component file, using type="text/scss" or lang="scss" to the style tag.

<style type="text/scss">
  $pink: rgb(200, 0, 220);
  p {
    color: black;
    span {
      color: $pink;
    }
  }
</style>

Dynamic values without a runtime

We’ve seen that Svelte comes with most of the benefits of CSS-in-JS out-of-the-box — but without external dependencies! However, there’s one thing that third-party libraries can do that Svelte simply can’t: use JavaScript variables in CSS.

The following code is not valid and will not work:

<script>
  export let cols = 4;
</script>

<style>
  ul {
    display: grid;
    width: 100%;
    grid-column-gap: 16px;
    grid-row-gap: 16px;
    grid-template-columns: repeat({cols}, 1fr);
  }
</style>

<ul>
  <slot />
</ul>

We can, however, achieve similar functionality by using CSS variables.

<script>
  export let cols = 4;
</script>

<style>
  ul {
    display: grid;
    width: 100%;
    grid-column-gap: 16px;
    grid-row-gap: 16px;
    grid-template-columns: repeat(var(--columns), 1fr);
  }
</style>

<ul style="--columns:{cols}">
  <slot />
</ul>

I’ve written CSS in all kinds of different ways over the years: Sass, Shadow DOM, CSS-in-JS, BEM, atomic CSS and PostCSS. Svelte offers the most intuitive, approachable and user-friendly styling API. If you want to read more about this topic then check out the aptly titled The Zen of Just Writing CSS by Rich Harris.


What I Like About Writing Styles with Svelte originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/what-i-like-about-writing-styles-with-svelte/feed/ 9 297067
Combining the Powers of SEM and BIO for Improving CSS https://css-tricks.com/combining-the-powers-of-sem-and-bio-for-improving-css/ https://css-tricks.com/combining-the-powers-of-sem-and-bio-for-improving-css/#comments Mon, 04 Jun 2018 14:07:15 +0000 http://css-tricks.com/?p=271711 CSS is easy, some might argue, but that “easiness” can cause messy code. This is especially true through power of preprocessors like Sass or Less where, if you aren’t careful, your CSS can become harder to deal with instead of …


Combining the Powers of SEM and BIO for Improving CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
CSS is easy, some might argue, but that “easiness” can cause messy code. This is especially true through power of preprocessors like Sass or Less where, if you aren’t careful, your CSS can become harder to deal with instead of easier. Sass? Harder? This Gist shows a great example of Sass nesting hell.

If your Sass code looks like that, you can definitely improve your code with SEM & BIO, a CSS technique I’ll introduce you to now!

In this article, I am going to use the code example below to explain how SEM and BIO works and how they can help enhance your CSS strategy.

See the Pen by thebabydino (@thebabydino) on CodePen.

Generally, SEM is concerned with high level CSS philosophy whereas BIO is an actual technique to help you write better CSS to achieve SEM. The main purpose of both SEM and BIO is to better handle the CSS specificity which is one of the most important concepts you should understand for CSS.

Credit: Nana Jeon

First of all, let’s talk about SEM.

SEM

SEM stands for:

  • Scalable
  • Extensible
  • Maintainable

Trying to achieve those three factors can definitely improve your CSS code and it helps you build your components much more solid.

Let’s talk more about each factor in detail.

Scalable

A scalable (or reusable) component means that the same looking components should be used wherever you want without making any coding changes.

Credit: Nana Jeon

From the CodePen example above, the “Search” button in the header looks exactly same as the ‘Link’ button in the sidebar. When we compare the HTML markup,

  • the “Search” button is <button> element
  • but the “Link” button is <a role="button" ...> element

…and even if the markup is different, the styles are identical by using the same classes: .c-btn and .c-btn--yellow.

The button styles are scalable and it allows you to add the same looking components anywhere you want as it won’t be polluted by its parents or siblings. This can save you from the big headache of not knowing why totally unrelated components are broken even if the changes are made on a different component from a totally different place.

Source: Cartoon Network

Extensible

An extensible component can easily provide additional features/functionalities without breaking itself or having to be written from scratch.

Let’s look at the CodePen example again.

See the Pen by iamryanyu (@iamryanyu) on CodePen.

The button in the header and in the main section look quite similar besides the 3D effect. In this case, instead of creating two different sets of buttons having totally different code bases, we could extend the plain button style by just adding the 3D effect to it.

It goes the same with the button in the footer. Even though the button has a different color and size, we could easily extend it by adding or removing new or different features.

Credit: Nana Jeon

Maintainable

Probably one of the biggest challenges for most front-enders is to understand CSS written by other people, or our past selves. We sometimes spend more time trying to understand the existing code than adding awesomely-written new code.

The issue usually comes from:

  • no comments, whatsoever
  • over-engineering
  • no single source of truth
  • no coding standard/best practice considered
  • or all of them above
Credit: Nana Jeon

With SEM and BIO, we can definitely improve the code and save others (including ourselves!) from messy, unmaintainable code.

BIO

There are many great techniques out there to improve the way we write CSS, and from my experience, I found the following three techniques that make up the BIO acronym work very well together

  • BEM
  • ITCSS
  • OOCSS
Credit: Nana Jeon

A lot of developers/engineers already know those famous techniques but I would like to go through each of them and talk about the way I use those techniques.

BEM

BEM is very popular methodology and it has been helping us significantly improve the way we think about CSS and Sass/Less.

BEM stands for:

  • Block
  • Element
  • Modifier
Credit: Nana Jeon

As the bad example above shows, we tend to overuse the power of Sass/Less and falling into nesting-hell. But with BEM, we start to have a very low CSS specificity by maintaining the styles in one (or two) levels of nesting.

If you’ve experienced any battles fighting higher CSS specificity, you will know how painful it is to come out a winner.

Going back to our example, the HTML markup looks like this:

<div class="o-grid">
  <div class="o-grid__item o-grid__header">
    ...
  </div>
  <div class="o-grid__item o-grid__main">
    ...
  </div>
  <div class="o-grid__item o-grid__sidebar">
    ...
  </div>
  <div class="o-grid__item o-grid__footer">
    ...
  </div>
</div>

The example consists of:

  • a block: .o-grid
  • elements: .o-grid__item, .o-grid__header, .o-grid__main, .o-grid__sidebar, .o-grid__footer

Because BEM provides a naming convention that stresses unique classes, we don’t have to go into deep nesting like:

.o-grid {
  .o-grid__item {
    ...
  }
}

Instead, we can define the styles it with fewer levels:

.o-grid__item {
  ...
}

This is the biggest merit of BEM; lowering the CSS specificity which improves the whole CSS coding efficiency and experience.

One issue I still see occasionally even with BEM is poor naming. If you don’t pay enough attention, you can wind up with a really long class name like:

/* Yikes! */
.o-grid__item-search-button-text-svg-icon {
  ...
}

When you create a class name, go with the core concept of BEM: your component is a block and all elements inside are individually attached to the block.

From our example again, I named .o-grid__form instead of .o-grid__item-form because the form itself is a separate component and doesn’t have to be tied with and be a child of o-grid__item.

Also, to more efficiently control styles, I have added another class name o-grid__header along with o-grid__item to extend the styles. Moreover, the button contains BEM-styled classes with the approach of OOCSS, which we’ll touch on next.

OOCSS

As we have already discussed, there are many great CSS methodologies and strategies helping us improve the way we write CSS. However, I see a lot of folks forcing themselves to decide on one methodology to use out of the bunch.

From my experience, combining methodologies can actually enhance their benefits by combining the best of multiple worlds. For example, I personally have found that BEM and OOCSS work very well together.

OOCSS stands for Object Oriented CSS and you can think of it working like Lego blocks:

Source: Flickr

OOCSS creates each individual part separately and then constructs them together in order to build components.

From our example, I have created buttons using the OOCSS naming convention:

  • .c-btn
  • .c-btn--yellow
  • .c-btn--blue
  • .c-btn--3d
  • .c-btn--large

To render the yellow search button in our example header, we combine these classes:

  • .c-btn
  • .c-btn--yellow

If we want to have the 3D button in the main section, we add in the 3D class, .c-btn--3d and call it a day.

And for the blue button in the footer, we can switch the yellow modifier to blue along with the large modifier. As you can see, the button is not depending on the header block giving us greater flexibility with how we use and repurpose components. And, by doing so, we can construct the buttons without impacting any other components or patterns while gaining the benefit of easily extending new presentational feature, like alternative colors and shapes.

Here example of a button collection created using OOCSS to create the variations:

See the Pen Modern Button Collection by Ryan Yu (@iamryanyu) on CodePen.

On top of BEM and OOCSS, with the help of ITCSS, we can further improve our CSS strategy. Let’s look at that method next.

ITCSS

ITCSS stands for Inverted Triangle CSS and it helps organize CSS by applying a structure that determines how specific to get with a specific component. Lubos Kmetko has written an excellent overview of ITCSS that is worth reading.

You can see how I have put ITCSS to use by splitting styles up by grouped levels of specificity in this Gist.

Based on that example, you can see how I named components by adding a namespace to the class. So, for example, a the “button” component is prefixed with a “c” (.c-button) to indicate the component status and prevent it from being mistaken for another item. By doing so, everyone working on the project knows the function of that specific class and how changing its properties might affect other areas.

Here’s a visual that illustrates all the ITCSS levels:

Let’s go through each section.

Settings

Settings are generally a collection of variables that do not generate CSS, but are applied to classes. Some examples include:

  • Base
  • Color
  • Typography
  • Animation
Tools

Tools also will not produce any CSS yet and are typically preprocessor functions that help write or extend properties on classes:

  • Functions
  • Placeholders
  • Mixins
  • Media queries
Vendors

Vendors are third-party styles that are being used on a project. Think of things like reset.css, normalize.css, or even Foundation and Bootstrap.

The reason these styles are higher up in the structure is so we can override them if needed. As you may recall, if the same class is called twice, the cascade will render the properties of the second instance, assuming the properties are exactly the same:

.btn--large {
  padding: 3em;
}

/* This one wins out */
.btn--large {
  padding: 5em;
}

Just for the side note, in Sass, you can use ~ to point to the node_modules folder so you are able to import style assets from the source rather than having to move it into your own directories.

@import '~modern-normalize/modern-normalize';
Objects

Objects (namespace: o-) are used for design patterns, such as layouts, where items are being arranged rather than decorated. Object classes are used across all pages, so if you make any changes to the object classes, you should be very careful because any changes are going to affect each and every page throughout the website.

The most common object classes I use are:

  • .o-page: the most outer container which usually contains max-width: 100vw and overflow: hidden.
  • .o-main: the outer container for the main area.
  • .o-container: the outer container for components and it usually provides a fixed width.
  • .o-content: in case if any extra configuration is needed for the actual content area.
  • .o-grid: if a grid layout with different number of columns are required.

Do you use any other object classes? If so, please share with me. 😃

Elements

Elements (namespace: e-) are the HTML native elements which we would not style based on the class names. For example, we should provide default styles to <a> element rather than .link class.

// Do this for the default link style
a {
  text-decoration: none;

  &:hover {
    background-color: blue;
    color: white;
  }
}

// Don’t provide the default link style to a class
.link {
  text-decoration: none;

  &:hover {
    background-color: blue;
    color: white;
  }
}

It is because, especially in a CMS like WordPress, you wouldn’t want to add a class every single time you want to use a link in content. Hence, we provide a default style to the <a> element so without any class, the link will still have good-looking styles.

Components

A component (namespace: c-) is a small feature that makes up a part of the website. Think buttons, accordions, sliders, modal dialogs, etc. Each component is fully functional by itself and does not rely on any other components. This fact should be considered when you name the component.

For example, the button in the main section from the example above shouldn’t be called .c-main-button because main scopes it inside the main section and limits the use of it in other places, like a sidebar. Something like .c-btn is much nicer because the button is no longer tied to any other specific sections of the page.

If you need any extra features, you can always extend properties with a BEM modifier (combining powers!) or use Scope, which is coming up in a bit.

Patterns

A lot of developers/engineers use the terms component and pattern synonymously and that’s totally fine if you are more comfortable with that. It is just my preference to separate those two terms.

For a general rule of thumb, I think of a pattern (namespace: p-) as a combination of components but in a way that is not scaleable.

For example, I would consider the accordion as a component. It is scaleable and reusable on its own, meaning that it can be used in other parts of the website without making any changes even if the accordion would contain other components such as buttons.

On the other hand, the header, for example, would be a pattern because it is not scaleable (the header cannot be used in the content or sidebar area) and also contains other components such as buttons, accordions, menus, logos, search form etc.

Scope

Be warned; I only use the scope if it’s absolutely necessary. The purpose of the scope (namespace: s-) is to give us the highest specificity so we can overwrite any styles for a specific purpose.

Remember, If you find yourself using the scope class many times, you might be writing styles that are too specific and you should consider refactor your CSS structure.

Here is a simple example of the use of the scope class, .s-home.

.c-accordion {
  .s-home & {
    // Changing the background color specically on the homepage
    background-color: tomato;
  }
}

As a side note, the above example could actually be refactored by providing a modifier to the accordion (e.g., .c-accordion--bg-tomato) instead of using the scope class. That would be a much more extensible way of writing and make the component more modular.

Utility

Sometimes you may want to make changes only for a certain style in a specific place. In that case, utility (namespace: u-) classes can help us update it without changing the whole CSS structure.

For example, the font-size of the accordion heading is set to 32px.

.c-accordion__heading {	 	 
  font-size: rem(32);	 	 
}

But if the font size is only different in the news section of your site and does not change anywhere else, then you might want to apply the utility class instead of setting higher specificity with the parent class or scope class.

<button aria-expanded="false" class="c-accordion__heading u-font-size--24" aria-controls="sect1" id="accordion1id" type="button">...</button>
.u-font-size--24 {	 	 
  font-size: rem(24) !important;	 	 
}

Please note that we all know !important is BAD but I added !important to the value. It is because when we use the utility class, we are absolutely sure we want the specific style to be updated as we want. Also the utility class should overwrite any other styles, so having the !important actually works well here for the utility classes. That said, the utility classes should only play a role as a helper. It should never be used for structuring your CSS.

Like scope classes, if you are using too many utility classes, you should check with designer if the design can be more consistent across the site.

Extra Namespace

On top of the namespaces we discussed above, there are two more I often use:

  • is-: this indicates the state of the block or element. Most commonly used class is .is-active, like the active link in navigation.
  • js-: this indicates that the specific element is bound to JavaScript events. For example, js-menu-click indicates that the element is bound to the click event.

Linting

Finally making rules with .stylelint and .eslint can significantly improve the code quality.

In the frontend workflow, I don’t make it as a recommendation; I make it mandatory so that failing of the rules won’t get approved.

In this way, we can ensure that the coding quality stays at its best and provide better code to other developers, including your future self.

In Action

In this section, I’d like to discuss how we could use SEM and BIO. I have made a simple, practical example to get us started:

See the Pen by iamryanyu (@iamryanyu) on CodePen.

The main practice with the example is to build an accordion that can be used as:

  • a normal accordion but with different color themes in the main section
  • a menu in the sidebar
  • a block displaying social media icons in the footer

What we’re achieving is a component that is:

  • Scalable: as it can be added in any part of the page without any coding changes
  • Extensible: as it can serve different functionalities with the core functions unchanged
  • Maintainable: as it is organized in a way that makes sense

To achieve SEM, BIO has been used including:

  • BEM: .c-accordion as a block and its children as elements, also used modifiers, e.g., .c-accordion--light and .c-accordion--dark
  • ITCSS: The ordering/sorting of SASS files handles the CSS specificity quite well. For example, the accordion button in the sidebar contains class="c-accordion__trigger p-sidebar-menu__button" which the pattern (p-) overwrites the component (c-) with no issues.
  • OOCSS: the accordion is constructed with several classes, for example, class="c-accordion c-accordion--dark c-accordion--single" which creates a dark theme with opening a single panel only each time.

Final thoughts

I have used this approach for almost all of my projects including universities, government departments, commercial retailers, and many other websites. In each case, I have successfully delivered all of the projects to the clients (almost no issues during the client approval stage and delivered on time); this approach has worked for me very well so far and I think it could for you as well.

That being said, technologies always change (especially on the front end) and I am more than happy to hear and discuss any of your ideas/approaches/strategies that worked for you. Let me know in the comments!


Combining the Powers of SEM and BIO for Improving CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/combining-the-powers-of-sem-and-bio-for-improving-css/feed/ 56 271711
Theming With Variables: Globals and Locals https://css-tricks.com/theming-with-variables-globals-and-locals/ https://css-tricks.com/theming-with-variables-globals-and-locals/#comments Fri, 16 Mar 2018 14:04:46 +0000 http://css-tricks.com/?p=268217 Setting CSS variables to theme a design system can be tricky: if they are too scoped, the system will lose consistency. If they are too global, you lose granularity.

Maybe we can fix both issues. I’d like to try to boil design system variables down to two types: Global and Component variables. Global variables will give us consistency across components. Component variables will give us granularity and isolation. Let me show you how to do it by taking a fairly simple component as an example.


Theming With Variables: Globals and Locals originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Cliff Pyles contributed to this post.

Setting CSS variables to theme a design system can be tricky: if they are too scoped, the system will lose consistency. If they are too global, you lose granularity.

Maybe we can fix both issues. I’d like to try to boil design system variables down to two types: Global and Component variables. Global variables will give us consistency across components. Component variables will give us granularity and isolation. Let me show you how to do it by taking a fairly simple component as an example.

Heads up, I’ll be using CSS variables for this article but the concept applies to preprocessor variables as well.

Global-scoped variables

System-wide variables are general concepts defined to keep consistency across your components.

Starting with an .alert component as an example, let’s say we want to keep consistency for all of our spaces on margins and paddings. We can first define global spacers:

:root {
  --spacer-sm: .5rem;
  --spacer-md: 1rem;
  --spacer-lg: 2rem;
}

And then use on our components:

/* Defines the btn component */
.btn {
  padding: var(--spacer-sm) var(--spacer-md);
}

/* Defines the alert component */
.alert {
  padding: var(--spacer-sm) var(--spacer-md);
}

The main benefits of this approach are:

  • It generates a single source of truth for spacers, and a single point for the author using our system to customize it.
  • It achieves consistency since every component follows the same spacing.
  • It produces a common point of reference for designers and developers to work from. As long as the designers follow the same spacing restrictions, the translation to code is seamless.

But it also presents a few problems:

  • The system loses modularity by generating a dependency tree. Since components depend on global variables, they are no longer isolated.
  • It doesn’t allow authors to customize a single component without overwriting the CSS. For example, to change the padding of the alert without generating a system wide shift, they’d have to overwrite the alert component:
.alert {
  padding-left: 1rem;
  padding-right: 1rem;
}

Chris Coyier explains the idea of theming with global variables using custom elements in this article.

Component-scoped variables

As Robin Rendle explain in his article, component variables are scoped to each module. If we generate the alert with these variables, we’d get:

.alert {
  --alert-color: #222;
  
  color: var(--alert-color);
  border-color: var(--alert-color);
}

The main advantages are:

  • It creates a modular system with isolated components.
  • Authors get granular control over components without overwriting them. They’d just redefine the value of the variable.

There is no way to keep consistency across components or to make a system-wide change following this method.

Let’s see how we can get the best of both worlds!

The two-tier theming system

The solution is a two-layer theming system where global variables always inform component variables. Each one of those layers follow a set of very specific rules.

First tier: Global variables

The main reason to have global variables is to maintain consistency, and they adhere to these rules:

  • They are prefixed with the word global and follow the formula --global--concept--modifier--state--PropertyCamelCase
    • a concept is something like a spacer or main-title
    • a state is something like hover, or expanded
    • a modifier is something like sm, or lg
    • and a PropertyCamelCase is something like BackgroundColor or FontSize
  • They are concepts, never tied to an element or component
    • this is wrong: --global-h1-font-size
    • this is right: --global--main-title--FontSize

For example, a global variable setup would look like:

:root {
  /* --global--concept--size */
  --global--spacer--sm: .5rem;
  --global--spacer--md: 1rem;
  --global--spacer--lg: 2rem;

  /* --global--concept--PropertyCamelCase */
  --global--main-title--FontSize: 2rem;
  --global--secondary-title--FontSize: 1.8rem;
  --global--body--FontSize: 1rem;

  /* --global--state--PropertyCamelCase */
  --global--hover--BackgroundColor: #ccc;
}

Second tier: Component variables

The second layer is scoped to theme-able component properties and follow these rules:

  • Assuming we are writing BEM, they follow this formula: --block__element--modifier--state--PropertyCamelCase
    • The block__element--modifier the selector name is something like alert__actions or alert--primary
    • a state is something like hover or active
    • and if you are not writing BEM class names the same principles apply, just replace the block__element--modifier with your classname
  • The value of component scoped variables is always defined by a global variable
  • A component variable always has a default value as a fallback in case the component doesn’t have the dependency on the global variables

For example:

.alert {
  /* Component scoped variables are always defined by global variables */
  --alert--Padding: var(--global--spacer--md);
  --alert--primary--BackgroundColor: var(--global--primary-color);
  --alert__title--FontSize: var(--global--secondary-title--FontSize);

  /* --block--PropertyCamelCase */
  padding: var(--alert--Padding, 1rem); /* Sets the fallback to 1rem. */
}

/* --block--state--PropertyCamelCase */
.alert--primary {
  background-color: var(--alert--primary--BackgroundColor, #ccc);
}

/* --block__element--PropertyCamelCase */
.alert__title {
  font-size: var(--alert__title--FontSize, 1.8rem);
}

You’ll notice that we are defining locally-scoped variables with global variables. This is key for the system to work since it allows authors to theme the system as a whole. For example, if they want to change the primary color across all components they just need to redefine --global--primary-color.

On the other hand, each component variable has a default value so a component can stand on its own, it doesn’t depend on anything and authors can use it in isolation.

This setup allows for consistency across components, it generates a common language between designers and developers since we can set the same global variables in Sketch as bumpers for designers, and it gives granular control to authors.

Why does this system work?

In an ideal world, we as creators of a design system, expect “authors” or users of our system to implement it without modifications, but of course, the world is not ideal, and that never happens.

If we allow authors to easily theme the system without having to overwrite CSS, we’ll not only make their lives easier but also reduce the risk of breaking modules. At the end of the day, a maintainable system is a good system.

The two-tier theming system generates modular and isolated components where authors have the possibility to customize them at a global and at a component level. For example:

:root {
  /* Changes the secondary title size across the system */
  --global--secondary-title--FontSize: 2rem;
}

.alert {
  /* Changes the padding on the alert only */
  --alert--Padding: 3rem;
}

What values should become variables?

CSS variables open windows to the code. The more we allow authors in, the more vulnerable the system is to implementation issues.

To keep consistency, set global variables for everything except layout values; you wouldn’t want authors to break the layout. And as a general rule, I’d recommend allowing access to components for everything you are willing to give support.

For the next version of PatternFly, an open-source design system I work on, we’ll allow customization for almost everything that’s not layout related: colors, spacer, typography treatment, shadows, etc.

Putting everything together

To show this concept in action I’ve created a CodePen project.

Global variables are nestled in _global-variables.scss. They are the base to keep consistency across the system and will allow the author to make global changes.

There are two components: alert and button. They are isolated and modular entities with scoped variables that allow authors to fine-tune components.

Remember that authors will use our system as a dependency in their project. By letting them modify the look and feel of the system through CSS variables, we are creating a solid code base that’s easier to maintain for the creators of the system and better to implement, modify, and upgrade to authors using the system.

For example, if an author wants to:

  • change the primary color to pink across the system;
  • change the danger color to orange just on the buttons;
  • and change the padding left to 2.3rem only on the alert…

…then this is how it’s done:

:root {
  /* Changes the primary color on both the alert and the button */
  --global--primary--Color: hotpink;
}

.button {
  /* Changes the danger color on the button only without affecting the alert */
  --button--danger--BackgroundColor: orange;
  --button--danger--hover--BorderColor: darkgoldenrod;
}

.alert {
  /* Changes the padding left on the alert only without affecting the button */
  --alert--PaddingLeft: 2.3rem;
}

The design system code base is intact and it’s just a better dependency to have.

I am aware that this is just one way to do it and I am sure there are other ways to successfully set up variables on a system. Please let me know what you think in the comments or send me a tweet. I’d love to hear about what you are doing and learn from it.


Theming With Variables: Globals and Locals originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/theming-with-variables-globals-and-locals/feed/ 13 268217
ABEM. A more useful adaptation of BEM. https://css-tricks.com/abem-useful-adaptation-bem/ https://css-tricks.com/abem-useful-adaptation-bem/#comments Wed, 13 Dec 2017 17:58:43 +0000 http://css-tricks.com/?p=263223 BEM (Block Element Modifier) is a popular CSS class naming convention that makes CSS easier to maintain. This article assumes that you are already familiar with the naming convention. If not you can learn more about it at getbem.com to …


ABEM. A more useful adaptation of BEM. originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
BEM (Block Element Modifier) is a popular CSS class naming convention that makes CSS easier to maintain. This article assumes that you are already familiar with the naming convention. If not you can learn more about it at getbem.com to catch up on the basics.

The standard syntax for BEM is:

block-name__element-name--modifier-name

I’m personally a massive fan of the methodology behind the naming convention. Separating your styles into small components is far easier to maintain than having a sea of high specificity spread all throughout your stylesheet. However, there are a few problems I have with the syntax that can cause issues in production as well as cause confusion for developers. I prefer to use a slightly tweaked version of the syntax instead. I call it ABEM (Atomic Block Element Modifier):

[a/m/o]-blockName__elementName -modifierName

An Atomic Design Prefix

The a/m/o is an Atomic Design prefix. Not to be confused with Atomic CSS which is a completely different thing. Atomic design is a methodology for organizing your components that maximizes the ability to reuse code. It splits your components into three folders: atoms, molecules, and organisms. Atoms are super simple components that generally consist of just a single element (e.g. a button component). Molecules are small groups of elements and/or components (e.g. a single form field showing a label and an input field). Organisms are large complex components made up of many molecule and atom components (e.g. a full registration form).

An Atomic Design Diagram showing atoms inside molecules inside an organism

The difficulty of using atomic design with classic BEM is that there is no indicator saying what type of component a block is. This can make it difficult to know where the code for that component is since you may have to search in 3 separate folders in order to find it. Adding the atomic prefix to the start makes it immediately obvious what folder the component is stored in.

camelCase

It allows for custom grouping

Classic BEM separates each individual word within a section with a single dash. Notice that the atomic prefix in the example above is also separated from the rest of the class name by a dash. Take a look at what happens now when you add an atomic prefix to BEM classic vs camelCase:

/* classic + atomic prefix */
.o-subscribe-form__field-item {}

/* camelCase + atomic prefix */
.o-subscribeForm__fieldItem {}

At a glance, the component name when reading the classic method looks like it’s called “o subscribe form”. The significance of the “o” is completely lost. When you apply the “o-” to the camelCase version though, it is clear that it was intentionally written to be a separate piece of information to the component name.

Now you could apply the atomic prefix to classic BEM by capitalizing the “o” like this:

/* classic + capitalized atomic prefix */
.O-subscribe-form__field-item {}

That would solve the issue of the “o” getting lost amongst the rest of the class name however it doesn’t solve the core underlying issue in the classic BEM syntax. By separating the words with dashes, the dash character is no longer available for you to use as a grouping mechanism. By using camelCase, it frees you up to use the dash character for additional grouping, even if that grouping is just adding a number to the end of a class name.

Your mind will process the groupings faster

camelCase also has the added benefit of making the grouping of the class names easier to mentally process. With camelCase, every gap you see in the class name represents a grouping of some sort. In classic BEM, every gap could be either a grouping or a space between two words in the same group.

Take a look at this silhouette of a classic BEM class (plus atomic prefix) and try to figure out where the prefix, block, element and modifier sections start and end:

classic BEM silhouette

Ok, now try this one. It is the exact same class as the one above except this time it is using camelCase to separate each word instead of dashes:

camel case BEM silhouette

That was much easier wasn’t it? Those silhouettes are essentially what your mind sees when it is scanning through your code. Having all those extra dashes in the class name make the groupings far less clear. As you read through your code, your brain tries to process whether the gaps it encounters are new groupings or just new words. This lack of clarity causes cognitive load to weigh on your mind as you work.

classic BEM + atomic prefix
classic BEM silhouette revealed
camelCase BEM + atomic prefix
camel case BEM silhouette revealed

Use multi class selectors (responsibly)

One of the golden rules in BEM is that every selector is only supposed to contain a single class. The idea is that it keeps CSS maintainable by keeping the specificity of selectors low and manageable. On the one hand, I agree that low specificity is preferable over having specificity run rampant. On the other, I strongly disagree that a strict one class per selector rule is the best thing for projects. Using some multi-class selectors in your styles can actually improve maintainability rather than diminish it.

“But it leads to higher specificity! Don’t you know that specificity is inherently evil?!?”

Specificity != bad.

Uncontrolled specificity that has run wild = bad.

Having some higher specificity declarations doesn’t instantly mean that your CSS is more difficult to maintain. If used in the right way, giving certain rules higher specificity can actually make CSS easier to maintain. The key to writing maintainable CSS with uneven specificity is to add specificity purposefully and not just because a list item happens to be inside a list element.

Besides, don’t we actually want our modifier styles to have greater power over elements than default styles? Bending over backwards to keep modifier styles at the same specificity level as normal styles seems silly to me. When do you actually want your regular default styles to override your specifically designated modifier styles?

Separating the modifier leads to cleaner HTML

This is the biggest change to the syntax that ABEM introduces. Instead of connecting the modifier to the element class, you apply it as a separate class.

One of the things that practically everyone complains about when they first start learning BEM is how ugly it is. It is especially bad when it comes to modifiers. Take a look at this atrocity. It only has three modifiers applied to it and yet it looks like a train wreck:

B__E–M:
<button class="block-name__element-name block-name__element-name--small block-name__element-name--green block-name__element-name--active">
  Submit
</button>

Look at all that repetition! That repetition makes it pretty difficult to read what it’s actually trying to do. Now take a look at this ABEM example that has all the same modifiers as the previous example:

A-B__E -M:
<button class="a-blockName__elementName -small -green -active">
  Submit
</button>

Much cleaner isn’t it? It is far easier to see what those modifier classes are trying to say without all that repetitive gunk getting in the way.

When inspecting an element with browser DevTools, you still see the full rule in the styling panel so it retains the connection to the original component in that way:

.a-blockName__elementName.-green {
  background: green;
  color: white;
}

It’s not much different to the BEM equivalent

.block-name__element-name--green {
  background: green;
  color: white;
}

Managing state becomes easy

One large advantage that ABEM has over classic BEM is that it becomes immensely easier to manage the state of a component. Let’s use a basic accordion as an example. When a section of this accordion is open, let’s say that we want to apply these changes to the styling:

  • Change the background colour of the section heading
  • Display the content area
  • Make a down arrow point up

We are going to stick to the classic B__E–M syntax for this example and strictly adhere to the one class per css selector rule. This is what we end up with (note, that for the sake of brevity, this accordion is not accessible):

See the Pen Accordion 1 – Pure BEM by Daniel Tonon (@daniel-tonon) on CodePen.

The SCSS looks pretty clean but take a look at all the extra classes that we have to add to the HTML for just a single change in state!

HTML while a segment is closed using BEM:

<div class="revealer accordion__section">
  <div class="revealer__trigger">
    <h2 class="revealer__heading">Three</h2>
    <div class="revealer__icon"></div>
  </div>
  <div class="revealer__content">
    Lorem ipsum dolor sit amet...
  </div>
</div>

HTML while a segment is open using BEM:

<div class="revealer accordion__section">
  <div class="revealer__trigger revealer__trigger--open">
    <h2 class="revealer__heading">One</h2>
    <div class="revealer__icon revealer__icon--open"></div>
  </div>
  <div class="revealer__content revealer__content--open">
    Lorem ipsum dolor sit amet...
  </div>
</div>

Now let’s take a look at what happens when we switch over to using this fancy new A-B__E -M method:

See the Pen Accordion 2 – ABEM alternative by Daniel Tonon (@daniel-tonon) on CodePen.

A single class now controls the state-specific styling for the entire component now instead of having to apply a separate class to each element individually.

HTML while a segment is open using ABEM:

<div class="m-revealer o-accordion__section -open">
  <div class="m-revealer__trigger">
    <h2 class="m-revealer__heading">One</h2>
    <div class="m-revealer__icon"></div>
  </div>
  <div class="m-revealer__content">
    Lorem ipsum dolor sit amet...
  </div>
</div>

Also, take a look at how much simpler the javascript has become. I wrote the JavaScript as cleanly as I could and this was the result:

JavaScript when using pure BEM:

class revealer {
  constructor(el){
    Object.assign(this, {
      $wrapper: el,
      targets: ['trigger', 'icon', 'content'],
      isOpen: false,
    });
    this.gather_elements();
    this.$trigger.onclick = ()=> this.toggle();
  }

  gather_elements(){
    const keys = this.targets.map(selector => `$${selector}`);
    const elements = this.targets.map(selector => {
      return this.$wrapper.querySelector(`.revealer__${selector}`);
    });
    let elObject = {};
    keys.forEach((key, i) => {
      elObject[key] = elements[i];
    });
    Object.assign(this,	elObject);
  }
  
  toggle(){
    if (this.isOpen) {
      this.close();
    } else {
      this.open();
    }
  }

  open(){
    this.targets.forEach(target => {
      this[`$${target}`].classList.add(`revealer__${target}--open`);
    })
    this.isOpen = true;
  }

  close(){
    this.targets.forEach(target => {
      this[`$${target}`].classList.remove(`revealer__${target}--open`);
    })
    this.isOpen = false;
  }
}

document.querySelectorAll('.revealer').forEach(el => {
  new revealer(el);
})

JavaScript when using ABEM:

class revealer {
  constructor(el){
    Object.assign(this, {
      $wrapper: el,
      isOpen: false,
    });
    this.$trigger = this.$wrapper.querySelector('.m-revealer__trigger');
    this.$trigger.onclick = ()=> this.toggle();
  }
  
  toggle(){
    if (this.isOpen) {
      this.close();
    } else {
      this.open();
    }
  }

  open(){
    this.$wrapper.classList.add(`-open`);
    this.isOpen = true;
  }

  close(){
    this.$wrapper.classList.remove(`-open`);
    this.isOpen = false;
  }
}

document.querySelectorAll('.m-revealer').forEach(el => {
  new revealer(el);
})

This was just a very simple accordion example. Think about what happens when you extrapolate this out to something like a sticky header that changes when sticky. A sticky header might need to tell 5 different components when the header is sticky. Then in each of those 5 components, 5 elements might need to react to that header being sticky. That’s 25 element.classList.add("[componentName]__[elementName]--sticky") rules we would need to write in our js to strictly adhere to the BEM naming convention. What makes more sense? 25 unique classes that are added to every element that is affected, or just one -sticky class added to the header that all 5 elements in all 5 components are able to access and read easily?

The BEM “solution” is completely impractical. Applying modifier styling to large complex components ends up turning into a bit of a grey area. A grey area that causes confusion for any developers trying to strictly adhere to the BEM naming convention as closely as possible.

ABEM modifier issues

Separating the modifier isn’t without its flaws. However, there are some simple ways to work around those flaws.

Issue 1: Nesting

So we have our accordion and it’s all working perfectly. Later down the line, the client wants to nest a second accordion inside the first one. So you go ahead and do that… this happens:

See the Pen Accordion 3 – ABEM nesting bug by Daniel Tonon (@daniel-tonon) on CodePen.

Nesting a second accordion inside the first one causes a rather problematic bug. Opening the parent accordion also applies the open state styling to all of the child accordions in that segment.

This is something that you obviously don’t want to happen. There is a good way to avoid this though.

To explain it, let’s play a little game. Assuming that both of these CSS rules are active on the same element, what color do you think that element’s background would be?

.-green > * > * > * > * > * > .element {
  background: green;
}

.element.-blue {
  background: blue;
}

If you said green due to the first rule having a higher specificity than the second rule, you would actually be wrong. Its background would be blue.

Fun fact: * is the lowest specificity selector in CSS. It basically means “anything” in CSS. It actually has no specificy, meaning it doesn’t add any specificity to a selector you add it to. That means that even if you used a rule that consisted of a single class and 5 stars (.element > * > * > * > * > *) it could still be easily overwritten by just a single class on the next line of CSS!

We can take advantage of this little CSS quirk to create a more targeted approach to the accordion SCSS code. This will allow us to safely nest our accordions.

See the Pen Accordion 4 – ABEM nesting bug fix by Daniel Tonon (@daniel-tonon) on CodePen.

By using the .-modifierName > * > & pattern, you can target direct descendants that are multiple levels deep without causing your specificity to get out of control.

I only use this direct targeting technique as it becomes necessary though. By default, when I’m writing ABEM, I’ll write it how I did in that original ABEM accordion example. The non-targeted method is generally all that is needed in most cases. The problem with the targeted approach is that adding a single wrapper around something can potentially break the whole system. The non-targeted approach doesn’t suffer from this problem. It is much more lenient and prevents the styles from breaking if you ever need to alter the HTML later down the line.

Issue 2: Naming collisions

An issue that you can run into using the non-targeted modifier technique is naming collisions. Let’s say that you need to create a set of tabs and each tab has an accordion in it. While writing this code, you have made both the accordion and the tabs respond to the -active class. This leads to a name collision. All accordions in the active tab will have their active styles applied. This is because all of the accordions are children of the tab container elements. It is the tab container elements that have the actual -active class applied to them. (Neither the tabs nor the accordion in the following example are accessible for the sake of brevity.)

See the Pen Accordion in tabs 1 – broken by Daniel Tonon (@daniel-tonon) on CodePen.

Now one way to resolve this conflict would be to simply change the accordion to respond to an -open class instead of an -active class. I would actually recommend that approach. For the sake of an example though, let’s say that isn’t an option. You could use the direct targeting technique mentioned above, but that makes your styles very brittle. Instead what you can do is add the component name to the front of the modifier like this:

.o-componentName {
  &__elementName {
    .-componentName--modifierName & {
      /* modifier styles go here */
    }
  }
}

The dash at the front of the name still signifies that it is a modifier class. The component name prevents namespace collisions with other components that should not be getting affected. The double dash is mainly just a nod to the classic BEM modifier syntax to double reinforce that it is a modifier class.

Here is the accordion and tabs example again but this time with the namespace fix applied:

See the Pen Accordion in tabs 2 – fixed by Daniel Tonon (@daniel-tonon) on CodePen.

I recommend not using this technique by default though mainly for the sake of keeping the HTML clean and also to prevent confusion when multiple components need to share the same modifier.

The majority of the time, a modifier class is being used to signify a change in state like in the accordion example above. When an element changes state, all child elements, no matter what component they belong to, should be able to read that state change and respond to it easily. When a modifier class is intended to affect multiple components at once, confusion can arise around what component that modifier specifically belongs to. In those cases, name-spacing the modifier does more harm than good.

ABEM modifier technique summary

So to make the best use of the ABEM modifier, use .-modifierName & or &.-modifierName syntax by default (depends on what element has the class on it)

.o-componentName {
  &.-modifierName {
    /* componentName modifier styles go here */
  }

&__elementName {
    .-modifierName & {
      /* elementName modifier styles go here */
    }
  }
}

Use direct targeting if nesting a component inside itself is causing an issue.

.o-componentName {
  &__elementName {
    .-nestedModifierName > * > & {
      /* modifier styles go here */
    }
  }
}

Use the component name in the modifier if you run into shared modifier name collisions. Only do this if you can’t think of a different modifier name that still makes sense.

.o-componentName {
  &__elementName {
    .-componentName--sharedModifierName & {
      /* modifier styles go here */
    }
  }
}

Context sensitive styles

Another issue with strictly adhering to the BEM one class per selector methodology is that it doesn’t allow you to write context sensitive styles.

Context sensitive styles are basically “if this element is inside this parent, apply these styles to it”.

With context sensitive styles, there is a parent component and a child component. The parent component should be the one that applies layout related styles such as margin and position to the child component (.parent .child { margin: 20px }). The child component should always by default not have any margin around the outside of the component. This allows the child components to be used in more contexts since it is the parent in charge of it’s own layout rather than its children.

Just like with real parenting, the parents are the ones who should be in charge. You shouldn’t let their naughty clueless children call the shots when it comes to the parents layout.

To dig further into this concept, let’s pretend that we are building a fresh new website and right now we are building the subscribe form component for the site.

See the Pen Context sensitive 1 – IE unfriendly by Daniel Tonon (@daniel-tonon) on CodePen.

This is the first time we have had to put a form on this awesome new site that we are building. We want to be like all the cool kids so we used CSS grid to do the layout. We’re smart though. We know that the button styling is going to be used in a lot more places throughout the site. To prepare for this, we separate the subscribe button styles into its own separate component like good little developers.

A while later we start cross-browser testing. We open up IE11 only to see this ugly thing staring us in the face:

IE11 does kind of support CSS grid but it doesn’t support grid-gap or auto placement. After some cathartic swearing and wishing people would update their browsers, you adjust the styles to look more like this:

See the Pen Context sensitive 2 – what not to do by Daniel Tonon (@daniel-tonon) on CodePen.

Now it looks perfect in IE. All is right with the world. What could possibly go wrong?

A couple of hours later you are putting this button component into a different component on the site. This other component also uses css-grid to layout its children.

You write the following code:

See the Pen Context sensitive 3 – the other component by Daniel Tonon (@daniel-tonon) on CodePen.

You expect to see a layout that looks like this even in IE11:

But instead, because of the grid-column: 3; code you wrote earlier, it ends up looking like this:

Yikes! So what do we do about this grid-column: 3; CSS we wrote earlier? We need to restrict it to the parent component but how should we go about doing that?

Well the classic BEM method of dealing with this is to add a new parent component element class to the button like this:

See the Pen Context sensitive 4 – classic BEM solution by Daniel Tonon (@daniel-tonon) on CodePen.

On the surface this solution looks pretty good:

  • It keeps specificity low
  • The parent component is controlling its own layout
  • The styling isn’t likely to bleed into other components we don’t want it to bleed into

Everything is awesome and all is right with the world… right?

The downside of this approach is mainly due to the fact that we had to add an extra class to the button component. Since the subscribe-form__submit class doesn’t exist in the base button component, it means that we need to add extra logic to whatever we are using as our templating engine for it to receive the correct styles.

I love using Pug to generate my page templates. I’ll show you what I mean using Pug mixins as an example.

First, here is the original IE unfriendly code re-written in mixin format:

See the Pen Context sensitive 5 – IE unfriendly with mixins by Daniel Tonon (@daniel-tonon) on CodePen.

Now lets add that IE 11 subscribe-form__submit class to it:

See the Pen Context sensitive 6 – IE safe BEM solution with mixins by Daniel Tonon (@daniel-tonon) on CodePen.

That wasn’t so hard, so what am I complaining about? Well now let’s say that we sometimes want this module to be placed inside a sidebar. When it is, we want the email input and the button to be stacked on top of one another. Remember that in order to strictly adhere to BEM, we are not allowed to use anything higher in specificity than a single class in our styles.

See the Pen Context sensitive 7 – IE safe BEM with mixins in sidebar by Daniel Tonon (@daniel-tonon) on CodePen.

That Pug code isn’t looking so easy now is it? There are a few things contributing to this mess.

  1. Container queries would make this far less of a problem but they don’t exist yet natively in any browser
  2. The problems around the BEM modifier syntax are rearing their ugly heads.

Now lets try doing it again but this time using context sensitive styles:

See the Pen Context sensitive 8 – IE safe Context Sensitive with mixins in sidebar by Daniel Tonon (@daniel-tonon) on CodePen.

Look at how much simpler the Pug markup has become. There is no “if this then that” logic to worry about in the pug markup. All of that parental logic is passed off to the css which is much better at understanding what elements are parents of other elements anyway.

You may have noticed that I used a selector that was three classes deep in that last example. It was used to apply 100% width to the button. Yes a three class selector is ok if you can justify it.

I didn’t want 100% width to be applied to the button every time it was:

  • used at all anywhere
  • placed inside the subscribe form
  • placed inside the side-bar

I only wanted 100% width to be applied when it was both inside the subscribe form and inside the sidebar. The best way to handle that was with a three class selector.

Ok, in reality, I would more likely use an ABEM style -verticalStack modifier class on the subscribe-form element to apply the vertical stack styles or maybe even do it through element queries using EQCSS. This would mean that I could apply the vertical stack styles in more situations than just when it’s in the sidebar. For the sake of an example though, I’ve done it as context sensitive styles.

Now that we understand context sensitive styles, let’s go back to that original example I had and use some context sensitive styles to apply that troublesome grid-column: 3 rule:

See the Pen Context sensitive 9 – context sensitive method with mixins by Daniel Tonon (@daniel-tonon) on CodePen.

Context sensitive styles lead to simpler HTML and templating logic whilst still retaining the reusability of child components. BEM’s one class per selector philosophy doesn’t allow for this to happen though.

Since context sensitive styles are primarily concerned with layout, depending on circumstances, you should generally use them whenever you are dealing with these CSS properties:

  • Anything CSS grid related that is applied to the child element (grid-column, grid-row etc.)
  • Anything flexbox related that is applied to the child element (flex-grow, flex-shrink, align-self etc.)
  • margin values greater than 0
  • position values other than relative (along with the top, left, bottom, and right properties)
  • transform if it is used for positioning like translateY

You may also want to place these properties into context-sensitive styles but they aren’t as often needed in a context sensitive way.

  • width
  • height
  • padding
  • border

To be absolutely clear though, context sensitive styles are not nesting for the sake of nesting. You need to think of them as if you were writing an if statement in JavaScript.

So for a CSS rule like this:

.parent .element {
  /* context sensitive styles */
}

You should think of it like you are writing this sort of logic:

if (.element in .parent) {
  .element { /* context sensitive styles */ }
}

Also understand that writing a rule that is three levels deep like this:

.grandparent .parent .element {
  /* context sensitive styles */
}

Should be thought of like you are writing logic like this:

if (
    (.element in .parent) &&
    (.element in .grandparent) &&
    (.parent in .grandparent)
  ) {
  .element { /* context sensitive styles */ }
}

So by all means, write a css selector that is three levels deep if you really think you need that level of specificity. Please understand the underlying logic of the css that you are writing though. Only use a level of specificity that makes sense for the particular styling that you are trying to achieve.

And again, one more time, just to be super clear, do not nest for the sake of nesting!

Summing Up

The methodology behind the BEM naming convention is something that I wholeheartedly endorse. It allows css to be broken down into small easily manageable components rather than leaving css in an unwieldy mess of high specificity that is difficult to maintain. The official syntax for BEM has a lot to be desired though.

The official BEM syntax:

  • Doesn’t support Atomic Design
  • Is unable to be extended easily
  • Takes longer for your mind to process the grouping of the class names
  • Is horribly incompetent when it comes to managing state on large components
  • Tries to encourage you to use single class selectors when double class selectors lead to easier maintainability
  • Tries to name-space everything even when namespacing causes more problems than it solves.
  • Makes HTML extremly bloated when done properly

My unofficial ABEM approach:

  • Makes working with Atomic Design easier
  • Frees up the dash character as an extra method that can be used for grouping
  • Allows your mind to process the grouping of the class names faster
  • Is excellent at handling state on any sized component no matter how many sub components it has
  • Encourages controlled specificity rather than just outright low specificity to mitigate team confusion and improve site maintainability
  • Avoids namespacing when it isn’t needed
  • Keeps HTML quite clean with minimal extra classes applied to modules while still retaining all of BEM’s advantages

Disclaimer

I didn’t invent the -modifier (single dash before the modifier name) idea. I discovered it in 2016 from reading an article. I can’t remember who originally conceptualised the idea. I’m happy to credit them if anyone knows the article though.

Update: 21st of January 2018 (comments response)

No one was able to link to the exact article where I learnt about the -modifier syntax. What I can say is that I learnt it from reading an article about BEVM (block__element–variation -modifier).

Here are some other people that came up with the -modifier syntax before me:

BEVM can still work with ABEM if you like that methodology (making it ABEVM). After using the -modifier syntax for a while though I eventually stopped using the &--modifier syntax altogether. I couldn’t really see any benefit in keeping the double dash around when the single dash was easier to use in my CSS and was making my HTML much cleaner.

There were a few people who referenced BEMIT as being quite similar. They’re right, it does share some similarities with BEMIT but it also has some differences.

You could merge ABEM and BEMIT together to an extent. I had people mention that they prefer the explicit “is” of the state based classes in BEMIT (eg. .is-active). That is perfectly fine, if you want to add the “is” to ABEM I would recommend writing the modifier like this .-is-modifierName. See what I mean by camelCase allowing for custom grouping?

The utilities can be carried across from BEMIT as well pretty easily, it would still be written as .u-utilityName. The “utilities” folder/file should maybe be placed in the same directory as the atoms, molecules and organisms folders. I think that might make it easier to find. The “object” and “component” name spaces in BEMIT wouldn’t carry across. They would be replaced with the Atomic Design name spaces in ABEM.

An interesting discussion in the comments was about using the @extend functionality in Sass. For example using <button class='subscribe-form__submit'></button> and .subscribe-form__submit { @extend .button; grid-column: 3; }. I think context sensitive styles are the better way to go. I pretty strongly disagreed with that implementation of @extend unless the CMS is forcing you down that path. You can see the full comment and my response here: https://css-tricks.com/abem-useful-adaptation-bem/#comment-1613824.

A thing many people had issue with was that I didn’t go into much depth around what Atomic Design is and how to use it. It was out of scope for this article. If I tried to go in depth on how to categorize components using Atomic Design principles, then it would have easily doubled the length of the article (and this article is already very long as it is). I gave enough of a summary to introduce the concept of Atomic Design and I linked to a resource that goes much more in depth on the topic. That was about as much attention as I wanted to give to explaining Atomic Design.

Since Atomic Design categorization is such a confusing subject, I have plans to write an article that will be all about how to go about categorizing Atomic Design components. I will attempt to create a set of clear guidelines to follow to help figure out what Atomic Design category a particular component belongs to. Don’t expect it any time soon though. It’s going to be a while before it gets published.

Update: 2nd of April 2019 (Atomic Categorization tool)

So those plans to write an Atomic Design article never came to fruition. I started planning one out, but I began to realize that writing an article to try and explain all the little things that you need to consider when categorizing modules was the wrong way to go about it. A tool that gave you a recommendation at the end would be far more useful.

So I got to work and I am happy to announce the launch of my brand new Atomic Categorizer tool!

It is a simple quiz that gives you points toward each category as you answer the questions. The questions and points might not be 100% perfect but I think it does a pretty good job of categorizing the components most of the time. Give it a try, it’s way more fun than reading another couple thousand words worth of text. 😊


ABEM. A more useful adaptation of BEM. originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/abem-useful-adaptation-bem/feed/ 37 263223
Caching the Current Selector (&) in Sass https://css-tricks.com/snippets/sass/caching-current-selector-sass/ https://css-tricks.com/snippets/sass/caching-current-selector-sass/#comments Tue, 14 Feb 2017 22:24:15 +0000 http://css-tricks.com/?page_id=251511 The & character in Sass is unique in that it represents the current selector. It changes as you nest. Let’s say you are nested, but you want access to a selector back up the nesting a bit. The trick is …


Caching the Current Selector (&) in Sass originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The & character in Sass is unique in that it represents the current selector. It changes as you nest. Let’s say you are nested, but you want access to a selector back up the nesting a bit. The trick is to cache & and use it deeper in the nesting. Like:

.parent {

  $this: &;
  
  &--elem {
    display: inline-block;
    
    &:hover,
    #{$this}__variation--active & {
      background: red;
    }
    
  }
  
}

Which compiles to:

.parent--elem {
  display: inline-block;
}
.parent--elem:hover, .parent__variation--active .parent--elem {
  background: red;
}

(Thanks to Sergey Kovalenko for sending in this trick!)

Meaning it allowed you to use .parent and .parent--elem within a selector at the same time. A little esoteric, but might be useful sometimes. Sort of avoids situations where you might need to use @at-root to back out all the way and re-make selectors.

Sergey’s gist has examples that are BEM-based:

<ul class="pagination">
  <li class="pagination__item">
    <a class="pagination__link" href="#">
      Page 1
    </a>
  </li>
  <li class="pagination__item pagination__item--active">
    <a class="pagination__link" href="#">
      Page 2
    </a>
  </li>
</ul>
$gray-very-light: #ccc;

.pagination {
  display: flex;
  padding: 0;
  list-style: none;

  $this: &;

  &__item {
    border: 1px solid $gray-very-light;

    & + & {
      margin-left: .5rem;
    }
  }

  &__link {
    display: block;
    padding: .25rem .5rem;
    text-decoration: none;

    &:hover,
    #{$this}__item--active & { // Here we get .pagination from $this variable
      background-color: $gray-very-light;
    }
  }
}

Output:

.pagination {
    display: flex;
    padding: 0;
    list-style: none;
}

.pagination__item {
    border: 1px solid #ccc;
}

.pagination__item + .pagination__item {
    margin-left: .5rem;
}

.pagination__link {
    display: block;
    padding: .25rem .5rem;
    text-decoration: none;
}

.pagination__link:hover,
.pagination__item--active .pagination__link {
    background-color: #ccc;
}

Caching the Current Selector (&) in Sass originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/snippets/sass/caching-current-selector-sass/feed/ 7 251511
Developing Extensible HTML and CSS Components https://css-tricks.com/developing-extensible-html-css-components/ https://css-tricks.com/developing-extensible-html-css-components/#comments Mon, 29 Aug 2016 13:15:15 +0000 http://css-tricks.com/?p=244866 The following is a guest post by Jon Yablonski. Jon is going to show us an example of how we might approach markup such that one component is particularly versatile. It works as-is, and has a standardized way of


Developing Extensible HTML and CSS Components originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The following is a guest post by Jon Yablonski. Jon is going to show us an example of how we might approach markup such that one component is particularly versatile. It works as-is, and has a standardized way of making variations (adding a single class) that allow the design to be altered to fit the situation.

Media patterns

The days of building fixed-width web pages from pixel-perfect Photoshop files are gone. In order to produce flexible layouts that smartly adapt to any screen size, our workflows have undergone changes to be more iterative and agile. We’ve come to understand the importance of modularity and how it facilitates the flexibility we need to stay nimble in the browser. As a designer and front-end developer, this flexibility is integral to how I approach web projects. I find myself making design decisions in the browser more often than design files, and to support this workflow I need the ability to build user interface modules that can be easily extended.

Extendable Modules

What I’ve come to value highly is extensibility, a systems design principle where the implementation takes future growth into consideration. The central theme of extensibility is to provide for change while minimizing impact to the existing system. For front-end development, this means building module variations that can easily be extended to fit the needs of the user interface while preserving the underlying foundation of the module. The end result is less code bloat, less fragmentation of the code base due to one-off solutions, and code that is easier to maintain.

Building for Extensibility

To ensure consistency in the structure of our components and patterns, it’s necessary to build them in a fashion that is repeatable and predictable. The following are the basic steps I take:

Step 1: Identify the Module Type

The first step is to identify the type of module we are working with, which can be classified into one of two categories: component or pattern. A component is an independent, modular object that has no children elements, but can have modifier states that change their appearance (example: buttons, messages, thumbnails). A pattern on the other hand is an object that has children (which can be stand-alone components as well), all of which is affected by the parent object (example: header, header logo, header nav). Both components and patterns can have modifier states that change their appearance or structure.

Step 2: Define the Module Foundation

The next step is to find the component or pattern’s foundational rules that all variations of the component will inherit. These rules should be relatively minimal and reserved for properties that will rarely change. More often than not, I find these rules are properties like margin, padding, position, and display.

All code examples in this article are using BEM (block, element, modifier) naming methodology. BEM offers a number of advantages, but perhaps my favorite is that I can simply look at a piece of markup is doing from its name alone. If you want to know more about this naming methodology, I’d recommend checking out this article for a good introduction.

HTML Foundation
<div class="block"></div>
CSS Foundation
.block {
  position: relative;
  margin: 0 0 1em;
}

Step 3: Define Common Elements

If you’re building a component, then you can skip this step and go straight to the next step; but if you’re building a pattern that will contain child elements, then the next step is to define common elements. These elements are thematically-related to the parent block (but can exists outside of the pattern as stand-alone components).

HTML Common Elements
<div class="block">
  <div class="block__element">…</div>
  <div class="block__another-element">…</div>
</div>
CSS
.block__element {
  padding: 1em;
  background: white;
  border: 1px solid black;
}

.block__another-element {
  position: absolute;
  top: 0;
  right: 0;
}

Step 4: Extend with Modifiers

The final step is to extend your component/pattern with modifiers. Modifiers are essentially variations that extend the foundational block and children, and can be created as you need them.

Example of HTML modifier class

<div class="block block—modifier">
  <div class="block__element">…</div>
  <div class="block__another-element">…</div>
</div>

Example of CSS Modification

.block—modifier {
  border-top: 3px solid red;
}

.block—modifier .block__element {
  background: grey;
}

Examples

Now that we’ve taken a look at the basic steps involved with building extendable components and patterns, it’s time to explore some examples. We’ll begin with a relatively simple component and how it can be extended to cover a variety of scenarios, and then we’ll look a slightly more complex pattern.

About Components

The following is a demo of several common components along with variations. Each component consists of a parent block and modifiers that extend the style of the block. This allows for variations to be rapidly created, giving you the flexibility to quickly iterate and adapt components to any circumstance in your user interface.

Common Components Example

See the Pen Common Extendable Components by Jon Yablonski (@jonyablonski) on CodePen.

Components by their nature should be relatively simple, as they do not contain child elements. Now, let’s take a look at a something that is slightly more complex.

About Patterns

A media pattern is an object that consists of a media element (this can be an image or video), and related content (usually in the form of text). You might be familiar with a variation of the media pattern known as a ‘media object’ or ‘flag object’, which we’ll touch on in a bit. This pattern is a great example of how building with extensibility in mind provides endless flexibility.

Media Default Pattern

We’ll start with our default pattern, or how it will be displayed with no modifiers. I’ve made some assumptions here by leveraging an <article> tag to provide more semantic information, but this can be changed to be any tag you want. The core styles of our media pattern are:

  1. A flex container in which its children do not wrap
  2. A bit of margin

These are styles that all media pattern’s will inherit. In addition, each media pattern will contain the media item (in this case an image), and the media body which consists of a title and a definition list.

See the Pen Default Media Pattern by Jon Yablonski (@jonyablonski) on CodePen.

Media Card Pattern

While this default variation of our media pattern might be sufficient in some circumstances, there will be plenty others in which you’ll want to drastically alter its appearance. The next step is to begin identifying variations which will allow our pattern to adapt to a variety of situations. Let’s begin with a variation that is not a huge departure from the default appearance — a card variation. The premise is that very little will need to change to our markup, and we can change the appearance of our pattern by simply adding a modifier class to the parent block:

See the Pen Media Card Pattern by Jon Yablonski (@jonyablonski) on CodePen.

Media Object Pattern

Let’s say, later on, I’ve discovered I need a pattern which the image and text are displayed side-by-side when there is enough space available. This is a pattern commonly known as a ‘media object’. To create it, we can simply extend the media pattern we already have in order keep redundant code minimal.

See the Pen Media Object Pattern by Jon Yablonski (@jonyablonski) on CodePen.

Media Slat Pattern

Let’s push things a bit further with a variation that will really put it to the test. The variations we defined thus far are accommodating pretty much all my design needs, but I need one more with a little more of an impact. Let’s create a variation that is spans the full-width of the window with the body filling half, and the image filling the other. In addition to this, I want to make sure the body content aligns with the other content on the page. We’ll call this variation a ‘media slat’:

See the Pen Media Slat Pattern by Jon Yablonski (@jonyablonski) on CodePen.

Now we have several variations of our media pattern: we have the default variation, the card variation, the object variation, and finally the slat variation. These variations of our pattern are all useful in different circumstances, and they all make sure of the same underlying foundation of code! What’s great about this is that any change that happens to our pattern will affect all patterns, so each instance of this pattern will remain in sync and consistent.

Conclusion

We have covered why extendable components and patterns are better when building interfaces, which center around flexibility and maintainability. And to illustrate this, we covered the steps involved in creating some extendable components. The advantages of building interfaces in this way will become apparent right away because you will spend less time refactoring due to an unexpected design change or addition, and your styling that makes up these components will be easier to maintain.


Developing Extensible HTML and CSS Components originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/developing-extensible-html-css-components/feed/ 23 244866
(To use or not-to-use) Classes https://css-tricks.com/use-not-use-classes/ Fri, 20 May 2016 12:35:56 +0000 http://css-tricks.com/?p=241910 Love me some blog debates! Papa Bear, Mama Bear, Baby Bear.

To Shared LinkPermalink on CSS-Tricks


(To use or not-to-use) Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Love me some blog debates! Papa Bear, Mama Bear, Baby Bear.

To Shared LinkPermalink on CSS-Tricks


(To use or not-to-use) Classes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
241910