Skip to content

Instantly share code, notes, and snippets.

@paceaux
Last active April 3, 2024 01:19
Show Gist options
  • Star 73 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save paceaux/8638765e747f5bd6387b721cde99e066 to your computer and use it in GitHub Desktop.
Save paceaux/8638765e747f5bd6387b721cde99e066 to your computer and use it in GitHub Desktop.
Tiny rules for how to name things in CSS and JS

Tiny rules for how to name stuff

CSS

How to name CSS classes

Stateful Class names

Is it a state that is only one of two conditions? (i.e. a boolean)

  • Prefix with is/has

Is it a state that is determined by something on its own element?

  • use .is; that describes the element's own state

e.g. .isOverflowHidden .isHidden .isScrollable

Is it a state that is determined by its children?

  • use .has; this describes the state of something inside the element
  • try to make the end part a noun

e.g. .hasOverflowHidden .hasHiddenChildren .hasScrollableChildren

Is it a state that is a negative ?

  • if you can, avoid this because it can be hard to use; try to re-write as a positive
  • Use isNot and/or hasNo
  • Use an adjective for "is"
  • Try to stick a noun at the end for "has"; "Els" is a fine abbreviation for elements
  • if all else fails, add "able"

e.g.: .isNotHidden, .hasNoHiddenEls .isNotScrollable, .hasNoScrollable, .hasNoScrollableEls

In general, try to write the class in a way that it directly answers a close-ended question that could start with is, has, will, did, can, or should.

Is it a CSS class that JavaScript needs?

  • Prefix with js/ui

Does JavaScript need it just to find it (no CSS being set)?

  • use .js

e.g. .jsSubmitButton .jsVideoPlay

Does JavaScript need to change it so that CSS can style it?

  • use .ui
  • use an adjective or a past-tense

e.g. .uiSubmitted .uiVideoPlayed

Does a Test need it?

  • use .qa

Are these classnames for a component/module?

  • Avoid words that prescribe the content
  • Avoid words that prescribe the markup
  • Avoid ambiguously describing scope or presentation
  • Avoid using words to describe variation or relationships

e.g.: avoid these

.logos // suggests it can only have logos (prescribed content)
.logoList // suggests can only be used with ul, ol, dl (prescribed markup)
.logoGridList // suggests it always makes it looks like a grid (ambiguous presentation)
.darkLogoGridList //not obviously related, (words describe variation or relation)
.logoGridListBlack // Not clear what is black (ambiguous scope) 
  • Prefer words that describe the purpose
  • Prefer describing scope
    • Consider abbreviating scope if meaning can be obvious
  • Prefer convention to prescribe variations
  • Prefer convention to describe relationships

e.g. prefer these:

.mediaSet // 'Set' -> purpose, 'media' -> scope (could apply to video, picture, img)
.mediaSet--grid-md // '--' -> variation by convention, 'grid' -> purpose  , 'md' -> scope (abbreviated)
.mediaSet--theme-dark // '--' -> variation by convention, 'theme' -> scope, '-dark' -> variation
.mediaSet__media // '__' -> relationship by convention , 'media' ->  purpose

BEM is a well-known convention that helps address relationships and variations. You don't have to use BEM; you just have to be consistent.

Should I Use hyphens or underscores to separate a class prefix?

  • Be consistent
  • If everyone else is using hyphens, you should, too.
  • If you're the first person on the project, use camelCase; it's easier to select camelCased text in an IDE than it is hyphenated text

Is this a SRP (single responsibility principle) kind of class?

Sometimes a class only has one property because it's used in combination with other classes.

  • Don't use the value of a specific CSS property
  • Do give the purpose of that specific CSS property
  • Avoid suggesting usage with only specific HTML elements
  • Try suggesting usage with kinds of content

e.g. Avoid this:

 .button--yellow {
  color: yellow;
 }

And instead try this:

 .button--warn {
   color: yellow 
 }

Avoid this:

 .imgFloatLeft {
  float: left;
 }
 
 .imgFloatRight {
  float: right;
 }

And instead try

.rtfMedia--left {
 float: left;
}

.rtfMedia--right {
 float: right;
}

Sass/SCSS/Stylus/CSS naming

Variables for Colors

  • don't let the variable name indicate the variable value (what if the value changes)

  • indicate relative aspects of the value like hue, lightness

  • use relatives and superlatives (er, est) for variations on a hue

     --colorNeutralDarkest
     --colorNeutralDarker
     --colorNeutralDark
     --colorWarmDarker
     --colorWarmerDarkest

Generic Variables

Is the variable going to be used more than once?

  • start with the UI element name

  • end with the CSS property it affects

  • never put any information about the value of the variable in the name

      $linkColor: rgb(165,220,220,220)
      --linkColor: var(--colorCoolDark)

Is this variable used more than once, but there's a different variable for pseudo classes?

  • start with the UI element name

  • Then add the CSS property it affects

  • End with the state

      $linkColor: rgb(165,220,220);
      $linkColorHover: rgb(165,165,220);
      --linkColorHover: var(--colorCoolDarker);

Is the variable used once?

  • start with class name that the variable is used in

  • end with the CSS property it affects

      .foo {
          $fooHeight: $containerHeight / 3;
          width: $fooHeight / 2;
          height: $fooHeight;
      }    

JS Naming

Functions that return things

Does the function return a boolean?

  • Prefix with "is" or "has"
  • Use "is" with an adjective
  • Use "has" with a noun
  • Avoid using a negative

e.g.

function isHot() {
 if (temperature > 100 ) {
   return false;
 } else {
   return true;
 }
}

function hasEggs(carton) { 
  if (carton.eggs.length > 0 ) { 
    return true;
  } else { 
    return false;
  }
}

Does the function return anything else ?

  • Prefix with get

  • End with thing it returns

  • Use a plural form if it returns an enumerable

      function getTemperature () {
        return temperature;
      }
      
      function getEggs() {
        const eggs = [];
        return eggs;
      }

Are you assigning the thing that the function returns to a variable?

Use the noun part of the function

const foods = getFoods();
const number = addNumbers();

Functions that do things

  • Start with a verb, end with a noun
  • Make the noun the thing that is the recipient of the action:

e.g.

calculateTemperature()
findThermometer();

Looping through stuff

  • Avoid using single-letter variable names (e.g. i);
  • Use at least-three letters.

Is the loop a.forEach on an array or array-like structure?

  1. Make the array's noun its plural form

  2. Make the item iterated on the singular form

     const fruits = ['banana', 'avocado', 'tomato'];
    
     fruits.forEach((fruit) => {
    
     });

Does the .forEach need an index?

  1. Start with idx

  2. Avoid single-letter variable names

     const fruits = ['banana', 'avocado', 'tomato'];
    
     fruits.forEach((fruit, idx) => {
    
     });

If you have to go more than one level deep, append idx to the item name:

    const foodGroups = [ ['banana', 'avocado', 'tomato'], ['steak', 'sausage' ] ];
    
    foodGroups.forEach((foodGroup, idx ) => {
    
        foodGroup.forEach((food, foodIdx) => {
        
        });
    });

Is the loop using for in or for of ?

  1. Make the object/array's noun a plural form

  2. Start any counter variables with idx

  3. If you have to go more than one level deep, append idx to the item name

    for (let idx = 0, fruit; idx < fruits.length; ++idx) { fruit = fruits[idx]; for (let goodFruitIdx = 0; goodFruit; goodFruitIdx < goodFruits.length; ++goodFruitIdx) { goodFruit = goodFruits[goodFruitIdx] } }

Functions in General

Complex Functions (functions with many parts)

Sometimes, the difficulty in naming a function comes from the fact that it does many things (has complexity).

  1. Identitfy all of the tasks within this function (units of work that have single, testable activities)
  2. Name those tasks (they either do or they return)
  3. Create functions whose names represent their tasks
  4. Re-evaluate the function now that it is a collection of named tasks and create a name that summarizes those tasks

Instead of this:

function getLiElement(titleNode) { // function name somewhat generic
    const listEl = document.createElement('li');
    
    const { tagName} = titleNode;
    let type = 'biggest';
	
    switch (tagName) { // task that determines a class name
	case 'H3':
		type = 'bigger';
		break;
	case 'H4':
		type = 'big';
		break;
	case 'H5':
		type = 'base';
		break;
	defaut:
		break;
		
    }
    const itemTypeClass = `articleTOC__item--${type}`;
    listEl.classList.add('articleTOC__item');
    listEl.classList.add(itemTypeClass);
    
    return listEl;
}

Prefer this

// function that does one thing with name that reflects what it does
function getTOCItemType(titleNode) {
	if (!titleNode) return;
		const { tagName} = titleNode;
		let type = 'biggest';
		
		switch (tagName) {
			case 'H3':
				type = 'bigger';
				break;
			case 'H4':
				type = 'big';
				break;
			case 'H5':
				type = 'base';
				break;
			defaut:
				break;
		}
		
		return `articleTOC__item--${type}`;
	}
 

function getTOCItemElement(titleNode) {
		const listEl = document.createElement('li');
		// variable that summarizes what the other function has done
        const tocElementTypeClassname = getTOCItemType(titleNode);
		
		listEl.classList.add('articleTOC__item');
		listEl.classList.add(tocElementTypeClassname);
		return listEl;																		
	}

Complicated functions (functions that are difficult to read)

Sometimes, the difficulty in naming a function comes from the fact that parts of it are confusing to read (it's complicated).

  1. Determine if it is complex. If it is, make it less so.
  2. Look at comparison operations (if, switch) and determine if it is self-evident what the logic is doing
    • Consider creating a variable for each logical comparison (follow the guidance for how to name boolean variables)
    • Consider creating a variable that summarizes the logical comparisons
  3. Eliminate "magic numbers" and "magic strings" (values that exist, but their reason for being those values is not self-evident)
    • Consider moving numbers in a setTimeout to variables
    • Consider making values used for validing parameters their own variables

Instead of this:

	function getTOCItemType(titleNode) {
   	if (!titleNode) return;
   	const { tagName} = titleNode;
   	let type = 'biggest'; // variable name whose purpose isn't explained
   	
   	switch (tagName) {
   		case 'H3':
   			type = 'bigger';
   			break;
   		case 'H4':
   			type = 'big';
   			break;
   		case 'H5':
   			type = 'base';
   			break;
   		defaut:
   			break;
   	
   	}
   	
   	return `articleTOC__item--${type}`; // "magic string" ; unclear why type is added to a string
   }

Prefer this:

function getTOCModifierClass(titleNode) {
   	if (!titleNode) return;
   	const { tagName} = titleNode;
       const blockName = 'articleTOC__item'; // variable that explains its value
       const modifierSeparator = '--' // variable that explains its value
   	let modifierName = 'biggest'; // changed variable name that explains why it changes
   	
   	switch (tagName) {
   		case 'H3':
   			modifierName = 'bigger';
   			break;
   		case 'H4':
   			modifierName = 'big';
   			break;
   		case 'H5':
   			modifierName = 'base';
   			break;
   		defaut:
   			break;
   	
   	}
   	
   	return `${blockName}${modifierSeparator}${modifierName}`; // clarity that this is returning a BEM class
   }

Using Functions (Function / argument parity)

Keep function parameters similar -- but not the same, as the function arguments:

/* parameters are firstNum, secondNum */
function addNumbers(firstNum, secondNum) {
    return firstNum + secondNum;
};

const first = 1;
const second = 2;
const sum = addNumbers(first, second); /* arguments are first, second */

Parameter names

  1. Don't include the type as part of the name; that's what comments are for

  2. If you feel like it's super important to include the type, put it at the beginning

    function addNumbers(numberFirst, numberSecond) {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment