Skip to content

Instantly share code, notes, and snippets.

@ModulesUnraveled
Last active December 28, 2022 21:59
Show Gist options
  • Save ModulesUnraveled/c38902fff36efdbdd694ade1e7c56283 to your computer and use it in GitHub Desktop.
Save ModulesUnraveled/c38902fff36efdbdd694ade1e7c56283 to your computer and use it in GitHub Desktop.
Examples of why to use Semantic variable names

We read our code far more than we write it, so plan accordingly.

Even if you don't plan on anyone reading your code, chances are someone will... even if it's you 12 months from now.

Why we use "semantic" variable names rather than "primitive" names.

What do we mean by "Primitive" names?

Primitive names typically call the thing what it is. Some examples are:

// Colors
$red: #ff0000;
$red-dark: #9b1111;
$yellow: #ffff00;

// Spacing
$space-10: 10px;
$space-20: 20px;

// Typography
$font-size-20: 20px;
$font-weight-bold: 700;

These are real easy to understand. You're calling it what it is. It's arguable whether there's any benefit to these over just using the value, but the benefit is that if you need to update a font-size across your code base from 20px to 24px, you can make that change in one place.

Although that would mean that $font-size-20 now equals 24... That's definitely not desired. So, you can do a find and replace in your codebase to change all examples of $font-size-20 to $font-size-24. Not the end of the world...

What do we mean by "Semantic" names?

Semantic names describe the use-case of the variable. Or maybe another way to think about it is the context of the variable. A "Semantic" name is NOT simply an alias of a primitive. For example, you should not use $color-text for the background-color of a component just because it computes to the color you want. It's labeled as a "text" component. So it should only be used as a text color.

Some examples include:

// Colors
$color-text: black;
$color-heading: gray;
$color-background: white;
$color-action: blue;
$color-danger: red;

// Spacing
$space-button-padding: 5px 10px;
$space-card-inset: 20px;
$space-card-stack: 10px;

What this allows us to do is style components with semantic variables, and then change them in one place to affect the entire code-base as necessary. For example:

body {
  color: $color-text;
}

.card {
  padding: $space-card-inset;
}

.card__heading {
  color: $color-heading;
}

.news-item {
  padding: $space-card-inset;
}

.search-result__heading {
  color: $color-heading;
}

Then if the designer decides headings should be a darker gray we just change the "color-heading" color. e.g. $color-heading: #444444 and instantly, the heading of any component that said it's heading color should be the global $color-heading color is updated.

Using CSS Custom Properties to simplify and standardize variations

The example above uses sass variables, but I prefer to define colors (and some other attributes) using css custom properties. This gives us some dynamic capabilities not possible with "static" variables. One example of when this is useful is when a design calls for "bands" that support different background colors, and various components can be placed inside that colored band. Inside a dark-colored band, we'd want text to be light, while inside a light-colored band, we'd want text to be dark. You could add more css to each component to make sure it supports all of the background color options, or you could define color sets - including background colors, text colors, as well as others. Here's some code to demonstrate:

This is how we'd have to handle it with sass variables.

Assuming this markup, which provides one band with a light-colored background, and some text, followed by a band with a dark-colored background and the same text component.

<div class="band" data-color-scheme="light">
  <p class="basic-text">Here's some text that should be dark.</p>
</div>

<div class="band" data-color-scheme="dark">
  <p class="basic-text">Here's some text that should be light.</p>
</div>
.band {
  &[data-color-scheme="light"] {
    background: $creme;
  }

  &[data-color-scheme="dark"] {
    background: $brown;
  }
}
.basic-text {
  color: $black;

  // Brown to work with the "light" background color
  [data-color-scheme="light"] & {
    color: $brown;
  }

  // Creme to work with the "dark" background color
  [data-color-scheme="dark"] & {
    color: $creme;
  }
}

In this example, we've had to define the text color three times (for this component... each component that should adjust would need to do the same). And this is just for two band colors, often sites that implement this feature have five or so. Let's take a look at how this can be simplified with css custom properties.

Assuming the exact same markup:

<div class="band" data-color-scheme="light">
  <p class="basic-text">Here's some text that should be dark.</p>
</div>

<div class="band" data-color-scheme="dark">
  <p class="basic-text">Here's some text that should be light.</p>
</div>

Here's how the css would change:

Let's assume that by default this site uses black text on a white background, as defined below.

:root {
  --color-background: $white;
  --color-text: $black;
}

body {
  background-color: var(--color-background);
  color: var(--color-text);
}

Now, in our "Band" css, we define what the text color should be in order to match the defined background color.

.band {
  &[data-color-scheme="light"] {
    --color-background: $creme;
    --color-text: $brown;
  }

  &[data-color-scheme="dark"] {
    --color-background: $brown;
    --color-text: $creme;
  }
}

Then, in our component file, we can just set the text to our custom property, and it'll automatically adjust based on context, and be the correct color whether it's against the background of a "Band" or not.

.basic-text {
  color: var(--color-text);
}

This is an example of defining the styles in a contextual way so that the thing that causes the change, defines the change. E.g. the text changes because of the background color, so the thing that's changing the background color, also changes the text color. In the sass example above, the Band is defining the background, and the text defines how the text changes to adjust. So we're defining things in two separate files that are tightly coupled in purpose.

In the css custom properties example, if we decide to change a band background color, we can change the associated text color at the same time, and in one place - rather than in all of the components that could be inside a Band. Or if we decide to get rid of the Band concept all-together, we just rip out the band folder, and we're done... as opposed to having to search the code-base for all cases where components varied based on the fact that they were placed inside a band.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment