1

I'm trying to create a webapp where I need to render user entered title and content. I'd like to render all the action buttons related to the title on the same line as the last word of the title ("displays" in the demo) if the action bar fits, or on the next line if there's not enough space to fit whole action bar on the same line.

I've created a demo which results in correct rendering here: https://jsfiddle.net/mtrantalainen/h6qyv7a4/1/ (Note how this results in nice rendering in all cases, including the case where everything fits on one line on wide display, all to the way to case where buttons barely fit on a single line alone. I've tested the demo with Chrome and Firefox only.)

Same demo here inline:

header
{
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
}

header > span /* I would like to h1 here instead */
{
  font-size: 2rem;
  outline: dotted 1px #ddd;
}

.buttons
{
  display: flex;
  flex: 1 0 auto;
  flex-wrap: nowrap;
}

.buttons a
{
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 auto;
  padding: 0.5rem;
  box-sizing: border-box;
  border: solid red 1px;
  cursor: pointer;
}

.buttons .fill
{
  flex: 1 0 auto;
  background: yellow;
}
<header>
<span>Here's</span> <span>lots</span> <span>of</span> <span>text</span> <span>as</span> <span>a</span> <span>header</span> <span>which</span> <span>cannot</span> <span>easily</span> <span>fit</span> <span>on</span> <span>one</span> <span>line</span> <span>on</span> <span>most</span> <span>displays</span>
<div class="buttons">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</div>
</header>

Screenshot (this is also the rendering I want): screenshot displaying the result when title takes one and a half lines

The intent is to keep all the action buttons with red borders on the same line and fit the whole action button block on the line with the last word of the title, if possible. The yellow area in the middle of action bar would be transparent filler with zero or more pixels and allows positioning selected actions near the title or the right margin if there's extra space on line.

The demo works by wrapping every word in the title as a separate <span> element and flex-wrap is used to allow title to wrap and the action bar to follow on the same line.

However, this doesn't allow semantic markup because I cannot even wrap all the words in an <h1> element. In addition, the current demo doesn't play nicely with copy-pasting the title because every word will end up on separate line if copied.

Can anybody suggest any way to result in similar rendering using only HTML5 and CSS given following markup?

<header>
<h1>Here's lots of text as a header which cannot easily fit on one line on most displays</h1>
<nav class="actions">
    <a>1</a>
    <a>2</a>
    <a>3</a>
    <span class="fill"></span>
    <a>4 with long label</a>
    <a>5</a>
</nav>
</header>

Another possibility for the actions markup in semantic way would be

<div class="actionbar">
<nav class="titleactions">
    <a>1</a>
    <a>2</a>
    <a>3</a>
</nav>
<nav class="extraactions">
    <a>4 with long label</a>
    <a>5</a>
</nav>
</div>

with the whole <header> as above. I used span.fill in the demo because it was easiest to implement and doesn't mess with the semantics too bad.

Mikko Rantalainen
  • 14,132
  • 10
  • 74
  • 112
  • Note that it's obviously possible to emit semantic markup and use JavaScript to convert it into demo markup for rendering but the semantic content is still lost in that case. And copy-paste still wouldn't work correctly. – Mikko Rantalainen Mar 18 '21 at 16:31
  • 2
    Please edit your question so that your [mcve] is here and not only at jsFiddle. The snippet feature in the editor can do what jsFiddle does – j08691 Mar 18 '21 at 16:32
  • I don't understand, you want the red buttons action bar to be on a single line (not near the big black title) and fit the screen on width? – Richard Mar 18 '21 at 16:41
  • 1
    You're essentially asking for the anchor elements to be _inside_ the rendering box of the heading, but without being inside the element. That's a tough one. Efforts to [add ellipses to strings of text](https://stackoverflow.com/a/24942428/1264804) in years past come to mind. – isherwood Mar 18 '21 at 16:44
  • @isherwood Yes, it could be considered to be logically close to `display:run-in` in reverse. Some kind of hack with `display:contents` might be possible, too. – Mikko Rantalainen Mar 18 '21 at 16:54
  • @Richard the title should be wrapped to *container width* and action bar should be put on the same line with the title if the whole bar can fit after the end of title within the container. Otherwise, the bar should be rendered on next line with the fill in the middle. Try the demo with different viewport widths. – Mikko Rantalainen Mar 18 '21 at 16:56
  • 1
    @j08691 Thanks, I wasn't aware of the snippet feature. I added inline demo here in stackoverflow, too. – Mikko Rantalainen Mar 18 '21 at 17:12

2 Answers2

0

I am not sure that I understood your question well but is that what you are looking for?

header
{
  display: flex;
  gap: 0.5em;
}

header > h1/* I would like to h1 here instead */
{
  font-size: 2rem;
  outline: dotted 1px #ddd;
}

.buttons
{
  display: flex;
  flex: 1 0 auto;
  flex-wrap: nowrap;
 width: 40%;
}
.spanDiv { width: 60%}

.buttons a
{
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 auto;
  padding: 0.5rem;
  box-sizing: border-box;
  border: solid red 1px;
  cursor: pointer;
}

.buttons .fill
{
  flex: 1 0 auto;
  background: yellow;
}
<header>
<div class="spanDiv">
<h1>Here's lots of text as  eader which cannot easily fit on one lineon most displays</h1>
</div>
<div class="buttons">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</div>
</header>
Evren
  • 4,147
  • 1
  • 9
  • 16
  • The action bar should be on the same line with the *last* word of the title (here "displays") or if it cannot fit, on the next line. As I wrote, I want the same rendering as the demo in the question, just with more semantic markup if possible. – Mikko Rantalainen Mar 18 '21 at 17:07
0

The least bad implementation I can figure out:

header
{
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
}

header > h1
{
  display: contents;
}

header > span
{
  font-size: 2rem;
  outline: dotted 1px #ddd;
}

.buttons
{
  display: flex;
  flex: 1 0 auto;
  flex-wrap: nowrap;
}

.buttons a
{
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 auto;
  padding: 0.5rem;
  box-sizing: border-box;
  border: solid red 1px;
  cursor: pointer;
}

.buttons .fill
{
  flex: 1 0 auto;
  background: yellow;
}
<header>
<h1><span>Here's</span> <span>lots</span> <span>of</span> <span>text</span> <span>as</span> <span>a</span> <span>header</span> <span>which</span> <span>cannot</span> <span>easily</span> <span>fit</span> <span>on</span> <span>one</span> <span>line</span> <span>on</span> <span>most</span> <span>displays</span></h1>
<div class="buttons">
<a>1</a>
<a>2</a>
<a>3</a>
<span class="fill"></span>
<a>4 with long label</a>
<a>5</a>
</div>
</header>

Problematic parts remaining:

  • Copy-paste is still broken (tested with Chrome only).
  • The display: contents browser support is still a bit poor.
  • Every word in the title still needs a separate wrapper <span> element.
  • Words in the title cannot ever hyphenate.
  • span.fill needed to introduce the space.
Mikko Rantalainen
  • 14,132
  • 10
  • 74
  • 112