On CL-CSS(en)

in common-lisp •  7 years ago  (edited)

Document the practical process of generating CSS using the Common Lisp package CL-CSS [1].

Original: https://github.com/SunDawning/literate-programming/blob/master/on-cl-css.org

[Created]:<2018-05-05 Sat 17:45:59 UTC+08:00>

[Update]:<2018-05-05 Sat 19:06:32 UTC+08:00>

Write a CSS rule pattern

CL-CSS supports multiple ways to splice the list of CSS to be generated. A CSS rule can freely use symbols, strings, and keywords, but in order to make the code appear to have a uniform format, artificially regulate a part of a CSS rule type.

The specification is as follows:

  • Selector is set to string type
  • Wrap between selectors and attributes
  • one line per attribute and value
  • The value is a string type
  • Use backquotes "`" instead of quotes "'"

Shaped like:

(css
 `(("body"
    :margin "5px"
    :padding "0px")))

"body { margin: 5px; padding: 0px; }
"

The following situations are allowed for CL-CSS but not within the specification:

(let ((color "black"))
  (css
   `((body
      :margin 5px)
     ("#root"
      :margin 5px)
     (footer
      :border ,(format nil "1px solid ~A" color)))))
"body { margin: 5px; }
#root { margin: 5px; }
footer { border: 1px solid black; }
"

The reasons for using this specification can also be seen in the above situation:

  • The selector is not only a single symbol, there are a variety of class selectors, ID selectors, multiple selectors, etc. These selectors can only use strings.
  • The value is not only a single value, there are multiple values ​​concatenated by spaces, multiple values ​​can only use strings.
  • Backquotes allow direct embedding of variables, making it easy to refer to common colors and common rules.

CL-CSS rules for generating CSS

The "css" operator only accepts one argument of "rules" ({list}), and each element in the argument ({list}} represents a CSS rule.

A standard CSS rule:

  • consists of three parts: selector, attribute, and value. Attributes and values ​​exist in pairs. The number is unlimited, and only one selector is allowed in a CSS rule.
  • consists of a selector, a nested rule, and the nested rule itself is a standard CSS rule

When a CSS rule actually generates CSS, the CSS selector is placed outside the curly braces, and the rest are placed inside braces. The list in the CSS rule represents nested CSS rules.

In nested CSS rules:

(css
 `(("body"
    :margin "5px")
   ("@print"
    ("@media (max-width:640px)"
     ("body"
      :margin "3px"))
    ("@media (max-width:360px)"
     ("body"
      :margin "0")))))

Standard nested CSS will be generated:

"body { margin: 5px; }
@print { @media (max-width:640px) { body { margin: 3px; } } @media (max-width:360px) { body { margin: 0; } } }
"

Handle CSS rules starting with @

"@media" is actually a kind of selector. According to the type of selector in the specification, these CSS rules starting with @ can be written according to the specification pattern:

(css
 `(("@media (max-width:640px)"
    ("body"
     :margin "5px"))
   ("@media (max-width:360px)"
    ("body"
     :margin "0"))))

produce:

"@media (max-width:640px) { body { margin: 5px; } }
@media (max-width:360px) { body { margin: 0; } }
"

Handle the @keyframes rule

The standard @keyframes rule [2]:

@keyframes mymove
{
    from {top:0px;}
    to {top:200px;}
}

According to Handle CSS rules starting with @
In the example, "@keyframes", "from" and "to" can actually be considered as selectors, but "from" will be used as a nested rule:

(css
 `(("@keyframes mymove"
    ("from"
     :top "0px")
    ("to"
     :top "200px"))))

"@keyframes mymove {from {top: 0px; } to { top: 200px; } }
""

Progress such as "0%" and "100%" is actually a selector. For standard CSS rules:

@keyframes mymove
{
0% {top:0px;}
25% {top:200px;}
50% {top:100px;}
75% {top:200px;}
100% {top:0px;}
}

You can create CSS rules like this:

(css
 `(("@keyframes mymove"
    ("0%"
     :top "0px")
    ("25%"
     :top "200px")
    ("50%"
     :top "100px")
    ("75%"
     :top "200px")
    ("100%"
     :top "0px"))))

generate:

"@keyframes mymove { 0% { top: 0px; } 25% { top: 200px; } 50% { top: 100px; } 75% { top: 200px; } 100% { top: 0px; } }
"

Mosaic multiple CSS rules

  1. Create css.lisp file

  2. Create a global variable to represent a CSS rule

    (defparameter *key*
      `((".keys"
         :display "flex")))
    
    (defparameter *do-not-use-right-key*
      `((".keys"
         :user-select "none")))
    
  3. Stitch multiple CSS rules

    (defparameter *css*
      (css
       `(,@*do-not-use-right-key*
         ,@*key*)))
    

Generate a standard CSS file

On the basis of the Mosaic multiple CSS rules, save the CSS string as a file:

(with-open-file (out "/tmp/css.css"
                     :direction :output
                     :if-exists :supersede)
  (princ *css* out))

CL-CSS has a "compile-css" operator to output CSS rules to a file in one step:

(compile-css "/tmp/css.css"
             '((body :margin 5px :padding 0px)))

The two methods have their own strengths and the same goal.

Footnotes

[1]: cl-css | Quickdocs: http://quickdocs.org/cl-css/

[2]: CSS3 @keyframes rules:
http://www.w3school.com.cn/cssref/pr_keyframes.asp

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!