lisp to css
css preprocessors⌗
Plain old CSS is easy to write, but hard to maintain. This is because CSS syntax lacks macros, transformation of variables, and is very very verbose.
CSS Preprocessors are a very good solution to this problem, they allow for generated CSS via loops and mixins. This is why most CSS frameworks are written in SASS, or LESS rather than pure CSS, simply because of ease of use.
Lisp also has a very powerful CSS Preprocessor that could integrate easily with your backend. The advantage of using a Lisp-based CSS preprocessor is that you don’t have to maintain another syntax, more functions are accessible to you, and lastly it is rather elegant compared to SASS or SCSS imo.
lass⌗
Meet LASS, a library made to transform lisp lists into CSS. Using is rather straightforward, you invoke the function lass:compile-and-write
provided by a list and it outputs css.
(defvar color "cyan")
(lass:compile-and-write
'(:media "only screen and (max-width: 700px)"
(main :background-color "red"))
'(* :font-family "monospace")
`(main ; comment
((:or h1 h2 h3 h4 h5 h6) :font-weight bold)
((:and a (:or :visited :link)) :color ,color)))
@media only screen and (max-width: 700px){
main{
background-color: red;
}
}
* {
font-family: monospace;
}
main h1,
main h2,
main h3,
main h4,
main h5,
main h6{
font-weight: bold;
}
main a:visited,
main a:link{
color: cyan;
}
So, in general, tag names are just tag names without any transformation. Properties start with a semicolon like so :color blue
. Property values do not necessararily need to be wrapped in quotes, but could be.
at-rules, like @media
, instead start with a semicolon, like so :media
and followed by one string parameter and a list of rules.
Key-word functions replace operators like &
and ,
so instead of writing .class1, .class2
, you write (:or class1 class2)
.
tips and tricks⌗
Since LASS only operates on lists, you can modify these lists in practical ways, like using a global variable from your application in your stylesheets. Or, ygenerate CSS tailwind-css style, like so:
(defvar lst nil)
(setf lst nil)
(loop for i from 1 to 10 do
(let ((var (read-from-string (format nil ".ok-~a" i))) (clr "blue"))
(setf lst
(append lst (list (list var :color clr))))))
(apply #'lass:compile-and-write lst)
While, this is particularly useless, you could adapt this to your needs. A good use of this would be to create a mathematical column system:
(defvar lst nil)
(setf lst nil)
(defvar max 12)
(defvar min 1)
(loop for i from min to max do
(setf lst
(append lst
(list
(list
(format nil ".col-~a~a/~a" i #\U+005C max)
:width (format nil "calc(100% / ~a)" i))))))
(format t "~a" (apply #'lass:compile-and-write lst))
.col-1\/12{
width: calc(100% / 1);
}
.col-2\/12{
width: calc(100% / 2);
}
.col-3\/12{
width: calc(100% / 3);
}
.col-4\/12{
width: calc(100% / 4);
}
.col-5\/12{
width: calc(100% / 5);
}
.col-6\/12{
width: calc(100% / 6);
}
.col-7\/12{
width: calc(100% / 7);
}
.col-8\/12{
width: calc(100% / 8);
}
.col-9\/12{
width: calc(100% / 9);
}
.col-10\/12{
width: calc(100% / 10);
}
.col-11\/12{
width: calc(100% / 11);
}
.col-12\/12{
width: calc(100% / 12);
}
conculsion⌗
In essence, the possiblities are endless with LASS. It is immensely powerful, and while it might take time to adapt to its quite eccentric syntax, it is worth it.