Sunday, August 25, 2013

Translucent text on a Bootstrap 3 cover image

I'm close to debuting a lightweight blogging engine using Go, App Engine, and Bootstrap 3, and I wanted to share a quick solution I found to what seems to be a common problem: putting text on top of a cover image without contrast problems, and without having to explicitly line up a translucent background color with the parent div's corners.

In this case, I'm using a simple Bootstrap 3 jumbotron with a background image declared with the css "background-image: url()" syntax. The jumbotron div has a child H1 element with a sample blog name ("Stories for Outcasts", which I thought was pretty funny, but [probably] won't be the final blog name I choose).

The background image is of my Tom Baker Dr. Who action figure peering at some API or other I was toying with on my laptop. It's mainly a dark image, so I chose white for the superimposed text. Here's the HTML stub:

<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <meta charset="utf-8">
 <link href="Blog_files/bootstrap.min.css" rel="stylesheet">

 <style type="text/css">
  #cover {
   background-size: 100% auto;
   background-image: url(static/cover.jpg);
   margin-top: -20px;
  }

  #cover h1 {
   color: #fff;
  }
 </style>
</head>
<body>
 <div class="container col-md-8">
  <div id="cover" class="jumbotron">
   <h1 class="text-center">Stories for Outcasts</h1>
  </div>
 </div>
</body></html>

...and what the result looks like:

As you can see, this mainly works, except for the edge of the laptop screen, where the white border of the displayed editor window contrasts badly with the superimposed text. I debated editing the background image to add a translucent alpha channel, but what I really wanted was a generic solution for when I swap out the cover image in the future, and which other users of the blog engine could use without needing to post-process their cover images.

I started with adding an RGBA background element to the H1 element using this CSS:

#cover h1 {
 color: #fff;
 background: rgba(0, 0, 0, 0.4);
}

This is declaring a background color of a 40% opaque black. The new jumbotron looked like this:

A step in the right direction, but the border of the H1 element was even more distracting than the original bad contrast. I played around for a little while with trying to blow up the H1's borders to match the parent div, while still inheriting the jumbotron's rounded border. The closest I came was setting the div to relative positioning, the H1 to absolute, and explicitly setting borders. The code was ugly, and I wasn't confident it would work in all cases (e.g., Bootstrap does some voodoo with layout for mobile devices with media queries). More importantly, it was counter to my idea of having a lightweight blog engine with simple code.

It turned out that I could switch the jumbotron class to the H1 instead of the parent div. Since this was counter to Bootstrap's expectations, there were naturally some side effects, specifically it removed the font-size and line-height formatting of the H1, and the rounded corners of the parent div, which I added back in explicitly. The final code:

<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <meta charset="utf-8">
 <link href="Blog_files/bootstrap.min.css" rel="stylesheet">

 <style type="text/css">
  #cover {
   background-size: 100% auto;
   background-image: url(static/cover.jpg);
   border-radius: 6px;
   margin-top: -20px;
  }

  #cover h1 {
   color: #fff;
   background: rgba(0, 0, 0, 0.4);
   font-size: 63px;
   line-height: 1.5em;
  }
 </style>
</head>
<body>
 <div class="container col-md-8">
  <div id="cover">
   <h1 class="text-center jumbotron">Stories for Outcasts</h1>
  </div>
 </div>
</body></html>

This still fell into my intuitive range of "simple", and resulted in the formatting and contrast I was aiming for:

So in short, to fix your contrast issues with superimposed text, leave the background image as-is on the parent div, and move the div's formatting down to the child text element, including the RGBA background definition.

Enjoy!

No comments:

Post a Comment