CoffeeMugg icon indicating copy to clipboard operation
CoffeeMugg copied to clipboard

Support CSS

Open wmertens opened this issue 13 years ago • 12 comments

Using the this swizzling trick I describe in #1, you could also support CSS for the @style section. The CSS syntax is here: http://www.w3.org/TR/css3-syntax/

Basically I'm thinking that there would be only a couple functions, @rule, @media, @import etc, and the @rule would take a selector string and one or more objects with the CSS properties as key-value pairs). When property order matters (only seldomly), then multiple @rule calls for the same selector could be used.

The @rule function could automagically add vendor extensions for new properties like box-sizing or border-radius.

Some hypothetical examples inspired by lesscss.org:

@style ->
  color="#4D926F"

  @import "other.css"

  @rule "#header", color: color;
  @rule "h2", color: color

  roundedCorners = (radius = "5px") ->
    "border-radius": radius

  @rule "#header", roundedCorners(), border: "2px solid red"
  @rule "#footer", roundedCorners("10px")

would result in

<style>
@import "other.css";
#header {
  color: #4D926F;
}
h2 {
  color: #4D926F;
}
#header {
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border: 2px solid red;
}
#footer {
  border-radius: 10px;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
}
</style>

wmertens avatar Aug 15 '12 21:08 wmertens

sounds useful, i'll look into this.

jaekwon avatar Aug 16 '12 00:08 jaekwon

I've been thinking about this some more and in the mean time I found SASS which has neat features like calculation on colors and nesting. I think CoffeeMugg could do the same.

@style would take objects, arrays of objects, or a function with separate @css statements which would do the same without adding a <style> tag.

The objects would be multi-level: The main object has selectors as keys and the values are property/value objects or sub-selector objects. Some properties can get objects as well, like font.

To avoid having to quote, properties could optionally be written with _ instead of -.

Finally sass has special syntax to handle colors and lengths. That could be done with classes, maybe at a later stage.

So where sass would say

$blue: #3bbfce
$margin: 16px

.content-navigation
  border-color: $blue
  color: darken($blue, 9%)

.border
  padding: $margin / 2
  border-color: $blue

table.hl
  margin: 2em 0
  td.ln
    text-align: right

li
  font:
    family: serif
    weight: bold

@mixin table-base
  th
    text-align: center
  td, th
    padding: 2px

@mixin left($dist)
  float: left
  margin-left: $dist

#data
  @include left(10px)
  @include table-base

CoffeeMugg could have

blue = cm.color "3bbfce"
margin = cm.px 16
table_base =
  th:
    text_align: center
  "td, th":
    padding: "2px"
left = (dist) ->
  float: "left"
  margin_left: dist

@style 
  ".content-navigation": 
    border_color: blue
    color: blue.darken 0.09

  ".border":
    padding: margin.div 2
    border_color: blue

  "table.hl":
    margin: "2em 0"
    "td.ln":
      text_align: right

  li:
    font:
      family: "serif"
      weight: "bold"

  "#data": [ table_base, left("10px") ]

The result for either should be something like

.content-navigation {
  border-color: #3bbfce;
  color: #2b9eab;
}
.border {
  padding: 8px;
  border-color: #3bbfce;
}
table.hl {
  margin: 2em 0;
}
table.hl td.ln {
  text-align: right;
}
li {
  font-family: serif;
  font-weight: bold;
}
#data {
  float: left;
  margin-left: 10px;
}
#data th {
  text-align: center;
  font-weight: bold;
}
#data td, #data th {
  padding: 2px;
}

Looks nice, no? Sass also offers selector inheritance which seems a little complicated to put into CoffeeMugg (you need to parse and cache selectors), and I don't think it adds much value over writing custom functions.

A limitation with this approach is that you can't use the same selector in the same object twice, but you can work around that with an array of objects.

I think CoffeeMugg shouldn't try very hard to make the CSS concise, there are CSS minifiers if that is needed.

I already took a stab at my first proposal but now I'll try this first. Should be doable, I'll see which features won't make it ;-)

wmertens avatar Aug 18 '12 11:08 wmertens

Good suggestions.

How about blue = @color '#3bbfce'? (vs cm.color) and keeping pixels as regular numbers? That way users can manipulate pixel values easier by using +/-/*...

On Aug 18, 2012, at 4:20 AM, wmertens wrote:

I've been thinking about this some more and in the mean time I found SASS which has neat features like calculation on colors and nesting. I think CoffeeMugg could do the same.

@style would take objects, arrays of objects, or a function with separate @css statements which would do the same without adding a

The objects would be multi-level: The main object has selectors as keys and the values are property/value objects or sub-selector objects. Some properties can get objects as well, like font.

To avoid having to quote, properties could optionally be written with _ instead of -.

Finally sass has special syntax to handle colors and lengths. That could be done with classes, maybe at a later stage.

So where sass would say

$blue: #3bbfce $margin: 16px

.content-navigation border-color: $blue color: darken($blue, 9%)

.border padding: $margin / 2 border-color: $blue

table.hl margin: 2em 0 td.ln text-align: right

li font: family: serif weight: bold

@mixin table-base th text-align: center td, th padding: 2px

@mixin left($dist) float: left margin-left: $dist

#data @include left(10px) @include table-base CoffeeMugg could have

blue = cm.color "3bbfce" margin = cm.px 16 table_base = th: text_align: center "td, th": padding: "2px" left = (dist) -> float: "left" margin_left: dist

@style ".content-navigation": border_color: blue color: blue.darken 0.09

".border": padding: margin.div 2 border_color: blue

"table.hl": margin: "2em 0" "td.ln": text_align: right

li: font: family: "serif" weight: "bold"

"#data": [ table_base, left("10px") ] The result for either should be something like

.content-navigation { border-color: #3bbfce; color: #2b9eab; } .border { padding: 8px; border-color: #3bbfce; } table.hl { margin: 2em 0; } table.hl td.ln { text-align: right; } li { font-family: serif; font-weight: bold; } #data { float: left; margin-left: 10px; } #data th { text-align: center; font-weight: bold; } #data td, #data th { padding: 2px; } Looks nice, no? Sass also offers selector inheritance which seems a little complicated to put into CoffeeMugg (you need to parse and cache selectors), and I don't think it adds much value over writing custom functions.

A limitation with this approach is that you can't use the same selector in the same object twice, but you can work around that with an array of objects.

I think CoffeeMugg shouldn't try very hard to make the CSS concise, there are CSS minifiers if that is needed.

I already took a stab at my first proposal but now I'll try this first. Should be doable, I'll see which features won't make it ;-)

— Reply to this email directly or view it on GitHub.

jaekwon avatar Aug 18 '12 18:08 jaekwon

@color works too, I didn't use it because at first I was considering using a function for each of the 290 CSS properties and it collided. For the lengths the problem is that px and em etc aren't easily convertible. Hmm, perhaps a default unit should be settable and then when you use a number for a property they get that unit? Means parsing the values though. A @px = (x) -> x + 'px' function and others like it could also be used — easier to type.

I think this functionality will see some iterations before we're happy :-)

wmertens avatar Aug 18 '12 19:08 wmertens

I think this functionality will see some iterations before we're happy :-)

Seems to be the name of the game!

jaekwon avatar Aug 18 '12 20:08 jaekwon

Hmm, Object key ordering is not guaranteed across JS implementations... Whereas rule ordering is important in CSS... This will probably cause headaches.

jaekwon avatar Aug 18 '12 21:08 jaekwon

Here's a jab at it...


@style unit:'pixels', ->

  blue = @color "#3bbfce"
  margin = 16

  # Helper functions could also be defined on this (@):
  @table_base = ->
    @_ "th",
      text_align: center
    @_ "td, th",
      padding: "2px"
  @left = (dist) ->
    @_ "&",
      float: "left"
      margin_left: dist

  # Object style
  # (length 1 enforced, to keep things clean)
  @_ ".content-navigation":   # rule name
    border_color: blue        # css property
    color: blue.darken 0.09   # css property

  # Object style in a procedure
  if someCondition
    @_ ".border":
      padding: margin.div 2
      border_color: blue

  # String with function style
  @_ "table.hl", ->           # Here we use a function block (->...) because we have multiple @_ rules.
    @_ "&":                   # You must proxy with '&', because the argument is always a rule, never a CSS property.
      margin: "2em 0"
    @_ "td.ln":
      text_align: right

  # String with an Object style
  @_ "li",
    font: [
      {family: "serif"},      # Objects in arrays get merged for you
      {weight: "bold"}
    ]

  # Same effect as above
  @_ "li",
    font:
      family: "serif"
      weight: "bold"

  # Procedures
  @_ "#data", ->
    @table_base()
    @left(10)

# All together without comments... hmm.
@style unit:'pixels', ->

  blue = @color "#3bbfce"
  margin = 16
  @table_base = ->
    @_ "th",
      text_align: center
    @_ "td, th",
      padding: "2px"
  @left = (dist) ->
    @_ "&",
      float: "left"
      margin_left: dist

  @_ ".content-navigation":
    border_color: blue
    color: blue.darken 0.09

  if someCondition
    @_ ".border":
      padding: margin.div 2
      border_color: blue

  @_ "table.hl", ->
    @_ "&":
      margin: "2em 0"
    @_ "td.ln":
      text_align: right

  @_ "li",
    font:
      family: "serif"
      weight: "bold"

  @_ "#data", ->
    @table_base()
    @left(10)

jaekwon avatar Aug 18 '12 21:08 jaekwon

Finally, the ultimate DSL hack... the letter 'o'

@style unit:'pixels', (o) ->

  blue = @color "#3bbfce"
  margin = 16

  table_base = ->
    o "th":
      text_align: center
    o "td, th":
      padding: "2px"

  left = (dist) ->
    o "&":
      float: "left"
      margin_left: dist

  o ".content-navigation":
    border_color: blue
    color: blue.darken 0.09

  if someCondition
    o ".border":
      padding: margin.div 2
      border_color: blue

  o "table.hl", ->
    o "&":
      margin: "2em 0"
    o "td.ln":
      text_align: right

  o "li":
    font:
      family: "serif"
      weight: "bold"

  o "#data", ->
    table_base()
    left(10)

jaekwon avatar Aug 18 '12 22:08 jaekwon

Indeed, that is a nice hack... I've already implemented the first syntax though :-)

Ordering in css is important, but only in certain cases (see here):

  • same property of a selector getting different values
  • same selector (because of the property)

Basically when you need ordering you're doing a bit of a hack and then using an array or multiple @css calls to enforce ordering and allow same keys seems fine, no?

e.g.

@style -> @css
  "h3": [
    display: "inline"
  , display: "run-in"
  ]

or

@style ->
  @css "h3": display: "inline"
  @css "h3": display: "run-in"

would do the right thing.

I dropped the font: { weight: xxx } thing for now, because I think it confuses matters more than it helps writing CSS.

I added the code to the css branch of my repo. Needs more tests and the prefix expansion. Thoughts?

wmertens avatar Aug 19 '12 07:08 wmertens

Ah, you're right about the ordering. Glad you knew that.

took a stab at the trailing empty rule problem:

https://github.com/jaekwon/CoffeeMugg/commit/209128237a2543a9f1d43814c8abaac5aa717a6c

jaekwon avatar Aug 19 '12 08:08 jaekwon

fixed a bug.

https://github.com/jaekwon/CoffeeMugg/compare/a0a8bb9c1cdce1c8ce747830cb008b2b9b4d2bd9...WM_css

jaekwon avatar Aug 19 '12 08:08 jaekwon

Yey, thanks!

I added prefixing, looks good I think!

Now for those color, length and animation classes... I think I'll first try to make some web pages.

wmertens avatar Aug 19 '12 14:08 wmertens