Skip to content

Understanding :before and :after

I wanted to use the CSS pseudoelement :before for manipulating input elements. I had <input class="before-test"/>, and I wanted to use CSS to add a label before the element on small screens only (on a larger screen I would have a table with the label as the <th> element). So

<style>
  .before-test:before { content: "label: "; }
</style>

ought to work, right?

No.

:before,despite its name, doesn't insert its content before the element specified. It inserts the content as the first child of the element specified. In other words, it works like jQuery's prepend, not like before. See Smashing Magazine's article for more details.

So the correct way to do this is:

<div class="before-test"><input/></div>

With the selector targeting the enclosing element.

Why bother:

Trying to make an order form responsive. It looks basically like this:

<form id=exampleform>
  <label>Your Name: <input /></label>
  <table>
    <thead>
      <tr><th>Item</th><th>Quantity</th></tr>
    </thead>
    <tbody>
      <tr><td><input/></td><td><input/></td></tr>
      <tr><td><input/></td><td><input/></td></tr>
      <tr><td><input/></td><td><input/></td></tr>
      <tr><td><input/></td><td><input/></td></tr>
      <tr><td><input/></td><td><input/></td></tr>
    </tbody>
  </table>
  <input type=button value="Enter Order" />
</form>

Which is all well and good, and an appropriate use of a <table>. But when the window shrinks (or we're looking at a small screen) the table overflows horizontally. We don't want to have to scroll horizontally! So we can use a media query to change the table to a bunch of vertically oriented blocks when appropriate:

@media (max-width: 480px) {
  form tr, form th, form td { display: block; }
}

But now, the table headers don't correspond to the input elements. So we need to label them. I'd like to use CSS rather than Javascript, so everything remains fluid without having to track window resizing events. So I just use Javascript to add the appropriate header as a <code>data- attribute, and display that:

$('#exampleform tr').each(function(){
  $('td',this).each(function(i){
    this.setAttribute("data-label",$('th', '#exampleform').eq(i).text()+': ');
  });
});

And we use CSS to display it (I also hide the now-useless header with clip, the way WordPress does, so it's not hidden from screen readers):

form td:before { content: attr(data-label); }
form thead { position: absolute !important; clip: rect(1px, 1px, 1px, 1px); }

And thus :before and content: attr come to the rescue.

Post a Comment

Your email is never published nor shared. Required fields are marked *