Goodbye, BEM

Computer code on a computer monitor

BEM (Block-Element-Modifier) in CSS is an industry standard in web development; I know a lot of people who use it. I learned it, mastered it and started using it in my own projects.

However, like all systems and tools I've used, I started to question it. Was BEM really the prized gem that I've always thought it was?

In today's blog post, I would like to talk about BEM, why I used it, and why I don't use it anymore.

What I like about BEM

BEM was magic when I first discovered it. It solved a few issues:

What I hate about BEM

With all the advantages listed above, I thought BEM was the perfect solution. Until I used it. Then I used it again. And again. And again.

Then I noticed a few shortcomings:

There was no cure for these issues; they are all inherent in BEM.

So you could imagine how elated (and surprised) I was to find a solution.

Introducing GPS

As I was looking for a solution to the shortcomings of BEM, I stumbled upon an article titled BEM is terrible.

In that article, the author introduced the concept of GPS: Global, Page (or View), Section. I have never heard of it, but I was intrigued to find out that it's a new system that could be better than BEM.

However, after reading the whole article, I discovered that the method is not new at all. In fact, it sounds more like how these technologies were supposed to be used.

In summary, the foundation of what he is saying is this:

If you follow these principles, everything falls in line. I used to think that IDs were evil because of specificity, but this could not be further from the truth. CSS becomes more powerful when you learn to embrace its strengths.

Usage examples of GPS

My blog

With BEM, the code for my blog home page was looking like this

<div class="feed">
    <article class="feed__item">...</article>
    <article class="feed__item">...</article>
    <article class="feed__item">...</article>
    <article class="feed__item">...</article>
</div>

With GPS, you'd have something simpler:

<div id="feed">
    <article>...</article>
    <article>...</article>
    <article>...</article>
    <article>...</article>
</div>

You see? Shorter names. Less bytes. Less cognitive load. More communication. No clutter. It's genius.

Now in CSS, instead of this with BEM:

.feed {
    /* CSS styles here */
}

.feed__item {
    /* CSS styles here */
}

I do this with GPS:

#feed {
    /* CSS styles here */
}

#feed > article {
    /* CSS styles here */
}

A client's website

Below is a simplified version of code I wrote for a client of mine using BEM:

<div class="appointment-summary">
    <h2>Appointment summary</h2>
    <div class="appointment-summary__cart">
        <div class="appointment-summary__cart__summary">
            <p>2 services</p>
            <div class="appointment-summary__cart__summary__details">
                <div class="container">
                    <span>$175.00</span>
                    <svg class="separator" viewBox="0 0 24 24">...</svg>
                    <div class="appointment-summary__cart__summary__details__duration">
                        <svg class="icon icon--time" viewBox="0 0 24 24">...</svg>
                        <span>2 hr</span>
                    </div>
                </div>
                <div class="appointment-summary__cart__summary__details__buttons">
                    <button class="button--arrow-toggle"><svg class="icon icon--chevron-up">...</svg></button>
                    <a id="book-appointment-mobile-button" href="booking-complete.html" class="button button--primary button--next button--book-appointment">Book Appointment</a>
                </div>
            </div>
        </div>
        <div class="appointment-summary__cart__services">
            <div class="appointment-summary__cart__services__service">
                <p>Wash and Blowdry</p>
                <span>$55.00</span>
                <svg class="icon icon--trash">...</svg>
            </div>
            <div class="appointment-summary__cart__services__service">
                <p>Jumbo Box Braids</p>
                <span>$120.00</span>
                <svg class="icon icon--trash">...</svg>
            </div>
        </div>
    </div>
    <a id="book-appointment-button" href="booking-complete.html" class="button button--primary button--next button--book-appointment">Book Appointment</a>
</div>

Using GPS, a lot of complexity goes away:

<div id="appointment-summary">
    <h2>Appointment summary</h2>
    <div id="cart">
        <div id="summary">
            <p>2 services</p>
            <div id="summary-details">
                <div class="row">
                    <span>$175.00</span>
                    <svg class="separator">...</svg>
                    <div id="summary-duration">
                        <svg class="icon time">...</svg>
                        <span>2 hr</span>
                    </div>
                </div>
                <div id="summary-buttons">
                    <button class="arrow-toggle"><svg class="icon chevron-up">...</svg></button>
                    <a id="book-appointment-mobile-button"
                        href="booking-complete.html"
                        class="button primary next book-appointment">
                        Book Appointment</a>
                </div>
            </div>
        </div>
        <div id="cart-services">
            <div class="service">
                <p>Wash and Blowdry</p>
                <span>$55.00</span>
                <svg class="icon trash">...</svg>
            </div>
            <div class="service">
                <p>Jumbo Box Braids</p>
                <span>$120.00</span>
                <svg class="icon trash">...</svg>
            </div>
        </div>
    </div>
    <a id="book-appointment-button"
        href="booking-complete.html"
        class="button primary next book-appointment">
        Book Appointment</a>
</div>

The CSS with BEM:

.appointment-summary {
    /* CSS styles here */
}

.appointment-summary h2 {
    /* CSS styles here */
}

.appointment-summary__cart {
    /* CSS styles here */
}

.appointment-summary__cart__summary {
    /* CSS styles here */

}

.appointment-summary__cart__summary p {
    /* CSS styles here */
}

.appointment-summary__cart__summary__details {
    /* CSS styles here */
}

.appointment-summary__cart__summary__details .container {
    /* CSS styles here */
}

.appointment-summary__cart__summary__details span {
    /* CSS styles here */
}

.icon {
    /* CSS styles here */
}

.icon--chevron-up {
    /* CSS styles here */
}

.appointment-summary__cart__summary__details__duration {
    /* CSS styles here */
}

.appointment-summary__cart__summary__details__duration span {
    /* CSS styles here */
}

.appointment-summary__cart__summary__details__buttons {
    /* CSS styles here */
}

.appointment-summary__cart__services {
    /* CSS styles here */
}

.appointment-summary__cart__services__service {
    /* CSS styles here */
}

.appointment-summary__cart__services__service p {
    /* CSS styles here */
}

.appointment-summary__cart__services__service span {
    /* CSS styles here */
}

With GPS:

#appointment-summary {
    /* CSS styles here */
}

#appointment-summary h2 {
    /* CSS styles here */
}

#appointment-summary #cart {
    /* CSS styles here */
}

#appointment-summary #summary {
    /* CSS styles here */
}

#appointment-summary #summary p {
    /* CSS styles here */
}

#appointment-summary #summary-details {
    /* CSS styles here */
}

#appointment-summary #summary-details > .row {
    /* CSS styles here */
}

#appointment-summary #summary-details > span {
    /* CSS styles here */
}

#appointment-summary .icon {
    /* CSS styles here */
}

#appointment-summary .chevron-up {
    /* CSS styles here */
}

#appointment-summary #summary-duration {
    /* CSS styles here */
}

#appointment-summary #summary-duration > span {
    /* CSS styles here */
}

#appointment-summary #summary-buttons {
    /* CSS styles here */
}

#appointment-summary #services {
    /* CSS styles here */
}

#appointment-summary #services > .service {
    /* CSS styles here */
}

#appointment-summary #services > .service p {
    /* CSS styles here */
}

#appointment-summary #services > .service span {
    /* CSS styles here */
}

There you have it. Shorter. Simpler. Clearer. ๐Ÿ˜„

Few criticisms on GPS

One thing I dislike about GPS is the recommendation of prefixes like g- for global styles and p- for page styles. I believe that prefixes are unnecessary, superfluous and make my CSS a little less readable.

I think the best thing is to allow these styles to be inferred by their context.

For instance, an About page may be structured like this:

<html>
    <body id="about">
        <div id="intro">
            <img src="images/our-team.webp">
            <p class="g-full-width">Meet our team</p>
        </div>
    </body>
</html>

The g- in g-full-width indicates that the values are read from the global styles.

However, I would argue that there is no difference between defining the selector as full-width (as opposed to g-full-width). I should not really care about where the value comes from. If I wanted to overwrite the value for some reason, I could use IDs to do so:

/* In global CSS */
.full-width {
    /* Full width in global context */
}

/* In page CSS */
#about .full-width {
    /* Full width in about page context */
}

I've never tried this before, but I plan to give it a shot and see if I run into any roadblocks. I believe this is a much simpler approach and could make my CSS code even more readable.

The bottom line

It's sad how I overlooked the basic principles of the web and dabbled into something that made using the web harder. ๐Ÿคฆ

Oh well, I'm happy to have found a way that works best for me. ๐Ÿ˜„

If you would like to reply to or comment on this blog post, feel free to email me at efe@mmhq.me.