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*/ }