AzaKotlinCSS is a DSL (Domain-specific language) designed for writing CSS using Kotlin – the greatest programming language in the World! 💥🔥👍
repositories {
jcenter()
}
dependencies {
compile 'azadev.kotlin:aza-kotlin-css:1.0'
}
val css = Stylesheet {
a {
width = 10.px
color = 0xffffff
opacity = .8
hover {
color = 0xf2cacf
}
}
}
css.render()
// This will produce the following CSS:
// a{width:10px;color:#fff;opacity:.8}a:hover{color:#f2cacf}
In addition, there are 2 other rendering methods: renderTo(StringBuilder)
and renderToFile(File|String)
:
css.renderTo(builder)
// Will append CSS to an exsisting StringBuilder
css.renderToFile("style.css")
css.renderToFile(File("style.css"))
// Will render CSS to the file
AzaKotlinCSS is able to construct very complex selectors with a huge portion of syntax sugar.
Stylesheet {
div { top = 0 }
// div{top:0}
a.hover { top = 0 }
// a:hover{top:0}
div and span { top = 0 }
// div,span{top:0}
li.nthChild(2) { top = 0 }
// li:nth-child(2){top:0}
input["disabled"] { top = 0 }
// input[disabled]{top:0}
}
Below I'll show you more detailed examples of building CSS selectors using the DSL.
Stylesheet {
a { top = 0 }
// a{top:0}
div.span.a { top = 0 }
// div span a{top:0}
div and span and ul.li { top = 0 }
// div,span,ul li{top:0}
}
You can define class-selectors in several ways:
Stylesheet {
".logo" { top = 0 }
c("logo") { top = 0 }
}
// .logo{top:0}
Id-properties can be declared similarly:
Stylesheet {
"#logo" { top = 0 }
id("logo") { top = 0 }
}
// #logo{top:0}
Of cource you can combine them as you need:
Stylesheet {
".class1.class2" { top = 0 }
// .class1.class2{top:0}
"#logo.class1" { top = 0 }
// #logo.class1{top:0}
"#logo"..".class1"..span { top = 0 }
// #logo .class1 span{top:0}
}
Stylesheet {
a.hover { top = 0 }
// a:hover{top:0}
"#logo".firstLetter { top = 0 }
// #logo:first-letter{top:0}
}
By now AzaKotlinCSS is using single :
for all the pseudo elements to be friendly with IE8. But in the future it will be replaced with ::
.
Some more examples:
Stylesheet {
div.nthChild(2) { top = 0 }
// div:nth-child(2){top:0}
div.nthChild(EVEN) { top = 0 }
// div:nth-child(even){top:0}
any.not(lastChild) { top = 0 }
// *:not(:last-child){top:0}
"items".not(li) { top = 0 }
// .items:not(li){top:0}
}
Stylesheet {
div.span { top = 0 }
div..span { top = 0 }
div.children.span { top = 0 }
// div span{top:0}
div / span { top = 0 }
div.child.span { top = 0 }
// div>span{top:0}
div % span { top = 0 }
div.next.span { top = 0 }
// div+span{top:0}
div - span { top = 0 }
div.nextAll.span { top = 0 }
// div~span{top:0}
}
Stylesheet {
input["disabled"] { top = 0 }
// input[disabled]{top:0}
input["type", "hidden"] { top = 0 }
// input[type=hidden]{top:0}
input["type", "hidden"]["disabled"] { top = 0 }
// input[type=hidden][disabled]{top:0}
a["href", startsWith, "http://"] { top = 0 }
// a[href^="http://"]{top:0}
"#logo"["type", "main"] { top = 0 }
// #logo[type=main]{top:0}
attr("disabled") { top = 0 }
// [disabled]{top:0}
}
AzaKotlinCSS supports any nesting you can even imagine.
Stylesheet {
div {
width = AUTO
a {
color = 0xffffff
hover {
color = 0xff0000
}
}
}
}
// div{width:auto}div a{color:#fff}div a:hover{color:#f00}
Stylesheet {
div {
color = 0xffffff
b and strong {
color = 0xff0000
}
child.span {
color = 0x00ff00
}
}
}
// div{color:#fff}div b,div strong{color:#f00}div>span{color:#0f0}
This DSL provides all the major dimension units: px
, em
, percent
, ex
, inch
, cm
, mm
, pt
, pc
.
Stylesheet {
width = AUTO
// width:auto
width = 10.px
// width:10px
width = .2.em
// width:.2em
width = 50.percent
// width:50%
width = 17.257.ex
// width:17.257ex
width = 1.55555.inch
// width:1.55555in
}
AzaKotlinCSS also has the convenient box
helper:
Stylesheet {
padding = box(10, 5, 0, 20)
// padding:10px 5px 0 20px
padding = box(10.ex, 5.percent)
// padding:10ex 5%
padding = box(10, 10, 10, 10)
// padding:10px
padding = box(10)
// padding:10px
}
As you can see, values without an explicitly defined dimension will be treated as px
.
Also don't forget that you can use dimensions directly, without box
. For example: padding = 10.px
.
To define a color you'll probably will be glad to use a hexademical notation of Integer
. It's really convinient and looks almost exacly like CSS:
Stylesheet {
a { color = 0xf2cacf }
// a{color:#f2cacf}
a { color = 0xffffff }
// a{color:#fff}
}
Note that 3-digit hex-values will be considered as 6-digit hex with 3 zeros at the beginning.
For example 0xfff
will be treated as 0x000fff
. There is nothing we can do with it since, as you remember, it's a hex representation of Integer
.
AzaKotlinCSS also provides rgb(a)
and hex
color-helpers:
Stylesheet {
a { color = rgb(0,10,255) }
// a{color:#000aff}
a { color = rgba(255, 255, 255, .47) }
// a{color:rgba(255,255,255,.47)}
a { color = hex(0xf2cacf) }
// a{color:#f2cacf}
a { color = hex("#f00") }
// a{color:#f00}
}
As the example shows, the hex
helper supports shorthand color notations.
AzaKotlinCSS lets you create at-rules using (guess what!) the at
helper:
Stylesheet {
at("keyframes animation1") {
"from" { top = 0 }
"30%" { top = 50.px }
"68%,72%" { top = 70.px }
"to" { top = 100.px }
}
}
// @keyframes animation1{from{top:0}30%{top:50px}68%,72%{top:70px}to{top:100px}}
Stylesheet {
at("font-face") {
fontFamily = "Bitstream Vera Serif Bold"
src = url("VeraSeBd.ttf")
fontWeight = BOLD
}
}
// @font-face{font-family:Bitstream Vera Serif Bold;src:url(VeraSeBd.ttf);font-weight:bold}
For media queries the DSL provides convenient media
helper, that joins all the passed arguments using the and
operator:
Stylesheet {
media("min-width: 100px", "orientation: landscape") {
div { top = 0 }
}
}
// @media (min-width: 100px) and (orientation: landscape){div{top:0}}
But of course, you can still use the at
helper for complex rules:
Stylesheet {
at("media not screen and (color), print and (color)") {
div { top = 0 }
}
}
// @media not screen and (color), print and (color){div{top:0}}
Also note that you can easily use media
as a nested rule. It will be pushed to the top of its hierarchy and will have all the selectors it was called within:
Stylesheet {
div {
top = 0
media("min-width: 100px") {
top = 1
}
}
}
// div{top:0}@media (min-width: 100px){div{top:1}}
And one more useful tip. Didn't you forget that all this stuff is written on Kotlin? This means that you can bravely create any extension-methods you need.
For example, let's create a custom media-rule, to use it later in several places and be able to change the rule any time you want:
fun Stylesheet.myMediaQuery(body: Stylesheet.()->Unit)
= media("min-width: 100px", "orientation: landscape").invoke(body)
Stylesheet {
myMediaQuery {
div { top = 0 }
}
}
// @media (min-width: 100px) and (orientation: landscape){div{top:0}}
To combine several Stylesheet
s together you can use the include
method:
val css = Stylesheet {
a { color = 0xffffff }
}
val css_a = Stylesheet {
a.hover { color = 0xff0000 }
}
val css_b = Stylesheet {
a.active { color = 0x00ff00 }
}
css.include(css_a).include(css_b).render()
// a{color:#fff}a:hover{color:#f00}a:active{color:#0f0}
If you want to add an in-place mixin, then use the lowercased stylesheet
helper:
val clrfix = stylesheet {
zoom = 1
after {
content = " "
display = BLOCK
clear = BOTH
}
}
Stylesheet {
div {
margin = 0
clrfix()
}
}
// div{margin:0;zoom:1}div::after{content:" ";display:block;clear:both}
For now AzaKotlinCSS doesn't optimize the and
selector, so be aware of possible code redundancies:
Stylesheet {
b and strong {
color = 0xffffff
span {
color = 0xff0000
}
}
}
// This will produce:
// b,strong{color:#fff}b span{color:#f00}strong span{color:#f00}
// But the better way would be:
// b,strong{color:#fff}b span,strong span{color:#f00}
This software is released under the MIT License. See LICENSE.txt for details.