npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

classy-loader

v1.3.3

Published

Classy-loader is a powerful tool for React application to manage your CSS/JS DOM elements class names. This loader connects JS and CSS class names so you can syncronize and obfuscate them. It has a smart built-in mechanism to merge your class names wi

Downloads

14

Readme

classy-loader npm

Classy-loader is a powerful tool for React application to manage your CSS/JS DOM elements class names.
This loader connects JS and CSS class names so you can syncronize and obfuscate them.
It has a smart built-in mechanism to merge your class names within JS code by using string queries.
It has a very flexible organization and perfectly helps to avoid css class name conflicts within complex applications.

Installation

NPM

npm install --save classy-loader

An example to play

Link to Github repository

Adding to Webpack config

At first you need to set required config.

const classy = require('classy-loader');
classy.init({
    attributeName: 'class',
    extraAttributeName: 'classes',
    globalPrefix: 'awesome-example-app',
    delimiter: '-',
    obfuscation: false,
    obfuscatedLength: 4,
    autoPrefixMode: false,
    prefixAutoResolving: false,
    cssAutoImport: true
});


//...
module: {
  rules: [
    {
      test: /\.js$/, 
      loaders: [
        {
            loader: 'babel-loader',
            options: {
               //....
            }
        },
        {
            loader: 'classy-loader?parser=js'
        }
      ]
    },
    {
      test: /\.s?css$/,
      loader: ExtractTextPlugin.extract(
          {
              fallback: 'style-loader',
              use: [
                  'css-loader?root=...',
                  'sass-loader',
                  'classy-loader?parser=css'
              ]
          }
      )
    }
  ]
}
//...

So it should be added after babel and standart css loaders to be processed first.

attributeName

An attribute name of DOM elements, that will be parsed by loader.
It can be whatever word you like and will be changed to className attribute.
By default, it has value "class".

render() {
  return (
    <div class=".self">
      ...
    </div>
  )
}

or

render() {
  return (
    <div whateverName=".self">
      ...
    </div>
  )
}

So "class" and "whateverName" are our attributeNames.
And after processing we'll get parsed value:

render() {
  return (
    <div className="awesome-example-app">
      ...
    </div>
  )
}

So "self" is a keyword that means your global or local prefix.
In this case we don't have a local prefix, so it will be our globalPrefix from the config we set up above.

extraAttributeName

An attribute name of React elements, that will be parsed by loader.
It be whatever word you like but not will be changed.
By default, it has value "classes".

render() {
  return (
    <Button classes=".action-button awesome-button">
      Do it!
    </Button>
  )
}

And after processing we'll get the same attribute "classes" but parsed:

render() {
  return (
    <Button classes="awesome-example-app-action-button awesome-button">
      Do it!
    </Button>
  )
}

If you need to parse a string to valid class names use $classy:

let className = $classy(".item item $classes");

It produces this code:

import classy from 'classy-loader/classy';
// ....
let className = classy("awesome-example-app-item", "item", classes);

globalPrefix

A prefix that will be added to your element class names.
Special syntax will tell the loader whether add prefixes or not.
By default, it has an empty value, so it means no prefix will be added if a local prefix not specified.

render() {
  return (
    <div class=".thing">
      ...
    </div>
  )
}

will be

render() {
  return (
    <div className="awesome-example-app-thing">
      ...
    </div>
  )
}

The point means class name should have a prefix.
More about parser syntax is written below.

delimiter

A symbol or word that class names and prefixes will be joined with.
By default, it has value "-".

render() {
  return (
    <div class=".some-item">
      ...
    </div>
  )
}

So if we have our delimiter like "_", we will have

render() {
  return (
    <div className="awesome-example-app_some-item">
      ...
    </div>
  )
}

prefixAutoResolving

If this is not false the loader will try to resolve the local prefix by itself.
By default, it has value false.
There are three variants:

prefixAutoResolving: "content"

At first the loader will try to find a line with:
export default (class|function) MySuperClassName

Then tries with:
export default connect(...)(MySuperClassName)

Then tries with:
class MySuperClassName

And at last it will get the first line with:
function MySuperClassName

so "MySuperClassName" will be parsed to "my" + delimiter + "super" + delimiter + "class" + delimiter + "name".

For CSS files the loader will search for JS index file in the same directory
and then get local prefix from the file, so JS and CSS will be syncronized.
You should put your JS loaders first before CSS loaders, because CSS parser will need cached JS prefixes.

export default class MySuperButton extends React.Component {
  render() {
    return (
      <div class=".self">
        <span class=".inner">
          ....
        </span>
      </div>
    )
  }
}

will be

export default class MySuperButton extends React.Component {
  render() {
    return (
      <div className="awesome-example-app-my-super-button">
        <span className="awesome-example-app-my-super-button-inner">
          ....
        </span>
      </div>
    )
  }
}

Also you can define JS/CSS local prefixes with special directives.
More about JS/CSS directives see below.

prefixAutoResolving: "file"

The loader will try to form local prefixes from JS/CSS file names:
"SuperItem.js" or "super-item.js" or "super_item.js" to prefix "super" + delimiter + "item"
so you'll have to syncronize JS and CSS file names

prefixAutoResolving: "folder"

The loader will try to form local prefixes from JS/CSS folder names:
"SuperItem/index.js" or "super-item/some.js" or "super_item/any.js" to prefix "super" + delimiter + "item"
so JS and CSS will be syncronized as they are both located in the same directory (aren't they?)

obfuscation

If true the loader will obfuscate class names in both JS and CSS files.
Be careful, you should check that all class names in JS defined with classy "attributeName" and extraAttributeName
or special $classy syntax (see below).
By default, it has value false.

render() {
  return (
    <div class=".button small">
      ...
    </div>
  )
}

will become

render() {
  return (
    <div className="w4fq5wq dhet7s5">
      ...
    </div>
  )
}

obfuscatedLength

Length of obfuscated class names.
By default, it has value "7".
So if you have "obfuscatedLength" equal 4

render() {
  return (
    <div className="ald8 jd6g">
      ...
    </div>
  )
}

autoPrefixMode

Loader will automatically add prefixes to your class names.
So you should use different format of class name query.
By default, it is false.

For example this is a query for non-automatic mode (prefixAutoResolving set to "content")

export default class Container extends React.Component {
  render() {
    return (
      <div class=".self wide ..area">
        <div class=".content content">
          ...
        </div>
      </div>
    )
  }
}

will be

export default class Container extends React.Component {
  render() {
    return (
      <div className="awesome-example-app-container wide awesome-example-app-area">
        <div class="awesome-example-app-container-content content">
          ...
        </div>
      </div>
    )
  }
}

Here the local prefix is "awesome-example-app-container" (global prefix plus the local prefix auto resolved from class name "Container").
So in this mode you need to add point(s) for prefixes: one for the local prefix and two points for global prefix.

And finally an example of a query for automatic mode (prefixAutoResolving set to "content").
In the end we'll get the same result.

export default class Container extends React.Component {
  render() {
    return (
      <div class="self ..wide .area">
        <div class="content ..content">
          ...
        </div>
      </div>
    )
  }
}

will be the same

export default class Container extends React.Component {
  render() {
    return (
      <div className="awesome-example-app-container wide awesome-example-app-area">
        <div class="awesome-example-app-container-content content">
          ...
        </div>
      </div>
    )
  }
}

In this mode you don't need to add a point for local prefix, one point for global one and two for class name without prefix.

So in css files this principle works the same (you need to add the same points or not to add):
None-automatic mode

/* directive that defines our local prefix (adds additional prefix to global one) */
.with.addedPrefix.container;

..self {
  position: relative;

  &...area {
    background-color: #eee;
    border: 1px solid #aaa;
  }

  &.wide {
    width: 80%;
  }

  ..content {
    padding: 10px;

    &.content {
      padding-top: 0;
    }
  }
}

will be

.awesome-example-app-container {
  position: relative;

  &.awesome-example-app-area {
    background-color: #eee;
    border: 1px solid #aaa;
  }

  &.wide {
    width: 80%;
  }

  .awesome-example-app-container-content {
    padding: 10px;

    &.content {
      padding-top: 0;
    }
  }
}

And the automatic mode

/* directive that defines our local prefix (adds additional prefix to global one) */
.with.addedPrefix.container;

.self {
  position: relative;

  &..area {
    background-color: #eee;
    border: 1px solid #aaa;
  }

  &...wide {
    width: 80%;
  }

  .content {
    padding: 10px;

    &...content {
      padding-top: 0;
    }
  }
}

will give the same result

.awesome-example-app-container {
  position: relative;

  &.awesome-example-app-area {
    background-color: #eee;
    border: 1px solid #aaa;
  }

  &.wide {
    width: 80%;
  }

  .awesome-example-app-container-content {
    padding: 10px;

    &.content {
      padding-top: 0;
    }
  }
}

cssAutoImport

Loader will automatically add imports of CSS files from the same directory.
If value is true, loader will try to find files with name "index".
If value is a string, loader will try to find files with names equal to this string.
If value is an array, loader will try to find files with names equal to each item which is string or true (index).
It will try to find files with different extensions: "css", "scss", "less", "sass".
All found files will added to the bundle.
By default, it is false.

Directives

JS directives

// non-automatic mode
// prefixAutoResolving: "content"
// ...imports

with prefix 'crazy-app';

export default class Container extends React.Component {
  render() {
    return (
      <div class=".self">
        <div class=".title ..bigger">
          ...
        </div>
        <div class=".content">
          ...
        </div>
      </div>
    )
  }
}

will be

// ...imports

export default class Container extends React.Component {
  render() {
    return (
      <div class="crazy-app-container">
        <div class="crazy-app-container-title awesome-example-app-bigger">
          ...
        </div>
        <div class="crazy-app-container-title">
          ...
        </div>
      </div>
    )
  }
}

the result when "prefixAutoResolving" set to false, so we don't have additional local prefix,
just overrided global

// ...imports

export default class Container extends React.Component {
  render() {
    return (
      <div class="crazy-app">
        <div class="crazy-app-title awesome-example-app-bigger">
          ...
        </div>
        <div class="crazy-app-title">
          ...
        </div>
      </div>
    )
  }
}
// non-automatic mode
// ...imports

with addedPrefix 'dialog';

export default class Dialog extends React.Component {
  render() {
    return (
      <div class=".self">
        <div class=".title ..bigger">
          ...
        </div>
        <div class=".content">
          ...
        </div>
      </div>
    )
  }
}

will be

// ...imports

export default class Dialog extends React.Component {
  render() {
    return (
      <div class="awesome-example-app-dialog">
        <div class="awesome-example-app-dialog-title awesome-example-app-bigger">
          ...
        </div>
        <div class="awesome-example-app-dialog-content">
          ...
        </div>
      </div>
    )
  }
}

CSS directives

CSS directives do absolutly the same and look pretty much like JS versions, except the last one

String queries syntax

render() {
  return (
    <div class="name .name ..name $name $$name prefix::name ~name .$name ..$name">
      ...
    </div>
  )
}

name

Gives class name without prefixes in non-automatic mode.
Gives class name with a local prefix in automatic mode.

render() {
  return (
    <div className="name">
      ...
    </div>

    //and

    <div className="local-prefix-name">
      ...
    </div>
  )
}

.name

Gives class name with a local prefix in non-automatic mode.
Gives class name with a global prefix in automatic mode.

render() {
  return (
    <div className="local-prefix-name">
      ...
    </div>

    //and

    <div className="global-prefix-name">
      ...
    </div>
  )
}

..name

Gives class name with a global prefix in non-automatic mode.
Gives class name without prefixes in automatic mode.

render() {
  return (
    <div className="global-prefix-name">
      ...
    </div>

    //and

    <div className="name">
      ...
    </div>
  )
}

$name

Merges a class name or an array of class names from a variable.
The loader automatically adds import of required module for class name merging.
The variable should already contain classes with prefixes or be already obfuscated.

render() {
  return (
    <div className={classy(name)}>
      ...
    </div>
  )
}

an example how to make it work:

in a parent using extraAttributeName: "classes"

render() {
  return (
    <Icon classes="..large green">
      resize
    </Icon>
  )
}

in the Icon

with addedPrefix 'icon';

export default function Icon({classes, children}) {
  return (
    <i class=".self $classes material-icons">
      {children}
    </i>
  )
}

so we will have

in a parent

render() {
  return (
    <Icon classes="awesome-example-app-large green">
      resize
    </Icon>
  )
}

in the Icon "import" will be automatically added

import classy from 'classy-loader/classy';

export default function Icon({classes, children}) {
  return (
    <i className={classy("awesome-example-app-icon", classes, "material-icons")}>
      {children}
    </i>
  )
}

so this is how the code will look like in a bundle

return _react2.default.createElement(
  'i',
  _extends({
    className: (0, _classy2.default)("awesome-example-app-icon", classes, "material-icons")
  }),
  children
);

$$name

The same as $name but tells the loader that this variable is a valid string and not an array or undefined,
so don't need to use merge function

render() {
  return (
    <div class="$classes">
        <div class="$$className">
           ...
        </div>
    </div>
  )
}

will be

render() {
  return (
    <div className={classy(classes)}>
      <div className={className}>
        ...
      </div>
    </div>
  )
}

prefix::name

Adds needed addiotinal prefix to class name.
See the example with the Icon above.
Let's modify this a little bit.
Added prefix is a local prefix in relation to the Icon.

render() {
  return (
    <Icon classes="..large green">
      <span class="icon::thing">
        resize
      </span>
    </Icon>
  )
}

also you can use just code like this for the same purpose, but first variant adds delimiter by itself

render() {
  return (
    <Icon classes="..large green">
      <span class="..icon-thing">
        resize
      </span>
    </Icon>
  )
}

so we will have this html

<i className="awesome-example-app-icon awesome-example-app-large green material-icons">
  <span class="awesome-example-app-icon-thing">
    resize
  </span>
</i>

~name

Make added prefix from tag name in which attributeName located.

render() {
  return (
    <SomeComponent 
      classes="~name"
      menu={(
        <SomeMenu
          classes="~cool-menu"/>
      )}>
      ...content
    </SomeComponent>
  )
}

will be

render() {
  return (
    <SomeComponent 
      classes="awesome-example-app-some-component-name"
      menu={(
        <SomeMenu
          classes="awesome-example-app-some-menu-cool-menu"/>
      )}>
      ...content
    </SomeComponent>
  )
}

.$name

Dynamical class name, local prefix plus value of a given variable.
It's always local prefix regardless whether the mode automatic or not.

with addedPrefix 'tab';

export default function Tab({classes, children, isActive}) {
  render() {
    let className = isActive ? 'active' : 'inactive';
    return (
      <div class=".self .$className $classes">
          {children}
      </div>
    )
  }
}

will be

import classy from 'classy-loader/classy';

export default function Tab({classes, children, isActive}) {
  render() {
    let className = isActive ? 'active' : 'inactive';
    return (
      <div className={classy("awesome-example-app-tab", "awesome-example-app-tab-" + className,  classes)}>
          {children}
      </div>
    )
  }
}

..$name

Dynamical class name, global prefix plus value of a given variable.
It's always global prefix regardless whether the mode automatic or not.

with addedPrefix 'button';

export default class Button extends React.Component {
  render() {
    let className = 'active';
    return (
      <div classes=".self ..$className">
          ...
      </div>
    )
  }
}

will be

export default class Button extends React.Component {
  render() {
    let className = 'active';
    return (
      <div className={"awesome-example-app-button awesome-example-app-" + className}>
          ...
      </div>
    )
  }
}

It's impossible to obfuscate dynamical class names so there are special fake $classy functions to make roadmaps for obfuscation.

This ia an example:

let className = $classy(color, '..color-', ['red', 'green']);
className = $classy(number, '.color-', ['blue', 'yellow']);
className = $classy(number, '..', ['one', 'two']);
className = $classy(quality, '.', ['good', 'bad']);
className = $classy(name, '', ['John', 'Rick']);

Here is the result for the non-automatic mode:

let className = {
  red: 'awesome-example-app-color-red',
  green: 'awesome-example-app-color-green'
}[color];

className = {
  blue: 'awesome-example-app-button-color-blue',
  yellow: 'awesome-example-app-button-color-yellow'
}[color];

className = {
  one: 'awesome-example-app-one',
  two: 'awesome-example-app-two'
}[number];

className = {
  good: 'awesome-example-app-button-good',
  bad: 'awesome-example-app-button-bad'
}[quality];

className = {
  John: 'John',
  Rick: 'Rick'
}[name];

And then the automatic mode will give this result:

let className = {
  red: 'color-red',
  green: 'color-green'
}[color];

className = {
  blue: 'awesome-example-app-color-blue',
  yellow: 'awesome-example-app-color-yellow'
}[color];

className = {
  one: 'one',
  two: 'two'
}[number];

className = {
  good: 'awesome-example-app-good',
  bad: 'awesome-example-app-bad'
}[quality];

className = {
  John: 'awesome-example-app-button-John',
  Rick: 'awesome-example-app-button-Rick'
}[name];

So variable "className" will have a real class name value and it can be obfuscated:

let className = {
  red: 'hby457r',
  green: 'fhelf76',
  blue: 'dh409gl',
  yellow: 'sl58sgf',
  orange: 'dl50gak',
  ...
}[color];

Another way to make a roadmap with different class name patterns.

let className = $classy(colorValue, {
  red: "..red item::reddish",
  green: "..green ..greenish",
  ...
});

It produces this code:

let className = {
  red: 'awesome-example-app-red awesome-example-app-item-reddish',
  green: 'awesome-example-app-green awesome-example-app-greenish',
  ...
}[colorValue];

Also there is the third way to use $classy:

with addedPrefix 'catalog';
// ....
let className = $classy(".item item ..some-item $classes");

It produces this code:

import classy from 'classy-loader/classy';
// ....
let className = classy("awesome-example-app-catalog-item", "item", "awesome-example-app-some-item", classes);

Conditional queries

Simple at first

// all with globalPrefix = 'app'
// all with autoPrefixMode = false
// all with addedPrefix = 'item'

render() {
  let active = true;
  return (
    <div class="name $active?active">
      ...
    </div>
    <div class=".name $active?.active">
      ...
    </div>
    <div class="$active?..active:..inactive">
      ...
    </div>
    <div class="$active?$className:disabled">
      ...
    </div>
    <div class="$!active?inactive">
      ...
    </div>
  )
}

will become

render() {
  let active = true;
  return (
    <div className={classy("name", active ? "active" : "")}>
      ...
    </div>
    <div className={classy("app-item-name", active ? "app-item-active" : "")}>
      ...
    </div>
    <div className={classy(active ? "app-active" : "app-inactive")}>
      ...
    </div>
     <div className={classy(active ? className : "disabled")}>
      ...
    </div>
    <div className={classy(!active ? "inactive" : "")} >
      ...
    </div>
  )
}

You can have spaces next to symbols "?" and ":" like

render() {
  return (
    <div class="$active ? active : inactive">
      ...
    </div>
  )
}

But not in conditional parts

render() {
  return (
    <div class="$active === true ? active : inactive">
      ...
    </div>
  )
}

This query will produce incorrect class name something like

render() {
  return (
    <div className="1 === true active inactive">
      ...
    </div>
  )
}

If you want to have spaces in conditions use parentheses

render() {
  return (
    <div class="$(active == 'something') ? active : inactive">
      ...
    </div>
  )
}

You can have only one variable sign "$" in your condition, it should be first of course

render() {
  return (
    <div class="$index==count-1 ? active : inactive">
      ...
    </div>
    
    // or

    <div class="$( index == count - 1 ) ? active : inactive">
      ...
    </div>
  )
}

And finally super short cherry on the cake querries

render() {
  return (
    <div class="$?active $?.active $?..active">
      ...
    </div>
  )
}

will be

render() {
  return (
    <div className={classy(active ? "active" : "", active ? "local-prefix-active" : "", active ? "global-prefix-active" : "")}>
      ...
    </div>
  )
}

And with negative sign

render() {
  return (
    <div class="!$?active !$?.active !$?..active">
      ...
    </div>
  )
}

will be

render() {
  return (
    <div className={classy(!active ? "active" : "", !active ? "local-prefix-active" : "", !active ? "global-prefix-active" : "")}>
      ...
    </div>
  )
}

Points work the same as usual

CSS syntax

Non-automatic prefix mode

One point for real class name without prefix.
Two points for class names with local prefix.
Three points for class names with global prefix.
"Self" is a keywords that means local prefix itself or global if local one not defined

..self {
  ..title {

  }
  ..content {

  }
  ...active {

  }
  .item {

  }
}

Automatic prefix mode

One point for class names with local prefix.
Two points for class names with global prefix.
Three points for real class name without prefix.

.self {
  .title {

  }
  .content {

  }
  ..active {

  }
  ...item {

  }
}

If a local prefix not defined global one will be added instead

CSS shorcutty special syntax

Here's an example

.container {
  var .abs.w100.h200.bc-000.c-fff.fs15;
}

will be

.container {
  position: absolute;
  width: 100px;
  height: 200px;
  background-color: #000;
  color: #fff;
  font-size: 15px;
}

can be also with spaces, should end with a semicolon or a new line

.container {
  var .fix .l .r .t .b .z999 .o3;
}

will be can be also with spaces, should end with a semicolon or a new line

.container {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 999;
  opacity: 0.3;
}

Full list of shorcuts

rubb = left: 0; right: 0; top: 0; bottom: 0;
l = left: 0;
lau = left: 'auto';
l10 = left: 10px;
l-10 = left: -10px;
l50p = left: 50%;
l-50p = left: -50%;

r = right: 0;
rau = right: 'auto';
r10 = right: 10px;
r-10 = right: -10px;
r50p = right: 50%;
r-50p = right: -50%;

t = top: 0;
tau = top: 'auto';
t10 = top: 10px;
t-10 = top: -10px;
t50p = top: 50%;
t-50p = top: -50%;

b = bottom: 0;
bau = bottom: 'auto';
b10 = bottom: 10px;
b-10 = bottom: -10px;
b50p = bottom: 50%;
b-50p = bottom: -50%;

z10 = z-index: 10;

wa = width: auto;
w = width: 100%;
w100 = width: 100px;
w50p = width: 50%;

ha = height: auto;
h = height: 100%;
h150 = height: 150px;
h20p = height: 20%;

wh = width: 100%; height: 100%;
wh20 = width: 20px; height: 20px;
wh20p = width: 20%; height: 20%;

mnw = min-width: 0;
mnw100 = min-width: 100px;
mnh = min-height: 0;
mnh100 = min-height: 100px;
mxw = max-width: none;
mxw100 = max-width: 100px;
mxh = max-height: none;
mxh100 = max-height: 100px;

auto = margin: auto;
m = margin: 0;
m5 = margin: 5px;
m10-5 = margin: 10px 5px;
m10-5-10-5 = margin: 10px 5px 10px 5px;

ml = margin-left: 0;
ml5 = margin-left: 5px;
ml-5 = margin-left: -5px;
ml5p = margin-left: 5%;
ml-5p = margin-left: -5%;

mr = margin-right: 0;
mr5 = margin-right: 5px;
mr-5 = margin-right: -5px;
mr5p = margin-right: 5%;
mr-5p = margin-right: -5%;

mt = margin-top: 0;
mt5 = margin-top: 5px;
mt-5 = margin-top: -5px;
mt5p = margin-top: 5%;
mt-5p = margin-top: -5%;

mb = margin-bottom: 0;
mb5 = margin-bottom: 5px;
mb-5 = margin-bottom: -5px;
mb5p = margin-bottom: 5%;
mb-5p = margin-bottom: -5%;

p = padding: 0;
p5 = padding: 5px;
p10-5 = padding: 10px 5px;
p10-5-10-5 = padding: 10px 5px 10px 5px;

pl = padding-left: 0;
pl5 = padding-left: 5px;
pl-5 = padding-left: -5px;
pl5p = padding-left: 5%;
pl-5p = padding-left: -5%;

pr = padding-right: 0;
pr5 = padding-right: 5px;
pr-5 = padding-right: -5px;
pr5p = padding-right: 5%;
pr-5p = padding-right: -5%;

pt = padding-top: 0;
pt5 = padding-top: 5px;
pt-5 = padding-top: -5px;
pt5p = padding-top: 5%;
pt-5p = padding-top: -5%;

pb = padding-bottom: 0;
pb5 = padding-bottom: 5px;
pb-5 = padding-bottom: -5px;
pb5p = padding-bottom: 5%;
pb-5p = padding-bottom: -5%;

flex = display: flex;
flcen = align-item: center; justify-content: center;
bl = display: block;
inb = display: inline-block;
none = display: none;
inl = display: inline;

fix = position: fixed;
abs = position: absolute;
rel = position: relative;
box = box-sizing: border-box;

ova = overflow: auto;
ovh = overflow: hidden;
ovv = overflow: visible;
ovs = overflow: scroll;

lt = text-align: left;
rt = text-align: right;
cen = text-align: center;
just = text-align: justify;

vtop = vertical-align: top;
vmid = vertical-align: middle;
vbot = vertical-align: bottom;
col = border-collapse: collapse;
lfix = table-layout: fixed;

cur = cursor: default;
cur-name = cursor: name;
pntr = cursor: pointer;
cnt = content: "";
nor = resize: none;
nosel = user-select: none; -moz-user-select: none; -webkit-user-select: none;

fl = float: left;
fr = float: right;
clr = clear: both;

bold = font-weight: bold;
norm = font-weight: normal;
it = font-style: italic;
un = text-decoration: underline;

lh = line-height: 0;
lh20 = line-height: 20px;
ls = letter-spacing: 0;
ls2 = letter-spacing: 2px;
fs = font-size: 0;
fs15 = font-size: 15px;
ff-name = font-family: name;

o = opacity: 0;
o5 = opacity: 0.5;
o10 = opacity: 1;

ol = outline: 0;
ol-000 = outline: 1px solid #000;
ol-EEE-2 = outline: 2px solid #EEE;
ol-EEE-2-dashed = outline: 2px dashed #EEE;

bo = border: 0;
bo-000 = border: 1px solid #000;
bo-EEE-2 = border: 2px solid #EEE;
bo-EEE-2-dashed = border: 2px dashed #EEE;

bol = border-left: 0;
bol-000 = border-left: 1px solid #000;
bol-EEE-2 = border-left: 2px solid #EEE;
bol-EEE-2-dashed = border-left: 2px dashed #EEE;

bor = border-right: 0;
bor-000 = border-right: 1px solid #000;
bor-EEE-2 = border-right: 2px solid #EEE;
bor-EEE-2-dashed = border-right: 2px dashed #EEE;

bot = border-top: 0;
bot-000 = border-top: 1px solid #000;
bot-EEE-2 = border-top: 2px solid #EEE;
bot-EEE-2-dashed = border-top: 2px dashed #EEE;

bob = border-bottom: 0;
bob-000 = border-bottom: 1px solid #000;
bob-EEE-2 = border-bottom: 2px solid #EEE;
bob-EEE-2-dashed = border-bottom: 2px dashed #EEE;

br = border-radius: 0;
br5 = border-radius: 5px;
br50p = border-radius: 50%;
br5-10-10-0 = border-radius: 5px 10px 10px 0;

bsp = border-spacing: 0;
bsp2 = border-spacing: 2px;

trans = background-color: transparent;
c-fff = color: #fff;
bc-fff = background-color: #fff;
boc-fff = border-color: #fff;

shad = box-shadow: none;
shad-000-10 = box-shadow: 0 0 10px #000;
shad-000-10-1-1 = box-shadow: 1px 1px 10px #000;
shad-in-000-10 = box-shadow: inset 0 0 10px #000;
shad-in-000-10-1-1 = box-shadow: inset 1px 1px 10px #000;

tshad = text-shadow: none;
tshad-000-2 = text-shadow: 0 0 2px #000;
tshad-000-2-1-1 = text-shadow: 1px 1px 2px #000;

tra-c-3-bc-3-o-3 = transition: color 0.3s, background-color 0.3s, opacity 0.3s;
rot20 = transform: rotate(20deg);
rot-45 = transform: rotate(-45deg);
ell = text-overflow: ellipsis; overflow: hidden; white-space: nowrap;
nowr = white-space: nowrap;
hid = visibility: hidden;

norep = background-repeat: no-repeat;
repx = background-repeat: repeat-x;
repy = background-repeat: repeat-y;
cvr = background-size: cover;

bpcen = background-position: 50% 50%;
bp-20-20 = background-position: 20px 20px;
bp-50p-20p = background-position: 20% 20%;
bp-c-b = background-position: center bottom;
bp-r-t = background-position: right top;
bp-l-10 = background-position: left 10px;

Background image style shortcuts

You need to define source directories of images with these directives.
Define few sources if you need. Just duplicate lines with different paths to folders (not files)

.with.image.source '../../assets/images/';
.with.image.source './bg-images';
.with.image.source './images/gifs';
.with.image.source '../svgs';

And then use code like this:

.item {
  var .png-arrow.jpg-bg.jpeg-line.png2-some-image;
  var .gif3-preloader.svg4-icon;
}

So add number 2 (3) if an image is from the second (third) source.
Shortcuts are named as image file extentions (PNG, GIF, JPG, JPEG, SVG).
Second parts are image file names.

So you will have these styles:

.item {
  background-image: url(../../assets/images/arrow.png);
  background-image: url(../../assets/images/bg.jpg);
  background-image: url(../../assets/images/line.jpeg);
  background-image: url(./bg-images/some-image.png);
  background-image: url(./images/gifs/preloader.gif);
  background-image: url(../svgs/icon.svg);
}

So shortcuts look like this:

png-png-filename = background-image: url(../some/path/png-filename.png);
jpg-jpg_filename = background-image: url(../some/path/jpg_filename.jpg);
jpeg-oneMoreJpgFilename = background-image: url(../some/path/oneMoreJpgFilename.jpeg);
gif-giffy = background-image: url(../some/path/giffy.gif);
svg-blabla = background-image: url(../some/path/blabla.svg);

Of cource you can add number of source folder

png2-a = background-image: url(../path/to/second/source/a.png);
gif33-d = background-image: url(../path/to/33-th/source/d.gif);

This two lines do the same

jpg-e = background-image: url(../path/to/first/source/e.jpg);
jpg1-e = background-image: url(../path/to/first/source/e.jpg);