block by nitaku aff4f425e7959290a1f7

Halos

Full Screen

A comparison between two common techniques for drawing halos to make labels readable regardless of the background color.

The first technique creates two SVG <text> elements one upon each other. The one in the background has a white stroke, while the one in the foreground has a black fill.

The second technique declares a combination of CSS text-shadows on a single text.

index.js

// Generated by CoffeeScript 1.10.0
(function() {
  var height, svg, width;

  svg = d3.select('svg');

  width = svg.node().getBoundingClientRect().width;

  height = svg.node().getBoundingClientRect().height;

  svg.attr({
    viewBox: (-width / 2) + " " + (-height / 2) + " " + width + " " + height
  });

  d3.range(4).forEach(function(i) {
    svg.append('text').text('This halo is made with two texts.').attr({
      "class": 'halo',
      x: -width / 4,
      y: i * (height / 6) - height / 4,
      dy: '0.35em'
    }).style({
      'font-size': (i + 1) * 6 + 'px'
    });
    svg.append('text').text('This halo is made with two texts.').attr({
      x: -width / 4,
      y: i * (height / 6) - height / 4,
      dy: '0.35em'
    }).style({
      'font-size': (i + 1) * 6 + 'px'
    });
    return svg.append('text').text('This halo is made with CSS.').attr({
      "class": 'texthalo',
      x: width / 4,
      y: i * (height / 6) - height / 4,
      dy: '0.35em'
    }).style({
      'font-size': (i + 1) * 6 + 'px'
    });
  });

}).call(this);

index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Halos</title>
    <link rel="stylesheet" href="index.css">
    <script src="//d3js.org/d3.v3.min.js"></script>
  </head>
  <body>
    <svg></svg>
    <script src="index.js"></script>
  </body>
</html>

index.coffee

svg = d3.select('svg')
width = svg.node().getBoundingClientRect().width
height = svg.node().getBoundingClientRect().height

svg
 .attr
   viewBox: "#{-width/2} #{-height/2} #{width} #{height}"
    
d3.range(4).forEach (i) ->
  
  svg.append('text')
    .text('This halo is made with two texts.')
    .attr
      class: 'halo'
      x: -width/4
      y: i*(height/6)-height/4
      dy: '0.35em'
    .style
      'font-size': (i+1)*6 + 'px'

  svg.append('text')
    .text('This halo is made with two texts.')
    .attr
      x: -width/4
      y: i*(height/6)-height/4
      dy: '0.35em'
    .style
      'font-size': (i+1)*6 + 'px'

  svg.append('text')
    .text('This halo is made with CSS.')
    .attr
      class: 'texthalo'
      x: width/4
      y: i*(height/6)-height/4
      dy: '0.35em'
    .style
      'font-size': (i+1)*6 + 'px'

index.css

@font-face {
  font-family: "Lacuna";
  src: url("lacuna.ttf");
}

body, html {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  font-family: sans-serif;
  font-size: 12px;
  overflow: hidden;
}
svg {
  width: 100%;
  height: 100%;
  background: #555;
}

text {
  text-anchor: middle;
  fill: black;
  font-weight: bold;
  font-family: "Lacuna";
}
.halo {
  fill: white;
  stroke: white;
  stroke-width: 3;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.texthalo {
  text-shadow: -1px -1px white, -1px 1px white, 1px 1px white, 1px -1px white, -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
}