naming – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Fri, 26 Aug 2022 13:44:50 +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 naming – CSS-Tricks https://css-tricks.com 32 32 45537868 Using Grid Named Areas to Visualize (and Reference) Your Layout https://css-tricks.com/using-grid-named-areas-to-visualize-and-reference-your-layout/ https://css-tricks.com/using-grid-named-areas-to-visualize-and-reference-your-layout/#comments Fri, 26 Aug 2022 13:44:49 +0000 https://css-tricks.com/?p=372634 Whenever we build simple or complex layouts using CSS Grid, we’re usually positioning items with line numbers. Grid layouts contain grid lines that are automatically indexed with positive and negative line numbers (that is unless we explicitly name them). …


Using Grid Named Areas to Visualize (and Reference) Your Layout originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Whenever we build simple or complex layouts using CSS Grid, we’re usually positioning items with line numbers. Grid layouts contain grid lines that are automatically indexed with positive and negative line numbers (that is unless we explicitly name them). Positioning items with line numbers is a fine way to lay things out, though CSS Grid has numerous ways to accomplish the same with an undersized cognitive encumbrance. One of those ways is something I like to think of as the “ASCII” method.

The ASCII method in a nutshell

The method boils down to using grid-template-areas to position grid items using custom-named areas at the grid container level rather than line numbers.

When we declare an element as a grid container using display: grid, the grid container, by default, generates a single-column track and rows that sufficiently hold the grid items. The container’s child elements that participate in the grid layout are converted to grid items, irrespective of their display property.

For instance, let’s create a grid by explicitly defining columns and rows using the grid-template-columns and grid-template-rows properties.

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(3, 200px);
}

This little snippet of CSS creates a 3×2 grid where the grid items take up equal space in the columns, and where the grid contains three rows with a track size of 200px.

We can define the entire layout with named grid areas using the grid-template-areas property. According to the spec, the initial value of grid-template-areas is none.

grid-template-areas = none | <string>+

<string>+ is listing the group of strings enclosed with a quote. Each string is represented as a cell, and each quoted string is represented as a row. Like this:

grid-template-areas: "head head" "nav main" "foot foot";

The value of grid-template-areas describes the layout as having four grid areas. They are,

  • head
  • nav
  • main
  • foot

head and foot span two column tracks and one row track. The remaining nav and main each span one column track and one row track. The value of grid-template-areas is a lot like arranging ASCII characters, and as Chris suggested a while back, we can get a visualization of the overall structure of the layout from the CSS itself which is the most trouble-free way to understand it.

(Full size GIF)

OK, so we created our layout with four named grid areas: head, nav, main, foot.

Now, let’s start to position the grid items against named grid areas instead of line numbers. Specifically, let’s place a header element into the named grid area head and specify the named grid area head in the header element using the grid-area property.

Named grid areas in a grid layout are called idents. So, what we just did was create a custom ident named head that we can use to place items into certain grid tracks.

header { grid-area: head; }

We can other HTML elements using other custom idents:

nav { grid-area: nav; }
main { grid-area: main; }
footer { grid-area: foot; }

Writing named area values

According to CSS Grid Layout Module Level 1, all strings must be defined under the following tokens:

  • Named cell token: This represents the named grid area in the grid. For instance, head is a named cell token.
  • Null cell token: This represents the unnamed grid area in the grid container. For instance, an empty cell in the grid is a null cell token.
  • Trash token: This is a syntax error, such as an invalid declaration. For instance, a disparate number of cells and rows compared to the number of grid items would make a declaration invalid.

In grid-template-area, every quoted string (the rows) must have the same number of cells and define the complete grid without ignoring any cell.

We can ignore a cell or leave it as an empty cell using the full-stop character (.)

.grid { 
  display: grid;
  grid-template-areas:
    "head head"
    "nav main"
    "foot .";
}

If that feels visually awkward or imbalanced to you, we can use multiple full-stop characters without any whitespaces separating them:

.grid {
  display: grid;
  grid-template-areas:
    "head head"
    "nav main"
    "foot ....";
}

A named cell token can span multiple grid cells, But those cells must form a rectangular layout. In other words, we’re unable to create “L” or “T”-shaped layouts, although the spec does hint at support for non-rectangular layouts with disconnected regions in the future.

ASCII is better than line-based placement

Line-based placement is where we use the grid-column and grid-row properties to position an element on the grid using grid line numbers that are automatically indexed by a number:

.grid-item {
  grid-column: 1 / 3; /* start at grid column line 1 and span to line 3 */
}

But grid item line numbers can change if our layout changes at a breakpoint. In those cases, it’s not like we can rely on the same line numbers we used at a specific breakpoint. This is where it takes extra cognitive encumbrance to understand the code.

That’s why I think an ASCII-based approach works best. We can redefine the layout for each breakpoint using grid-template-areas within the grid container, which offers a convenient visual for how the layout will look directly in the CSS — it’s like self-documented code!

.grid {
  grid-template-areas:
    "head head"
    "nav main"
    "foot ...."; /* much easier way to see the grid! */
}

.grid-item {
  grid-area: foot; /* much easier to place the item! */
}

We can actually see a grid’s line numbers and grid areas in DevTools. In Firefox, for example, go to the Layout panel. Then, under the Grid tab, locate the “Grid display settings” and enable the “Display line number” and “Display area names” options.

Enabling grid settings.

This ASCII approach using named areas requires a lot less effort to visualize and easily find the placement of elements.

Line-based placement versus ASCII Art placement.

Let’s look at the “universal” use case

Whenever I see a tutorial on named grid areas, the common example is generally some layout pattern containing header, main, sidebar, and footer areas. I like to think of this as the “universal” use case since it casts such a wide net.

The Holy Grail layout in rectangles.

It’s a great example to illustrate how grid-template-areas works, but a real-life implementation usually involves media queries set to change the layout at certain viewport widths. Rather than having to re-declare grid-area on each grid item at each breakpoint to re-position everything, we can use grid-template-areas to “respond” to the breakpoint instead — and get a nice visual of the layout at each breakpoint in the process!

Before defining the layout, let’s assign an ident to each element using the grid-area property as a base style.

header {
  grid-area: head;
}

.left-side {
  grid-area: left;
}

main {
  grid-area: main;
}

.right-side {
  grid-area: right;
}

footer {
  grid-area: foot;
}

Now, let’s define the layout again as a base style. We’re going with a mobile-first approach so that things will stack by default:

.grid-container {
  display: grid;
  grid-template-areas:
    "head"
    "left"
    "main"
    "right"
    "foot";
}

Each grid item is auto-sized in this configuration — which seems a little bit weird — so we can set min-height: 100vh on the grid container to give us more room to work with:

.grid-container {
  display: grid;
  grid-template-areas:
    "head"
    "left"
    "main"
    "right"
    "foot";
  min-height: 100vh;
}

Now let’s say we want the main element to sit to the right of the stacked left and right sidebars when we get to a slightly wider viewport width. We re-declare grid-template-areas with an updated ASCII layout to get that:

@media (min-width: 800px) {
  .parent {
    grid-template-columns: 0.5fr 1fr;
    grid-template-rows: 100px 1fr 1fr 100px;
    grid-template-areas:
      "head head"
      "left main"
      "right main"
      "foot foot";
  }
}

I tossed some column and row sizing in there purely for aesthetics.

As the browser gets even wider, we may want to change the layout again, so that main is sandwiched between the left and right sidebars. Let’s write the layout visually!

.grid-container {
  grid-template-columns: 200px 1fr 200px; /* again, just for sizing */
  grid-template-areas:
    "head head head"
    "left main right"
    "left main right"
    "foot foot foot";
}

Leveraging implicit line names for flexibility

According to the spec, grid-template-areas automatically generates names for the grid lines created by named grid areas. We call these implicitly-named grid lines because they are named for us for free without any additional work.

Every named grid area gets four implicitly-named grid lines, two in the column direction and two in the row direction, where -start and -end are appended to the ident. For example, a grid area named head gets head-start and head-end lines in both directions for a total of four implicitly-named grid lines.

Implicitly assigned line names.

We can use these lines to our advantage! For instance, if we want an element to overlay the main, left, and right areas of our grid. Earlier, we talked about how layouts have to be rectangular — no “T” and “L” shaped layouts allowed. Consequently, we’re unable to use the ASCII visual layout method to place the overlay. We can, however, use our implicit line names using the same grid-area property on the overlay that we use to position the other elements.

Did you know that grid-area is a shorthand property, sort of the same way that margin and padding are shorthand properties? It takes multiple values the same way, but instead of following a “clockwise” direction like, margin — which goes in order of margin-block-start, margin-inline-end, margin-block-end, and margin-inline-startgrid-area goes like this:

grid-area: block-start / inline-start / block-end / inline-end;
Showing the block and inline flow directions in a left-to-right writing mode.

But we’re talking about rows and columns, not block and inline directions, right? Well, they correspond to one another. The row axis corresponds to the block direction, and the column axis corresponds to the inline direction:

grid-area: grid-row-start / grid-column-start / grid-row-end / grid-column-end;
Block and inline axis.

Back to positioning that overlay element as a grid item in our layout. The grid-area property will be helpful to position the element using our implicitly-named grid lines:

.overlay {
  grid-area: left-start / left-start / right-end / main-end;
}

Creating a minimal grid system

When we focus on layouts like the “universal” use case we just saw, it’s tempting to think of grid areas in terms of one area per element. But it doesn’t have to work like that. We can repeat idents to reserve more space for them in the layout. We saw that when we repeated the head and foot idents in the last example:

.grid-container {
  grid-template-areas:
    "head head head"
    "left main right"
    "left main right"
    "foot foot foot";
}

Notice that main, left, and right are also repeated but in the block direction.

Let’s forget about full page layouts and use named grid areas on a component. Grid is just as good for component layouts as full pages!

Here’s a pretty standard hero component that sports a row of images followed by different blocks of text:

A row of weightlifting photos above a heading, blurb, then a row of three links.

The HTML is pretty simple:

<div class="hero">
  <div class="image">
    <img src="..." alt="" />
  </div>
  <div class="text">
    <!-- ... -->
  </div>
</div>

We could do this for a real fast stacked layout:

.hero {
  grid-template-areas:
    "image"
    "text";
}

But then we have to reach for some padding, max-width or whatever to get the text area narrower than the row of images. How about we expand our ASCII layout into a four-column grid instead by repeating our idents on both rows:

.hero {
  display: grid;
  grid-template-columns: repeat(4, 1fr); /* maintain equal sizing */
  grid-template-areas:
    "image image image image"
    "text  text  text  text";
}

Alright, now we can place our grid items into those named areas:

.hero .image {
  grid-area: image;
}

.hero .text {
  grid-area: text;
}

So far, so good — both rows take up the entire width. We can use that as our base layout for small screens.

Showing grid lines on the stacked mobile version of the page.

But maybe we want to introduce the narrower text when the viewport reaches a larger width. We can use what we know about the full-stop character to “skip” columns. Let’s have the text ident skip the first and last columns in this case.

@media (min-width: 800px) {
  main {
    grid-template-columns: repeat(6, 1fr); /* increase to six columns */
    grid-template-areas:
      "image image image image image image"
      "..... text  text  text  text  .....";
  }
}

Now we have the spacing we want:

Showing grid lines for a table-sized layout of the page.

If the layout needs additional tweaking at even larger breakpoints, we can add more columns and go from there:

.hero {
  grid-template-columns: repeat(8, 1fr);
  grid-template-areas:
    "image image image image image image image image"
    "..... text  text  text  text  text  text  .....";
}

Dev tool visualization:

Showing grid lines for a large table sized layout of the page.

Remember when 12-column and 16-column layouts were the big things in CSS frameworks? We can quickly scale up to that and maintain a nice visual ASCII layout in the code:

main {
  grid-template-columns: repeat(12, 1fr);
  grid-template-areas:
    "image image image image image image image image image image image image"
    "..... text  text  text  text  text  text  text  text  text  text  .....";
}

Let’s look at something more complex

We’ve looked at one fairly generic example and one relatively straightforward example. We can still get nice ASCII layout visualizations with more complex layouts.

Let’s work up to this:

Three images positioned around a fancy heading.

I’ve split this up into two elements in the HTML, a header and a main:

<header>
  <div class="logo"> ... </div>
  <div class="menu"> ... </div>
</header>
<main>
  <div class="image"> ... </div>
  <h2> ... </h2>
  <div class="image"> ... </div>
  <div class="image"> ... </div>
</main>

I think flexbox is more appropriate for the header since we can space its child elements out easily that way. So, no grid there:

header {
  display: flex;
  justify-content: space-between;
  /* etc. */
}

But grid is well-suited for the main element’s layout. Let’s define the layout and assign the idents to the corresponding elements that we need to position the .text and three .image elements. We’ll start with this as our baseline for small screens:

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-areas:
    "image1 image1 .....  image2"
    "texts  texts  texts  texts"
    ".....  image3 image3 .....";
}

You can already see where we’re going with this, right? The layout is visualized for us, and we can drop the grid items into place with the custom idents:

.image:nth-child(1) {
  grid-area: image1;
}

.image:nth-last-child(2) {
  grid-area: image2;
}

.image:nth-last-child(1) {
  grid-area: image3;
}

h2 {
  grid-area: texts;
}
Showing grid lines on a mobile layout of the page.

That’s our base layout, so let’s venture into a wider breakpoint:

@media (min-width: 800px) {
  .grid {
    grid-template-columns: repeat(8, 1fr);
    grid-template-areas:
      ". image1 image1 ...... ......  ...... image2 ."
      ". texts  texts  texts  texts   texts  image2 ."
      ". .....  image3 image3 image3  image3 ...... .";
  }
}

I bet you know exactly how that will look because the layout is right there in the code!

Showing grid lines for a table-sized layout of the page.

Same deal if we decide to scale up even further:

.grid {
  grid-template-columns: repeat(12, 1fr);
  grid-template-areas:
    ". image1 image1 .....  .....   .....  .....  .....  .....  .....  .....  ."
    ". texts  texts  texts  texts   texts  texts  texts  texts  texts  image2 ."
    ". .....  image3 image3 image3  image3 .....  .....  .....  .....  .....  .";
}
Showing grid lines for a desktop-sized layout of the page.

Here’s the full demo:

I’m using the “negative margin hack” to get the first image to overlap the heading.

Wrapping up

I’m curious if anyone else is using grid-template-areas to create named areas for the benefit of having an ASCII visual of the grid layout. Having that as a reference in my CSS code has helped de-mystify some otherwise complex designs that may have been even more complex when dealing with line numbers.

But if nothing else, defining grid layouts this way teaches us some interesting things about CSS Grid that we saw throughout this post:

  • The grid-template-areas property allows us to create custom idents — or “named areas” — and use them to position grid items using the grid-area property.
  • There are three types of “tokens” that grid-template-areas accepts as values, including named cell tokens, null cell tokens, and trash cell tokens.
  • Each row that is defined in grid-template-areas needs the same number of cells. Ignoring a single cell doesn’t create a layout; it is considered a trash token.
  • We can get a visual ASCII-like diagram of the grid layout in the grid-template-areas property value by using required whitespaces between named cell tokens while defining the grid layout.
  • Make sure there is no whitespace inside a null cell token (e.g. .....). Otherwise, a single whitespace between null cell tokens creates unnecessary empty cells, resulting in an invalid layout.
  • We can redefine the layout at various breakpoints by re-positioning the grid items using grid-area, then re-declaring the layout with grid-template-areas on the grid container to update the track listing, if needed. There’s no need to touch the grid items.
  • Custom named grid areas automatically get four implicitly assigned line names — <custom-ident>-start and <custom-ident>-end in both the column and row directions.

Using Grid Named Areas to Visualize (and Reference) Your Layout originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/using-grid-named-areas-to-visualize-and-reference-your-layout/feed/ 5 372634
The Dilemma of Naming Font Size Variables https://css-tricks.com/the-dilemma-of-naming-font-size-variables/ https://css-tricks.com/the-dilemma-of-naming-font-size-variables/#comments Tue, 06 Jul 2021 14:41:22 +0000 https://css-tricks.com/?p=343149 Normally, a project will have a set of pre-determined font sizes, usually as variables named in such a way that seeks some semblance of order and consistency. Any project of considerable size can use something like that. There are always …


The Dilemma of Naming Font Size Variables originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Normally, a project will have a set of pre-determined font sizes, usually as variables named in such a way that seeks some semblance of order and consistency. Any project of considerable size can use something like that. There are always headings, paragraphs, lists, etc. You could set font sizes explicitly and directly everywhere (e.g. font-size: 18px). Raw CSS, as it were. I do see that occasionally — mixing not just sizes but also units like px, rem and em in mindless chaos.

That’s why the CSS of a project typically uses variables or mixins — we’re shooting for structure, maintainability and, ultimately, consistency. We all know naming is hard and it doesn’t take looking much further than naming font size variables to see why. How should we name a small font size variable so it’s clear that it’s smaller than a large font size variable? And what happens if we need to insert a new variable in between them — is that one named in a way that clearly explains its relationship to the other size variables?

We’ll continue talking about naming font size variables in this post. But, really, the issue extends beyond font sizes to any sort of size or length value. Think paddings, margins, widths, heights, border radii, etc. These things need structure and consistency, too!

How do you define font sizes in your project? Does it look something like this with custom variables:

:root {
  /* Font size variables */
  --small: 12px;
  --medium: 16px;
  --large: 24px;
}

Or perhaps in Sass (which is what we’ll be using throughout this article) you might have variables for $small, $medium, and $large font sizes.

Fine. After a while, let’s say the designer adds a new <h1> heading for a hero section. And it is very large. Larger than anything you have in the project. No problem, you reply. You add an $xlarge to the project, and go about your day.

The following day, the designer makes a nice form label, which again has a new font size. This new size, though, is larger than small, but smaller than medium.

Here we go.

What should you call it? $small-medium? $small-2? $smedium? Whatever you name it, you won’t be happy with it. Because there is no word for that.

Or should you maybe refactor it? Create a new $xsmall, and change all instances of $small to $xsmall? And then you can use $small for the form label? There’s a small risk that you will forget to change somewhere and, hey, presto: a bug. What happens next time, when something is introduced that has a larger size than the $medium variable value? Do we have to refactor $large and $xlarge too?

I suggest adhering to a scale, always. An easy fix would be to further abstraction, perhaps ditching numbers and sizes in favor of functional names, like $form-label instead of $small-2 or $xsmall.

But imagine having a set of font sizes like this:

$small: 12px;
$form-label: 14px;
$medium: 16px;
$large: 24px;

That is a broken scale. It’s a size concept and a component concept mixed together. It raises questions. Should an alert or a button be allowed to use $form-label? Yuck.

Maybe you have a Greek thing going on, naming the variables $alpha, $beta, $gamma? Let me ask you then, what is then bigger than $alpha? $alpha-large? Or wait, is $alpha the small one?

I have also seen names like $button-font-size, $label-font-size, $blockquote-font-size. That seems to me like one variable per element used, instead of a scale, and sounds like it could be a lot of duplicated code if the same value is being used in multiple places, but with different names.

Perhaps you’re working with one base font size and percentages only? Sure, but I would say you need variables for the percentages. That’s how Geoff handles font sizing and even he admits that the setup raises his own eyebrows. Calculations with subjectively-named variables might be clear to you, but crazy-looking and complicated for anyone else jumping into the project.

h1 {
  font-size: clamp(var(--text-size-large), calc(var(--text-size-base) * var(--text-size-scaler)), var(--text-size-huge));
}

We need a better system

Adding and removing stuff constantly is the way we want to work. This is modern day development — MVP, Agile, and all the other hot buzzwords.

What we need is a scale syntax that allows room for changes. Adding a new size to the scale should be easy without introducing breaking changes. I’m thinking of a kind of scale that is both flexible and infinite. It must be more sophisticated than $small, $medium and $large.

It should be also be descriptive and intuitive. Preferably, you shouldn’t have to look up the variable names in the settings file or the config, or wherever you store these things. I don’t have the slightest clue if $epsilon comes before or after $sigma. Do you?

Using existing systems

Before trying to invent something new, is there an existing syntax or system we can leverage? Here are a few I’ve encountered.

International system of units

Surely, you’re familiar with terms like “kilobyte” and “megabyte.” Europeans are very used to “millimeter” and “centimeter.” Other examples are “giga,” “tera,” and “peta.” These prefixes can be used for length, weight, volume and more. Could a $centi font size work? It is intuitive to a certain extent, that is, if you’re familiar with the metric system. This is a finite scale. And there’s no room to add new sizes because they are already set.

Traditional point-size names

Long before computers and desktop publishing, books and newspapers were printed with lead type. The type setters had different names for different sizes. The sizes have a reference to a point size (pt) and could, in theory, be used for pixel sizes (px).

The type sizes in this system are called “Nonpareil,” “Pica,” “Cicero,” and “Great Primer,” just to name a few. The names are different depending on continent and country. Plus, the same name can have different sizes, so… quite confusing.

That said, I do like this system in a way because it would be like paying respect to an old craftsmanship from times past. But the names are so weird and specifically meant for type sizing, that it feels like a stretch to use for things like breakpoints and spacing.

Placing everyday objects on a scale

How about using stuff from our everyday life? Say chili peppers.

There are many kinds of chili peppers. The $habanero, is hotter than the $cayenne, which is hotter than the $jalapeno. That would be fun, yeah?

But as much as I enjoy the idea of writing font-size: $tabasco, I see two problems. If you’re not into peppers, you cannot know which pepper is hotter than another pepper — so, it’s not universally intuitive. Also, the bell pepper is 0 on the Scoville scale, and nothing is below that. Carolina Reaper is the hottest pepper in the world, so the scale is finite.

And yeah, peppers scale-wise are not larger or smaller, they are hotter. Bad concept. Maybe something more common, like types of balls?

There‘s a large range of different kinds of balls. You have handballs, soccer balls, volleyballs, etc. Need something larger than a medicine ball? Use $beach. Something smaller than a tennis ball? Use $pingpong. This is very intuitive, as I’d imagine everyone has played with all sorts of balls at some point, or at least are familiar of them from sports.

But is a ping pong ball larger than a golf ball? Who knows? Further, a bowling ball and a soccer ball are actually the same size. So… again, not perfect.

Scaling up to planets could work, but you would have to be knowledgeable in astronomy.

How about straight-up numbers? We’re unable to use numbers alone because tools like stylelinter will protest. But would something like this work:

$font-14: 14px;
$font-16: 16px;
$font-24: 24px;

Well, it’s infinite as there is always room for new additions. But it’s also incredibly specific, and there are some downsides to have the actual value be part of the name like that. Let’s assume that $font-18 is used in a lot of places. And now, they say, all places with 18px must be changed to 19px (because reasons). Now we need to rename the variable from $font-18 to $font-19 then change the value of $font-19 from 18px to 19px. And that’s before we finally update all places using $font-18 to $font-19. This is almost like using raw CSS. Low score for maintainability.

What about the animal kingdom?

Mother Nature has provided a myriad of species on this earth, which comes in handy in this situation. Imagine something like this:

$mouse: 12px;
$dog: 16px;
$hippo: 24px;

Need something smaller than a mouse? Use $bee, $ant or $flea. Larger than a bear? Try $moose or $hippo. Larger than an elephant? Well, you have the $whale, or heck, we can go prehistoric and use $t-rex. There’s always an animal to squeeze in here. Very versatile, very intuitive, also infinite (almost). And fun, too — I wouldn’t mind doing font-size: $squirrel. 🤩

But then again, even that might require needing to reference the variables, unless we know exactly which animals are contained in our zoo of font sizes. But maybe that’s not a big deal as long as it scales.

I have spent way too much time pondering this

Or have I? The code base is where you spend your working hours. It’s your work environment, just like chairs and monitors. And the workplace should be a nice place.

How do you handle your font size scales? Do you have one system for fonts and another for things like margins? Can anyone jump right into your code and understand how everything is organized? Please tell in the comments!


The Dilemma of Naming Font Size Variables originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-dilemma-of-naming-font-size-variables/feed/ 46 343149
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
Working Towards Better Naming https://css-tricks.com/working-towards-better-naming/ https://css-tricks.com/working-towards-better-naming/#comments Mon, 26 Feb 2018 14:12:54 +0000 http://css-tricks.com/?p=266639 There is a quote that I bet every one of you has heard many times. You know the one. The one that reminds you how hard naming is.

Let’s talk names.

We talk often about how hard naming is, but …


Working Towards Better Naming originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
There is a quote that I bet every one of you has heard many times. You know the one. The one that reminds you how hard naming is.

Let’s talk names.

We talk often about how hard naming is, but it’s less common see people talk about how to get better at it. Even naming philosophies lend structure to naming, but don’t pick names for you. Names are more than just some hard thing we get needlessly caught up in. They’re essential to good code. Good names can make a code base easy to pick up and work with. Bad names are hard to understand, or worse yet, prone to error.

Naming Examples

Let’s look at some examples in JavaScript.

function processData(data) {
  var result = JSON.parse(data);
  return result;
}

Reading only the function name, parameter name, and returned variable, we see that processData gets data and returns a result. These names have added nearly zero information to the reader. Code like this is easy to write when you just want to get it working or you’re trying to stay flexible to changes, and that’s okay. It’s always a good idea to go over your code with fresh eyes to fix things, and names should be on your quality checklist.

Here’s a more descriptive way we could have written the last example:

function parseJson(string) {
  var jsonObject = JSON.parse(string);
  return jsonObject;
}

Technology is one of the most abbreviation and acronym heavy fields there are, and they are key to great names. FTP is easier to read and understand than “File Transfer Protocol.” In some cases though, the reader can be left out.

Here’s an example where the abbreviations are convenient for the developer writing the code, but not so handy for anyone else who needs to read or contribute to it:

function cts(con, ack) {
  if (con && ack) {
    return true;
  }
  else {
    return false;
  }
}

Often I’ll read code with an acronym and have to switch to my web browser to do a search, only to find results for car models. A perfect example of that is cts, which returns a lot of Cadillac results. ack does show up on a search, but I’d rather not leave it my text editor. con can be misunderstood many ways. Is it a connection? A count? A container? Maybe it’s a scam. These things may be obvious if you are familiar with the code base, but it adds a learning curve to those joining the project. A few extra seconds can save several minutes for readers over years.

Here’s the previous example written without abbreviations:

function clearToSend(connectionExists, acknowledgementStatus) {
  if (connectionExists && acknowledgementStatus) {
    return true;
  }
  else {
    return false;
  }
}

Let’s turn to some HTML examples because HTML is perhaps the most name heavy language of them all.

<section class="new-promotion-parent">
  <img class="logo" src="small-square-logo-monochrome.png"/>
  <div class="get-your-coupon">
    <p>Get Your Coupon</p>
  </div>
</section>

We can imagine that the word “new” was used here likely because a designer was told to update the promotion-parent element, but to also keep support for the existing class, maybe for old HTML floating about. The term “new” is an accurate description for the first few months, but over time it becomes more and more ironic. A better idea might be to add a separate class that describes what is new. For example, if a new flat design is being implemented, then a class name of flat-design might work. For an added bonus, you can let the CSS from the existing promotion-parent class cascade if you’d like to reuse some of the styles.

Similarly, logo seems like a sensible class name at first. Inevitably, however, a second logo will come along somewhere, which gets the name alt-logo. The logos keep coming, and so do the increasingly bad names. Most assets have several variations, such as different shapes, sizes, color schemes and more. That said, small-square-logo-monochrome wouldn’t be a great class name either, because the image itself should be able to be swapped without the class name becoming obsolete. A better idea might be a name that describes the role of the asset rather than the type or appearance.

Here, the language of the div has been used to name the div get-your-coupon. The content of an HTML document is meant to continually evolve; names are not. A coupon code today might be an email signup in the future, while keeping the same styles and functionality. HTML is one place where names are often too specific instead of too vague.

Here’s that same HTML code taking the suggestions into consideration:

<section class="flat-design promotion-parent">
  <img class="promotion-branding-image" src="small-square-logo-monochrome.png"/>
  <div class="primary-promotion-text">
    <p>Get Your Coupon</p>
  </div>
</section>

We can even look at the names in a database for better naming. Tables often get used countless times across an application in several very different contexts.

Here’s a simplified database table:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `type` bit(1) NOT NULL,
  `sort` int(12) NOT NULL,
  `order` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

What does type mean in the context of books? Does it mean fiction or non-fiction? Does it mean paperback or hardcover? Maybe it means physical or digital?

The sort column is equally confusing. Is it representing ASC or DESC? Does it represent which column is being used to sort? Maybe it decides if sorting is active? Or maybe it decides show the books in some other alternate order?

And then there’s order. Aside from being equally ambiguous, order is a reserved word in MySQL and many other languages. You can work around this using backticks (`) for MySQL, but it’s probably a better idea to avoid using reserved words altogether.

Here’s how the table could be written in a more descriptive way:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `cover_type` bit(1) NOT NULL,
  `sort_order` int(12) NOT NULL,
  `purchase_order_number` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Naming Conventions

Let’s talk naming conventions.

if (oldmanshaven) {
  return true;
}

Did you read that as Old Mans Haven or Old Man Shaven? Either way, it forces you to slow down and think which adds up and might one day lead to a misunderstanding. PascalCase, camelCase, snake_case, kebab-case are all excellent choices. Use them, and just as important, be consistent.

Here’s that same code in snake_case, which is less likely to be misread:

if (old_man_shaven) {
  return true;
}

One more example:

if (!isNaN(number)) {
  alert('not a number')
}
else if (!number > 50) {
  alert('number too large')
}
else if (!number < 10) {
  alert('number too small')
}
else {
  // code here
}

I looked at some of my first lines of code for inspiration writing this post. I didn’t see many bad names because I wrote code in a way that didn’t use names. I used very few functions, rarely used assignments, and would abuse variables by making them do a dozen different things. Having plenty of names in your code is often a sign that you’re abstracting things properly.

Here’s one example from my code:

function validateNumber(number) {
  var maximumValue = 50;
  var minimumValue = 10;
  if (isNaN(number)) {
    alert('not a number')
    return false;
  }
  if (number > maximumValue) {
    alert('number too large')
    return false;
  }
  if (number < minimumValue) {
    alert('number too small')
    return false;
  }
}

if (validateNumber(number)) {
  // code here
}

Caveats

Naming things is an art, not a science. There’s some things outside the name to consider when evaluating if a name is good or bad.

Context

Context can give generic terms much more meaning. For example, “item” is a vague name but, in the context of a getCustomerSalesOrder() function, we can tell it likely refers to a product that was purchased. A function that is short, focused, and takes context into account can reduce the need for verbose names. I still prefer a good name. Context can disappear easily over time as functions get longer or re-factored. Names are more permanent markers of meaning.

Comments

Code comments are important to readable code, but they can’t do it all by themselves. Comments should pick up where names leave off, giving details you can’t cram into a name, noting the reason for a particular way of doing things, or ranting about a broken library.

/* This refers to a product that was purchased and relates to the customer-sales-order class. */
.product-item {
  display: block;
  text-transform: uppercase;
  width: 100vw;
}

Reading Length

Longer names create more to read and wider lines. It can especially be problematic when accessing deep into an array, such as:

$order_details['customer']['ship_to_address']['default']['street_address']['line_1']

That said, even that straw man example I just gave, while verbose, is crystal clear and gives me no reason to stop reading to think or look over the rest of the function to understand the context.

Names are everywhere in Code

Most of the characters of a code file probably aren’t brackets or syntax, but names. It might be variable names, function names, HTML tags or attributes, database tables or columns, or any of the countless things that we give names to in any given project.

I still struggle with naming things. I often find myself sitting frozen at my text editor, trying to name some minor variable. I’ve learned that when that happens, it’s likely because I’m dealing with something difficult to conceptualize, which makes it all the more important to find the right name for it.


Working Towards Better Naming originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/working-towards-better-naming/feed/ 12 266639
Naming Things is Only Getting Harder https://css-tricks.com/naming-things-is-only-getting-harder/ https://css-tricks.com/naming-things-is-only-getting-harder/#comments Wed, 21 Jun 2017 10:07:22 +0000 http://css-tricks.com/?p=255971 I was working with CSS Grid and came to the grid-column and grid-row properties. I paused for a moment.

They’re not overly complicated. They are shorthand properties for expressing where an element should start and end on a grid’s defined …


Naming Things is Only Getting Harder originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I was working with CSS Grid and came to the grid-column and grid-row properties. I paused for a moment.

They’re not overly complicated. They are shorthand properties for expressing where an element should start and end on a grid’s defined columns and rows.

What caught me was the fact that I can name these lines. It’s not a requirement (you can use numbers), but the ability to name the grid lines is something we can do here. In fact, naming lines can open up neat CSS tricks.

Grid lines are another item in a long list of examples where front-end developers have the power to name things. Class names and IDs have always been things we need to name in CSS, but consider a few of the more historically recent things where naming is important when it comes to styling:

  • Variables: Naming values for context, such as re-usable colors or numeric values whether in preprocessors or new CSS variables.
  • Data attributes: Selecting elements based on their HTML attributes rather than a class name.
  • Components: Like what we’re seeing in React and future CSS features like Web Components.
  • CSS files: Organizational methods like Atomic Design have accentuated the importance of naming our files, including preprocessor partials.
  • Media queries: We know naming them after devices is futile, so that has to make sense as well.

It’s not that naming things is ridiculously hard in and of itself. It’s more that there is a sense of power that comes with the ability to name things. As the saying goes: with power comes great responsibility. In this case, naming has an impact on everything from how code is written and organized to its overall performance and maintainability. Poorly named elements are smelly by nature and often indicative of the overall quality of the code. It can lead to the wariness of a growing code base.

Let’s just say I’ve spent more time naming some CSS classes than I spent naming my own two kids. I’m embarrassed to say that, but it’s the truth.

Naming grid lines is just another item in the growing cascade of things we are responsible for as front-enders. It’s not a bad thing or even an annoying one, but yet another reminder of how front-end development is development, design, and architecture all in one.


Naming Things is Only Getting Harder originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/naming-things-is-only-getting-harder/feed/ 6 255971
Coding CSS for Context https://css-tricks.com/coding-css-context/ Thu, 16 Feb 2017 14:40:26 +0000 http://css-tricks.com/?p=251555 Snook on naming a class:

Here’s what’s important:

  • We want to identify that this is a variation on our button.
  • We want to indicate the purpose of this button style.
  • We want to avoid tying the code to a particular


Coding CSS for Context originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Snook on naming a class:

Here’s what’s important:

  • We want to identify that this is a variation on our button.
  • We want to indicate the purpose of this button style.
  • We want to avoid tying the code to a particular context that could change.

To Shared LinkPermalink on CSS-Tricks


Coding CSS for Context originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
251555
CSS Rooster https://css-tricks.com/css-rooster/ Fri, 10 Feb 2017 15:06:32 +0000 http://css-tricks.com/?p=251366

A Bot that Writes CSS Classes for HTML with Deep Learning

I played with it for a bit to see if I could get it to do anything impressively analytic. I took some semantic HTML and removed all the class …


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

]]>

A Bot that Writes CSS Classes for HTML with Deep Learning

I played with it for a bit to see if I could get it to do anything impressively analytic. I took some semantic HTML and removed all the class names from it with the RegEx class="[a-zA-Z0-9:;\.\s\(\)\-\,]*". I dropped the class-free HTML into the Rooster, and it did generate new classes:

But the new classes seemed entirely based on what the tag is. <ul class="list">, <a class="link"> and such. That was without feeding it any CSS at all though. After I dropped in my whole stylesheet in a style block, I think I confused it. I got some new weird classes that weren’t in my styles and stuff like <br class="desc" />. Oh well, it’s just a fun experiment I think. Naming is hard, but we should probably still be doing it for ourselves.

To Shared LinkPermalink on CSS-Tricks


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

]]>
251366
Managing Typography on Large Apps https://css-tricks.com/managing-typography-on-large-apps/ Mon, 22 Feb 2016 21:30:54 +0000 http://css-tricks.com/?p=238300 Harry Roberts suggest very minimal styles for h1-h6, then using heading-specific class names to actually style them, regardless of what element they turn out to be.

I could get behind that. In the past I’ve done .h1, .h2, etc rather …


Managing Typography on Large Apps originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Harry Roberts suggest very minimal styles for h1-h6, then using heading-specific class names to actually style them, regardless of what element they turn out to be.

I could get behind that. In the past I’ve done .h1, .h2, etc rather than use the tag selectors, but heck, you might as well just give them names.

To Shared LinkPermalink on CSS-Tricks


Managing Typography on Large Apps originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
238300