How to fill remaining space on last line for wrapped text? - html

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

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>

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.

Related

How do I get flex elements not to grow on click?

Hobbyist who really sucks at css.
I have the following three divs:
The problem is, when I click on the middle one, the box grows, and so do the other two boxes:
How do I make boxes start off and stay the same size even after click. The reason the box is growing is do to adding the "arrow-icon"
Code looks like this:
HTML
<section class='modes-flex__options'>
<div class='options'>
<h2 class='options__title'>Options</h2>
<div class='options__item-container'id='1v1' onClick="selectedGameOption(this.id)">
<h3 class='options__item'>Player vs AI (1 v 1) </h3>
<div class='arrow-icon__div'>
<i></i>
</div>
</div>
<div class='options__item-container' id='1v1-tourny' onClick="selectedGameOption(this.id)">
<h3 class='options__item'>Player vs AI (Tournament)</h3>
<div class='arrow-icon__div'>
<i></i>
</div>
</div>
<div class='options__item-container' id='ai-v-ai-tourny' onClick="selectedGameOption(this.id)">
<h3 class='options__item' >AI vs AI (Tournament)</h3>
<div class='arrow-icon__div'>
<i></i>
</div>
</div>
</div>
</section>
CSS
.modes-flex{
display: flex;
margin-top: 3rem;
&__options{
flex:1;
display: flex;
justify-content: end;
}
&__description{
flex:1;
display: flex;
flex-direction: column;
}
}
.options{
margin-right: 5rem;
&__title{
font-size: 1.2rem;
padding-bottom:2rem;
}
&__item{
flex: 1;
padding-right: 5rem;
}
}
.description{
&__title{
font-size: 1.2rem;
padding-bottom:2rem;
}
}
.options__item-container {
padding: 1.5rem 1rem 1.5rem 1rem;
margin-bottom: 2rem;
box-shadow: 0 0 10px lightgrey;
border: 1px solid lightgrey;
display: flex;
align-items: center;
&:hover{
cursor: pointer;
}
}
.arrow-icon__div{
text-align: right;
}
.active-option{
background-color: $dark-navy;
color: white;
}
Tried to set min and max width and was still growing , just want them to stay even width after adding the icon.
You said it: The reason the box is growing is do to adding the "arrow-icon".
In my experience, in these situations, I always added to the default size of the boxes so that when another element (i.e. arrow-icon) is added, it doesn't change the size. (Because there is enough space in the box for arrow-icon to be added). With doing so, all the boxes remain the same through any actions.

Center a paragraph element when text wraps without centering the text using flex

Before this gets down-voted into oblivion, let me say I've searched through the numerous SO questions that looked similar to this one, but none that I found addressed my issue.
I'm using flexbox to center some <p> tags both horizontally and vertically within an element. I don't want to center the text within the <p> element, just center the <p> elements themselves.
.app-outer {
display: flex;
flex-direction: column;
}
.app {
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
align-items: center;
}
.app p {
display: inline-block;
}
.title-bar {
background-color: #202225;
color: #72767D;
font-weight: bold;
padding: 0 0 2px 8px;
display: flex;
flex-direction: row;
width: 100%;
}
<div class="app-outer">
<div class="title-bar">
<span class="draggable">Skipwars</span>
<span class="btns">
<button id="btn-minimize" tabindex="-1">-</button><!--
--><button id="btn-close" tabindex="-1">×</button>
</span>
</div>
<div class="app">
<p>Add a browser source pointed at <!--http://localhost:3333/--></p>
<p>
Optional parameter <code style="display:inline">threshold=n</code>. ex: http://localhost:3333/?threshold=4 (default 8)
</p>
</div>
</div>
My app is 300px wide (I'm using electron).
As you can see, if the paragraph doesn't have enough text for multiple lines, it works fine. If it does, the paragraph expands to the width of .app, and the text is left-justified.
This is what I'm looking for:
I thought that setting the paragraphs' display to inline-block would do the trick, but it doesn't.
It's working as expected, but since the <p> tags are the same width as the viewport, they are flush to the left when the vp is too small, and in this case the url is so long that it wraps to the next line and leaves a space on the first, making it appear that it is not centered. I added some horizontal padding to the <p> tags to better illustrate:
.app-outer {
display: flex;
flex-direction: column;
}
.app {
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
align-items: center;
}
.app p {
display: inline-block;
padding: 0 20px;
}
.title-bar {
background-color: #202225;
color: #72767D;
font-weight: bold;
padding: 0 0 2px 8px;
display: flex;
flex-direction: row;
width: 100%;
}
<div class="app-outer">
<div class="title-bar">
<span class="draggable">Skipwars</span>
<span class="btns">
<button id="btn-minimize" tabindex="-1">-</button><!--
--><button id="btn-close" tabindex="-1">×</button>
</span>
</div>
<div class="app">
<p>Add a browser source pointed at
<!--http://localhost:3333/--></p>
<p>
Optional parameter <code style="display:inline">threshold=n</code>. ex: http://localhost:3333/?threshold=4 (default 8)
</p>
</div>
</div>

Flexbox content not spreading evenly with links and images

I'm using flex to build footer. I want the footer to be 60% of the width of the website and centered which is working perfectly. When I add content into the footer of text, links, and image links and try to justify space-evenly it doesn't work properly and there is a lot of extra white space on the right side within the footer. How do I remove it?
Footer
CSS
.site-wide-footer {
display: flex;
flex-wrap: wrap;
width: 60%;
height: auto;
border: 2px solid black;
border-radius: 24px;
color: white;
background-color: black;
margin: auto;
justify-content: space-between;
align-items: center;
}
HTML
<footer>
<div class="site-wide-footer">
<p>© 2018 copyright</p>
<p> ♦STORE</p>
<p>♦ABOUT US</p>
<p>♦SITEMAP</p>
<div class="social-footer">
<p><a href="discord url">
<img src="images/Discord-Logo-White.png" alt="Discord Logo"
class="discord-footer" onmouseover="hover(this);"
onmouseout="unhover(this);"></a>
<a href="facebook url/"><img
src="images/facebook-icon.png" alt="Facebook Icon" class="facebook-
footer"></a></p>
</div>
</div>
</footer>
How about using justify-content: space-evenly; instead? It will also make sure the the child elements are still centered even when it is wrapped over to the next line.
I think you might want to consider setting a flex rule for the flex-box children.
I'm not sure I understand what exactly you try to achive, but if you play with this flex rule, you can achieve a lot.
.site-wide-footer {
display: flex;
flex-wrap: wrap;
width: 60%;
height: auto;
border: 2px solid black;
border-radius: 24px;
color: white;
background-color: black;
margin: auto;
justify-content: space-around; /*you can play with it*/
align-items: center;
padding: 0 15px 0; /*fixed space on left and right of the flex-box*/
}
.site-wide-footer > { /*flex-box children */
flex: 1 0; /*play with this one a bit. you could also give it a minimum width like that: flex: 1 0 100px;*/
}`
And of course, you may find all the answers on this Complete Guide to Flexbox
Itamar

CSS button like vertical align feature

Pre History
I am building html form, with elements having multiple options ...., but instead of showing it as dropdown, i would like to show them as buttons without using any js, I removed buttons with label pointing to input checkbox.
Problem
I need label (or anchor or div) tag behave exactly like button tag without any extra wrapper tags, I googled all variation doesn't provide same result as native tag button.
<button class="button">
Text
<div>Small Text</div>
</button>
Solutions not work
line-height, padding does not provide same functionality, because button height/width and text length may vary. I tried special webkit style -webkit-appearance: button; no changes.
Mustery Flex
I tried flex
.button {
flex-wrap: wrap;
align-items: center;
justify-content: center;
display: inline-flex;
}
<div class="button">
Text
<div>Small Text</div>
</div>
but child div inside button not breaking/warping to new line.
p.s Environment tested, Google Chrome, Safari
I found solution using flex with flex-direction: column; so text and div treats like column items, here is code
label.button {
flex-direction: column;
justify-content: center; /* <-- actual veertical align */
display: inline-flex;
text-align:center;
}
JS Fiddle Demo
Does this does the job ?
div.button {
align-items: center;
text-align: center;
display: inline-block;
border: 1px solid black;
}
div.button div {
clear: both;
}
<div class="button">
Text
<div>Small Text</div>
</div>
Ghost element trick looks work well.
.wrap {
text-align: center;
background: #ededed;
margin: 20px;
}
.wrap:before {
content: '\200B';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.centered-guy {
display: inline-block;
vertical-align: middle;
width: 300px;
padding: 10px 15px;
border: #777 dotted 2px;
background: #666;
color: #fff;
}
<div class="wrap" style="height: 512px;">
<div class="centered-guy">
<h1>Some text</h1>
<p>Bool!<br>Look at me, mama!</p>
</div>
</div>

Break elements onto new line with flex-grow and flex-wrap

I have a parent div (.tags) that contains links and a title.
The parent div is set to display: flex; with flex-wrap: wrap;.
I would like the link elements to break onto a new line, clearing the title when the wrap effect takes place.
I have tried using flex-grow: 1 on the title, but this makes it push the links to the right of the screen at all times, which is not what I am after.
I have attached the code I have so far, but here is a link to the Codepen
What I am trying to achieve:
Default - the width of the screen is large enough so nothing wraps and everything is on one line >
Wrapped - the width of the screen is smaller, the wrap has occurred - the title now has 100% width and the links clear it >
Note that the number of links could vary.
.container {
background: lightgray;
width: 100%;
}
.tags {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
}
.tags span {
margin: 1rem;
}
.tags .tag {
margin: 0.2rem;
padding: 0.2rem;
background: dodgerblue;
color: white;
}
<div class="container">
<div class="tags">
<span>Tagged in:</span>
<a class="tag" href="#">capabilities</a>
<a class="tag" href="#">sales</a>
</div>
</div>
Yes, with a change in the structure.
Wrap the tags in their own div with flex:1. Then it will expand automatically and the tags will drop to the second line when the wrap occurs.
.container {
background: lightgray;
width: 100%;
}
.tags {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
}
.tags span {
margin: 0 1rem;
}
.tags .tag-wrap {
display: flex;
flex: 1;
}
.tags .tag {
margin: 0.2rem;
padding: 0.2rem;
background: dodgerblue;
color: white;
}
<div class="container">
<div class="tags">
<span>Tagged in:</span>
<div class="tag-wrap">
<a class="tag" href="#">capabilities</a>
<a class="tag" href="#">sales</a>
</div>
</div>
</div>
Codepen Demo
flex grow of 1, flex shrink of 0, flex basis auto:
span {
flex:1 0 auto;
}