15

Update

I put up a bounty, but a correct answer was never achieved. I have implemented a JS solution that works for me, but I'm not going to mark an answer as correct just yet. If it is possible with just CSS/HTML, I would still love to see it. But the general consensus is that it's not currently possible.

The Goal

CodePen here, runnable snippet at the bottom.

I have some HTML content that I would like to annotate with a small message floating directly above it, on the far left side, kind of like <ruby> annotations (but not exactly). There can be many pieces of content each with their own annotations. The content must follow normal text flow. Here's my current HTML:

<div class='item' style='color: red'>
  <div class='annotation'>nope</div>
  <div class='content'>It's a bird, </div>
</div>
<div class='item' style='color: green'>
  <div class='annotation'>still no</div>
  <div class='content'>it's a plane, </div>
</div>
<div class='item' style='color: blue'>
  <div class='annotation'>yeah!</div>
  <div class='content'>it's Superman! </div>
</div>
<div class='item' style='color: orange'>
  <div class='annotation'>muahaha</div>
  <div class='content'>Go get the Kryptonite</div>
</div>

Working Example

Below, the sentence It's a bird, it's a plane, it's Superman! Go get the Kryptonite has 4 separate parts (4 pieces of content), each represented by a different color. Each piece of content has its own annotation, displayed in italics above it.

enter image description here

I have this working by making both the content and the annotation float: left and giving annotation a negative margin. This is Example 1 in the CodePen.

Broken Example 1

The problem occurs when the annotation is longer than the content. Below, the annotation of still no has changed to the longer you may be right. The two content lines continue to follow normal inline flow (as desired), but because the annotations are still lined up to the left edge of their content, they overlap.

enter image description here

This is Example 2 in the CodePen.

Broken Example 2

A proposed solution was to use a table with visibility:collapse to do the alignment, which works well at preventing overlap, but it results in extra space after the annotations, in cases where the annotation starts past the left edge of the content.

Broken ex 2

How It Should Work

I want the annotations to follow their own flow, but without breaking the natural inline flow of the content. See below how the content line is still a single unbroken sentence, but yeah! gets shifted over to the right to allow the long you may be right to have all the room it needs. However, the muahaha corrects back, because it has room to sit directly atop Go get the kryptonite.

enter image description here

I can change both the CSS and the HTML to make this happen, but a CSS-only solution would be optimal. Thanks.

.item {
  margin-top: 20px;
}
.content, .annotation {
  float: left;
  white-space: pre;
}
.annotation {
  margin-top: -25px;
  font-style: italic;
}


h3 {
  clear: both;
  margin: 0;
  padding: 20px 0;
}

td:first-child {
  color: red;
}
td:nth-child(2) {
  color: green
}
td:nth-child(3) {
  color: blue;
}
td:nth-child(4) {
  color: orange;
}
<h3>Working Example</h3>
<div class='item' style='color: red'>
  <div class='annotation'>nope</div>
  <div class='content'>It's a bird, </div>
</div>
<div class='item' style='color: green'>
  <div class='annotation'>still no</div>
  <div class='content'>it's a plane, </div>
</div>
<div class='item' style='color: blue'>
  <div class='annotation'>yeah!</div>
  <div class='content'>it's Superman! </div>
</div>
<div class='item' style='color: orange'>
  <div class='annotation'>muahaha</div>
  <div class='content'>Go get the Kryptonite</div>
</div>


<h3>Broken Example 1 (note the overlap)</h3>
<div class='item' style='color: red'>
  <div class='annotation'>nope</div>
  <div class='content'>It's a bird, </div>
</div>
<div class='item' style='color: green'>
  <div class='annotation'>you may be right</div>
  <div class='content'>it's a plane, </div>
</div>
<div class='item' style='color: blue'>
  <div class='annotation'>yeah!</div>
  <div class='content'>it's Superman! </div>
</div>
<div class='item' style='color: orange'>
  <div class='annotation'>muahaha</div>
  <div class='content'>Go get the Kryptonite</div>
</div>

<h3>Broken Example 2 (note the overlap)</h3>
 <table>
  <tr style='font-style: italic'>
    <td>nope</td><td>you may be right</td><td>yeah!</td><td>muahaha</td>
  </tr>
  <tr style="visibility:collapse;"><td>It's a bird, </td><td>it's a plane, </td><td>it's Superman! </td><td>Go get the kryptonite</td></tr>
</table>
<table style="margin-top:-25px;"><tr><td>It's a bird, </td><td>it's a plane, </td><td>it's Superman!</td><td>Go get the kryptonite</td></tr></table>

<h3>How it should look (cheating with positioning)</h3>
<div class='item' style='color: red'>
  <div class='annotation'>nope</div>
  <div class='content'>It's a bird, </div>
</div>
<div class='item' style='color: green'>
  <div class='annotation'>you may be right</div>
  <div class='content'>it's a plane, </div>
</div>
<div class='item' style='color: blue'>
  <div class='annotation' style='margin-left: 35px'>yeah!</div>
  <div class='content'>it's Superman! </div>
</div>
<div class='item' style='color: orange'>
  <div class='annotation'>muahaha</div>
  <div class='content'>Go get the Kryptonite</div>
</div>
Brandon Horst
  • 1,921
  • 16
  • 26
  • Does the annotation need to be visible at all times? I imagine you could resolve your overflow issue by doing some kind of hover instead of having everything up at once. It could get pretty confusing to the end-user if they can't tell the difference between annotated text and regular text. – CIA May 29 '15 at 18:44
  • In the real use-case, the annotation is going to be about half the font size of the content, so the confusion shouldn't be a problem. I want the ability to see all of the annotations at the same time, but I am investigating some other solutions at this point. – Brandon Horst May 29 '15 at 19:45
  • Have you considered a pop-up annotation? or are you set on seeing all annotations at once? Alternatively, you could do something like offsetting the annotations vertically, but that would require huge spacing between lines. – CIA May 30 '15 at 15:08
  • 1
    is it possible to add more informastion to each annotation (e.g `data-size="60"` or even a special `.class`) to signify the size it might have? This is a change in html but the rest can be pure css – Nikos M. May 30 '15 at 20:33
  • That may be the best bet - I could encode the string length of each annotation in the HTML, and then style it accordingly. It's not monospace but these annotations will be fairly controlled (not expecting to see "WWWWWWWWW" or something). – Brandon Horst Jun 01 '15 at 01:07
  • Have you considered that your cheat is not a cheat at all? You could use javascript to detect overlap and apply a margin until there is no overlap. http://stackoverflow.com/questions/12066870/how-to-check-if-an-element-is-overlapping-other-elements – Joseph Casey Jun 02 '15 at 15:54
  • That's the solution that I have implemented currently, and it works alright. It is causing a few performance issues and I wanted a CSS solution - it doesn't appear to be possible. – Brandon Horst Jun 02 '15 at 15:56
  • So none of the answers actually achieved the goal I was shooting for. I'm going to give the bounty to @loli, because he answered the question as it existed, before I added some clarifying details (and it taught me something!). The problem has still never been resolved, though. – Brandon Horst Jun 03 '15 at 14:46

8 Answers8

4

Maybe this will suit you :

<table>
  <tr>
    <td>nope</td>
    <td>you may be right</td>
    <td>yeah it is!</td>
  </tr>
  <tr style="visibility:collapse;">
    <td>It's a bird,</td>
    <td>it's a plane,</td>
    <td>it's Superman!</td>
  </tr>
</table>
<table style="margin-top:-25px;">
  <tr>
    <td>It's a bird,</td>
    <td>it's a plane,</td>
    <td>it's Superman!</td>
  </tr>
</table>
David Mulder
  • 26,123
  • 9
  • 51
  • 114
loli
  • 1,058
  • 8
  • 14
  • This does not allow the annotations to extend further than the content it is annotating, as required for the annotation/content pair (you might be right/it's a plane). Using a table causes it to wrap instead. – Brandon Horst May 26 '15 at 16:26
  • so you don't care if the annotations are not above the content? Because that's what will happen if the annotation gets bigger. – loli May 26 '15 at 16:29
  • Precisely. See the last example in the question. – Brandon Horst May 26 '15 at 16:33
  • That's really slick, but it can't adjust additional annotations to make up for the extra space. I added a 4th annotation/content pair, and "Broken Example 2" to demonstrate the problem. – Brandon Horst May 26 '15 at 17:09
3

http://codepen.io/anon/pen/OVWBLv

I think I got it with just CSS:

.item {
  display: inline-block;
}
.content, .annotation {
  display: inline;
  white-space: pre;
}
.annotation {
  font-style: italic;
}

.annotation:after {
  content: "";
  display: inline-block;
  width: 100%;
}

The pseudo-element forces the content to the next line of the annotation, while the parent .item's are inline-blocked to remain next to each other.

Emily
  • 211
  • 1
  • 4
  • I think the only problem I see with this is that I believe the bottom text is intended to be one contiguous line of text. It almost seems like a paper review web application they is writing. – Joseph Casey Jun 02 '15 at 15:56
1

I'm not sure if that is what you're after, but here is modified CodePen

HTML:

<!-- first group -->
<div class='item'>
  <div class='annotation'>I'm an annotation</div>
  <div class='content'>I am the actual content </div>
</div>
<div class='item'>
  <div class='annotation'>I'm a second annotation</div>
  <div class='content'>I am a second piece of content</div>
</div>

<!-- second group -->
<div class='item'>
  <div class='annotation'>I'm a particularly long annotation</div>
  <div class='content'>I am the actual content </div>
</div>
<div class='item'>
  <div class='annotation'>I'm a second annotation</div>
  <div class='content'>I am a second piece of content</div>
</div>   

CSS:

.item {
  font-size: 20px;
  margin-top: 30px;
  float: left;
}
.content, .annotation {
  white-space: pre;
}
.annotation {
  margin-top: -25px;
  font-style: italic;
}

I basically moved float:left declaration from .content, .annotation elements to .item.

Hope this helps.

robjez
  • 3,740
  • 3
  • 32
  • 36
  • Not exactly. I want the `content` to be unaffected by the `annotations`. In your result, you will see that the `content` that has the `I'm a particularly long annotation` `annotation` has some extra space on its right side. I need it to look like the second Code Block in my question - the `contents` are arranged normally, and the `annotations` fall in line above them. – Brandon Horst May 13 '15 at 15:09
  • I don't think what you're after here is possible in the DOM and box model. At least not without some serious hacking :). May I ask why you need this? If this is crucial I would suggest restructuring you HTML, and wrapping all your `.content` elements into separate 'wrapper', as well as `.annotations`, and start from there. Maybe "flexbox" could help you here? – robjez May 13 '15 at 15:54
  • Working on an NLP tool, and I want to show the user what their sentence components are inline, without breaking the flow of the sentence they have typed. I don't *think* flex allows for this but I could be wrong. – Brandon Horst May 13 '15 at 16:28
0

I'm not entirely clear on what you are after but if there are going to be many annotation for each item/content then it makes sense to wrap these in their own container (say called notes).

Then the annotations can be declared as inline without disrupting the flow of the other elements.

As I said without a better idea of what you are after I think the below is the closest I can come.

Codepen Demo

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.item {
  font-size: 20px;
  float: left;
  width: 50%;
  overflow: hidden;
  margin-bottom: 10px;
  border: 1px solid red;
}
.notes {
  overflow: hidden;
}
.annotation {
  font-style: italic;
  display: inline;
  margin-right: 1em;
}
<div class='item'>
  <div class="notes">
    <div class='annotation'>I'm an annotation</div>
    <div class='annotation'>I'm a second annotation</div>
  </div>
  <div class='content'>I am the first content</div>
</div>
<div class='item'>
  <div class="notes">
    <div class='annotation'>I'm an annotation</div>
    <div class='annotation'>I'm a second annotation</div>
  </div>
  <div class='content'>I am the second content</div>
</div>

<div class='item'>
  <div class="notes">
    <div class='annotation'>I'm an long long long long annotation</div>
    <div class='annotation'>I'm a second annotation</div>
  </div>
  <div class='content'>I am the third content</div>
</div>

<div class='item'>
  <div class="notes">
    <div class='annotation'>I'm an long long long long annotation</div>
    <div class='annotation'>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, aspernatur.</div>
  </div>
  <div class='content'>I am the fourth content</div>
</div>
Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • Your 'diagrams' are all very well but I think we need design images of how this is supposed to look....or at least a live page that shows how this might work. At the moment I cannot really grasp why you are using divs when everything just seems to be a bunch of spans one after another. – Paulie_D May 13 '15 at 15:56
  • Thanks...basically...I don't think you can do this with **any** current layout methods...even flexbox but if someone can prove me wrong it will be interesting. – Paulie_D May 13 '15 at 16:21
  • Yeah, I don't know of any solutions either, but I figured I'd throw it out here in case anyone had any clever ideas. I'll probably start working on a JS solution. – Brandon Horst May 13 '15 at 16:26
0

As the consensus seems to say that it's not possible in CSS alone, I have a JS solution, below, but it has some nasty edge cases with wrapping.

CodePen

Basically putting the annotations and contents on separate lines, inline-block

<div class='annotations'>
  <div class='annotation' style='color: red'>nope</div>
  <div class='annotation' style='color: green'>you might be right</div>
  <div class='annotation' style='color: blue'>hell yeah it is</div>
</div>
<div class='contents'>
  <div class='content'style='color: red'>It's a bird, </div>
  <div class='content' style='color: green'>it's a plane, </div>
  <div class='content' style='color: blue'>it's Superman!</div>
</div>

.content, .annotation {
  white-space: pre;
  display: inline-block;
}
.annotation {
  font-style: italic;
}

And then using JS to set the width of each annotation larger of the two widths (its own or its content's).

const items = _.zip(
  _.toArray(document.getElementsByClassName('annotation')),
  _.toArray(document.getElementsByClassName('content'))
)

_.forEach(items, ([annotation, content]) => {
  const max = Math.max(content.offsetWidth, annotation.offsetWidth)
  annotation.style.width = `${max}px`
})

Results in the desired:

enter image description here

Brandon Horst
  • 1,921
  • 16
  • 26
0

What about something like this? Codepen here.

Edit, 6/1: This answer is the only one that comes even remotely close to solving your problem. Do you just not want multi-line annotations? Keeping the annotations left-aligned and allowing them to wrap to the next line improves clarity and readability for the end user. Would love some feedback!

.content {
      margin: 50px auto;
    }
    .has-annotation {
      position: relative;
      display: inline-block;
    }
    
    .annotation {
      position: absolute;
      bottom: 20px;
      font-style: italic;
    }
    
    #a { color: red; }
    #b { color: green; }
    #c { color: blue; }
    #d { color: orange; }
<div class="content">
      <div class="has-annotation" id="a">
        <span class="annotation">nope</span>
        It's a bird, 
      </div>
      <div class="has-annotation" id="b">
        <span class="annotation">you may be right</span>
        it's a plane, 
      </div>
      <div class="has-annotation" id="c">
        <span class="annotation">yeah!</span>
        it's Superman! 
      </div>
      <div class="has-annotation" id="d">
        <span class="annotation">muahaha</span>
        Go get the Kryptonite
      </div>
    </div>
Anne Gray
  • 99
  • 5
  • No, the whole point is that I do NOT want multi-line annotations. I want the annotations to fill a single line above the single-line of content. It's a strange requirement, but it's what I need. – Brandon Horst Jun 02 '15 at 12:59
0

I have changed the annotation class from div to span and embedded in content div.

http://jsbin.com/qejemeredi/2/

 .item {
  margin-top: 20px;
}

.content {
  float: left;
margin-right:-25px;
}
.annotation {
  margin-top: -25px;
  font-style: italic;
   float: left;
  white-space: pre;

}



td:first-child {
  color: red;
}
td:nth-child(2) {
  color: green
}
td:nth-child(3) {
  color: blue;
}
td:nth-child(4) {
  color: orange;
}

HTML

<div class='item' style='color: red'>

  <div class='content'><span class='annotation'>nope</span> It's a bird,     </div>
</div>

 <div class='item' style='color: green'>

  <div class='content'>
    <span class='annotation'>you may be rightsdfdsg</span>
    it's a plane, </div>
</div>
<div class='item' style='color: blue'>

  <div class='content'><span class='annotation'>yeah!</span>it's Superman! </div>
</div>
<div class='item' style='color: orange'>

  <div class='content'><span class='annotation'>muahaha</span>
    Go get the Kryptonite</div>
</div>
Prime
  • 3,530
  • 5
  • 28
  • 47
0

You may want to following like this:

.item {
  float: left;
  width: calc(100% - 20px);
}
.annotation {
  font-style: italic;
}
.content,
.annotation {
  display: inline-flex;
  float: left;
  min-width: 60px;
  padding: 5px;
  text-align: left;
  white-space: nowrap;
}
h3 {
  clear: both;
  margin: 0;
  padding: 20px 0;
}
<h3>example1</h3>
<div class='item' style='color: red'>
  <div class='annotation'>nope</div>
  <div class='annotation'>you may be right</div>
  <div class='annotation'>yeah!</div>
  <div class='annotation'>muahaha</div>

</div>
<div class='item' style='color: green'>
  <div class='content'>It's a bird,</div>
  <div class='content'>it's a plane,</div>
  <div class='content'>it's Superman!</div>
  <div class='content'>Go get the Kryptonite</div>
</div>
<h3>Example 2</h3>
<div class='item' style='color: red'>
  <div class='annotation'>nope</div>
  <div class='annotation'>Still no</div>
  <div class='annotation'>yeah!</div>
  <div class='annotation'>muahaha</div>

</div>
<div class='item' style='color: green'>
  <div class='content'>It's a bird,</div>
  <div class='content'>it's a plane,</div>
  <div class='content'>it's Superman!</div>
  <div class='content'>Go get the Kryptonite</div>
</div>
Ahosan Karim Asik
  • 3,219
  • 1
  • 18
  • 27