To style roads with SLD, you can use a LineSymbolizer for the road geometries and a TextSymbolizer for the road names. To achieve nice results at all zoom levels, you can rely on scale-based styling rules, world-sized units of measure (UOM), halo effects and labels that follow the curvature of roads. This article illustrates such an approach by styling the sample SHP file samples/resources/Data/Shp/Dc/streets.shp, with road data for Washington DC.

When you zoom out on the map, you don’t want to see too much detail to prevent clutter in the view. You can use a scale-based styling rule to show the roads only when map users reach an appropriate map scale, such as 1:75000.

Program: Defining a styling rule to show roads at a map scale of 1:75000
<Rule>
  <MinScaleDenominator>5000</MinScaleDenominator>
  <MaxScaleDenominator>75000</MaxScaleDenominator>
  <LineSymbolizer>
    <Stroke>
      <SvgParameter name="stroke-width">3</SvgParameter>
      <SvgParameter name="stroke">#7D8083</SvgParameter>
    </Stroke>
  </LineSymbolizer>
  <LineSymbolizer>
    <Stroke>
      <SvgParameter name="stroke-width">1</SvgParameter>
      <SvgParameter name="stroke">#EEF0F2</SvgParameter>
    </Stroke>
  </LineSymbolizer>
</Rule>

This styling rule defines two LineSymbolizer elements with different widths and colors. The two line symbolizers result in a halo effect that makes the roads visible on many backgrounds:

roadsWithHaloEffect
Figure 1. Road styling with a halo effect

When map users zoom in further, it makes sense to show the names of the roads too. This styling rule defines a TextSymbolizer that shows road names at a map scale of 1:25000:

Program: Defining a styling rule to show road names at a map scale of 1:25000
<Rule>
  <MinScaleDenominator>1000</MinScaleDenominator>
  <MaxScaleDenominator>25000</MaxScaleDenominator>
  <TextSymbolizer>
    <Label>
      <ogc:PropertyName>STREET</ogc:PropertyName>
    </Label>
    <Font>
      <SvgParameter name="font-family">Dialog</SvgParameter>
      <SvgParameter name="font-weight">normal</SvgParameter>
      <SvgParameter name="font-size">12</SvgParameter>
    </Font>
    <Halo>
      <Radius>1</Radius>
      <Fill>
        <SvgParameter name="fill">#171818</SvgParameter>
      </Fill>
    </Halo>
    <Fill>
      <SvgParameter name="fill">#EEF0F2</SvgParameter>
    </Fill>
    <VendorOption name="followLine">true</VendorOption>
  </TextSymbolizer>
</Rule>

The label styling rule applies a halo effect to make the labels visible on many backgrounds.

To let the labels follow the curvature of the roads, the label styling rule enables a custom followLine vendor option. Such an option is custom because the OGC SLD/SE standards don’t support this capability. This results in the following visualization:

roadsWithCurvedLabels
Figure 2. Road styling with curved labels

When users zoom in closely, you can switch to a world-sized unit of measure to let the road width scale with the zoom level. To apply a world-sized unit of measure to the roads at a certain scale, define a meter UOM on a LineSymbolizer:

Program: Defining a styling rule to apply world-sized road widths beyond a scale of 1:5000
<Rule>
  <MaxScaleDenominator>5000</MaxScaleDenominator>
  <LineSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
    <Stroke>
      <SvgParameter name="stroke-width">3.5</SvgParameter>
      <SvgParameter name="stroke">#7D8083</SvgParameter>
    </Stroke>
  </LineSymbolizer>
  <LineSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
    <Stroke>
      <SvgParameter name="stroke-width">2.5</SvgParameter>
      <SvgParameter name="stroke">#EEF0F2</SvgParameter>
    </Stroke>
  </LineSymbolizer>
</Rule>

Similar to the first styling rule, this rule includes two LineSymbolizer elements to apply a halo effect to the roads. As users zoom in further, the roads widen. At that point, it makes sense to remove the halo effect from the road labels, because they will always appear within the road:

Program: Defining a styling rule to show road labels without a halo at a map scale of 1:1000
<Rule>
  <MaxScaleDenominator>1000</MaxScaleDenominator>
  <TextSymbolizer>
    <Label>
      <ogc:PropertyName>STREET</ogc:PropertyName>
    </Label>
    <Font>
      <SvgParameter name="font-family">Dialog</SvgParameter>
      <SvgParameter name="font-weight">normal</SvgParameter>
      <SvgParameter name="font-size">12</SvgParameter>
    </Font>
    <Fill>
      <SvgParameter name="fill">#171818</SvgParameter>
    </Fill>
    <VendorOption name="followLine">true</VendorOption>
  </TextSymbolizer>
</Rule>

The combination of this styling rule and the world-sized road styling rule results in the following visualization:

roadsWithWorldSizedWidths
Figure 3. Road styling with world-sized road widths and labels inside the roads

The SLD style with all road styling rules

<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml"
                  xmlns:xlink="http://www.w3.org/1999/xlink"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://www.opengis.net/ogc http://schemas.opengis.net/filter/1.1.0/filter.xsd http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd http://www.opengis.net/se http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/base/gml.xsd http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd "
                  version="1.1.0">
  <Rule>
    <MinScaleDenominator>5000</MinScaleDenominator>
    <MaxScaleDenominator>75000</MaxScaleDenominator>
    <LineSymbolizer>
      <Stroke>
        <SvgParameter name="stroke-width">3</SvgParameter>
        <SvgParameter name="stroke">#7D8083</SvgParameter>
      </Stroke>
    </LineSymbolizer>
    <LineSymbolizer>
      <Stroke>
        <SvgParameter name="stroke-width">1</SvgParameter>
        <SvgParameter name="stroke">#EEF0F2</SvgParameter>
      </Stroke>
    </LineSymbolizer>
  </Rule>
  <Rule>
    <MaxScaleDenominator>5000</MaxScaleDenominator>
    <LineSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
      <Stroke>
        <SvgParameter name="stroke-width">3.5</SvgParameter>
        <SvgParameter name="stroke">#7D8083</SvgParameter>
      </Stroke>
    </LineSymbolizer>
    <LineSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
      <Stroke>
        <SvgParameter name="stroke-width">2.5</SvgParameter>
        <SvgParameter name="stroke">#EEF0F2</SvgParameter>
      </Stroke>
    </LineSymbolizer>
  </Rule>
  <Rule>
    <MinScaleDenominator>1000</MinScaleDenominator>
    <MaxScaleDenominator>25000</MaxScaleDenominator>
    <TextSymbolizer>
      <Label>
        <ogc:PropertyName>STREET</ogc:PropertyName>
      </Label>
      <Font>
        <SvgParameter name="font-family">Dialog</SvgParameter>
        <SvgParameter name="font-weight">normal</SvgParameter>
        <SvgParameter name="font-size">12</SvgParameter>
      </Font>
      <Halo>
        <Radius>1</Radius>
        <Fill>
          <SvgParameter name="fill">#171818</SvgParameter>
        </Fill>
      </Halo>
      <Fill>
        <SvgParameter name="fill">#EEF0F2</SvgParameter>
      </Fill>
      <VendorOption name="followLine">true</VendorOption>
    </TextSymbolizer>
  </Rule>
  <Rule>
    <MaxScaleDenominator>1000</MaxScaleDenominator>
    <TextSymbolizer>
      <Label>
        <ogc:PropertyName>STREET</ogc:PropertyName>
      </Label>
      <Font>
        <SvgParameter name="font-family">Dialog</SvgParameter>
        <SvgParameter name="font-weight">normal</SvgParameter>
        <SvgParameter name="font-size">12</SvgParameter>
      </Font>
      <Fill>
        <SvgParameter name="fill">#171818</SvgParameter>
      </Fill>
      <VendorOption name="followLine">true</VendorOption>
    </TextSymbolizer>
  </Rule>
</FeatureTypeStyle>

See Styling data with OGC SLD for more information about using and applying OGC SLD/SE styling.