Go to file
Shinmera 98493030b8 Fix for lists in subblocks leading to an error 2014-11-11 10:33:36 +01:00
LICENSE MAKE IT SO 2014-09-03 14:43:10 +02:00
README.md Fixed exports 2014-09-08 19:18:51 +02:00
about.html Fixed exports 2014-09-08 19:18:51 +02:00
binary-lass.asd Copyright header update to Shirakumo 2014-10-09 21:44:52 +02:00
binary.lisp Copyright header update to Shirakumo 2014-10-09 21:44:52 +02:00
compiler.lisp Documentation for property function stuff. 2014-10-29 11:25:54 +01:00
generate-binary.sh Added binary generation tools. 2014-09-05 13:15:58 +02:00
lass.asd Basic support for special reading behaviour on a property-basis. Added property functions and some basic default cases. 2014-10-29 11:05:08 +01:00
lass.el Added emacs LASS.EL support file. 2014-09-05 19:19:16 +02:00
lass.lisp Copyright header update to Shirakumo 2014-10-09 21:44:52 +02:00
package.lisp Fix for define-property-function-case, added define-simple-property-functions 2014-10-29 16:46:41 +01:00
property-funcs.lisp Fix for lists in subblocks leading to an error 2014-11-11 10:33:36 +01:00
readable-list.lisp Basic support for special reading behaviour on a property-basis. Added property functions and some basic default cases. 2014-10-29 11:05:08 +01:00
special.lisp Fixed HSV->HSL name 2014-10-29 19:03:06 +01:00
writer.lisp Copyright header update to Shirakumo 2014-10-09 21:44:52 +02:00

README.md

About LASS

Writing CSS files comes with a lot of repetition and is generally much too verbose. With lispy syntax, shortcuts, and improvements, LASS aims to help you out in writing CSS quick and easy. LASS was largely inspired by SASS.

How To

LASS supports two modes, one being directly in your lisp code, the other in pure LASS files. Adding LASS into your code is easy:

(lass:compile-and-write
 '(div
   :background black))

"div{
    background: black;
}"

LASS works on the following simple principles: A list is a block. The first argument in the list is a selector. The body of the list makes up the properties and sub-blocks. A property is started with a keyword that is used as the property name. Following is a bunch of property arguments until a new keyword, list, or the end is reached. A list inside a block is, again, a block with the twist that the parent block's selector is prepended to the sub-block's selector.

(lass:compile-and-write
 '(nav
   (ul
    :list-style none
    (li
     :margin 0 :padding 0
     :display inline-block)))))

"nav ul{
    list-style: none;
}

nav ul li{
    margin: 0;
    padding: 0;
    display: inline-block;
}"

Since LASS' COMPILE-SHEET simply takes a bunch of lists as its argument, you can use the backquote and comma to integrate variables from your lisp environment:

(let ((color "#0088EE"))
  (lass:compile-and-write
   `(div
     :background ,color))))

"div{
    background: #0088EE;
}"

Alternatively however, and this is especially useful in pure LASS files, you can use the LET block to create LASS-specific bindings:

(lass:compile-and-write
 '(:let ((color "#0088EE"))
   (div
    :background #(color))))

"div{
    background: #0088EE;
}"

LASS' selector mechanism is very flexible and allows for some complex logic to reduce duplication:

(lass:compile-and-write
 '(article
   ((:or p blockquote)
    :margin 0 :padding 0

    (a
     :color black)
      
    ((:and a :hover)
     :color darkred))))

"article p, article blockquote{
    margin: 0;
    padding: 0;
}

article p a, article blockquote a{
    color: black;
}

article p a:hover, article blockquote a:hover{
    color: darkred;
}"

But it can go even further:

(lass:compile-and-write
 '((:and
    (:or article section)
    (:= data-author (:or yukari ran chen))
    (:nth-child (:or 1 2 3)))
   :display none))

"article[data-author=\"yukari\"]:nth-child(1),
 article[data-author=\"yukari\"]:nth-child(2),
 article[data-author=\"yukari\"]:nth-child(3),
 article[data-author=\"ran\"]:nth-child(1),
 article[data-author=\"ran\"]:nth-child(2),
 article[data-author=\"ran\"]:nth-child(3),
 article[data-author=\"chen\"]:nth-child(1),
 article[data-author=\"chen\"]:nth-child(2),
 article[data-author=\"chen\"]:nth-child(3),
 section[data-author=\"yukari\"]:nth-child(1),
 section[data-author=\"yukari\"]:nth-child(2),
 section[data-author=\"yukari\"]:nth-child(3),
 section[data-author=\"ran\"]:nth-child(1),
 section[data-author=\"ran\"]:nth-child(2),
 section[data-author=\"ran\"]:nth-child(3),
 section[data-author=\"chen\"]:nth-child(1),
 section[data-author=\"chen\"]:nth-child(2),
 section[data-author=\"chen\"]:nth-child(3){
    display: none;
}"

Whoa nelly!

Some CSS properties are not fully specified yet and require browser-specific prefixes. LASS can help you with that, too:

(lass:compile-and-write
 '(.fun
   :linear-gradient "deg(45)" black 0% darkgray 100%
   :transform rotate -45deg))

".fun{
    background: -moz-linear-gradient(deg(45), black 0%, darkgray 100%);
    background: -o-linear-gradient(deg(45), black 0%, darkgray 100%);
    background: -webkit-linear-gradient(deg(45), black 0%, darkgray 100%);
    background: -ms-linear-gradient(deg(45), black 0%, darkgray 100%);
    background: linear-gradient(deg(45), black 0%, darkgray 100%);
    -moz-transform: rotate(-45deg);
    -o-transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    transform: rotate(-45deg);
}"

LASS also supports the various @QUERY operator blocks:

(lass:compile-and-write
 '(:media "(max-width: 800px)"
   (div
    :margin 0)))

"@media (max-width: 800px){
    div{
        margin: 0;
    }
}"

By default LASS activates pretty-printing and inserts newlines and spaces where appropriate in order to make the result readable and easy to debug. However, you can also deactivate that and directly produce minified CSS:

(let ((lass:*pretty* NIL))
  (lass:compile-and-write
   '(:media "(max-width: 800px)"
     (div
      :margin 0))))

"@media (max-width: 800px){div{margin:0;}}"

As mentioned above you can write pure LASS files to compile down to a CSS file. To do that, simply use GENERATE:

generate-example

Extending LASS

Pretty much every part of LASS is extensible through methods. Most useful will however probably be the DEFINE-SPECIAL-PROPERTY, DEFINE-BROWSER-PROPERTY and DEFINE-SPECIAL-SELECTOR helper-macros. Here's some examples from the SPECIAL.LISP file that defines some standard special handlers:

(define-special-property font-family (&rest faces)
  (list (make-property "font-family" (format NIL "~{~a~^, ~}" (mapcar #'resolve faces)))))

(define-browser-property linear-gradient (direction &rest colors)
  (:default (property)
    (make-property "background" (format NIL "~a(~a~{, ~a ~a~})"
                                         property (resolve direction) (mapcar #'resolve colors)))))

For more control, have a look at the various COMPILE-* generic functions.

Emacs Support

LASS includes a tiny elisp file, lass.el. Add LASS' directory to your emacs LOAD-PATH and REQUIRE lass.

(add-to-list 'load-path "[path-to-lass-source-dir]/")
(require 'lass)

Once you visit a .lass file, it will automatically start in the LASS major-mode, which is a derived-mode from COMMON-LISP-MODE. Whenever you save, it will automatically try to compile the lass file to its CSS equivalent. If slime is connected, it will try to quickload LASS and evaluate GENERATE. If slime is not connected, it instead executes a shell command. In order for that to work, the lass binary must be in your path.

If your operating system is not directly supported with a binary, you can build it yourself using a build tool like Buildapp, the ASDF system BINARY-LASS and the entry-point BINARY-LASS:CMD-WRAPPER.