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>

8
  • 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. Commented May 29, 2015 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. Commented May 29, 2015 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. Commented May 30, 2015 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 Commented May 30, 2015 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). Commented Jun 1, 2015 at 1:07

8 Answers 8

4
+100

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>

Sign up to request clarification or add additional context in comments.

4 Comments

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.
so you don't care if the annotations are not above the content? Because that's what will happen if the annotation gets bigger.
Precisely. See the last example in the question.
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.
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.

1 Comment

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.
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.

3 Comments

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.
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?
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.
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>

3 Comments

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.
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.
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.
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

Comments

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>

Comments

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>

1 Comment

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.
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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.