Recently I needed to create headings with border only in the corners. I realized there are multiple interesting ways how to achieve this, so I decided to sum these up.

Technique #1: pseudo-elements

At first, all the headings were on a solid color background, so I just used pseudo elements for that.

Cons

  • You cannot use this method when the background is not a solid color
  • The text itself has to be wrapped and positioned relatively to place it above the pseudo elements
  • Limited variability – you have only 2 pseudo-elements you can use for masking

Pros

  • Actual border
  • Quite quick when you're in a time press (I was at the monent)
  • No mixins or external tools needed
  • Maybe easier to understand when not much familiar with SVG and data URIs which are used in the next examples

Technique #2: multiple SVG as data URIs

Later new design arrived and one of the headings was placed on a background image. So I came up with another solution which is a bit longer, but offers a lot of variability and solves all the problems with the previous technique.

This solution uses multiple background images placed in corners. To save extra requests and files I wanted the images to be directly in the CSS. You can use base64 for that, however there are security threads connected with this. (That's the reason I couldn't use it anyway because this will be blocked in the project I was working on.) But that's no problem nowadays.

You want the image to be SVG in most cases anyway. And SVG is easy to be encoded as data URI without converting it to base64. You just have to escape all those special characters with some URI/URL encoder. Or use this cool mixin for that.

Let's say you want corner borders 8px (0.5em) thick and 40px (2.5em) wide:

  .corners-border {
  padding: 1em + 0.5em; // you need to include the border width in the padding (or 16px + 8px)

  background-repeat: no-repeat;

  background-position: left top,
                       right top,
                       left bottom,
                       right bottom;

  background-size: 2.5em 2.5em, // width/height of the corner (or 40px 40px)
                   2.5em 2.5em,
                   2.5em 2.5em,
                   2.5em 2.5em;

  // special characters in data URIs have to be encoded, see the compiled CSS in the codepen below
  // (also do not wrap the lines, that's just for better uderstanding)
  background-image: url(data:image/svg+xml;charset=utf8,
                      <svg xmlns="..." viewBox="0 0 40 40">
                        <polygon points="40 0 8 0 0 0 0 8 0 40 8 40 8 8 40 8 40 0" fill="#000" />
                      </svg>),
                    url(data:...,<svg ...><polygon ... transform="translate(40, 0) rotate(90)" /></svg>),
                    url(data:...,<svg ...><polygon ... transform="translate(40, 40) rotate(180)" /></svg>),
                    url(data:...,<svg ...><polygon ... transform="translate(0, 40) rotate(270)" /></svg>);
}

I created a mixin for that which enables you easily change all the dimensions, color and also switch between relative units and pixels. Pixels are especially useful for thin borders. See the codepen below:

Cons

  • You need extra mixin for data URI encoding of SVG or use some URI/URL encoder
  • The border is not an actual border so you need to increase the padding accordingly
  • The border color cannot be inherited (because it's standalone image) and has to be specified explicitly

Pros

  • Variability – you can use unlimited amount of any shapes you want and place them exactly where you want
  • You can use CSS preprocessor variables in the SVGs for dimensions, colors etc. which is really cool
  • You're not limited to solid color background, no overlaying is necessary here
  • You don't need any extra markup – this can be done on a single element, even on an element which doesn't support pseudo elements

Technique #3: SVG data URI border-image

When writing this article I realized there is another much simpler solution with border-image property. I have used the border image probably only once before because it's not something you need unless there's something specific in the design. And that's why it's usually not the first thing that pops into your head (or at least into my head 😉).

The border images are well supported (IE11 and above). If you need to support older browsers for some reason and progressive enhancement is not an option for you, you can use the previous method.

I consider this technique preferred one because the border image was designer exactly for such things.

Let's say you want to make the same corner borders as in the previous example:

  .corners-border {
  border-style: solid;
  border-width: 0.5em; // or 8px

  // special characters in data URIs have to be encoded, see the compiled CSS in the codepen below
  // (also do not wrap the lines, that's just for better uderstanding)
  border-image-source: url(data:image/svg+xml;charset=utf8,
    <svg xmlns="..." viewBox="0 0 80 80">
      <rect x="4" y="4" width="72" height="72" fill="transparent" stroke="#000" stroke-width="8" />
    </svg>);

  border-image-slice: 50%; // slice the image to 4 parts through the middle

  border-image-width: 2.5em; // width/height of the corners (or 40px)
}

I also created a mixin for this like in the previous demo:

Cons

  • Unless you need to support archaic browsers and you cannot use progressive enhancement for this, you shouldn't have problems with this technique.
  • You don't have that unlimited amount of variability as with the previous technique (max 9 slices and limited positioning) but you probably won't need that anyway. Ever.
  • The border color cannot be inherited (because it's standalone image) and has to be specified explicitly

Pros

  • You can use CSS preprocessor variables in the SVGs for dimensions, colors etc. which is really cool
  • You're not limited to solid color background, no overlaying is necessary here
  • You don't need any extra markup – this can be done on a single element, even on an element which doesn't support pseudo elements
  • True border – border image property was created for such cases
  • Less code
  • You need only one image (which will be sliced)
  • Rounding – in the case you'd needed whole number of repeated items. This is cool and probably unachievable another way.

As you see, each of these techniques has some pros and cons. However you should really consider starting with the technique #3 because it's the less hacky one – it uses border image property designed for such cases. This also means less of code. Consider one of the other options only when you have some good reason not to use it in your current project.

Happy to hear about other ideas you have how to create the corner-only borders in CSS.


2,542 3 26