GrooCSS - code CSS in Groovy

Download

GrooCSS

GrooCSS let's you code your CSS in Groovy, using a natural Groovy DSL with optional code completion.

Like Less but with the fullness of Groovy and the JVM.

It was created by Adam L. Davis (@adamldavis) and inspired by the many other Groovy-based projects out there, like Gradle, Grails, Spock, Ratpack, and grooscript.

Principles: Stay in pure Groovy, get as close to CSS as possible, and maximize code reuse.

  • DSL similar to CSS but with camel-case and some modifications to make it valid Groovy.
  • Keyframes, media, charset, and font-face support.
  • Automatically adds -webkit, -ms, -moz, -o extensions! (configurable)
  • Color support with rgb, rgba, hex, named colors, and several color changing methods (mix, tint, shade, saturate, etc.)
  • Minimization (compress)
  • Support for transforms directly (transformX, etc),
  • Math functions (sqrt, sin, cos, toRadians, etc.) and built-in Measurement math.
  • Unit methods (unit, getUnit, convert) and some validation of unit types.
  • Ability to extend style-groups and add internal groups.
  • Pseudo-classes in DSL (nthChild, etc.)
  • Multiple ways to configure: Config.builder() or using withConfig
  • Close to CSS syntax using getAt, putAt, operator-overloading, underscore, methodMissing, and propertyMissing
  • Translator to convert from existing CSS.
  • Available pretty print (using Config)
  • Gradle Plugin available and asset-pipeline plugin.
  • Ability to create and reuse groups of styles using styles{} syntax.
  • Ability to import other files and optionally pass them values (importFile)

Examples

Static DSL Code Completion

From 1.0-M1 onwards, GrooCSS uses groovy extension modules to extend String, Integer, and Number so the following syntax can be used fully with IDE code completion.

def myColor = 'fe33ac'.color   // creates a Color object
def mySize = 100.px

'.box'.sg {             //sg or $ can be used interchangeably whichever you prefer
  color myColor          // resolves to color: #fe33ac
  borderColor whiteSmoke // borderColor becomes border-color; built-in named colors
  padding 2.em           // resolves to 2em; validated
}
table {
    color myColor background black //fluent
}
'table.my-class'.$ {
    color darken(myColor)  // tint, shade, lighten, mix, fade, and many other methods
}
input %odd {          // becomes input:nth-child(odd)
    background yellow
}
'formId'.id {       // resolves to #formId
    minWidth mySize      // resolves to 100px
    maxWidth mySize*2    // resolves to 200px
    fontSize 1.cm + 2.mm // you can add different types
    extend(table)        // ability to extend previously defined styles
}
$('.box div') {      // can use jQuery-style as well
  boxShadow '0 0 5px rgba(0, 0, 0, 0.3)'
}

Dynamic Styles DSL/More Operators

def myColor = c('#fe33ac')

_.box {           // _.box becomes .box
  color myColor
  borderColor '#fdcdea'
}
table {
    color myColor
}
table.my_class {           //can be configured to replace _ with -
    color myColor.darker()
}
input['class$="test"'] = { //becomes input[class$="test"]
    background yellow
}
sg '#formId', {     // sg useful for ID's
    minWidth 100.px // resolves to 100px
}
_.box div {
  boxShadow '0 0 5px rgba(0, 0, 0, 0.3)'
}
p + div {
    border '1px solid black'
}
p.red | a.red { color red } // | => ,
p >> a { color blue }       //>> => >
p * a { color blue }        // * => *
p - a { color blue }        // - => ~(tilde)
p ^ a { color blue }        // ^ =>  (space)

Dynamic vs. Static/XOR Not always needed

For many cases, XOR (^) is not actually needed. Keep in mind when you use dynamic method calls it will disable code completion. For example, using dynamic groovy (CSS on left, GrooCSS on right):


"div p.test a{text-decoration: none;}" => { div p.test a { textDecoration 'none' } }
"div.man p.test a{text-decoration: none;}" => { div.man p.test a { textDecoration 'none' } }
"div.man .test a{text-decoration: none;}" => { div.man _.test a { textDecoration 'none' } }
"body div p a{text-decoration: none;}" => { body div p a { textDecoration 'none' } }
"body div.test p a{text-decoration: none;}" => { body div.test p a { textDecoration 'none' } }
"body div.test p li a{text-decoration: none;}" => { body div.test p li a { textDecoration 'none' } }

If you prefer having NO dynamic code (all static) use the sg method whenever a styleClass is needed. For example:

sg 'div p.test a', { /*DSL*/ } or 'div p.test a'.sg { /*DSL*/ }