2

I have some text which is constrained to a particular width, so it wraps. I want to display a border around the wrapped text. When I add a border, it wraps the text plus the unused space around it. Is there a way to apply the border to just the text? Here's an illustration of what I mean: I have drawn a red line where I want the right-hand edge of the element to be:

enter image description here

HTML:

  <div>
    Supercalifragilistic expialidocious
  </div>

CSS:

div {
  max-width: 200px;
  display: inline-block;
  border: 1px solid black;
}

JSFiddle

Alex
  • 7,639
  • 3
  • 45
  • 58

1 Answers1

0

Could work for short text. Combining attr() and pseudo.

.outer {
  width: 200px;
  background-color: #ccc;  
  border: 1px solid black;
  display: inline-block;
}
.inner {      
  display: inline;
  position:relative;
}
.inner:before {
  content: attr(data-text) " ";
  color: transparent;
  position: absolute;
  left:0;top:0;
  border: 1px solid red;
  pointer-events: none;
}
<div class="outer">
  <div class="inner" data-text="Supercalifragilistic expialidocious">Supercalifragilistic expialidocious</div>
</div>

Edit: Absolute positioning inside inline elements & limitations of the above example.

From CSS2.1 specs 10.1.4: if an element is absolute positioned inside a inline element spanning multiple lines, its containing block is undefined.

By defining the top and left positions,we get the browsers to align the pseudo to the corresponding top and left edges of the first box created by its 'ancestor'. By definition, pseudo is a virtual child of any selected element and an absolute looks for a nearest positioned ancestor. Though the inline rule points to no containing block, the position rule works in favour for the top/left sides.

We then allow the pseudo to take the height as computed from its content/intrinsic dimension. Since attr() pulls the same content, it more or less overlaps well on the text in its ancestor. (when without any font inconsistencies).

But do note, while it may work for single line text its dependent on the white-space/wrap/font and its not consistent across browsers when dealing with multi-line inline elements.

Here is what I mean.

.outer {
  width: 200px;
  background-color: #ccc;
  border: 1px solid black;
  margin-bottom: 30px;
  font-family: monospace;
}
.inner {
  color: black;
  position: relative;
}
.inner:after {
  content: attr(data-text) " ";  
  position: absolute;
  left:-1px;top:-1px;right:-1px; /* compensating for the border */
  pointer-events: none;
  color: transparent;
  border: 1px solid red;
}
<div class="outer"><span class="inner" data-text="single line inline">single line inline</span></div><div class="outer"><span class="inner" data-text="This is a multi-line inline element which may not hold an absolute positioned pseudo element. Fails in Chrome.">This is a multi-line inline element which may not hold an absolute positioned pseudo element. Fails in Chrome.</span></div>
Community
  • 1
  • 1
AA2992
  • 1,559
  • 3
  • 17
  • 23
  • Don't know why you were downvoted. This looks like it could work, although it would be good if you could explain what's happening here. I guess the `::before` pseudo-element takes the width of the `.inner` div by default? – Alex Sep 07 '16 at 14:51
  • Cos its absolute positioned. It doesn't wrap like a normal inline element would. Its fills the parent instead. And cos the parent is an inline element setting border the way you need would be easy. – AA2992 Sep 07 '16 at 14:57