Add border as wide as the longest text line of multiline h1

Viewed 266

I need to decorate some pretty big multiline headlines with a thick border above them. The border should always be as long as the longest line in the text block, but no longer than that. Here's an image to illustrate what it should look like: enter image description here

I found a whole bunch of question that address similar issues, but nothing that quite fit my problem.

So far I've tried different approaches, which can be found in the fiddle below.

  • Set the headline to inline-block and adding a top border or :before element, which works perfectly for single-line headlines, but as soon as the text wraps, the inline-block element expands to 100% width and the border ends up too long. (corresponds to the yellow & red borders in the fiddle)
  • Wrapped the text in a span, setting the span relative and tried to absolutely position a border. This worked well when the last line of text is the longest, but when the last line was shorter than the ones before, the border ends up too short. (corresponds to the blue borders in the fiddle)
  • Add border-top on the inline-element, which of course results in borders on all lines of text. Something like the :first-line pseudo-class might help here, but I couldn't find anything like that.

I also tried fiddling around with setting display: inline-block; and settings width: max-content or width: fit-content, but those only worked for my problem when I manually added line-breaks, not when the text wrapped on its own.

https://jsfiddle.net/rj8k2tmg/56/

body {
  width: 700px;
}

h1 {
  font-family: sans-serif;
    margin-top: 0.75em;

    position: relative;
    max-width: max-content;

    text-transform: uppercase;
}

.headline:before {
  content: '';
  display: block;
  position: relative;
  top: 0;
  left: 0;
  right: 0;
  border: 0;
  border-top: 4px solid red;
}


.headline__wrapper {
  display: inline;
  position: relative;
}

.headline__wrapper:before {
  content: '';
  display: block;
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  border: 0;
  border-top: 4px solid blue;
}

.headline__inline-border {
  border-top: 4px solid green;
}
<p>Before Element on headline, doesn't fit when text wraps</p>
<h1 class="headline">
  Short headline
</h1>

<h1 class="headline">Long headline that wraps, first&nbsp;line&nbsp;shorter&nbsp;than&nbsp;the&nbsp;2nd</h1>


<h1 class="headline">Long&nbsp;headline&nbsp;that&nbsp;wraps, the 2nd line should be shorter.</h1>

<hr>

<p>Works fine for cases 1 and 2, but not for case 3 where the second line is shorter.</p>

<h1 class="headliner__w-wrapper">
  <span class="headline__wrapper">
     Short headline
  </span>
</h1>

<h1 class="headliner__w-wrapper">
  <span class="headline__wrapper">
    Long headline that wraps, first&nbsp;line&nbsp;shorter&nbsp;than&nbsp;the&nbsp;2nd
    </span>
</h1>


<h1 class="headliner__w-wrapper">
  <span class="headline__wrapper">
    Long&nbsp;headline&nbsp;that&nbsp;wraps, the 2nd line should be shorter.
    </span>
</h1>

<hr>

<p>Border-top on inline-wrapper / Adds border on all lines</p>

<h1 class="headliner__w-wrapper">
  <span class="headline__inline-border">
     Short headline
  </span>
</h1>

<h1 class="headliner__w-wrapper">
  <span class="headline__inline-border">
    Long headline that wraps, first&nbsp;line&nbsp;shorter&nbsp;than&nbsp;the&nbsp;2nd
    </span>
</h1>

<h1 class="headliner__w-wrapper">
  <span class="headline__inline-border">
    Long&nbsp;headline&nbsp;that&nbsp;wraps, the 2nd line should be shorter.
    </span>
</h1>

2 Answers

Try this:

  1. Add border to your heading.
  2. Give the heading display: inline-block;

Here's an example:

HTML:

<h1>Add border 
as wide 
as the longest text line blah
of 
multiline h1</h1>
<p>Some more page content</p>

CSS:

h1 {
    display: inline-block;
    border-top: 2px solid #000;
    white-space: pre-wrap;
}

white-space: pre-wrap; isn't necessary, it's only here to give you more control over the line lenght in the heading (the lines will break where you break them in the HTML code). :-)

Since this is not possible with any normal methods, I thought I'd try something a bit weird, so here's a (not very pretty) proof of concept:

  • Using one of the few properties that still works line-by-line, we add a massive border-top to each row of the title, which will stretch over the above lines and reach the desired location (The extra is cut off with an overflow: hidden)

This leaves us with something like this: Example with visible borders

  • Then use the mix-blend-mode (Documentation)(Browser support) along with a linear gradient background, to effectively "mask" the border to the top 4px of the span.

.tester {
  resize: both;
  overflow: auto;
  border: 2px solid #555;
  padding: 20px 0;
}

.headline {
  position: relative;
  background-color: #fff;
  font-family: sans-serif;
  margin-top: 0.75em;
  max-width: max-content;
  text-transform: uppercase;
  overflow: hidden;
  padding-top: 4px;
}

.headline span {
  border-top: rgba(0,0,0,0.5) 1000px solid;
}

.headline::after {
  position: absolute;
  content: '';
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: linear-gradient(180deg, #000 0%, #000 4px, #fff 4px, #fff 100%);
  mix-blend-mode: color-dodge;
}
You can resize this container:
<div class="tester">
  <h1 class="headline"><span>This is a long headline that should wrap in various places.</span></h1>
</div>

(The above example is resizable to test other title lengths)

Again: This is definitely not good enough for customer facing content in this state, but perhaps someone who is more familiar with blend modes can take this approach and make it viable.

Related