Categories
CSS and SCSS Uncategorized Web Development

Sustainable Styles: An Object-Oriented twist on BEM

I have been working in the web for a long time, and I have worked full-time professionally at UL for almost 5 years.  In that time, I’ve learned a lot about how developers perceive CSS, and why so many projects are absolutely littered with novice-level CSS.

BEM was introduced a few years ago to deal with one of CSS’ biggest problems: taxonomy, the art of naming things.  Its primary goal was the provide a sane, sustainable method for writing class names.  Another goal was to create a sustainable approach for changes in state..  For example, BEM provides an answer for “How do we style a blog post (block) that is featured (modifier)?”  Consider some of these candidates

.blogPostFeatured {}
.blog-post.featured {}
.blog .post.featured {}

None of these fully address the application of a block-specific featured state, and the intended portability of a CSS class. BEM methodology here is going to be as atomic as possible with components (like a post), and as verbose as possible to avoid collisions.  For example, using .featured with .blog is fine, but what if another entity, like .page comes along, and also uses the .featured class?  What happens when these two entities (posts and pages) need different styles for featured?

Tweaking .featured for one entity will also affect the other.  Unintended changes across the app lead to what I call this the Pick Up Sticks problem.  For this reason, using verbose Modifiers is the solution to the problem.  Consider the following SCSS. Notice that .post--featured only works with .post, and so the modifier’s effect is isolated to the block.

.post {
    &.post--featured {} // => .post.post--featured
}

.page {
    &.page--featured {} // => .page.page--featured
}

Now, examine the accompanying HTML markup…

<!-- Works great! -->
<div class="post post--featured"></div>
<div class="page page--featured"></div>

<!-- Featured states have no effect when misapplied -->
<div class="page post--featured"><div>
<div class="post page--featured"></div>

Essentially, this creates namespaces for the .page and .post blocks, and any of the modifiers for these blocks are useless outside of the associated namespaces.  This is a powerful, clean, sustainable approach that will help you tame and harness the cascade, and master CSS.

Styling relationships

When parent-child relationships exist within a data model, it is common to see that relationship reflected by markup and styles. Consider the following data model, written in TypeScript.

class Post {
    public comments: Comment[];
}

class Comment {}

It’s easy to see that Post has many Comment, as indicated by the Post.comments array of Comment objects. How do we turn this into a sustainable CSS design system?

First, start with two root-level selectors to represent the Post and the Comment.

.post {}
.comment {}

Since Post has a property to contain many comments, represent this relationship in with an Element (preceded by two underscores) in the SCSS:

.post { // block
    .post__comments {} // element
}
.comment {} //block

Have a look at the markup that could be styled by this stylesheet…

<div class="post">
    <div class="post__comments">
        <div class="comment">…</div>
        <div class="comment">…</div>
        <div class="comment">…</div>
    </div>
</div>

So far so good!  It’s clean, easy to understand, easy to maintain, and it’s only the slightest bit verbose.  You can see that the Post block contains a Post Comments Element, and we put many Comment blocks into the Post Comments Element.

Let’s continue to style two Comment blocks when they are next to each other in the Post Comments Element…  We can use a variant of the lobotomized owl to create a simple spacing system that doesn’t bring unnecessary gaps of whitespace in our page.

.post {
    .post__comments {
        > .comment + .comment {
            margin-top: 1.5rem;
        }
    }
}

Styling boolean states

Next, consider representing boolean states on a Block.  The boolean test might look like this…

class Post {
    comments: Comment[] = [];
    get hasComments(): boolean {
        return this.comments && this.comments.length > 0
    }
}

The boolean is represented in SCSS as a Modifier:

.post {
    .post--has-comments {} // post.hasComments() === true
    .post--no-comments {} // post.hasComments() === false

    .post__comments {}
}

When the post has comments, our markup will represent this by including the modifier with the block:

<div class="post post--has-comments">
    <div class="post__comments">
        <div class="comment">…</div>
        <div class="comment">…</div>
        <div class="comment">…</div>
    </div>
</div>

We are now able to modify the Post appearance, as well as the children, when the has-comments modifier is added:

.post {
    // post.hasComments() === true
    &.post--has-comments {
        background: url('comments-icon.png') top right;

        // post.comments when post.hasComments
        .post__comments {
            border: solid 1px #ccc;
        }
    }

    // post.hasComments() === false
    &.post--no-comments {
        .post__comments { display: none }
    }
}

The has-comments state can be used to leverage the cascade (the C in CSS), to further affect descendant elements, without a bunch of bloat.

<div class="post post--has-comments">
    <div class="post__comments"></div>
</div>

Our class names are written to represent our schema, its relationships, and its states.  This prevents the pick-up sticks problem, and makes the entire project easier to style.  Consider a new scenario where a blogging platform allows multiple blogs to exist, so we need to style a series of posts…

class Blog {
    title: string;
    posts: Post[]
}

No problem! We already have styles for Post so we just need to author the styles for the Blog block which contains many Post blocks. We’ll add a simple spacing rule, and some nice styles for a title. We also benefit from the styles that were written for Comments within Post.

.blog {
    .blog__title { font-weight: bold; font-size: 2.5rem; }
    .blog__posts {
        // within .blog__posts, any direct-descendant post that is 
        // after any post gets a margin-top to space things out
        > .post + .post { margin-top: 1.5rem; } 
    }
}

By being verbose, and using a reliable strategy to map state and schema to CSS appearance, we avoid a host of architectural issues that have been confusing developers for decades.

Putting it together

Here’s a cheat sheet to help apply BEM methodology to the mapping of objects to class names.

When you’re styling…Use…For example…
A business entity (a row in a database)
a Block
.post
.comment
.user
A property on an entity (a column in a database)
an Element
.post__title
.post__content
A child relationship
an Element filled with blocks
.post__comments > .comment + .comment
.comment__author > .user
A state
a Modifier
.post--is-featured
.comment--is-post-author
.user--is-admin
Categories
Plugins Web Development WordPress

Exciting WordPress Developments

I have been working on some exciting new WordPress things that I plan on releasing in compliance with the GPL.

First, since there wasn’t a decently simple (free) front-end profile management system, I decided to write one if my own. It is completely customizable with short codes and allows you to validate input with regular expressions before you save the data. All of this is controlled in the post editor. It is nonced using WordPress’ nonce API. It’s pretty elegant in its implementation.

Next, I plan to release some sort of iteration of my SCSS/CSS and WordPress template framework tools. I have tons of code generation spreadsheets that make grid design and implementation a piece of cake. Provide a couple parameters and the spreadsheet will calculate responsive grids. The grid is based on 6 columns and intelligently resizes all the way down to small screens. I have spreadsheets to make a lot of development work easier. It would be a shame if I didn’t share.

Categories
Javascript Programming Web Development

jQuery Goodies!

I started a new GitHub repo to fill with jQuery utilities and behaviors.

The initial commit is filled with viewport sizing utilities.  The utilities make it easy to use viewport-relative sizing in situations where browsers do not support VW and VH.

Something that I use a lot is the Letterboxing module.  Simply by adding .jq-letterbox, you can strictly enforce an element to have a widescreen aspect ratio.  This is very handy for sites that show lots of YouTube movie trailers.

Grab the Repo

https://github.com/bradkovach/jqUtilities

Installation

1. Import a recent version of jQuery

Note: script tags do not need type=”text/javascript” when using HTML5.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

2. Import the utilities AFTER jQuery

<script src="jqUtilities.viewport.js"></script>

 Usage

Full usage information is available at the head of the jqUtilities.viewport.js file.

/*
.js-vh: Viewport Height positioning
	required classes:
		js-vh
	required attributes:
		data-vh: a numeric value greater than 0 (zero).  1vw is 1% of the viewport's height.
	example:
		<div class="js-vh" data-vh="50"
			<!-- this will be half the height of the viewport -->
		</div>
	output:
		via jqu_log: reports new height in vh
		via jqu_log: reports when requested vh is invalid
*/

Help

By default, these utilities log errors to the console.

Known Limitations

  • Mixed markup and style information.  Style information is hard-coded into HTML markup.  This might be undesirable.
  • This is not a polyfill.  It is a workaround.  Nice polyfills exist, and that might be a better option for you.

 

Categories
Programming Web Development

The Developer’s New Struggle: Data Caps

These past 10 years have hosted a huge evolution in our data distribution technology. Since 2000, we’ve watched household broadband speeds move from about 0.5 mbps to somewhere around 20 mbps on average. This is awesome.

We have new LTE networks that are capable of pushing around 50 mbps over the air. Please note: this is faster than most household connections.

We live in an era of increasing bandwidth, and this is good news for web developers. This allowed sites like YouTube to become popular, because they finally had customers that could enjoy their product.

But developers have new struggles! Now, developing truly mobile applications (both native apps and web apps) must account for the new obstacle: carrier data caps.

How annoying. We’ve finally been given a trove of bandwidth (both low latency and high capacity), and we have to start using it very carefully–dare I say responsibly…

It’s food for thought. We have better networks and more ubiquitous access but increasingly more consumers have charted courses for the edge of a bandwidth cliff every single month.

So we must continue to adapt.

Things That Are Concerning

  • Popular development frameworks can be rather bloated.  Twitter Bootstrap (minified) is 101kb and another 17kb if you want the responsive tweaks. .
  • Responsive images are not really taking off. Even Apple does not have a decent implementation for responsive image serving that doesn’t involve convoluted Javascript.
  • Developers that don’t pay attention to client-side caching techniques.  Make browsers get changes by using ?ver=[autoincrement] to force browsers to reload only when content changes.
  • Everybody wants “apps” and these apps need data. Lots of these apps send a lot of data (either as JSON or XML) without implementing a cache mechanism.  Twitter uses a neat trick to keep data transfer down: the since_id query parameter.  This minimizes payload by ignoring content that the client probably already has.
  • XML has too much data overhead on structure to be considered efficient, yet it is hailed as a great data interchange format–NOT FOR THE WEB!  Typically ever XML tag is matched by a closing version of the tag.  Look at the overhead here: <strong>this is bold text</strong>.  The strong tag and its closing tag take up 17 characters, which is equal to the length of the content it formats.  This is a massive overhead!  Mobile clients shouldn’t rely on XML for updating content (like a timeline of continuously updating information).

This was merely a brief rant about implications about data load.  This doesn’t even consider some of the changes that occur with data throttling, and packet shaping.

Worrying about data overhead is the new black.