F.E.L.T.

Functionally Equivalent Language Translation

Coding for CSS

The current implementation of the CSS coder class is as simple as it needs to be to allow you to create most CSS rules so long as you know where the cracks in the pavement are. This page will show you both the pavement and the cracks as well as equip you with the information you need to avoid them and be able to generate workable CSS using FELT.

It does not yet (if ever) meet the complete W3C specifications with respect to the awesomely awesome XPath selectors and all that stuff because, quite simply, I didn't need them for day to day web development. Most people don't and it's most people I'm aiming at. If you find that you just can't live without a specific rule, use a normal ".css" file an dhave done with it.

FELT mode or CSS mode ?

I appreciate that old habits die hard and therefore anybody that is currently able to "think" in CSS will hopefully appreciate the fact that I have made the current version of the CSS back-end able to cope with strict FELT syntax and traditional CSS syntax at one and the same time.

This means that if you intend to re-use the FELT code for something else you can use the strict format but if you know that you are only ever going to be using the contents of a particular FELT source file for CSS then you can enter it in a way that is more familiar to you. We'll cover this in detail in just a little while.

Strict FELT Mode

What do we mean by strict felt mode? Simply, it means that everything that isn't a number should be enclosed in quotes, single or double, or else prefixed by the ":" colon, which in FELT is used to define a "keyword". In most back-end coders in most situations this will be turned into a single-quoted string. That is certainly true for PHP and Javacript coders as they stand. This makes it cleaner to declare associative arrays because you can visually distinguish between the keys and the values, keys tend to look like :foo and values can be any legal expression.

In strict mode you can also potentially reap "added value" from your effort by wrapping the rules in a (RETURN) instruction. This means that your CSS, if run through say the PHP back-end would give you a bunch of functions you could call that would answer a key-value array of the CSS! Now that has got to be useful to somebody somewhere hasn't it! A little demonstration is shown in the code boxes on the homepage. Imagine your site uses FELT and it dynamically generates the CSS... you could offer unlimited user tweaking or be able to have your server code dynamically fiddle the CSS according to the environment of the browser at the time the page is requested. The sky is the limit.

A simple BODY definition in strict mode

Let's consider this FELT CSS rule, using the strict syntax described plus the 'return' technique and see what it looks like and what it might be useful for...

(defun body ()
  (return {
      :background-color :black
      :background-image (url "../images/foobar.png")
      :color            :#fff
      :font-family      [ "Times New Roman" "Georgia" "Serif" ]
      :font-size        :15px
      :font-size        "15px"
      :font-size        15px
      }))

But you said anything that's a number... yes but by rights "15px" is actually a string and thus needs to be prefixed with the ":" or you could just quote it. Remember this is strict mode! Also, you don't have to lay it out like that, you can pack it on one line if you like, I am just a great believer that if code looks good it is easier to read. Notice the second two font size definitions, they are there so you can see what happens to them if you dont follow "da rules".

We can see that pretty much everything is preceded by a quote except for the bona-fide strings, and note that being a list type, the font family names are enclosed in square brackets (the (ALIST) instruction) and separated by spaces not commas.

Let's see what the rendered CSS for this looks like, then we will show it as PHP and Javascript too so you can see why you might want to take the time to write your CSS rules this way...

body {
  background-color:black;
  background-image:url("../images/foobar.png");
  color:#fff;
  font-family:"Times New Roman", "Georgia", "Serif";
  font-size:15px;
  font-size:"15px";
  font-size:15px
}

This has been "tidied" for clarity here... normally it will be rendered out as one long line, like i said before, FELT is not in the business of producing good looking output, just functionally equivalent output! If you want more real examples, download the site and check out the "sitecode/css" folder.

Now let us render the above as PHP and Javascript code... then you can see what all the fuss is about...and guess what, we get an error. Here is the full brutal output from running it through the CLI utility:

$ felt -as phpcoder temp.felt
Failed to translate: temp.felt
Dump: Array (
    [status] => 
    [output] => *** FELT-ERROR ***A syntax error has been detected in your source: temp.felt
    Location (approx.) row: 9, column: 21. Reason: PHPCoder failed to convert: 15px in the asName() method
)

I have tidied it a little but guess what... the PHP coder isn't at all happy about that last font size declaration. Now you should begin to realise that the PHP back-end is looking to turn the string "15px" into a variable name and according to PHP rules, that doesn't work so it blew. Let's remove those last two font sizes and try again... remember for language portable code you must follow FELT rules or take the consequences! OK, trying again now with that junk deleted...

function body()
    {return array(
            'background-color' => 'black',
            'background-image' => url("../images/foobar.png"),
            'color' => '#fff',
            'font-family' => array("Times New Roman", "Georgia", "Serif"),
            'font-size' => '15px'); }

Whooaaaa there Bubbah! That's my CSS right? Yup! And just to prove the point, let's do a little PHP command line session and prove that it actually works as PHP... this time we tell the felt utility to use the -cw (code wrap) and -o (output to file) options as well, then we load an interactive PHP session with that output file...guess what, another error strikes but patience FELT hacker, all is not lost, it's simple, let's fix it. Here's the error (abridged output):

PHP Fatal error:  Call to undefined function url()...

Huh? Yes. Once again, FELT has translated what it saw but it knows nothing about the final environment in which that code will be executed. The onus is on you to provide any functions that may be called and in this case, in a browser, the (url) function would have been there for us, however, in PHP land that is not the case and so we must provide one. All it needs to do is return the string it was given. Let's modify our source to be...

(defun body ()
  (return {
      :background-color :black
      :background-image (url "../images/foobar.png")
      :color            :#fff
      :font-family      [ "Times New Roman" "Georgia" "Serif" ]
      :font-size        :15px
      }))

(defun url (x) (return x))

which will then render out as before but the missing function will be in scope allowing us to try that interactive PHP session again, this time knowing that all dependencies have been met. var_dump() has been used as that will show the resulting PHP data types...

$ felt -as phpcoder temp.felt -cw -o temp.php
$ php -a
$ php > require 'temp.php';
require 'temp.php';

$ php > var_dump(body());
var_dump(body());

array(5) {
  ["background-color"]=>
  string(5) "black"
  ["background-image"]=>
  string(20) "../images/foobar.png"
  ["color"]=>
  string(4) "#fff"
  ["font-family"]=>
  array(3) {
    [0]=>
    string(15) "Times New Roman"
    [1]=>
    string(7) "Georgia"
    [2]=>
    string(5) "Serif"
  }
  ["font-size"]=>
  string(4) "15px"
}

So you can see that by following "strict mode mentality" that you can re-use your FELT code as CSS and PHP... oh yes, perhaps you are using Javascript or Node.js instead...

$ felt -as jscoder temp.felt -o temp.js

and the contents of that file will be like this...

function body()
    {return
      { 'background-color' : 'black',
        'background-image' : url("../images/foobar.png"),
        'color' : '#fff',
        'font-family' : ["Times New Roman", "Georgia", "Serif"],
        'font-size' : '15px'
      };
    }

function url(x) {return x;}

And hammering it through "node" on my development machine yields this...

$ node
> .load ./temp.js
> function body()
... {return {'background-color' : 'black', 'background-image' : url("../images/foobar.png"), 'color' : '#fff', 'font-family' : ["Times New Roman", "Georgia", "Serif"], 'font-size' : '15px'};}
undefined
> function url(x)
... {return x;}
undefined
> body();
{ 'background-color': 'black',
  'background-image': '../images/foobar.png',
  color: '#fff',
  'font-family': 
   [ 'Times New Roman',
     'Georgia',
     'Serif' ],
  'font-size': '15px' }
> 

Sweet. So once again, by following the "strict rules" we have been able to produce not only CSS from our single source file but also working PHP code and working Javascript code that happens to run under Node.js. Not bad and that's not even close to what you can do with FELT if you stick with it.

CSS Traditional Mode

So what if I only ever want to generate CSS using FELT... what can I actually get away with when I only ever specify the -as csscoder option? In a nutshell, murder!

If you want to relax and enter CSS as you would normally do in a plain old ".css" file then go ahead, do it and FELT ought to be fine with that. If it's not, let me know immediately and I will instruct it in the error of its ways, and more likely it's implementation code!

So why not use a ".css" file then? That's your decision readers, not mine. If you really want to use CSS as you normally do because you can't see why FELT is worth the effort then by all means go ahead and do what ever works for you and is most time efficient. Relearning FELT syntax just to re-enter something you already know would be mad especially if, as is common, you have a PHB floating around and deadlines are tight!

From this point on all of the examples will use the "relaxed mode" if you like, so you can see that it is as easy as "normal CSS" coding. Remember though that only the CSS back-end will be able to translate it from now on, that's the only guarantee. Using any other code may or may not work, YMMV!

CSS Rule / Selector Names

In all of the preceding example code we didn't really draw any real attention to anything to do with exactly how the CSS generation of selector names etc. takes place. We'll remedy that now and remember that all examples are "natural CSS" mode from now on, killing two bords with one stone as it were.

Within the realms of FELT, pretty much anything that's printable can be used as a variable name and the selected back-end will do its best to turn that into something valid, complaining loudly and stopping if it can't.

The CSS coder interprets some of these characters printable in a 'special way' so that well-formed CSS rules can be generated that are complex enough for most situtations. The following table shows what characters are processed during translation and after that, an explanation of how to exploit this information...

Special Characters

The following characters pass through unchanged:

Source Character CSS Usage
HASH # target unique element
PLUS + sibling rules
BANG ! !important rules
DOT . target element with class
GT > descender rules


The following characters are translated:

Source Character Translated to
UNDERSCORE _ SPACE

Space is an Underscore

The FELT lexer assumes that a SPACE or TAB marks the end of one token in the input and thus you cannot ever create a function name that contains spaces. Why you'd want to is anybodies guess. So if you cannot have spaces in variable or function names, as that upsets the way in which FELT parses the source code, how do you create a CSS rule that looks like this...

div#main ul li > a.external

That's a bit of a mouthful but not uncommon in CSS especially these days with people hell bent on doing everything with CSS. I still like and use TABLE tags. Call me old fashioned but they just work. Enough of that already, let's go abck to the rule name we want, here it is...

(defun div#main_ul_li_>_a.external () {})

Thus etching rule#1 firmly in your head: Use an underscore where you would normally space separate parts of the CSS selector rule. This will get you going and enable most of the rules you will ever need.

Conclusion

We have now seen that FELT happily generates CSS output from its source code, and you can use strict FELT syntax to be able to re-use those definitions or you can use a more relaxed mode if you know that you are only ever going to use it for CSS. In that case, I would say "use CSS" if you are more comfortable.

If you want some examples of writing CSS with FELT then go to the REPL page and select the CSS examples. These include the two CSS files that style the site.