Skip to main content

Map Style

The MapCSS style file consists of rules that apply to each object from top to bottom.

For example, a style:

node[natural=tree] {
icon-image: "tree.svg";

will display a picture of tree.svg for points where the tag natural has the value tree.

Each rule in the style consists of two parts. Filter node[natural=tree] and draw parameters icon-image: tree.svg;. The query chooses which objects to apply the parameters to.

Rules can be nested and set parameters at each level.

|z16- {
icon-scale: 0.50;
icon-tint: @color_icon_tint;

[amenity=bicycle_parking] {
icon-image: "bike_parking.svg";
[amenity=bicycle_rental] {
icon-image: "bike_rental.svg";
[amenity=bicycle_repair_station] {
icon-image: "bike_service.svg";

These nested style rules make the style concise, with a clearly visible structure. In this way, general parameters can be set once in advance, without having to repeat it, possibly multiple times.

This documentation describes the MapCSS dialect used in the Guru Maps application. Important to note that some origianl drawing parameters have not been implemented at all. But at the same time preprocessing macros, nested rules and new functions for the evaluated operations have been added. The style used in Guru Maps can be found in the repository.


Let's consider a complex filter:


It consists of:

  1. filter by type node,area. It can be node for points, line for lines, area for polygons. If you need to specify several types, they are separated by a comma. You can also use * if the type is not important.
  2. zoom filters z14-. It specifies for which zoom leves the rule should be triggered. It can be only the minimum zoom level z8-, or the interval z3-9. In this case the rule will be applied on zoom levels 3 to 8 inclusive.
  3. parameter filters [boundary=forest_compartment][ref]. Such filter will leave only objects that have the boundary tag with the value forest_compartment and also set any value for the ref tag. To leave the objects that don't have the ref tag, use the filter [!ref].

Several filters can be separated by a comma:


In this example common parametres can be set on separate level:

node,area|z14-[ref] {
[boundary=forestry_compartment] {


Sometimes it is necessary to join several rules into a group. It starts with a left parenthesis ( and ends with a right parenthesis ). The group will combine several filters and it is not necessary to start a block with rules after the group.

[boundary=forestry_compartment]) {

Preprocessing macros

The preprocessor prepares the style for parsing. Substitutes the values, turns on or turns off some blocks depending on the settings.

Substitution Macros


Inserts the content of the specified file:

@import "polygons.mapcss";


Inserts the value of the macro, in all places where it is used:

// Define color using
@color_ground: #EAE3D3;

// then use it as
fill-color: @color_ground;



Checks the parameter and includes or excludes a block from the style:

@if Theme == Dark
@import "colors_dark.mapcss";
@else // Default colors
@import "colors.mapcss";

Guru Maps uses the following preprocessor parameters:

  • Theme {Light, Dark} - current app theme,
  • Style {Default, Outdoor} - current map style,
  • SubStyle {Car, Hike, Bike}
    • Car used for the driving,
    • Hike и Bike used for hikeing and biking activities respectively.


Specifies a block of code to be executed, if the first condition is false.


Contains a condition to be run if the previous conditions did not work.


Closes the block of the current condition.

Draw parameters

The parameters control how to draw objects on the map.

Parameter values


Line thickness or width can be specified in pixels 1px, points 2pt, meters 3m or calculated using the expression eval( zlinear( 13, 1px,1pt,max(2pt, 4m)). );. Read more about expressions in separate section.


Color can be specified in the following formats: #RGB, #RRGGBB, #RGGBBAA or a color constant from [CSS list] (


Any sequence of characters between single or double quotes is considered text.

"another string"

Draw order parameters


The layer number is needed to separate the different levels on the map.

// for any object with tag 'layer', set it's 'layer' property, to the value of 'layer' tag
*|z9-[layer] {
layer: eval(tag(layer));


z-index sets the order of drawing objects of the same type inside one layer.

area|z10-[natural=wood] {
z-index: -3;
fill-color: @color_wood;

area[natural=oceanwater] {
z-index: -2;
fill-color: @color_water;

Polygon parameters


Fill color of the polygon

area|z5-[natural=water] {
fill-color: @color_water;


Fill image of the polygon

// fill image of military area desplayed on top of the other objects
area|z11- {
[military=danger_area] {
z-index: 2;

fill-image supports inline style with base64 data.

// same as arrow.svg
fill-image: eval(data("PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTI2IDNoMTBWMWw1IDMtNSAzVjVIMjZ6IiBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIG9wYWNpdHk9Ii40Ii8+PC9zdmc+Cg=="))

color and width for polygon

Polygon border color and border width

area|z15-[building] {
z-index: 3;
width: 1px;
color: @color_landuse_residential_stroke;

Line parameters

color and width for line

Line color and width

line|z13-[natural=tree_row] {
width: 3pt;
color: @color_wood;
z-index: -10;

casing-color and casing-width

Line casing color and casing width. Used mostly for roads.

line|z11-[highway=motorway_link] {
color: @color_motorway;
casing-color: @color_motorway_casing;
casing-width: 0.5pt;


Indicates the lengths of painted and blank segments. The sum of numbers must be equal to the power of 2 (4, 8, 16, 32, 64, etc.). Each number is the length of the line segment in points.

line|z15-[highway=cycleway] {
dashes: 2,2,2,2;
dashes-color: @color_cycleway_dashes;

dashes-color and dashes-width

Line dashes color and dashes width. Used for trails, paths, stairs and borders.

line|z15-[highway=steps] {
dashes-color: @color_footway_dashes;
dashes-width: eval( zlinear( 16, 3pt, 4pt ) );


The shape of the line edges. Possible values: none, square, round.


Line joint form. Possible values round, miter, bevel, auto.

Text params


The text to be written next to a point, in the center of the line or in the center of the polygon.

node,area|z2-8[place=country] {
text: eval(locTag('name'));
// other params skipped


The thickness of the text or font weight. Possible values: bolder, bold, normal, light, ligther.

node,area|z12-[place=hamlet] {
font-stroke-color: @color_label_stroke;


Font size.

font-stroke-width and font-stroke-color

Font stroke width and color.


Text color.

node,area|z2-8[place=country] {
text: eval(locTag('name'));
text-color: @color_name_text;
text-priority: 10;
// other tags skipped


When there is a lot of text nearby, the text priority allows you to specify which text to draw first.


Allows you to allow the display of text with overlapping. Several labels, one on top of the other.


Indicates that the text needs 2 times more free space around it. Used for the names of significant human settlements (city, town, suburb, etc.), so that labels do not obscure the entire map.


The name of the picture to be shown in the center of the polygon or at a point.

node,area|z17-[amenity=library] {
icon-image: "library.svg";
icon-scale: 0.37;
icon-tint: @color_icon_tint;

icon-image supports inline style with base64 data.

// same as poi_circle_small.svg


The scale of the picture allows you to make the picture bigger or smaller than its original size.


A tint allows you to repaint the picture in a different color. The colours of the picture are changed in the following way. #FFF white remains white, #CCC becomes lightened tint-color, #888 becomes identical to the color in tint-color, #444 - darkened tint-color and #000 black remains black. At all intervals, the color will change smoothly between the specified colors.

icon-offset-x and icon-offset-y

You can move the picture relative to the anchor point. By default, image is centered at the point on the map for which the image was shown. icon-offset-y: 0; for example, allows you to show the pin on the map with a needle at the point for which it was shown. Values from 0 to 1 are used. Where 0 is the bottom for icon-offset-y and the left side for icon-offset-x and 1 is the top and right side respectively.


Enables one-to-one overlay of pictures.

Details parameters

details-text and details-description are used to set a name and description for GeoJSON objects. The text set in details-text will be displayed as a name, and the text set in details-description will be displayed as a description. If details-text or details-description is not filled, tap on such objects is not processed. Expressions can be used in these parameters.

* {
details-text: eval(tag('name'));
details-description: eval(tag('description'));


Not only filters, but also object parameters may depend on external factors, be calculated by formula or vary depending on the scale.

If the parameter's value should be calculated, it always starts with eval() function.

The following functions can be used inside:

min and max

Returns the minimum or maximum value from the parameters. The number of parameters is not limited.


Returns the first non null value from the parameters. The number of parameters is not limited.


Decodes base64 string. Can be used for icon-image and fill-image.


Returns the value of the tag specified in the parameter, or null if there is no value.


Returns localized tag values depending on the language settings of the user. For example, if the order of languages is English, Russian and Native language. For locTag(name) will check name:en, name:ru and name, the first found value will be used. Languages supported by Guru Maps is: be, cs, da, de, en, es, fr, it, ja, ko, nl, pl, ru, sv, uk, zh. The languages listed can be checked by locTag(). Other languages should be written explicitly with tag().


The first parameter contains a logical expression, the second will be returned if the expression is true, the third if the expression is false.

// check addr:housenumber
text: eval( cond( tag('addr:housenumber'),
// if there is addr:housenumber, then concatenate next condition
tag('addr:housenumber') . cond( any( locTag('name'), tag('addr:housename') ),
// if there is name or addr:housename - put them between ()
' (' . any( locTag('name'), tag('addr:housename') ) . ')',
// empty line otherwise
// if there is no housenumber just use any from name or addr:housename
any( locTag('name'), tag('addr:housename') ) ) );


Converts the value to Boolean type. If there is no value or it is equal to 0, No, Off, False case insensitive - the function will return false. In other cases true.


Smoothly changes the value as the zoom changes. The first parameter is the initial zoom level. Then any number of values for all zoom levels starting from the initial one.

line|z13-[highway=residential] {
width: eval( zlinear( 13, 1px, 1pt, max(2pt, 4m) ) );
color: @color_small_road;
linecap: round;

In this example, the road width at 13 zoom level is 1 pixel, at 14 zoom level is 1 point, at 15+ zoom level will be used the greater of 2 points or 4 meters.


The numeric parameter of this function changes type to meters.

line|z12-[highway=tertiary] {
width: eval( zlinear( 12, 1px, 1pt, 1pt, max(3pt, metric(any(tag(lanes),2)*2)) ));

In this example, the number of lines is multiplied by 2 - the result is considered to be the distance in meters. max(3pt, metric()) will return a larger value, width in meters or in points.

Expression operators

The following mathematical operators can be used in expressions: +, -, *, \, string concatenation operator - ., comparison operators < - less, > - more, == - exact equality, ~= - presence of substring in the string.