This library implements a domain-specific language for cascading
style sheets as used in web pages. It allows you to specify your
style sheets in regular Haskell syntax and gives you all the
additional power of server-side document generation.

Tutorial

Style sheets are values of type CSS. This type denotes style sheets,
including for different media and is itself a monoid, so that you can
build your style sheets either in a chunk-by-chunk fashion or using a
writer monad. The latter is the recommended way, because it gives you
access to a large library of predefined properties with additional type
safety. It is recommended to enable the OverloadedStrings extension
for this library and is assumed for the rest of this tutorial.

Style properties are usually specified by using the predefined property
writers:

display InlineDisplay
direction LeftToRight
float LeftFloat

If a property is not pre-defined you can set it by using setProp or
its infix variant $=.

Lengths

For convenience lengths can and should be specified by using predefined
prisms like _Cm (see HasLength):

lineHeight $ Just (_Cm # 1)

This will render as line-height: 10mm. All compatible lengths are
saved and rendered in a canonical unit. For example centimeters,
millimeters, inches, picas and points are all rendered as their
correspondingly scaled millimeter lengths, i.e. _In # 1 will render
as 25.4mm.

For convenience there are also two ways to specify percental lengths.
The lengths _Percent # 150 and _Factor # 1.5 are equivalent
and both render as 150%.

There are also two special lengths, zeroLen and autoLen, which
render as 0 and auto respectively.

Colors

Colors are specified by using the Colour and AlphaColour types from
the colour library. They are rendered as either #rgb, #rrggbb or
rgba(r,g,b,a) depending on what color you specify and whether it is
fully opaque. The following renders as border-left-color: #0f0:

import Data.Colour.Names
borderColor (LeftEdge lime)

The colour library gives you both correct color space handling, sensible
operators for mixing colors and a large library of predefined colors in
the Data.Colour.Names module. To mix two colors you can use blend
for mixing or over for alpha blending:

blend 0.5 lime red
(lime `withOpacity` 0.5) `over` black

Colors are all rendered in the (non-linear) sRGB color space, as this is
the assumed color space by most user agents and screens.

Edge-oriented properties

Many CSS properties are edge-oriented, for example margin, padding
and borderColor. This library provides a unified interface to these
properties through the Edge type. Examples:

Imports

To import an external stylesheet you can use importFrom or
importUrl. The former allows you to specify raw URLs:

importFrom "screen" "/style/screen.css"

In web frameworks like Happstack you would usually work on top of a
MonadRoute-based monad (like RouteT) as defined in the web-routes
library. In this case the importUrl function allows you to use your
type-safe URLs conveniently:

importUrl "all" (Style "screen")

To import a stylesheet for multiple media types, just use the import
functions multiple times for the same URL:

mapM_ (`importFrom` "/style/screen.css") ["screen", "print"]

This will render as:

@import url("/style/screen.css") print, screen;

Miscellaneous

Important properties

To set the !important tag on a property you can use the important
function:

important (display InlineDisplay)

This renders as:

display: inline !important;

Inheriting

To inherit a property value use inherit. You have to spell out the
property name in this case:

inherit "display"

This renders as:

display: inherit;

Optimizations

The underlying representation is a straightforward list of selectors and
properties. There may be closer or more efficient representations, but
all of them need to make some compromises along the way. Consider the
following stylesheet:

p {
border-color: #0f0;
border-color: rgba(0, 255, 0, 1);
}

You can optimize this to a single property, but which one? It depends
on whether the user agent supports CSS level 3, so we would need to make
assumptions. We also can't use a map of properties to a list of values.
Consider the following stylesheet:

p {
border-bottom-color: #0f0;
border-color: #f00;
}

The order of the properties does matter here, so we need to preserve it.
This rules out a map from properties to lists of values. The final
question is: Can we use a map from selectors to property lists? As it
turns out no, because CSS specificity does not always apply:

a:link { /* ... */ }
a:blah { /* ... */ }

These two selectors have the same specificity. CSS allows unsupported
pseudo-classes and user agents must ignore them, so in edge cases the
order can matter.

Other than media types CSS does not seem to exhibit any commutativity,
so we use regular lists. Also since most authors use mostly
hand-written stylesheets with little property overlap the list
representation is usually faster anyway, so this choice seems to be
sensible.

The only optimization performed by this library is the minified output
it produces. Pretty-printing is currently not supported.