sigildocs

CSS

S-expression CSS with nesting, themes, and media queries.
(import (sigil css))

Basic Rules

The css macro creates CSS rules. Properties are written as (property-name value) where the property name is captured literally (not evaluated).

(css->string
  (css ".button"
    (background "#007bff")
    (color "white")
    (padding "0.5rem 1rem")
    (border-radius "4px")))

Output:

.button {
  background: #007bff;
  color: white;
  padding: 0.5rem 1rem;
  border-radius: 4px;
}

Nested Selectors

Use & to create nested rules, similar to Sass/SCSS. The suffix is appended directly to the parent selector.

(css->string
  (css ".card"
    (padding "1rem")
    (border "1px solid #ddd")
    (& ":hover"
      (box-shadow "0 2px 8px rgba(0,0,0,0.15)"))
    (& " .title"
      (font-weight "bold")
      (font-size "1.25rem"))))

Output:

.card {
  padding: 1rem;
  border: 1px solid #ddd;
}

.card:hover {
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

.card .title {
  font-weight: bold;
  font-size: 1.25rem;
}

Nested css forms create child selectors (space-separated):

(css ".nav"
  (display "flex")
  (css ".item"
    (padding "0.5rem")))

css->string

Render any number of CSS fragments (rules, variables, media queries, keyframes) into a single CSS string.

(css->string
  (css-vars (--primary "#007bff"))
  (css ".btn" (background "var(--primary)"))
  (css ".btn-lg" (padding "1rem 2rem")))

CSS Variables

Define CSS custom properties with css-vars. Creates a :root block.

(css->string
  (css-vars
    (--bg "#0a0a0a")
    (--fg "#e0e0e0")
    (--accent "#f0c040"))
  (css "body"
    (background "var(--bg)")
    (color "var(--fg)")))

Media Queries

Wrap rules in a @media block with css-media.

(css->string
  (css ".sidebar" (width "250px"))
  (css-media "(max-width: 768px)"
    (css ".sidebar" (display "none"))
    (css ".content" (width "100%"))))

Keyframes

Define CSS animations with css-keyframes. Step names are symbols (from, to, or percentage symbols).

(css->string
  (css-keyframes "fade-in"
    (from (opacity "0"))
    (to (opacity "1")))
  (css ".fade" (animation "fade-in 0.3s ease-in")))

Themes

Create reusable theme definitions and convert them to CSS custom properties.

(define dark-theme
  (make-theme
    '(bg "#0a0a0a")
    '(fg "#e0e0e0")
    '(accent "#f0c040")))

;; Look up a theme value
(theme-ref dark-theme 'bg)    ; => "#0a0a0a"

;; Reference as CSS variable
(theme-var 'bg)               ; => "var(--bg)"

;; Convert to :root CSS variables
(css->string
  (theme->css-vars dark-theme)
  (css "body"
    (background (theme-var 'bg))
    (color (theme-var 'fg))))

Unit and Color Helpers

Helpers for common CSS units and color functions.

HelperExampleResult
px(px 16)"16px"
em(em 1.5)"1.5em"
rem(rem 2)"2rem"
%(% 50)"50%"
rgb(rgb 255 128 0)"rgb(255, 128, 0)"
rgba(rgba 0 0 0 0.5)"rgba(0, 0, 0, 0.5)"
hsl(hsl 200 50 60)"hsl(200, 50%, 60%)"
important(important "red")"red !important"
(css->string
  (css ".box"
    (width (% 100))
    (padding (rem 1))
    (font-size (px 14))
    (color (important "red"))))

Additional Utilities

css-import

Add @import rules for external stylesheets or fonts.

(css->string
  (css-import "https://fonts.googleapis.com/css2?family=Inter")
  (css "body" (font-family "Inter, sans-serif")))

css-raw

Insert raw CSS strings for edge cases not covered by the DSL.

(css->string
  (css-raw "/* Browser-specific hack */")
  (css ".main" (display "grid")))

css-combine

Group CSS fragments into a list for modular organization.

(define button-styles
  (css-combine
    (css ".btn" (padding "0.5rem 1rem") (border "none"))
    (css ".btn-primary" (background "blue") (color "white"))
    (css ".btn-danger" (background "red") (color "white"))))

(css->string button-styles)

Common Patterns

Component Styles

(import (sigil css))

(define card-styles
  (css-combine
    (css ".card"
      (border "1px solid #e0e0e0")
      (border-radius "8px")
      (padding "1.5rem")
      (& ":hover"
        (box-shadow "0 4px 12px rgba(0,0,0,0.1)"))
      (& " .card-title"
        (font-size "1.25rem")
        (margin-bottom "0.5rem"))
      (& " .card-body"
        (color "#666")))))

Responsive Design

(css->string
  (css ".grid"
    (display "grid")
    (grid-template-columns "repeat(3, 1fr)")
    (gap (rem 1)))
  (css-media "(max-width: 768px)"
    (css ".grid"
      (grid-template-columns "1fr"))))

Themed Application

(import (sigil css)
        (sigil sxml))

(define theme
  (make-theme
    '(bg "#ffffff")
    '(fg "#1a1a1a")
    '(primary "#007bff")))

(define app-css
  (css->string
    (theme->css-vars theme)
    (css "body"
      (background (theme-var 'bg))
      (color (theme-var 'fg)))
    (css ".btn-primary"
      (background (theme-var 'primary))
      (color "white"))))

(sxml->html `(style (*raw* ,app-css)))