Tatjana Heuser
Tatjana Heuser

Reputation: 1019

Semantic way of stacking two characters in a ::before element?

I'm trying to add checklist symbols to the left edge of table cells. So far, this does work. When I'm trying to stack another char on top of the checklist symbol though, things get ugly. I have found several ways to achieve the result I'm after, but none of them looks particularly good to me. Does anyone have a better idea, preferably one that'd allow to concentrate on the semantics?

.checklist::before {
  content: "◯ ";
}
.checklistabs::before {
  content: "◯ ";
  position: absolute;
}
.check::before {
  content: " ✘";
  position: absolute;
  font-size: 130%
}
.checked {
  position: absolute;
  font-size: 130%
}
.checklisttext {
  margin-left: 1.5em;
}
<table>
  <tr>
    <td class="checklist">
      perfect as long as nothing needs to be overlaid 
    </td>
  </tr>
  <tr>
    <td>
      <b class="checked">✘</b>
      ◯ Seems to work best, but has explicit bullet symbol as part of the text.
    </td>
  </tr>
  <tr>
    <td>
      <div class="checklistabs" />
      <div class="check" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If the bullet symbol goes into another absolutely positioned item, we need to make space at the beginning of the text. ::before would have been much more elegant.
    </td>
  </tr>
  <tr>
    <td class="checklist">
      <div class="check" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;why does this introduce a linebreak?

    </td>
  </tr>
  <tr>
    <td class="checklistabs">
      <div class="check" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Saving on divs
    </td>
  </tr>
  <tr>
    <td>
      <div class="checklistabs" />
      <div class="check" />
      <div class="checklisttext">So this works...</div>
    </td>
  </tr>
  <tr>
    <td class="checklist check">
      Looks preferrable from a semantic point of view but does not work - see http://stackoverflow.com/questions/11998593/can-i-have-multiple-before-pseudo-elements-for-the-same-element
    </td>
  </tr>
</table>

Upvotes: 0

Views: 99

Answers (2)

pstenstrm
pstenstrm

Reputation: 6489

If you position both the ::before and ::after absolutely and add a padding to the <td> element you can get the effect you want. It requires more CSS and some values heavily tied to your font-size. But if you change the px values to em it should scale well.

table {
  width: 350px;
}
 
.checklist {
  padding: 0 0 0 20px;
  position: relative;
}

.checklist::before,
.checked::after {
  position: absolute;
  left: 0;
  top: 0;
  width: 17px;
  text-align: center;
  line-height: 20px;
}

.checklist::before {
  content: "◯ ";
}

.checked::after {
   content: " ✘";
   font-size: 130%;
}
<table>
  <tr>
    <td class="checklist checked">
      A little more CSS and positioning, but will work well if the text linebreaks.
    </td>
  </tr>
</table>

Upvotes: 2

Michael Coker
Michael Coker

Reputation: 53709

I would display the ◯ as an inline element, then place the ✘ over it using absolute positioning. Seems to work without any unnecessary markup.

.checklist:before {
  content: "◯ ";
}
.checklist:after {
  content: " ✘";
  position: absolute;
  left: .6em;
  font-size: 1.3em;
  top: .6em;
}
<table>
  <tr>
    <td class="checklist">
      perfect as long as nothing needs to be overlaid perfect as long as nothing needs to be overlaid perfect as long as nothing needs to be overlaid perfect as long as nothing needs to be overlaid perfect as long as nothing needs to be overlaid 
    </td>
  </tr>
</table>

why does this introduce a linebreak?

Because .check is a div with display: block; so it's contents will display on it's own line. Set it to display: inline-block; or apply float: left; to the .checklist:before element, and those elements will be on the same line.

Upvotes: 1

Related Questions