An extensible PHP based CSS preprocessor

The Tour


; Some aliases for box-sizing
box-sizing[] = -webkit-box-sizing
box-sizing[] = -moz-box-sizing
Excerpt from aliases file

Vendor prefixing

In CSS Crush vendor prefixes are automatically generated with aliases that are stored in an editable file.

The aliases file is pre-populated with CSS properties, functions and @-rules that have vendor prefixed equivalents.


/* Before */
p { box-sizing: border-box; }

/* After */
p {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

/* Before */
div { background: linear-gradient( to right, red, white ) fixed; }

/* After */
div {
  background: -webkit-linear-gradient( left, red, white ) fixed;
  background: -moz-linear-gradient( left, red, white ) fixed;
  background: -o-linear-gradient( left, red, white ) fixed;
  background: linear-gradient( to right, red, white ) fixed;
}

/* Before */
@keyframes myanim {
  0%   { left: 0; }
  100% { left: 100px; }
}

/* After */
@-webkit-keyframes myanim {
  0% { left: 0; } 100% { left: 100px; }
}
@-moz-keyframes myanim {
  0% { left: 0; } 100% { left: 100px; }
}
@-o-keyframes myanim {
  0% { left: 0; } 100% { left: 100px; }
}
@keyframes myanim {
  0% { left: 0; } 100% { left: 100px; }
}

/* Defining variables */
@define {
  helvetica:  "Helvetica Neue", Helvetica, Arial, sans-serif;
  sky-blue:   #88CDEA;
  breakpoint: 960px;
}

/* Applying variables */
@media only screen and ( max-width: $( breakpoint ) ) {
  ul, p {
    background-color: $( sky-blue );
  }
}

/* Specifying a fallback value as second argument */
.foo {
  color: $( theme-blue, #00f );
}

/* Variable interpolation */
.greeting {
  content: "Hi $( username )!";
}

Variables

Macro-like variables are available in CSS Crush with a familiar syntax.

Declare variables in your CSS with the @define directive.

Apply variables using a dollar function. You can supply a fallback value as the second argument for when the variable name has not been defined.

Global variables and/or file scoped variables can be added dynamically (via PHP) at runtime in a number of ways.


/* Before */
@import "print.css" print;
@import url( "small-screen.css" ) screen and ( max-width: 500px );

/* After */
@media print {
  /* Contents of print.css */
}
@media screen and ( max-width: 500px ) {
  /* Contents of small-screen.css */
}

Direct @import

CSS Crush scans for @import directives and inlines them directly in the output file so no http requests are wasted.

If you specify a media designation following the import URL — as per the CSS 2.1 standard — the imported file contents will be wrapped in an @media block.


/* Before */
.column-1 {
  width: percent( 200, 960 );
  font-size: ( 12 / 16 )em;
}

/* After */
.column-1 {
  width: 20.83333%;
  font-size: 0.75em;
}
Handy for relative values

Functions

A small collection of custom functions are built-in to CSS Crush, including:

  • math : calculates expressions ( allowed operators: + - / * and parenthesis ), all other non numeric/decimal characters are ignored
  • percent : returns first argument as a percentage of the second argument
  • data-uri : generates a data uri from a relative file path
  • h-adjust : manipulates the hue of a color value
  • s-adjust : manipulates the saturation of a color value
  • l-adjust : manipulates the lightness of a color value
  • a-adjust : manipulates the opacity of a color value

Parenthesised expressions without a function name are shorthand for the math function (see example).

Data URIs are automatically generated when referencing images, svgs or web fonts inside the data-uri function:


/* Before */
ul li {
  background-image: data-uri(../my-bg.png);
}
/* After */
ul li {
  background-image: url("data:image/png;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");
}

Color values can be lightened, darkened or desaturated using the l-adjust and s-adjust functions:


/* Before */
div {
  /* Lighten by 10% */
  color: l-adjust( hotpink 10 );
  /* Desaturate */
  background-color: s-adjust( #f00 -100 );
}

/* After */
div {
  color: #ff9cce;
  background-color: #808080;
}

/* Before */
.negative-text {
  overflow: hidden;
  text-indent: -9999px;
}

.sidebar-headline {
  @extend .negative-text;
  background: url( headline.png ) no-repeat;
}

/* After */
.negative-text,
.sidebar-headline {
  overflow: hidden;
  text-indent: -9999px;
}

.sidebar-headline {
  background: url( headline.png ) no-repeat;
}


Rule inheritance

Using the @extend directive and passing it a previously used selector it's possible to share styles more efficiently across a stylesheet.

Abstract rules can also be used if you want to extend an arbitary set of declarations that you don't need as standalone rules.


/* Before */
@abstract call-to-action {
  color: seagreen;
  font-variant: small-caps;
}

.cta {
  @extend call-to-action;
}

/* After */
.cta {
  color: seagreen;
  font-variant: small-caps;
}

/* Before */
@in .homepage {
  .content {
    font-size: 110%;
  }
  &.blue {
    color: powderblue;
  }
  .no-js & {
    max-width: 1024px;
  }
}

/* After */
.homepage .content {
  font-size: 110%;
}
.homepage.blue {
  color: powderblue;
}
.no-js .homepage {
  max-width: 1024px;
}

Block nesting

Rule blocks can be nested with the @in directive.

Especially useful if you need to group lots of styles under a common prefix.


/* Before */
@mixin display-font {
  font: arg( 0 ) FooDisplay, sans-serif;
  letter-spacing: .1em;
}

.text-glow {
  text-shadow: 0 0 10px goldenrod;
  color: gold;
}

/* Using the @include directive */
.headline {
  @include display-font( 120%/1.5 ), .text-glow;
}

/* After */
.headline {
  font: 120%/1.5 FooDisplay, sans-serif;
  letter-spacing: .1em;
  text-shadow: 0 0 10px goldenrod;
  color: gold;
}

Mixins

Simply put, mixins enable the embedding of one set of declarations inside other.

Mixins are created with the @mixin directive.

Positional arguments with the arg() function extend the capability of mixins for repurposing in different contexts.

arg() accepts an optional second argument as the default value.

Abstract rules and normal rules that appear earlier in the stylesheet can also be 'mixed in' as is; without arguments.

Multiple mixins can be applied to a rule by supplying a comma delimited list of values.

Caveat: Due to the nature of mixins they can bloat the size your output css file if used frequently.


/* Before */
@fragment input-placeholder {
  ::-webkit-input-placeholder { color: arg( 0 ); }
  :-moz-placeholder           { color: arg( 0 ); }
  ::placeholder               { color: arg( 0 ); }
  .placeholder-state          { color: arg( 0 ); }
}

@fragment input-placeholder( #ccc );

/* After */
::-webkit-input-placeholder { color: #ccc; }
:-moz-placeholder           { color: #ccc; }
::placeholder               { color: #ccc; }
.placeholder-state          { color: #ccc; }

Fragments

Fragments are similar to mixins, except that they work at block level.

Fragments are defined and invoked with the @fragment directive.


/* Before */
p {
  color: plum;
  background: #000;
  opacity: .5;
  position: absolute;
}

/* After */
p {
  position: absolute;
  opacity: .5;
  color: plum;
  background: #000;
}
Property sorter plugin

Plugins

If aliases are not sufficient, plugins can make more extensive transformations.

There are a number of stock plugins bundled with CSS Crush which cover CSS3 shims, property sorting, IE legacy hacks and experimental features such as composite pseudo classes.

Plugins can be disabled or enabled to suit.

The behaviour of some plugins — like the property sorter example at left — can be easily customized to your preference.


/* Before */
:any( .sidebar, .block ) a:any( :hover, :focus ) {
  color: lemonchiffon;
}

/* After */
.block a:hover,
.block a:focus,
.sidebar a:hover,
.sidebar a:focus {
  color: lemonchiffon;
}

Selector grouping

Selector grouping with the :any pseudo class (modelled after CSS4 :matches) simplifies the creation of complex selector chains.


/* Defining selector aliases */
@selector-alias :radio input[type="radio"];
@selector-alias :checkbox input[type="checkbox"];
@selector-alias :heading :any(h1, h2, h3, h4, h5, h6);

/* Before */
.sidebar :heading {
  color: honeydew;
}

/* After */
.sidebar h1, .sidebar h2,
.sidebar h3, .sidebar h4,
.sidebar h5, .sidebar h6 {
  color: honeydew;
}

Selector aliases

Selector aliases can be useful for grouping together common selector chains for reuse.

They're defined with the @selector-alias directive, and can be used anywhere you might use a psuedo class.

Minification & caching

By default all CSS Crush output is minified (you can disable minification for formatted output).


/* Before */
body {
  color: papayawhip;
  padding: 0 0 0 0;
  margin: 20px auto 0px;
  background-color: #ffffff;
}

/* After */
body{color:#ffefd5;padding:0;margin:20px auto 0;background-color:#fff}

The date-modified timestamp of the host-file and all the files files imported via @import are stored and checked on every subsequent running of the script. If any of the files have been modified a new file is compiled. If none have been modified a cached file is returned.

Source

CSS Crush is on GitHub. Download the latest stable release in zip or tar formats.

If you have Git installed you can clone the project with the following one-liner in your terminal:


% git clone git://github.com/peteboere/css-crush

Got composer?  CSS Crush is available on packagist.

Fork me on GitHub