-
Notifications
You must be signed in to change notification settings - Fork 64
More on CSS Renaming
Before reading this article, you should have already read the section on renaming from the Closure Stylesheets overview. This article explains more of the options related to CSS renaming.
There are two command-line flags of interest with respect to CSS renaming:
-
--rename
tells Closure Stylesheets how to rename CSS classes -
--output-renaming-map-format
tells Closure Stylesheets how to format the renaming map
Each of these command line flags supports several different values. This is done to accommodate different styles of development.
The --rename
flag determines the algorithm that Closure Stylesheets uses to
rename your CSS classes. The options are as follows:
NONE
should be used when no renaming should be done. This is the default
option.
DEBUG
should be used when debugging CSS renaming. Each CSS class is
trivially renamed by taking each part of the class name (where parts are
delimited by hyphens) and appending a trailing underscore.
This mode is helpful as a "debug" mode of sorts to catch cases where a class
name is not wrapped with goog.getCssName()
. For example, if you use DEBUG
renaming in development and you notice that the style of a DOM element does not
look right, then you should take a look to see what its CSS class name is. If
you notice that it does not contain any underscores but you expected it to be
renamed, then you should be able to track down the reference to the class name
in your code and add the appropriate goog.getCssName()
wrapper. If NONE
renaming were used, then this bug would not reveal itself in development, and if
CLOSURE
renaming were used, it would take more work to reverse-map the
obfuscated class name in the DOM to the original class name in your code.
CLOSURE
should be used when minifying class names for production. Each CSS
class name is split into parts (as delimited by hyphens), and then parts are
renamed using the shortest available name. Parts are renamed consistently, so if
.foo-bar
is renamed to .a-b
, then .bar-foo
will be renamed to .b-a
.
This focus on splitting on hyphens stems from the fact that the
goog.getCssName()
function in the Closure Library has an optional second
argument that is appended using a hyphen. For example, both of the following
could be used to construct the CSS class .foo-bar
:
// Using the single-argument form:
goog.getCssName('foo-bar');
// Using the two-argument form:
goog.getCssName(goog.getCssName('foo'), 'bar');
Both of the above expressions will yield the string 'foo-bar'
in the absence
of any renaming map. Because the classes in the stylesheet are renamed without
any knowledge of how the class names will be constructed in the JavaScript code,
it must use a renaming scheme that supports both forms of construction.
For historical reasons, the second argument to goog.getCssName()
is appended
using a hyphen. This is somewhat unfortunate because hyphens are also frequently
used as visual separators in long CSS names, making it impossible to distinguish
which parts come from the "base" name and which parts come from the "suffix" by
looking at the name alone.
This is unfortunate because it often results in slightly suboptimal CSS. For
example, if a stylesheet has only one CSS class named .foo-bar
that is
exclusively referenced via goog.getCssName('foo-bar')
in JavaScript code, it
will be renamed to .a-b
rather than .a
in both the CSS and JS. One
workaround is to adopt the convention of using an underscore as a visual
separator rather than a hyphen. That is, name your class .foo_bar
if it is
referenced exclusively via goog.getCssName('foo_bar')
in your JavaScript
code. This will result in a single-letter renaming, as desired.
Note that although non-ASCII characters are allowed in CSS class names, which
could be used to produce class names with fewer characters, this generally
results in less efficient gzip compression of the minified stylesheet. For this
reason, the class names produced by CLOSURE
renaming are limited to
alphanumeric ASCII characters.
The renaming map produced by Closure Stylesheets often needs to be consumed by another tool, such as the Closure Compiler. Closure Stylesheets provides several output formats to provide straightforward integration with the Closure Tools, while also providing the opportunity for you to build your own tools on top of Closure Stylesheets.
CLOSURE_COMPILED
should be used when compiling JavaScript with the
Closure Compiler in either SIMPLE
or ADVANCED
mode. When
CLOSURE_COMPILED
is specified, the output is a JSON map of renaming
information wrapped in a call to goog.setCssNameMapping()
, such as:
goog.setCssNameMapping({
"foo": "a",
"bar": "b"
});
This file should be passed as an input to your compilation. The Compiler will
remove this call to goog.setCssNameMapping()
and use the object literal that
is passed to it as the basis for replacing all calls to goog.getCssName()
in
the compiled code.
CLOSURE_UNCOMPILED
should be used with uncompiled Closure Library code.
When CLOSURE_UNCOMPILED
is specified, the output is a JSON map of renaming
information assigned to the global variable CLOSURE_CSS_NAME_MAPPING
, such as:
CLOSURE_CSS_NAME_MAPPING = {
"foo": "a",
"bar": "b"
};
This file should be loaded via a <script>
tag before base.js
is loaded for
the Closure Library. This is because base.js
checks to see whether the global
CLOSURE_CSS_NAME_MAPPING
variable is declared, and if so, uses its value as
the renaming data for goog.getCssName()
. This ensures that the mapping data is
set before any calls to goog.getCssName()
are made.
JSON
should be used when building a tool that wants to consume the
renaming map data. When JSON
is specified, the output is a pure JSON map, such
as:
{
"foo": "a",
"bar": "b"
}
Currently, JSON
is the default value for the --output-renaming-map-format
option.
PROPERTIES
should be used as an alternative to JSON
if, for some reason,
your toolchain does not have a JSON parser available. When PROPERTIES
is
specified, the output is a
.properties file formatted as
key=value
pairs without any comments, such as:
foo=a
bar=b
This format is extremely strict and simple so that it should be easy to write a custom parser for it in whatever language you are using to process the renaming map data.