In my webpage I have a div with fixed width and using the following css:
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
The ellipsis is working, the problem is that it cuts the final word, and I wanted it to put the ellipsis (...) in the final of a full word.
For instance, if I have the text: "stackoverflow is the best", and if it need to be cutted near the end, I want it to display "stackoverflow is the ..." instead of "stackoverflow is the be..."
I’m afraid it’s impossible. There was once text-overflow: ellipsis-word, which would do just this, but it was not implemented in browsers and it was removed from CSS3 drafts.
Of course it's possible. (If you're willing to change your markup a bit.)
https://jsfiddle.net/warphLcr/
<style>
.foo {
/* Make it easy to see where the cutoff point is */
border: 2px solid #999;
padding-right: 18px; /* Always have room for an ellipsis */
width: 120px;
height: 1.1em; /* Only allow one line of text */
overflow: hidden; /* Hide all the text below that line */
background-color: #fff; /* Background color is required */
}
.foo > span {
display: inline-block; /* These have to be inline block to wrap correctly */
position: relative; /* Give the ellipsis an anchor point so it's positioned after the word */
background-color: #fff; /* Cover the ellipsis of the previous word with the same background color */
white-space: pre; /* Make sure the only point where wrapping is allowed is after a whole word */
}
.foo > span:after {
position: absolute; /* Take the ellipsis out of the flow, so the next item will cover it */
content: "…"; /* Each span has an ellipsis */
}
.foo > span:last-child:after {
content: ""; /* Except for the last one */
}
</style>
<div class="foo">
<!-- These *must not* have white space between them, or it will collapse to a space before the next word, and the ellipsis will become visible -->
<span>stackoverflow</span><span> is</span><span> the</span><span> best</span>
</div>
There's a jQuery plugin that does this, called dotdotdot.
It also works for multi-line text, and adapts responsively if the text reflows e.g. if the screen size changes. It also includes smart truncation of pathnames e.g. http://example.com/some/long/.../path.html
Be aware of the possibility of width-based timing issues in cases where the width changes or becomes unavailable in ways the plugin might not expect, such as if the text is initially hidden or if it changes font (e.g. loading web fonts on some browsers). Might require re-applying or being applied after such changes.
But 99% of the time, the plugin seems fast and robust.
If you want to display one line of text that would end in ellipsis, like a news ticker for example, just do:
p { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
Related
It seems there is some magic around the <button>element that I don't understand.
Consider this markup:
<button class="button">Some Text</button>
<div class="button">Some Text</div>
And this CSS:
.button{
background: darkgrey;
height: 40px;
border: 2px solid grey;
width: 100%;
box-sizing: border-box;
font-size: 14px;
font-family: helvetica;
text-align: center;
margin-bottom: 20px;
/*I'm aware I could use this to center it*/
/*line-height: 40px;*/
}
What makes the text in the button element vertically centered? Webkit seems to predefine a -webkit-box-align with a value of center for the <button> element. If I set that to initial the text is no longer aligned to the center. But that doesn't seem to be the full magic, since on the other hand I had no luck centering the text on the div using the -webkit-box-align property.
Here is a fiddle: http://jsfiddle.net/cburgdorf/G5Dgz/
I know this is a couple of years old, but I'll add my thoughts after some investigation in to issue while writing a reset stylesheet for a project.
NOTE** This is based on looking through the Firefox source because it was the easiest to obtain and read through. However, based on similar behaviour in other browsers the implementation is probably similar.
Firstly, the main issue here is that <button> elements - atleast in Firefox - are built with an internal element between the <button> tag and it's children. In Firefox it's called moz-button-content and isn't something that can be reached with CSS and has been set to display block without inheriting the height of the button, you can see this style declaration in the useragent stylesheet:
From "source/layout/style/res/forms.css"
*|*::-moz-button-content {
display: block;
/* Please keep the Multicol/Flex/Grid/Align sections below in sync with
::-moz-scrolled-content in ua.css and ::-moz-fieldset-content above. */
/* Multicol container */
-moz-column-count: inherit;
-moz-column-width: inherit;
-moz-column-gap: inherit;
-moz-column-rule: inherit;
-moz-column-fill: inherit;
/* Flex container */
flex-direction: inherit;
flex-wrap: inherit;
/* -webkit-box container (aliased from -webkit versions to -moz versions) */
-moz-box-orient: inherit;
-moz-box-direction: inherit;
-moz-box-pack: inherit;
-moz-box-align: inherit;
/* Grid container */
grid-auto-columns: inherit;
grid-auto-rows: inherit;
grid-auto-flow: inherit;
grid-column-gap: inherit;
grid-row-gap: inherit;
grid-template-areas: inherit;
grid-template-columns: inherit;
grid-template-rows: inherit;
/* CSS Align */
align-content: inherit;
align-items: inherit;
justify-content: inherit;
justify-items: inherit;
}
Because you can't affect any of the styles on this element, you are forced to add you styling on the <button> tags. This leads into the second issue - The browser is hard coded to vertically position the content of the button.
From "source/layout/forms/nsHTMLButtonControlFrame.cpp"
// Center child in the block-direction in the button
// (technically, inside of the button's focus-padding area)
nscoord extraSpace =
buttonContentBox.BSize(wm) - contentsDesiredSize.BSize(wm);
childPos.B(wm) = std::max(0, extraSpace / 2);
// Adjust childPos.B() to be in terms of the button's frame-rect:
childPos.B(wm) += clbp.BStart(wm);
nsSize containerSize = (buttonContentBox + clbp.Size(wm)).GetPhysicalSize(wm);
// Place the child
FinishReflowChild(aFirstKid, aPresContext, contentsDesiredSize,
&contentsReflowInput, wm, childPos, containerSize,
ReflowChildFlags::Default);
Given these two issues you can start to see how the button force the content to be centered, consider:
<button> tag
+------------------------+ ^
| button extra space | |
| | |
+------------------------+ |
|| ::moz-button-content || | button height
|| display: block; || |
+------------------------+ |
| | |
| button extra space | |
+------------------------+ v
If you give the button a height - like the 48px from your fiddle, the text will be centered because the moz-button-content element is display block and will only have the height of the content (most likely the line-height of the content by default) and when put next to another element you get this behaviour:
* {
box-sizing: border-box;
margin: 0;
border: 0;
padding: 0;
font-family: san-serif;
background: none;
font-size: 1em;
line-height:1;
vertical-align: baseline;
}
button, a {
height: 3em;
}
button {
background: red;
}
a {
display:inline-block;
background: green;
}
<button>Button content</button>
<a>Link Content</a>
This bug and this bug in the Firefox issue tracker was about a close as I could find to any actually documented bug. But the threads give the impression that despite this not appearing in any actual spec, the browsers have just implemented it this way "because the other browsers are doing it that way"
There is a work-around to the issue if you actually want to change the default behaviour, but it doesn't completely solve the problem and YMMV depending on your implementation.
If you insert a wrapper <span> with display: block as the only child of the button and put all your content inside it you can use it to skip over the moz-button-content element.
You will need to make this <span> element have height: inherit so it correctly fills the height of the button and then add your normal button styling to the <span> instead, you will get basically behaviour you want.
* {
box-sizing: border-box;
margin: 0;
border: 0;
padding: 0;
font-family: san-serif;
background: none;
font-size: 1em;
line-height:1;
vertical-align: baseline;
}
button, a {
height: 3em;
}
button {
background: red;
}
button::-moz-focus-inner {
border: 0;
padding: 0;
outline: 0;
}
button > span {
display: block;
height: inherit;
}
a {
display:inline-block;
background: green;
}
button.styled > span , a.styled{
padding: 10px;
background: yellow;
}
<button><span>Button content</span></button>
<a><span>Link Content<span></a><br/>
<button class="styled"><span>Button content</span></button>
<a class="styled"><span>Link Content<span></a>
It's also worth mentioning the appearance CSS4 rule (Not yet available):
While this is not a viable option (as of the 5th January) yet. There is a proposal to redefine the appearance rule in the CSS4 draft that might actually do the right thing an remove all assumptions made by the browser. I only mention it for completeness because it may become useful in the future.
UPDATE - 30/08/2016
You should actually use a <span> instead of a <div>, as div's aren't valid children for <button> elements. I have updated the answer to reflect this.
You could use padding.
For example
padding: 20px 10px;
I think that the only reason for this behaviour is that Google Chrome or browsers in general will take the default styles from your operating system.
For example, if you compare the button or scrollbar on Google Chrome run in windows 7 and windows 8:
In windows 7, the button will have a horizontal gradient line in the center of your button
In windows 8, the scrollbar are able to fade in and fadeout on click
This is just my opinion but hope that it can give you some ideas :)
You can use display:table-cell;
vertical-align: middle; as an alternate method.
On Mozilla Firefox I got the -moz-appearance property :
-moz-appareance: button;
In the HTML5 draft, there is a Rendering section, but doesn't details the placement :S
Button elements by default centers child elements vertically. It isn't done in a conventional CSS way, and therefor isn't trivial to override.
The best solution I have found is setting the button to flex column.
button {
height: 100px;
display: flex;
flex-direction: column;
}
span {
height: 20px;
width: 100px;
background-color: blue;
display: block;
}
<button>
<span></span>
</button>
Some answers suggested adding an inner wrapper, and setting it's height to inherit. This might not work for elements that have their height calculated dynamically.
In case you need to get rid of this behavior you can just add span as a child of button. Works better than trying to trick all the browsers.
In a website menu, I have implemented some wishes of my customer concerning typography in CSS. She needs a different tracking on the font, no problem. But, she wants the active link to be underlined. As I have not implemented the code to target the active link, I just underlined them all to see how it would look. The CSS is as follows:
.main-navigation a {
display: block;
color: black;
font-weight: bold;
letter-spacing: 0.45em;
line-height: 4.5em;
text-decoration: underline;
text-transform: uppercase;
}
And this is the result:
The problem is that the letter spacing kind of messes up the underlining. I've drawn some vote magnets freehand circles to indicate the problem. The line starts nicely at the left side but is extended with the value of letter-spacing to the right.
Screenshot is from Firefox 25. Jsfiddle to see for yourself.
I could solve this using borders and using margins instead of line height, but is this fixable otherwise?
CSS Text underlining too long when letter-spacing is applied?
http://jsfiddle.net/isherwood/JWcGh/2
.main-navigation a:after {
/* absolute positioning keeps it within h1's relative positioned box, takes it out of the document flow and forces a block-style display */
position: absolute;
/* the same width as our letter-spacing property on the h1 element */
width: 0.45em;
/* we need to make sure our 'mask' is tall enough to hide the underline. For my own purpose 200% was enough, but you can play and see what suits you */
height: 200%;
/* set the background colour to the same as whatever the background colour is behind your element. I've used a red box here so you can see it on your page before you change the colour ;) */
background-color: #fff;
/* give the browser some text to render (if you're familiar with clearing floats like this, you should understand why this is important) */
content: ".";
/* hide the dynamic text you've just added off the screen somewhere */
text-indent: -9999em;
/* this is the magic part - pull the mask off the left and hide the underline beneath */
margin-left: -.40em;
}
My HTML is like this:
<li>Facebook</li>
I'm using the fontello icon font system however, I can't seem to work out how to make the word Facebook disappear and the icon remain! The generated content looks like this:
<li>:before "Facebook"</li>
Thanks
(note: I know I can add a span to the text and toggle it but I thought there may have been a purely CSS way to do it?)
This is one way
.icon-facebook {
text-indent: -9999px; /* sends the text off-screen */
background-image: url(/the_img.png); /* shows image */
height: 100px; /* be sure to set height & width */
width: 600px;
white-space: nowrap; /* because only the first line is indented */
}
.icon-facebook {
outline: none; /* prevents dotted line when link is active */
}
and there's also another. I found this question answered here:
Hide text using css
I have the following situation (I express with images):
1st situation: In the image below has a small text, and already meet the first problem. The edge of my list is not obeying the picture too: (. Wish she always fell short of my message, regardless of message size.
2nd situation: When we have a very long text, it does not obey he ends up falling (not getting to the side of the image)
The result I expect is the following:
Must be some alignment in my css as'm no expert on the subject just know my way around with some things. Someone manages to come help me? Follow my file jsFiddle. Already very grateful for the time invested it :) HERE JSFIDDLE DEMO
li {
border-bottom:1px solid gray;
text-align: left;
display:block;
}
.chat-window-user-img > img {
height:50px;
width:50px;
float:left;
padding:5px;
}
.chat-window-user-message{
direction: ltr;
white-space: pre-wrap; /* CSS3 */
white-space: -moz-pre-wrap; /* Firefox */
white-space: -pre-wrap; /* Opera <7 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* IE */
border-collapse: collapse;
border-spacing: 0;
}
Both problems can be solved with overflow: auto, a useful trick I only recently picked up:
Add to .chat-window-user-message:
display: block;
overflow: auto;
(A <div> would also have worked, instead of display: block)
And to li:
overflow: auto;
Example: http://jsfiddle.net/L6Pwq/14/
See also: CSS: Clearing Floats with Overflow
We are using strike-through to actually show oldprice vs new price for a product.
If you open this link, at the bottom of the page, we have a product on sale.
http://www.gkelite.com/Gymnastics-Shopby-GiftoftheWeek
The strike-through for the old price is not centered vertically for the text.
Can any one help out as to why it's happening?
A strike-through is traditionally some percentage (70% to 90%) of the x-height (or the height of a lower case 'x'). If the line were at the 50% of cap-height, it may be possible the strike-through would be above or at the top of any lowercase letter in the set. A strike-through is supposed to put a line through all letters in the text, which is why is gauged from the x-height.
Whether or not browsers actually use the x-height for their strikethrough calculation, this tradition is why is why strike-throughs are displayed short of the 50% of cap height.
See the following illustration for some examples of the terms:
I found a solution for it utilizing psuedo elements http://jsfiddle.net/urjhN/
.strike-center {
position: relative;
white-space: nowrap; /* would center line-through in the middle of the wrapped lines */
}
.strike-center:after {
border-top: 1px solid #000;
position: absolute;
content: "";
right: 0;
top:50%;
left: 0;
}
However this technique fails if the text is wrapped between lines, the line would be centered among those lines.
It seems to work among all major browsers; for IE7 (and prior) you could just fallback to the classic line-through using conditional comments.
There is no way to control the offset/placement of a strike-through, but, there is a way for controlling this using for text-decoration: underline using the below combination:
span {
background: lightyellow;
text-decoration: underline;
text-underline-offset: -40%; /* <-- this */
text-decoration-skip-ink: none;
}
output { display:inline-block; width:50px; }
<output>-40%</output>
<input type='range' min='-100' max='100' value='-40' oninput='this.nextElementSibling.style.textUnderlineOffset=this.value+"%"; this.previousElementSibling.innerHTML=this.value+"%"'/>
<span>Text with strike-through</span>
👉 Here's a Codepen of mine with an alternative strike-through approach:
https://codepen.io/vsync/pen/KKQoVRZ