Greetings, friends!
It all started with the fact that I intended to develop something so to speak for the soul. The React application had to be rendered on top of something else, for example, some website, the question arose that the CSS classes of my application might conflict with the existing infrastructure, well, of course I came to the conclusion that you need to implement prefixes for every seediest class, well, or wrap all the definitions in the class of my main container, I still chose the prefixes. But soon I was tired of them, they turned out so much that it all seemed empty copy-paste to me, and then I thought about creating my own loader for the webpack. As a result, work on it turned from a fly into an elephant, ideas overwhelmed me and as a result, my mind and hands created a monster that almost went out of my control.
I admit, during these weeks and a half of writing it, I am wildly tired of thinking, coding and documenting first in English, then translating from my clumsy English to a slightly less clumsy native language, I would rather have it already. But now I am a distinguished markdown programmer and a regular user.
So, I just needed a mechanism to replace the classname with my-app-classname, but in the end I’ll describe what I’ll describe in detail. I published the result of my work on npm.
For starters, perhaps someone will be interested in how to create your own webpack loader. Simple enough: create a folder, call it my-divine-loader, in it an index JS file and such code:
const {getOptions} = require('loader-utils'); module.exports = function(source) { // // this // getOptions , webpack.config.js return source; }
npm install --save classy-loader
const classy = require('classy-loader'); classy.init({ attributeName: 'class', extraAttributeName: 'classes', globalPrefix: 'awesome-example-app', delimiter: '-', obfuscation: false, obfuscatedLength: 4, autoPrefixMode: false, prefixAutoResolving: false }); //... 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' ] } ) } ] } //...
As you can see from the example, the loader should be added after Babel and standard style loaders.
The name of the DOM attribute of the elements that will be parsed by the loader.
It can be anything and will be converted to the standard attribute "className".
By default, this parameter is "class".
render() { return ( <div class=".self"> ... </div> ) }
or so
render() { return ( <div whateverName=".self"> ... </div> ) }
So "class" and "whateverName" are our attributeName names.
After processing by the loader, the code will look like this:
render() { return ( <div className="awesome-example-app"> ... </div> ) }
For the loader, "self" is a keyword that means our global or local prefix of the class name.
Specifically, in this case, we do not have a local prefix, so "self" will be equal to the global value.
The name of the attribute for React elements, which will be parsed in the same way, but not change its name.
It can also be used for the names of variables and keys of objects that need to be parsed.
By default it is "classes".
render() { return ( <Button classes=".action-button awesome-button"> ! </Button> ) } let classes = ".some-class"; let object = { classes: ".some-other-class" };
At the output we get all the same attribute "classes":
render() { return ( <Button classes="awesome-example-app-action-button awesome-button"> Do it! </Button> ) } let classes = "awesome-example-app-some-class"; let object = { classes: "awesome-example-app-some-other-class" };
The prefix that will be added to the class names of the DOM elements.
Special syntax will tell the loader whether to add one of the prefixes or not.
By default, it is empty, so this means that no prefix will be added if no local prefix is ​​specified.
render() { return ( <div class=".thing"> ... </div> ) }
will become
render() { return ( <div className="awesome-example-app-thing"> ... </div> ) }
A dot means that the class name must have a prefix.
More about parser syntax is presented below.
A character or word with which prefixes and class names will be combined.
The default is "-".
render() { return ( <div class=".some-item"> ... </div> ) }
So, if our "delimiter" is "_", the code will be like this:
render() { return ( <div className="awesome-example-app_some-item"> ... </div> ) }
If this parameter is set, the loader will try to determine the local prefix on its own.
By default it is not set.
There are three choices:
prefixAutoResolving: "content"
To begin with, the loader will try to find a string that contains:
export default (class | function) MySuperClassName
Then will search for:
export default connect (...) (MySuperClassName)
If not find:
class MySuperClassName
Well, in the end, take the first line with the following code:
function MySuperClassName
So "MySuperClassName" will be converted to the local prefix "my" + delimiter + "super" + delimiter + "class" + delimiter + "name".
For CSS files, the loader will look for data in the cache, which is populated when processing JS files.
If the cache contains information about the prefixes for the index file in the same directory,
they will be used, so JS and CSS will be synchronized.
You should have JS loaders in front of the CSS loaders so that the parser has the right cache.
export default class MySuperButton extends React.Component { render() { return ( <div class=".self"> <span class=".inner"> .... </span> </div> ) } }
will become
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> ) } }
You can also set JS / CSS local prefixes using special directives.
More about them is written below.
prefixAutoResolving: "file"
The loader will form a local prefix from the names of the JS / CSS files:
"SuperItem.js" or "super-item.js" or "super_item.js"
will turn into the prefix "super" + delimiter + "item".
For this method, the files must be named the same so that they are synchronized.
prefixAutoResolving: "folder"
The loader will form a local prefix from directory names:
"SuperItem / index.js" or "super-item / some.js" or "super_item / any.js"
will become the prefix "super" + delimiter + "item".
The easiest way to synchronize JS / CSS, also your structure will be more understandable.
If set to true, the loader will obfuscate the class names in the JS and CSS files.
Be careful, all CSS classes will be changed anyway, and JS is only inside the "attributeName" and extraAttributeName attributes .
By default, this option is not active.
render() { return ( <div class=".button small"> ... </div> ) }
will become
render() { return ( <div className="w4fq5wq dhet7s5"> ... </div> ) }
The length in characters up to which class names will be obfuscated.
The default value is "7".
So, if we have "obfuscatedLength" equal to 4
render() { return ( <div className="ald8 jd6g"> ... </div> ) }
Loader will automatically add prefixes to our class names.
You will need to use a slightly different string format for class names.
By default, this option is disabled.
For example, this is a CSS class entry for non-autoprefix mode:
( "prefixAutoResolving" is 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 converted to
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 automatically added on behalf of the class "Container").
So in this mode you need to add points for prefixes: one for local and two for global.
And finally, an example of the description of CSS classes for auto-prefix mode
( "prefixAutoResolving" is set to "content")
As a result, we get the same thing as in the first case.
export default class Container extends React.Component { render() { return ( <div class="self ..wide .area"> <div class="content ..content"> ... </div> </div> ) } }
will also
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 do not need to add a point for the local prefix; one must be added for the global and two for the names of the classes without the prefix.
In CSS files, everything works according to the same principles (you need to add the same number of points, so you will get a maximum of three points)
Non-autoprefix mode:
/* , ( ) */ .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 same for auto-prefix mode:
/* , ( ) */ .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; } } }
// // 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 become
// ...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> ) } }
And now the result for the case when "prefixAutoResolving" is set to false,
so we don't have an added local prefix,
only redefined 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> ) } }
// // ...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 do exactly the same thing and look very similar to JS versions,
the only difference is in the last directive, which is not for JS files
render() { return ( <div class="name .name ..name $name $$name prefix::name .$name ..$name"> ... </div> ) }
Indicates the name of a class without prefixes in non-autoprefix mode.
Indicates the name of a class with a local prefix in auto-prefix mode.
render() { return ( <div className="name"> ... </div> //and <div className="local-prefix-name"> ... </div> ) }
Indicates the name of a class with a local prefix in non-autoprefix mode.
Indicates the name of a class with a global prefix in auto-prefix mode.
render() { return ( <div className="local-prefix-name"> ... </div> //and <div className="global-prefix-name"> ... </div> ) }
Indicates the name of a class with a global prefix in non-autoprefix mode.
Indicates the name of a class without prefixes in auto-prefix mode.
render() { return ( <div className="global-prefix-name"> ... </div> //and <div className="name"> ... </div> ) }
"Merjit" is a class name or an array of names from a variable.
The loader will automatically add the "import" of the module necessary for the "merging".
The variable should already contain the name / class names with prefixes or be obfuscated.
render() { return ( <div className={classy(name)}> ... </div> ) }
An example of how this works in principle:
In the parent component, use extraAttributeName: "classes"
render() { return ( <Icon classes="..large green"> resize </Icon> ) }
in the child (named Icon)
with addedPrefix 'icon'; export default function Icon({classes, children}) { return ( <i class=".self $classes material-icons"> {children} </i> ) }
so in the end we get
in parent:
render() { return ( <Icon classes="awesome-example-app-large green"> resize </Icon> ) }
in the component "Icon" import is 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> ) }
And so the code will look in the assembled "bundle":
return _react2.default.createElement( 'i', _extends({ className: (0, _classy2.default)("awesome-example-app-icon", classes, "material-icons") }), children );
The same as with the variable above, but tells the loader that the variable is a string, not an array or "undefined",
so that the loader does not use the merging function, however, if there are other variables of the form $ name, the function will still be used
render() { return ( <div class="$classes"> <div class="$$className"> ... </div> </div> ) }
will become
render() { return ( <div className={classy(classes)}> <div className={className}> ... </div> </div> ) }
Adds a local (with respect to the child component) prefix to the class name.
Take the example of Icon above and slightly modify it.
render() { return ( <Icon classes="..large green"> <span class="icon::thing"> resize </span> </Icon> ) }
In principle, you can simply use the ".icon-thing" entry,
but the first option will connect them with the necessary separator.
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>
Dynamic class name, local prefix plus variable value.
This is always a local prefix regardless of mode.
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> ) } }
Dynamic class name, global prefix plus variable value.
This is always a global prefix regardless of mode.
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 is impossible (or just hs how) obfuscate such a dynamic class
but for such purposes a special "fake" function $ classy has been introduced.
She creates a "map" of class names for the obfuscator.
Here is an example:
let className = $classy(color, '..color-', ['red', 'green']); className = $classy(color, '.color-', ['blue', 'yellow']); className = $classy(number, '..', ['one', 'two']); className = $classy(quality, '.', ['good', 'bad']); className = $classy(name, '', ['John', 'Rick']);
In non-autoprefix mode will be converted to:
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 in autoprefix mode will be:
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 the variable "className" will be the real name of the class, which can be obfuscated and look like:
let className = { red: 'hby457r', green: 'fhelf76', blue: 'dh409gl', yellow: 'sl58sgf', orange: 'dl50gak', ... }[color];
Another way for these needs, but with different “patterns”:
let className = $classy(colorValue, { red: "..red item::reddish", green: "..green ..greenish", ... });
Will give the code:
let className = { red: 'awesome-example-app-red awesome-example-app-item-reddish', green: 'awesome-example-app-green awesome-example-app-greenish', ... }[colorValue];
Well, the last way you can use $ classy :
with addedPrefix 'catalog'; // .... let className = $classy(".item item ..some-item $classes");
will become
import classy from 'classy-loader/classy'; // .... let className = classy("awesome-example-app-catalog-item", "item", "awesome-example-app-some-item", classes);
// globalPrefix = 'app' // autoPrefixMode = false // 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 add spaces between the characters "?" and ":"
render() { return ( <div class="$active ? active : inactive"> ... </div> ) }
But in the condition spaces are not allowed:
render() { return ( <div class="$active === true ? active : inactive"> ... </div> ) }
Such an entry will be converted to an incorrect view class name.
render() { return ( <div className="1 === true active inactive"> ... </div> ) }
If you so want to add spaces, wrap the condition in parentheses.
render() { return ( <div class="$(active == 'something') ? active : inactive"> ... </div> ) }
It is possible to specify only one "$" sign at the beginning of the condition,
for the remaining condition variables, the sign can be omitted
render() { return ( <div class="$index==count-1 ? active : inactive"> ... </div> // or <div class="$( index == count - 1 ) ? active : inactive"> ... </div> ) }
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 denial
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 on the same principles as always, depending on the mode.
One point for real class names without prefixes.
Two dots for names with local prefix.
Three dots for names with global prefix.
"Self" is a keyword denoting a local or global prefix, if any, otherwise the class name will simply be self
..self { ..title { } ..content { } ...active { } .item { } }
One point for class names with local prefix.
Two dots for names with global prefix.
Three points for real class names without prefixes.
.self { .title { } .content { } ..active { } ...item { } }
If the local prefix is ​​not defined, the global one will be used.
Sugar syntax example:
.container { var .abs.w100.h200.bc-000.c-fff.fs15; }
will be converted to:
.container { position: absolute; width: 100px; height: 200px; background-color: #000; color: #fff; font-size: 15px; }
You can also with spaces:
.container { var .fix .l .r .t .b .z999 .o3; }
will become
.container { position: fixed; left: 0; right: 0; top: 0; bottom: 0; z-index: 999; opacity: 0.3; }
The expression must begin with the key word "var" and end with a semicolon or a line break.
rubb = left: 0; right: 0; top: 0; bottom: 0;
l = left: 0;
l10 = left: 10px;
l-10 = left: -10px;
l50p = left: 50%;
l-50p = left: -50%;
r = right: 0;
r10 = right: 10px;
r-10 = right: -10px;
r50p = right: 50%;
r-50p = right: -50%;
t = top: 0;
t10 = top: 10px;
t-10 = top: -10px;
t50p = top: 50%;
t-50p = top: -50%;
b = bottom: 0;
b10 = bottom: 10px;
b-10 = bottom: -10px;
b50p = bottom: 50%;
b-50p = bottom: -50%;
z10 = z-index: 10;
w = width: 100%;
w100 = width: 100px;
w50p = width: 50%;
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;
fix = position: fixed;
abs = position: absolute;
rel = position: relative;
box = box-sizing: border-box;
ova = overflow: auto;
ovh = overflow: hidden;
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;
cur = cursor: default;
cur-name = cursor: name;
pntr = cursor: pointer;
cnt = content: "";
nor = resize: none;
fl = float: left;
fr = float: right;
clr = clear: both;
bold = font-weight: bold;
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;
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;
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-cb = background-position: center bottom;
bp-rt = background-position: right top;
bp-l-10 = background-position: left 10px;
It's all the more difficult, and first you need to determine the source (s) of files.
, , .
:
.with.image.source '../../assets/images/'; .with.image.source './bg-images'; .with.image.source './images/gifs'; .with.image.source '../svgs';
:
.item { var .png-arrow.jpg-bg.jpeg-line.png2-some-image; var .gif3-preloader.svg4-icon; }
:
:
.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); }
, .
:
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);
:
png2-a = background-image: url(../path/to/second/source/a.png);
gif33-d = background-image: url(../path/to/33-th/source/d.gif);
:
jpg-e = background-image: url(../path/to/first/source/e.jpg);
jpg1-e = background-image: url(../path/to/first/source/e.jpg);
, , , , - , . , , , . , , , . , !
Source: https://habr.com/ru/post/344974/
All Articles