How can I truncate text as the page gets smaller with CSS?
Currently, as the page gets smaller, the text goes under the elements and isn't truncated.
<div class="flex-parent has-child">
<div class="flex-child long-and-truncated-with-child-corrected">
<div class="logo">logo </div>
<div>
<h2> This is a long string that is OK to truncate please and thank you</h2>
</div>
</div>
<div class="flex-child short-and-fixed">
<div></div>
<div></div>
<div></div>
</div>
</div>
.flex-parent {
display: flex;
align-items: center;
padding: 10px;
margin: 30px 0;
}
h2 {
font-size: 1rem;
font-weight: normal;
}
.short-and-fixed {
white-space: nowrap;
> div {
width: 30px;
height: 30px;
border-radius: 10px;
background: lightgreen;
display: inline-block;
}
}
.long-and-truncated-with-child-corrected {
display: flex;
align-items: center;
gap: 20px;
flex: 1;
min-width: 0; /* or some value */
h2 {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
body {
padding: 40px;
}
or try codepen
If users access this on their laptops or tablets, they will be able to see the whole text(This is a long string that is OK to truncate please and thank you).
However, they shouldn't see the text when they use their phones since there is not enough space for it.
Also, the text(This is a long string that is OK to truncate please and thank you) is dynamic so there will be the time when text is shorter or longer so I don't want to set max-width or width.
Attempts
I found multiple links doing similar things but didn't apply to my case.
Truncate text with css
How can I truncate centered text by letter with CSS?
How can I truncate the multiline text from the database? (html/css/php)
Related
This question already has answers here:
Make container shrink-to-fit child elements as they wrap
(4 answers)
Closed 1 year ago.
Below is simple example illustrating the problem. I have "Stackoverflow Stackoverflow" string and in first case it is displayed as a single line and in the second case word wrap happens. As you can see in the second case width of the div element is wider than a single "Stackoverflow" word. Is there a way to get rid of this empty space on the right? Resulting element has width 200px as specified per max-width but I want element to have actual width which is enough to fit it into 200px after word wrap.
body {
font-size: 30px;
}
.row {
margin-bottom: 10px;
}
.text-no-wrap {
background: yellowgreen;
white-space: nowrap;
display: inline-block;
}
.text-wrap {
max-width: 200px;
background: tomato;
white-space: normal;
display: inline-block;
}
<div class="row">
<div class="text-no-wrap">Stackoverflow Stackoverflow</div>
</div>
<div class="row">
<div class="text-wrap">Stackoverflow Stackoverflow</div>
</div>
You could try adding width: max-content; to the div's insde the .row
Note that width: max-content; isn't supported in Internet Explorer, but is supported on all other browsers.
Check the support of width: max-content; here.
I've added flex-direction: column; to the .row so the children of those
div's will appear underneath each other.
If you need display: flex; on the .row div, then This is the way to go. If you don't need display: flex; on the .row div, just simply remove it. And only use width: max-content; on the children;
body {
font-size: 30px;
}
.row {
display: flex;
flex-direction: column;
margin-bottom: 10px;
}
.text-no-wrap {
width: max-content;
background: yellowgreen;
}
.text-wrap {
width: max-content;
background: tomato;
}
<div class="row">
<div class="text-no-wrap">Stackoverflow1 Stackoverflow2</div>
</div>
<div class="row">
<div class="text-wrap">Stackoverflow1 Stackoverflow2</div>
<div class="text-wrap">Stackoverflow1 Stackoverflow2</div>
</div>
I believe this one is not a text-wrap issue. If you check the following code you will get multiple spaces in between wrapping text. This one is due to the
max-width: 200px;
specified for
.text-wrap.
body {
font-size: 30px;
}
.row {
display: flex;
margin-bottom: 10px;
}
.text-no-wrap {
background: yellowgreen;
white-space: nowrap;
}
.text-wrap {
max-width: 200px;
background: tomato;
white-space: normal;
}
<html>
<body>
<div class="row">
<div class="text-no-wrap">Stackoverflow Stackoverflow</div>
</div>
<div class="row">
<div class="text-wrap">Stackoverflow Stackoverflow testing text wrapping space issue</div>
</div>
</body>
</html>
Go through the demo you can see that after "testing text" multiple spaces is there.
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.
I'm trying to get a page to display something like this, when there's space for it:
Name: Peter Petersen
And then if the name is too long for the page, it should NOT break between words, but move the entire line down, a la:
Name:
Peter Petersen
I'm currently using two separate paragraphs for the title and the value, with the following CSS:
.title {
float:left;
width: 40%;
}
.value {
width: 60%
}
If I run it like that, it shows:
Name: Peter
Petersen
Which is not what I want. I tried adding white-space: nowrap to the value, but then the text never wraps down to the line below, but just continues off the edge of the screen.
word-break: keep-all; is not what I'm looking for either, since that just keeps words together.
Every other question on this I've been able to find has just been about disabling word-breaking, without caring that the line as a whole never breaks.
Flex box will do the trick ;)
HTML:
<div class="a">
<span>name:</span>
<span class="name">Peter Peterson</span>
</div>
CSS:
.a {
display: flex;
flex-wrap: wrap;
}
.name {
white-space: nowrap;
}
https://jsfiddle.net/y06d8vu4/
The words you don't want to break should be in their own element with white-space: nowrap
* {
box-sizing: border-box;
}
span:nth-of-type(1) {
float: left;
margin-right: 1em;
font-weight: bold;
}
span:nth-of-type(2) {
white-space: nowrap;
}
.wrapper {
width: 500px;
border: 1px solid red;
margin-bottom:1em;
}
.wrapper.narrow {
width: 100px;
}
<div class="wrapper">
<span>Name:</span>
<span>Peter Peterson</span>
</div>
<div class="wrapper narrow">
<span>Name:</span>
<span>Peter Peterson</span>
</div>
html code:
<div class = "wrap">
<span>Name: </span>
<span>Peter Peterson</span>
</div>
css code :
.wrap {
display: flex;
flex-wrap: wrap;
}
.wrap span:first-child {
margin-right: 5px;
}
While trying to create a homepage for a certain company, I came across the following issue.
<p class="headline">Headline<br><span class="bottomline">Bottomline</span></p>
The following valid HTML code will work just fine, however I want to adjust the created space in between the content. I tried using the margin rule in CSS with no avail. The bottomline just won't move. Back to the question at hand: how do you insert a line break in a paragraph that you can adjust at your own will? It would appear as if my problem is a bug in my implementation. Therefore, I will provide a code snippet copied from the actual source code.
div#article > div.parallex {
display: flex;
flex: 1 0 auto;
position: relative;
width: 100%;
height: 100vh;
z-index: -1;
justify-content: center;
align-items: center;
transform: translateZ(-2px) scale(3);
}
div#article > div.parallex > p.headline {
color: black;
font-size: 15px;
font-weight: bold;
}
span.bottomline {
color: #c3c3c3;
letter-spacing: 3px;
}
<div id="article">
<div class="parallex">
<p class="headline">Company<sup style="color: #37924e;">■</sup><span class="bottomline">Description</span></p>
</div>
</div>
brs are not the best practice for vertical spacing. Of course you can do multiple brs to increase the space, but a better solution would be to use css margin or padding.
.bottomline {
margin-top: 10px
}
The fact that you try tu put a inline element in another inline element make your example also not work. You should use two paragraphs below each other and space them with margin.
You can use the pre tag which preserves line-breaks and spaces or white-space: pre in CSS. Use line-height to adjust the space between the content.
<pre>
Header
Text
</pre>
<div style="white-space: pre; line-height: 10px;">
Header
Text
</div>
<div style="white-space: pre; line-height: 50px;">
Header
Text
</div>
div#article > div.parallex {
display: flex;
flex: 1 0 auto;
position: relative;
width: 100%;
height: 100vh;
z-index: -1;
justify-content: center;
align-items: center;
transform: translateZ(-2px) scale(3);
white-space: pre;
}
div#article > div.parallex > p.headline {
color: black;
font-size: 15px;
font-weight: bold;
}
span.bottomline {
color: #c3c3c3;
letter-spacing: 3px;
}
<div id="article">
<div class="parallex">
<p class="headline">Company<sup style="color: #37924e;">■</sup>
<span class="bottomline">Description</span></p>
</div>
</div>
I have a two-column layout created with flexboxes.
In the right column, I have two rows, the first containing a header and the second containing the page content.
Within the header I have three columns, a button, some text, and a button.
I want the buttons to sit on the left and right of the column with the text taking up any additional room.
Finally, I want the text to have white-space:nowrap and text-overflow:ellipsis properties to truncate long titles.
My problem is this: I cannot get the text wrapping to work correctly in a flexbox that is nested in another flexbox, as shown in this fiddle:
http://jsfiddle.net/maxmumford/rb4sk3mz/3/
.container {
display: flex;
height: 100vh;
}
.left {
width: 200px;
background-color: yellow;
}
.right {
flex: 1;
background-color: blue;
color: white;
}
.header {
background: red;
color: white;
display: flex;
flex-direction: row;
}
.header .content {
white-space: nowrap;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.header .buttons {
background: green;
flex: 1 0 auto;
}
.header .content:hover {
white-space: normal;
}
<div class="container">
<div class="left">
content left
</div>
<div class="right">
<div class="header">
<div class="buttons">buttons</div>
<div class="content">
This content is really long and should wrap with ellipses, but for some reason it doesn't work when it's nested in a container with display: flex
</div>
<div class="buttons">buttons</div>
</div>
content right
</div>
</div>
However, the exact same code works when the header is not nested within a flex box:
http://jsfiddle.net/maxmumford/p7115f2v/1/
.header {
background: red;
color: white;
display: flex;
flex-direction: row;
}
.header .content {
white-space: nowrap;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.header .buttons {
background: green;
flex: 1 0 auto;
}
<div class="header">
<div class="buttons">buttons</div>
<div class="content">
This content is really long and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long
and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long and is wrapped correctly...
</div>
<div class="buttons">buttons</div>
</div>
How can I achieve what I want in the first fiddle?
Thanks
There are two issues in your code preventing the ellipsis from working:
div.right contains div.header, which in turn contains the button and text.
div.right is a flex item in the main container (.container).
By default, a flex item cannot be smaller than the size of its content. The initial setting on flex items is min-width: auto.
This means that the length of your text, which is not wrapping, will set a minimum size for parent flex items. One way to enable flex items to shrink past their content is to set a flex item to min-width: 0.
You've done this already for the .content flex item, but it needs to be set on the .right item, as well.
You've got the .content element set to flex: 0 1 auto.
This tells the flex item to use the size of the content (flex-basis: auto). The text sets the size.
Instead, set the width to 0 and let the flex container distribute space, as necessary. You can do this with flex: 1 1 0, which is the same as flex: 1.
.container {
display: flex;
height: 100vh;
}
.left {
width: 200px;
background-color: yellow;
}
.right {
flex: 1;
background-color: blue;
color: white;
min-width: 0; /* NEW */
}
.header {
background: red;
color: white;
display: flex;
flex-direction: row;
}
.header .content {
white-space: nowrap;
flex: 1; /* ADJUSTMENT */
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.header .buttons {
background: green;
flex: 1 0 auto;
}
.header .content:hover {
white-space: normal;
}
<div class="container">
<div class="left">
content left
</div>
<div class="right">
<div class="header">
<div class="buttons">buttons</div>
<div class="content">
This content is really long and should wrap with ellipses, but for some reason it doesn't work when it's nested in a container with display: flex
</div>
<div class="buttons">buttons</div>
</div>
content right
</div>
</div>
revised fiddle
The values of :
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
Will work only if the content of your element exceeds it's width.
You can set the width of .header .content:
.header .content {
width: 50%;
}
And it will work as you expect it to:
http://jsfiddle.net/t82pqks4/
I hope this solution helps someone as nothing else I found worked because of how my page was a giant nested combination of flexbox. so min-width 0 didn't work, nothing I tried worked except this.
Inside the flex column that has the copy you want to wrap, you need to do this.
.row {
display: flex;
}
.col1 {
position: relative;
flex: 1 1 70%;
overflow: hidden;
}
.nested {
width: 100%;
position: absolute;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.col2 {
flex: 1 1 30%;
padding-left: 1rem;
}
<div class="row">
<div class="col1">
<div class="nested">This is my really long copy that will push it out of the screen, and will not respect the elippse no matter what I do!!!</div>
</div>
<div class="col2">
Last Text
</div>
</div>