Absolutely Positioning Generated Content
Yesterday, I was marking up a mockup (as you’ll often find me doing). It was time to convert this little navigation progress indicator:
So, when marking this up, it’s clearly a list. Since it is a list of steps you will take as you progress through this feature, it’s an ordered list. So, here’s the markup:
<ol class="basic_info" id="steps">
<li id="i-have">
<span class="icon"></span>
<span class="label">I have</span>
</li>
<li id="i-am">
<span class="icon"></span>
<span class="label">I am</span>
</li>
<li id="my-status">
<span class="icon"></span>
<span class="label">My status is</span>
</li>
</ol>
It’s a little span-heavy, I’ll admit. We tend to use an empty span.icon for dropping in icons from sprites. I would ideally just use background images, but this image needs to be reused in many different formats, so there’s no good way to avoid exposing the remainder of the image in all cases. So, if you want to use sprites and you want to re-use the image in multiple arrangements, this is sometimes the best way to go.
Besides, the span doesn’t actually appear in the unstyled markup. So, we’re cool.
Here’s how I’m styling this. Yes, it’s in Sass, but Sass is so easy to read that I’m sure you know what it means.
ol#steps
+reset
border-bottom: 1px solid #0B3DA0
list-style: none
padding: 30px
text-align: center
li
+reset
+alternate_header_font
display: inline-block
font-size: 120%
font-weight: bold
margin-left: 40px
min-width: 100px
position: relative
&#i-have
+sprite_icon(0, -100px, 60px, 60px, "span.icon", $quick_start_sprite)
&#i-am
+sprite_icon(-140px, -100px, 60px, 60px, "span.icon", $quick_start_sprite)
&#my-status
+sprite_icon(-279px, -100px, 60px, 60px, "span.icon", $quick_start_sprite)
&:before
color: #ececec
content: ‘»’
font-size: 60px
font-weight: normal
left: -40px
position: absolute
top: -20px
&:first-child
margin-left: 0
&:before
content: ”
span.icon
display: inline-block
span.label
display: block
text-align: center
Just so you know, here are some mixins I use here:
- +reset is just a simple mixin we drop in to kill the padding and margin on an element.
- +alternate_header_font is what we use to drop in Lucida Grande. It also adjusts the
letter-spacingwhen that typeface is used. - +sprite_icon is totally badass. Using syntax like
+sprite_icon(-279px, -100px, 60px, 60px, "span.icon", $quick_start_sprite), I can (in one line) establish which sprite to use ($quick_start_spriteis a variable that directs to the path of the image), which element to apply the mixin to (span.icon), set the background positioning (-279px -100px) and the height and width (60px and 60px). It’s basically magic.
But today, I want to focus on this part:
li
position: relative
&:before
color: #ececec
content: ‘»’
font-size: 60px
font-weight: normal
left: -40px
position: absolute
top: -20px
&:first-child
margin-left: 0
&:before
content: ”
Those right angle quotes between the images bugged me a bit. They certainly shouldn’t be list items. In fact, they’re purely presentational, so they shouldn’t appear in the markup at all. I originally thought “background-image“. But a right angle quote is just text. That seemed like overkill. So, I opted for pseudo-elements.
Once I created the angle quotes using the :before pseudo-element (content: '»'), they stacked themselves on top of the images. That’s no good. So, I tried absolutely positioning them. It never occurred to me until yesterday that I could absolutely position generated content. But it was easy.
I used the :first-child pseudo-element to nix the margin on the first list item and then used two pseudo-elements at once to remove (yup, that’s a selector that looks like ol#steps li:first-child:before) the generated content from the first list item.
As this dude would say, KA CHOW.
“But Adam, what about IE???” IE9? You’re covered. IE8? You’re also fine. IE7 and IE6? Guess what? They won’t appear. You’ll see three icons, but no angle braces. This works for me. It should work for you. This isn’t like your logo is missing or something. They are presentational angle quotes.
If not showing the angle quotes in IE7 and IE6 really bugs you, you could make a background image and serve it just to those two “browsers”. Seriously, have fun with that.