2
Fork 0
An s-expression Domain-Specific Language that compiles nested CSS selectors and declarations into plain CSS text.
  • Common Lisp 97.6%
  • Just 2.4%
Find a file
Marcus Kammer 94e1662fb6
refactor: rename system to dev.metalisp.libcss and package to ml-libcss
Rename the ASDF system dev.metalisp.css to dev.metalisp.libcss and the package ml-css to ml-libcss, including the test system, suite keyword, documentation, and justfile.
2026-11-05 14:40:21 +01:00
doc refactor: rename system to dev.metalisp.libcss and package to ml-libcss 2026-11-05 14:40:21 +01:00
src refactor: rename system to dev.metalisp.libcss and package to ml-libcss 2026-11-05 14:40:21 +01:00
tests refactor: rename system to dev.metalisp.libcss and package to ml-libcss 2026-11-05 14:40:21 +01:00
.gitignore feat: initial s-expression CSS DSL 2026-11-05 08:54:51 +01:00
dev.metalisp.libcss.asd refactor: rename system to dev.metalisp.libcss and package to ml-libcss 2026-11-05 14:40:21 +01:00
justfile refactor: rename system to dev.metalisp.libcss and package to ml-libcss 2026-11-05 14:40:21 +01:00
LICENSE feat: initial s-expression CSS DSL 2026-11-05 08:54:51 +01:00
README.md refactor: rename system to dev.metalisp.libcss and package to ml-libcss 2026-11-05 14:40:21 +01:00

dev.metalisp.libcss

An s-expression Domain-Specific Language that compiles nested CSS selectors and declarations into plain CSS text.

Requirements

Fedora Linux and SBCL are the expected baseline. The system depends only on Common Lisp; tests require fiveam, available through Quicklisp.

Quickstart

Load the system with Quicklisp/ASDF:

sbcl --non-interactive --eval '(ql:quickload :dev.metalisp.libcss)' --eval '(uiop:quit 0)'

Run the test suite:

sbcl --non-interactive --eval '(ql:quickload :dev.metalisp.libcss/tests)' \
     --eval '(asdf:test-system :dev.metalisp.libcss)' --eval '(uiop:quit 0)'

Example

(ql:quickload :dev.metalisp.libcss)

(ml-libcss:css
  (:nav
   :background "#333"
   (:ul
    :list-style :none
    (:li
     :display :inline)))
  (:button
   :padding "8px 16px"
   ("&:hover"
    :background "#005")))

renders:

nav {
  background: #333;
}
nav ul {
  list-style: none;
}
nav ul li {
  display: inline;
}
button {
  padding: 8px 16px;
}
button:hover {
  background: #005;
}

Public API

  • css — macro that compiles its s-expression body to a CSS string, validating at macroexpansion time.
  • render-stylesheet — function that compiles a stylesheet list to a CSS string.
  • with-css-file — macro that compiles its body atomically to a file.
  • with-css-variables — macro that lexically binds CSS variables, referenced with (:var name).
  • define-css-mixin — macro that defines a named mixin, included with (:mixin name).
  • css-syntax-error — condition signaled on malformed stylesheets or unbound variables/mixins.
  • *minify-css* — special variable; bind to a non-NIL value to emit minified single-line CSS.

Minified output:

(let ((ml-libcss:*minify-css* t))
  (ml-libcss:css (:nav :background "#333" (:ul :list-style :none))))
;; => "nav{background:#333;}nav ul{list-style:none;}"

Writing to a file:

(ml-libcss:with-css-file (stream #p"style.css" :minify t)
  (:body :margin 0 :color "#333")
  (:h1 :color "red"))

Variables and mixins:

(ml-libcss:define-css-mixin :box
  :margin 0
  :padding 0)

(ml-libcss:with-css-variables ((:brand "#d33"))
  (ml-libcss:css
    (:div
     (:mixin :box)
     :color (:var :brand))))

At-rules:

(ml-libcss:css
  (:media "screen and (max-width: 600px)"
    (:body :margin "8px")))
;; => "@media screen and (max-width: 600px) {\n  body {\n    margin: 8px;\n  }\n}\n"

Full grammar and combinators: see doc/dev.metalisp.libcss.org.