From OpenStreetMap Wiki
Jump to: navigation, search

Play with it!

The easiest way to get acquainted with MapCSS is to play with it.

You can have a go at . Just edit the stylesheet on the right and click 'Refresh' to see your changes. You'll find it instantly accessible if you've ever written any CSS for a webpage before. (Halcyon was unavailable when checked on 2013-01-29.)

This is a first draft. See MapCSS/0.2 for improvements under discussion to the MapCSS spec.


Line properties

definition example Halcyon Kothic
z-index Specifies a sublayer within an OSM layer; Halcyon supports values of 0-10 + +
width Line width. Halcyon currently supports numbers only (i.e. 5, not 5px) width: 5 + +
color Colour of the line - either a hex value or a CSS colour name color: blue
color: #0000FF
+ +
opacity How transparent the line is, from 0 (transparent) to 1 (opaque) opacity: 0.5 + +
dashes An array of alternating on/off lengths dashes: 2,2,4,2 + +
linecap The style for the end of the line: 'none' (default), 'round' or 'square' + +
linejoin The style for line corners: 'round' (default), 'miter' or 'bevel' + +
fill-color Colour in which to fill the area, if closed - hex value or CSS colour fill-color: lightgreen + +
fill-opacity How transparent the fill is, from 0 (transparent) to 1 (opaque). Halcyon: Works only on fill-color, fill-image is always full opaque. fill-opacity: 0.2 + +
fill-image The URL (absolute or relative) of an image with which to fill the area fill-image: fills/grass.png + -
casing-width Width of the casing (border) of the line. This is the width of the entire line, so for a 1px border on either side of a 7px line, you would specify a casing-width of 9 casing-width: 9 + +
casing-color The colour (hex or CSS name) of the casing + +
casing-opacity The transparency of the casing + +
casing-dashes An array of alternating on/off lengths + +
casing-linecap Style for the end of the casing line (defaults to value of "linecap") - +
casing-linejoin The style for casing line corners (defaults to value of "linejoin") - +

Point/icon properties

definition example Halcyon Kothic
icon-image URL (absolute or relative) of an image to use as an icon + -

Label properties

definition example Halcyon Kothic
font-family Name of the font to use font-family: DejaVu + -
font-size Size of the text (Halcyon supports number only at present, no units) font-size: 12 + +
font-weight 'bold' or 'normal' font-weight: bold + -
font-style 'italic' or 'normal' font-style: italic + -
text-decoration 'none' or 'underline' text-decoration: underline + -
text-transform 'none' or 'uppercase' text-transform: uppercase + -
text-color A hex value or CSS colour name text-color: #07CF20 + +
text-position Whether the text follows the path of the way ('line') or is centred on the area ('center') text-position: center + +/- (only center now)
text-offset The vertical offset from the centre of the way or point. An offset of 5, on a line of width 3, would put the text "along" the line rather than within it. Similarly, an offset of 8, on a point with a 16-high icon, would put the text below the icon. text-offset: -5 + -
max-width The maximum width of a text label for a point, after which it should wrap onto the next line max-width: 30 + -
text The tag key whose value is used for the label. For example, 'text: name' would render the name tag text: name + +
text-halo-color The colour (hex or CSS) of the 'halo' or 'pull-out' used to make the text stand out from features underneath it text-halo-color: white + +
text-halo-radius The radius of the halo text-halo-radius: 2 + +

Shield properties

Shield properties are not yet supported by Halcyon but are likely to be shield-image and shield-text.


Selectors - elements

The selector elements are the core OSM objects:

  • node
  • way
  • relation

When a rule applies to two selectors, we can group them with a comma:

way[highway=primary], way[highway=trunk]

The descendant combinator is used when one object is contained in another. For example, a way in a relation, or a node in a way.

way[highway=footpath] node[barrier=gate] { icon-image: icons/gate.png; }
relation[type=route] way[highway] { stroke-color: red; }

We can be liberal in how we treat white space: the latter would be unambiguous as

relation [type=route]
 way [highway]
  { stroke-color: red; }

Selectors - tests

Basic tests are added as you'd expect:

way[highway=primary]       /* way with the highway tag set to primary */

You can also simply test whether a tag is set or not, in one of two ways:

way[highway]               /* way with the highway tag set */
way[!highway]              /* way with the highway tag not set */
way .highway               /* way with the highway tag set (see pseudo-classes below) */

A wide range of attribute selectors (special conditions) are supported:

way[highway=~/primary/]    /* regex */
way[!highway]              /* way without a highway tag */

and in a little bit of invisible magic,


also looks for =true or =1.

The test for a zoom level works well using the CSS namespace selector:


and of course, if it's not specified, it applies to all zoom levels. Theoretically this could be extended to cope with other units of measurement, e.g. way|s50000 for a 1:50,000 printed map.

The role in a relation is exposed via the 'role' pseudo-tag, so you can test for:

relation[type=route] way[role=proposed] { color: blue; }

(This is not yet supported by Halcyon.)


Declarations are almost exactly as you'd expect, echoing common CSS vocabulary where possible - see above.

Additional declarations:

{ exit; }            /* stops parsing (just a performance optimisation) */
{ set tag=value; }   /* set a tag */
{ set tag; }         /* set a tag to 'yes' */

You can compute values using an eval instruction:

{ opacity: eval('population/100000'); }
{ set width_in_metres=eval('lanes*3'); }

(Note that Halcyon currently only supports numeric eval, though string eval is planned.)

Halcyon has the ability to 'stack' renderings for a particular rule, so you can have several stokes for a particular way.

This means you can have more than one declaration block:

  { z-index: 0; width: 5px; stroke-color: red; }
  { z-index: 1; width: 1px; stroke-color: black; dashes: 1, 3, 2, 3; }


You can set tags beginning with a full-stop to simulate classes:

{ set .minor_road; }

You can then use the .minor_road test (as above) in the selector:

way .minor_road { width: 2pt; color: yellow; }

This opens up possibilities when used with the @import rule and a media type. You can have a set of rules for each medium (e.g. direct from an OSM database, or from the product of osm2pgsql), each of which set pseudo-classes. The main stylesheet is then applied to these styles:

 @import url("osmtags.css") osmtags;
 @import url("osmpostgis.css") osmpostgis;

(The @import rule is not yet supported by Halcyon.)


Interactive clients can support :hover and :active pseudo-classes.

The :area pseudo-class applies if a way is 'closed' (first and last nodes are the same).