This is a short collection of notes about how to do map styling with CartoCSS!
Software-wise, you've got two good options:
- The original not-terrible way to make web maps.
- Open source (BSD license).
- Developed by Mapbox.
- Soon to be old hat. These days virtually all development attention is focused on Mapbox Studio.
- Download: https://www.mapbox.com/tilemill/
- Was originally developed as Tilemill 2 but was rebranded before release.
- Was only released a few weeks ago, though has been in dev for long before that.
- Harder, better, faster, stronger than Tilemill.
- Requires a Mapbox account (there's a free tier).
- Includes really easy access to global datasets (e.g. streets, terrain, imagery)
- Not as good as Tilemill for publishing maps outside of the Mapbox service (though theoretically possible if you're using only your own data).
- Open source (BSD license).
- Download: https://www.mapbox.com/mapbox-studio
A rule-based language for applying styles to maps. Has a lot of similarity to plain old CSS (used for styling web pages).
Looks like so:
#water {
polygon-fill: #639EB7;
line-color: #407E99;
line-width: 1;
}
Structure of a CSS rule:
selector {
attribute: value;
another-attribute: another-value;
...
}
Note that the semicolons ;
at the end of each attribute line are important.
These are describe specific stylistic elements (color, size, etc) that should be applied to data. They have some general categories depending on the type of data being styled (e.g. points, lines, polygons, text).
#water {
polygon-fill: #639EB7;
line-color: #407E99;
line-width: 1;
}
In that example, we can assume water features are polygons and this rule says
that the inside of the polygon (polygon-fill
) should be colored #639EB7
. The
outside of the polygon (line-color
) should be colored #407E99
, and that
outline should have a width (line-width
) of 1 pixel.
There are a lot of different attribute names. Way too many to go over them one by one, but they follow a logical naming scheme and the example projects are a good way to get a feel of the most common ones.
A full reference list is here: https://github.com/mapbox/carto/blob/master/docs/latest.md
There are two main types of selectors: ID selectors and Class selectors.
ID selectors target a dataset by its ID and are prefixed by the #
symbol. For
example:
#myRoadDataset {
...
}
Note that IDs should be unique.
Class selectors target potentially multiple datasets all of the same "class".
Class selectors are prefixed by the .
symbol. For example:
.roads {
...
}
Classes are determined by you as the designer and data keeper. For example you
might have several specific road datasets, each with their own ID
(#austinRoads
, #sanAntonioRoads
, etc.), but you want to apply the same rules
to all of them. In this case, give each dataset the class .roads
.
Map
is used to set the background attributes (wherever there is no
data to style):
Map {
background-color: #fefef1;
}
Filters make selectors more specific. For example, they can be used to apply rules at certain zoom levels:
#road[zoom>=13] {
...
}
Or refer to features in a dataset that match some attribute:
#road[type='major'] {
...
}
When separated by a comma, the rule is applied if either filter is true:
#road[zoom>=13], #road[type='major'] {
...
}
When chained together, the rule is applied when both filters are true:
#road[type='major'][zoom>=13] {
...
}
Rules are applied in order of appearance, and style attributes will be over-written by subsequent rules:
#road[type='major']{
line-color: #1E2A2F2;
}
#road[type='major'][zoom>=13] {
line-width: 1;
}
#road[type='major'][zoom>=17] {
line-width: 2;
}
Selectors can be nested inside of other rules. This helps keep things organized:
#road[type='major']{
line-color: #1E2A2F2;
[zoom>=13] {
line-width: 1;
}
[zoom>=17] {
line-width: 2;
}
}
More technical details on selectors: https://www.mapbox.com/tilemill/docs/guides/selectors/
Variables are place-holders where values can be stored so they can be referred to later in rules. They allow some value to be defined once and reused multiple times. They are used extensively in the example projects that come with Tilemill and Mapbox Studio.
Example:
@water: #639EB7;
#river {
polygon-fill: @water;
}
#stream {
line-fill: @water;
}
Colors can be defined a few ways:
- name:
blue
(note that not all colors have names) - hex:
#47DAD3
- rgb (red, green, blue):
rgb(71, 218, 211)
- rgba (red, green, blue, alpha):
rgba(71, 218, 211, 0.5)
- hsl (hue, saturation, lightness):
hsl(177, 67%, 57%)
- hsla (hue, saturation, lightness, alpha):
hsla(177, 67%, 57%, 0.5)
See this link to play with CSS colors: https://developer.mozilla.org/en-US/docs/Web/CSS/Tools/ColorPicker_Tool
To help come up with some color palettes:
- http://paletton.com/
- http://design-seeds.com/index.php/search
- https://kuler.adobe.com/create/color-wheel/
- http://www.colourlovers.com/
Styles are applied in order, and defining a style attribute twice on the same
data layer will override the previous definition. But sometimes it's useful to
have two styles applied to the same data. For example, adding a glow effect to a
border can be accomplished by defining a line style twice (once with a
large semi-transparent line style, and once with a thicker line style). To
accomplish this, you can use the ::<name>
syntax. These names are called symbolizers
they can be any string, and there can be multiple symbolizers. These symbolizers
create separate layers to draw styles from, so they can be used to compose
advanced styles.
#layer {
line-color: #C00;
line-width: 1;
}
#layer::glow {
line-color: #0AF;
line-opacity: 0.5;
line-width: 4;
}
More info can be found in these links:
- https://www.mapbox.com/tilemill/docs/manual/carto/
- https://www.mapbox.com/tilemill/docs/guides/symbol-drawing-order/
- Screencast of styling in Mapbox Studio: https://vimeo.com/mapbox/review/104757116/dc2bb1a46c
- Big list of CartoCSS attributes: https://github.com/mapbox/carto/blob/master/docs/latest.md