SunDawning avatar

On CL-CSS

sundawning

Published: 05 May 2018 › Updated: 05 May 2018On CL-CSS

On CL-CSS

记录使用Common Lisp包CL-CSS[1]生成CSS的实践过程。

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

[创建时间]:<2018-05-05 Sat 17:45:59 UTC+08:00>

[更新时间]:<2018-05-05 Sat 19:06:32 UTC+08:00>

编写CSS规则的范式

CL-CSS支持多种方式来拼接将要生成CSS的列表,一条CSS规则里能自由地使用符号、字符串、关键字,但为了让代码看起来具有统一的格式,人为地规范一条CSS规则各部分的类型。

规范如下:

  • 选择器设置为字符串类型
  • 选择器与属性之间换行
  • 一行一条属性和值
  • 值为字符串类型
  • 使用反引号"`"而不是引号"'"

形如:

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

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

以下情况CL-CSS都允许使用,但不在规范内:

(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; }
"

从上述情况里也可以看出使用该规范的原因:

  • 选择器不只有单一的符号,还有各种各样的类选择器、ID选择器、多个选择器等等,这些选择器只能使用字符串。
  • 值不只有单一的值,还有由空格拼接起来的多个值,多个值只能使用字符串。
  • 反引号允许直接内嵌变量,便于引用常用颜色、常用规则。

CL-CSS生成CSS的规则

"css"操作符只接受一个"rules"∈{列表}的自变量,自变量里的每个元素∈{列表}代表一条CSS规则。

一条标准的CSS规则:

  • 由选择器、属性、值三部分组成,属性和值成对存在,数量不限,一条CSS规则里只允许存在一个选择器。
  • 由选择器、嵌套的规则两部分组成,嵌套的规则本身就是一条标准的CSS规则

一条CSS规则实际生成CSS的时候,CSS选择器放在大括号的外面,其余的都放在大括号里面,CSS规则里的列表表示嵌套的CSS规则。

在层层嵌套的CSS规则中:

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

将生成标准的嵌套的CSS:


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

处理以@开头的CSS规则

media@media"实际上也是一种选择器,按照规范里的选择器的类型,将这些以@开头的CSS规则照规范的模式书写即可:

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

产生:


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

处理keyframes@keyframes规则

标准的keyframes@keyframes规则[2]:

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

根据 处理以@开头的CSS规则
里的示例,"keyframes@keyframes"、"from"和"to"实际都可以看作是选择器,只是"from"将作为一个嵌套的规则:

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

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

诸如"0%"、"100%"等进度,实际也是选择器。对于标准的CSS规则:

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

可以如此创建CSS规则:

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

生成:


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

模块化拼接多条CSS规则

  1. 创建css.lisp文件

  2. 创建全局变量来代表某条CSS规则

    (defparameter *key*
      `((".keys"
         :display "flex")))
    
    (defparameter *do-not-use-right-key*
      `((".keys"
         :user-select "none")))
    
  3. 拼接多条CSS规则

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

生成标准的CSS文件

模块化拼接多条CSS规则 基础上,将CSS字符串保存为文件:

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

CL-CSS存在"compile-css"操作符,将CSS规则一步位的输出到文件:

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

两种方法,各有所长,殊途同归。

Footnotes

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

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

Leave On CL-CSS to:

Written by

Read more #common-lisp posts


Best Posts From SunDawning

We have not curated any of sundawning's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From SunDawning