Notes, sketches, and frameworks inspired by fall 2011 map styling workshop held in SF
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

CSS Inspired Map Styling

Notes, sketches, and frameworks inspired by October 2011 map styling workshop held in SF

Question: Core bits should be universal. Extras should be wrapped in a Carto 2.0 designator?



  1. CSS-like map design language. Syntax extends the foundation laid by Cascadenik and Carto (overview) and the power of Less.js. GeoServer is also joining the mix.
  2. Better support for reference-style maps by formalizing the use of @variables for color swatches, and mixins for graphic styles and text character styles.
  3. ¿Add support for thematic data cartography with data statistics like MIN, MAX, MEAN and use of those keywords in high-level filters that are under a dozen lines of code? Allow for both loose and hard connections between data and symbology. 1. GeoServer has 3 great simple functions for much of this now in SLD ---- 2. Direct link to reference docs

#Result should be:

  1. Reference documentation and examples that are compelling.
  2. Syntax should be easy to write for average designer, reusable, and shareable. - NVK stubbed out designer focused Tools directory 30 May.
  3. Syntax should be fast for the renderer draw. Text and shields are special cases we want to allow for. Mike put this as it's </div> friendly.
  4. Should have reasonable style defaults / implementation routines that make sense for the designer and for the renderer. Reasonable defaults make it quick to explore a dataset (not just present the final results). Example: draw points to see a distribution, classify points, lines and polygons by thematic attribute and color quickly. See: NVK's Thematic Carto Tools repo
  5. Core syntax is interoperable with other style languages between renderer implementations (Mapnik, GeoServer, etc) and between flavors implementation dialects for the same renderer. Extensions allow extra awesome things. - NVK on 31 May.
  6. Clearly identify ambiguities (and document recommended solutions).
  7. Standard adhers to Semantic Versioning. Watch background video (youtube). - MM and NVK add 18 May 2012.
  8. First principles based so it's easy to implement across software. - NVK add 19 May 2012.

NOTE: Extensions might include data formats (csv, shp in zip), data statistics (count, min, max), data locations (local/remote/offline), experimental styling keywords (feature class heigherachy ala, styles with absolute and relative values (gradients, choropleth/quantiles/nat'lbreaks/etc, lighter, darker, smaller text, larger text), and rendering (like for shields?), interactivity (one layer, multiple layers).

#Atomic bits (nouns, verbs):

  1. CSS target: marker, stroke, fill, text, shield, and ¿data? and ¿interactivity?.

     Note: reimagined a bit from basic HTML CSS and Cascadenik, Carto. 
     Marker is new in 1.0 (was `point`, for a while `anchor`).
     Text is more consistent in 1.0 and powerful in 2.0.
     Interactivity and data formalized 2/3/4? Separate but parellel formats?
  2. Size by: markers, strokes, and labels have a 2d extrusion measurement (eg: 2px)

     For images, the size is implied by a non-repeat dimension of the source image. 
     Others are determined by default style CSS. Continues from Cascadenik/Carto 1.0.
     Note: Lines can end either with or without semicolons at block ends, per CSS spec. Cascadenik (2.3.0)
  3. Ink with for color (mask) areas (extrusion of stroke, or fill): rgb, cmyk, hsv, gradient, image (with repeat options).

    Note: All color spaces/images/gradient are coallpsed in "ink" verb in Carto 2.0?

     1.0: `color:#rgb` and `color:#rrggbb` with `opacity:1.0`
     2.0: Other color spaces. See below.
     3.0: gradients as colors? see **gradients on strokes** section far below.
  4. Object geometry type filter: point, line, polygon, continuous-field aka raster.

     New in 2.0
  5. Object geometry component filter: The component polys, rings, & vertex.

     New in 4.0
  6. Rendering target: (pivots off geometry type) registration, edge, interior, LABEL, DATA, INTERACTIVITY.

     New in 4.0. With optional masks and positioning/attachment hints.

#Mappy CSS bits

  1. Core bits (Mappy CSS 1.0)

    1. Basic CSS syntax: stroke, fill, marker, raster - marker was point, also talked about anchor
    2. Filters for feature attributes. Exactly equal, not equal, less than, greater than, less than or equal to, greater than or equal to based on class or id selectors.
    3. Point geoms have an edge available for stroking.
    4. Basic CSS syntax: text labels - New "label once" text-name:[fieldname] where the [fieldname] grabs attributes per feature on render. This is extended either with :: layer attachements or keyword-attachments to gain multiple text labels, shield symbolizers, etc.
    5. Markers instead of points: or anchor? Marker is more widely supported in Gmaps world. Mapnik's point should be hidden in this generic spec. JL, NVK and NVK on 25 May and 29 May.
    6. For backwards compatability: points are are synonym for markers Point would have a depreciation, new implementations might optionally support. MM and NVK 29 May.
    7. Layers, classes, ids, and layer metadata - Layers are defined in the MML file and can include class="class1 class2 class3" or id="id1". Layers could have a name. Layers could have metadata.
    8. Zoom and scale denominator
    9. !important - ensure your setting takes precedence in the CSS parser over filters, appearance styling that would otherwise be more important in order-of-operations.
  2. Basic bits (Mappy CSS 2.0)

    1. Advanced CSS syntax for colors - RGBA, CYMK, HSV, etc other color spaces.
    2. @variables for color swatches, this is preprocessor to actual result. Moved 23 May 2012 per TMCW, split off graphic styles and text character styles 29 May
    3. geometry type selectors (point, line, polygon, raster) eg: geom_type_selector.classname { ... } or .classname geom_type_selector { ... } (which is less CSS like, but more like the sketches below) Advanced: only test the first feature's type in a data store, assumes homogenious data in a single data store. THIS IS THE ONLY SHOW STOPPER, might be relatively easy to implement in Cascadenik?
    4. Advanced CSS syntax: stroke background color and attached markers
    5. display:none - like !important, but for not showing stuff, regardless of other rules. Speeds up stylesheets by ignoring unused elements in renderer specific export.
    6. FontSets: very important for multilingual characters and UTF-8 labels, font fallbacks
    7. default.css for geometry type selectors results in layers auto display TRUE instead of FALSE. Override with display:none;
    8. Advanced CSS syntax: shields
    9. well-known-symbols marker images - where image could be png, gif, jpg, svg, etc?. Ideally vector so sizing can be applied and still looks good.
    10. Advanced Mappy CSS: raster colorizer
  3. Advanced bits (Mappy CSS 3.0)

    1. variable expresions modifying color swatches, stroke-widths, and @variables, etc.
    2. RegEx filters
    3. layer-based style attachments :: are a repeated version of the exact selection, but with a different appearance styling on a new virtual layer. Useful for applying multiple labels, shields, or graphic styles. OR should we move away to a procedure versus declarative? See also, "repeated properties" below.
    4. feature-based style instances / similar to nested styles, but within the same original layer.
    5. keyword-based style attachments .roads name { text-size:12px; text-color:#000; } and .roads ref { shield... } are a repeated version of the exact selection, but with a different appearance styling on a new virtual layer. Useful for applying multiple labels, shields, or graphic styles.
    6. nesting combinator filters
    7. repeated properties - Like anonymous layer-based style attachements (::), see above.
    8. nested styles - from Less.js and Carto.
    9. mixins for graphic styles, and text character styles. Split off per TMCW, NVK, and MM conversation on 29 May
  4. Extremely advanced bits (Mappy CSS 4.0)

    1. data variables/expansion aka string expressions for keys other than text-name.
    2. functional expressions evaluation of variable expressions with a predefined function.
    3. Selectors for object advanced geometry components: inner outer rings, vertex index and first, last.
    4. Dependant attachments && depend on the previous bits being rendered in that selection. Useful for text labels to require the anchor symbolization being placed. eg: point&&text.
    5. Shorthand style properties
    6. Special rendering targets w/r/t attachements (placement): interior, edge, registration, vertexes, parts there-of.
    7. Rendering/compositing targets are implied but can be explicate or overridden: fill-, stroke-, anchor-, and data-. Note: color:#hex is implied as fill-color:#hex.
    8. Blending modes ala Photoshop, Illustrator, new compositing branch of Mapnik, cutting edge CSS.
    9. gradients on strokes - The future come-ith.
    10. heterogenious geometry type selectors (point, line, polygon, raster) eg: geom_type_selector.classname { ... } or .classname _geom_type_selector { ... } (which is less CSS like, but more like the sketches below) Advanced: tests per feature for feature type, important for GeoJSON etc. THIS IS THE ONLY SHOW STOPPER.
    11. building symbolizer

#Reasonable Mappy CSS 2.0 defaults:

WARNING: if the defaults.mss file is included, the default for layer visibilty becomes ON instead of off.

  • Text -> geom_centroid -> Registration/Text:

      .class * { text-size:12px; text-color:#000000; text-face:Arial; text-placement: [point, line, centroid, etc?] }
  • Marker -> Point -> Registration:

      .class Point { stroke-width:2px; stroke-color:#000000; cap:round; }
  • Stroke -> Line -> Edge:

      .class Line { stroke-width:1px; stroke-color:#000000; cap:square; }
  • Fill -> Polygon -> Interior:

       .class Polygon { fill-color:#eeeeee; }
  • Raster Pixels -> Point > Registration:

       .class Raster { ... }
       Per pixel colored by the RGB channel values. Kinda like a RGB #hex gradient per 0-255 values?
       CSS tk tk tk.

#File structure

  • MSS for the Mappy CSS styling definition. See above.

  • MML for the datasources and their layering. See below.

    NOTE 1: Mappy CSS MML spec can embed the MSS part rather than linking to external file (the default).

    NOTE 2: Mappy CSS MML spec can be implemented in either XML (Cascadenik) or JSON (Carto) formats.


      Map object with several properties including:
          srs string --- for the projection, usually web mercator but can be any proj4 string.
          background-color: #rrggbb etc.
          background-image (should be background-color: url(...); ?)
          buffer: 20px;
          font-directory: path/subdir
      Stylesheet usually as an external (local) include. Inline MSS is allowed.
          See above for spec.
      Layer definitions with properties:     
          "class": "name1",
          "id": "value2",
          "name": "name3",
          "srs": "+proj=latlong +ellps=WGS84 +datum=WGS84 +no_defs",
          "Datasource": {
              "file": "world_borders",
              "type": "shape"

    XML: Used by Cascadenik.

      <?xml version="1.0" encoding="utf-8"?>
      <Map srs="+proj=latlong +ellps=WGS84 +datum=WGS84 +no_defs">
                  map-bgcolor: #69f;
                  line-width: 1;
                  line-color: #696;
                  polygon-fill: #6f9;
          <Layer srs="+proj=latlong +ellps=WGS84 +datum=WGS84 +no_defs">
                  <Parameter name="type">shape</Parameter>
                  <Parameter name="file">world_borders</Parameter>

    Use XML when any of these are important:

      1. Allows multi-line DB queries in MML where JSON does not allow unescaped line breaks. This creates more legible code.
      2. Can add inline comments using standard XML <!-- comment --> syntax. This allows notes to now self and future self and for collaborators.
      3. Can temporarily disable a block of code, also using <!-- disabled --> syntax.
      4. DataSourcesConfig, see below.

    JSON: Used by Carto.

          "srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
          "Stylesheet": [{"id":"style.mss","data":"Map {\n  background-color: #fff;\n}\n\n#world {\n  line-color: #ccc;\n  line-width: 0.5;\n  polygon-fill: #eee;\n}"}],
          "Layer": [{
              "id": "world",
              "name": "world",
              "srs": "+proj=latlong +ellps=WGS84 +datum=WGS84 +no_defs",
              "Datasource": {
                  "file": "world_borders",
                  "type": "shape"

    NOTE 3: Data source definition can be inline or an import in the MML. Cascadnik now. Easy in XML format, harder in JSON?

##For the MML layer setup:

  1. Local versus remote data files.

    Supported by: Carto, Cascadenik

    Carto does this as of the 0.2.0 release via separate millstone.

  2. DataSourcesConfig an XML tag similar to the Stylesheet tag that allows you to externalize elements in an easy to manage format. More info »

    Supported by: Cascadenik via native XML property. Hard to accomplish in Carto's JSON format?

     natural_earth_110m_base_url =
     file = %(natural_earth_110m_base_url)s/physical/
  3. interactivity templates: should apply both to full vector and UTF8 grid approximations.

    Supported by: UTFGRID spec, passed thru by Carto and Cascadenik?

    Note: Carto supports passthru of the interactivity templates in TileMill, but doesn't support it explicately.

    The interactivity spec Carto wraps is utfgrid-spec.


  • What promises are we making, what is arbitrary up to the user?
  • Set reasonable expectations

#Full details:

Read more »

Syntax details, implementation recommendations, avoids, demos, open questions, housekeeping, quotes, display:none, carto 1.x nitpicks, more questions.








Extended examples:

WARNING: the .layer interior {marker-image: url() } example below is incorrect. It should show markers just inside the polygon, with none spilling outside. More like a mask or a polygon-fill: url()? Or is there a slight difference?