90

When I specify text-align:center for an element with a width that is greater than the width of the text, the text is centered within the content box of the element (as expected).

When I specify text-align:center for an element with a width that is less than the width of the text, the text is aligned to the left edge of the content box and overflows the right edge of the content box.

You can see the two cases in action here.

Can any CSS magic make the text equally overflow both the left edge and the right edge of the content box, so that it stays centered?

Nathan Ryan
  • 12,893
  • 4
  • 26
  • 37

8 Answers8

122

I know this question is old, but I just had the same Problem and found a much easier solution with just a span. http://jsfiddle.net/7hy3w2jj/

<div>some text</div>
<div>
    <span class="text-overflow-center">some text that will overflow</span>
</div>

Then you just need this definition

.text-overflow-center {
    margin-left: -100%;
    margin-right: -100%;
    text-align: center;
}

If you can work with pseudo elements, it can be done with no html at all. Just add these definition to your text container. http://jsfiddle.net/7287L9a8/

div:before {
    content: "";
    margin-left: -100%;
}
div:after {
    content: "";
    margin-right: -100%;
}

The only downside to the pseudo variant is that it only works with one line of text.

Nemo64
  • 2,535
  • 3
  • 20
  • 24
  • 3
    oh thank gods for negative margins! I used `-99px` instead of % value for a child element that is much smaller than the parent which has variable dimensions and `overflow: hidden` anyway – Aprillion Jan 14 '16 at 12:46
  • Can't this be simplified to `margin:0 -100%;` ? – Aziz Feb 05 '16 at 06:26
  • 2
    @Aziz probably. But I like to only define properties that I use. – Nemo64 Feb 05 '16 at 07:13
  • MS Edge browser is breaking ;-( – jfroom Mar 09 '16 at 23:28
  • 3
    For MSEdge, if you [can use flexbox](http://caniuse.com/#feat=flexbox) — then putting `display: flex; justify-content: center;` on the `div` works better cross-browser. http://jsfiddle.net/jfroom/2u5x1hmj/1/ @Nemo64 consider an update? – jfroom Mar 09 '16 at 23:49
  • IE 11 also needed `display:flex;` on the pseudo elements. http://jsfiddle.net/jfroom/2u5x1hmj/4/ – jfroom Mar 10 '16 at 00:16
  • @jfroom thanks. Isn't `text-align: center` still required for ie9 and below? – Nemo64 Mar 10 '16 at 08:12
  • @Nemo64 Yes, `text-align: center` still needed for fallback - just tested on IE9 and breaks without it. I don't have any IE8 or below images handy at the moment to test further back. That prop is also on the last v4 link. – jfroom Mar 10 '16 at 17:48
  • 2
    This doesn't work at all, does it? Try making the div 15px wide instead of 100px, and things won't be centered anymore. – Clément Aug 13 '16 at 14:08
  • I have a small div which has fixed width and text therein overflow. I don't want all the text to be in one line, which is the case when I apply your solution. I want text to be multiple lines and when some line is overflowing it should overflow equally to both left and right rather than just overflowing in one direction. Here is the link to my fiddle https://jsfiddle.net/ew52qj7b/ I don't want to use break-word as it doesn't look good – Gaurav Feb 16 '17 at 09:45
  • 1
    @Gaurav i think there is no way to achieve this without having all lines overflowing equally, like this: https://jsfiddle.net/ew52qj7b/1/ You could take a look at hyphenation but the browser support isn't that good for automatic hyphenation: http://caniuse.com/#feat=css-hyphens but depending on the situation you can use ­ to allow hyphens in a specific spot. – Nemo64 Feb 16 '17 at 13:48
  • @Nemo64 Actually I'm fine with all the lines overflowing, so your solution is the best I am possibly gonna get, Thanks – Gaurav Feb 17 '17 at 08:18
  • Here's a one-liner to apply this answer to a centre-aligned text element `e` in JavaScript: `if(e.offsetWidth < e.scrollWidth) e.style.marginRight = e.style.marginLeft = "-100%";`. Or to set just one margin, and use non-relative values, `if(e.offsetWidth < e.scrollWidth) e.style.marginLeft = (e.offsetWidth - e.scrollWidth)/2 + 'px';`. Note that these must be called after adding the element to the DOM, so that their offsetWidth & scrollWidth can be calculated! – Jamie Birch Apr 10 '17 at 13:50
  • Very nice, thanks. People (at least one!) are still having this problem today. It should be noted that the -100% is the size of the containing box, not the size of the text, so the solution requires knowing roughly the maximum ratio between overflowed text and the box size. – Victoria Jan 01 '18 at 08:34
42

This looks some old question.

Now I think there is some good answer with flex.

You can do this simply like this:

<div id="small_div">overflowing text</div>

#small_div {
    display: flex;
    justify-content: center;
}

That's it.

Hope much help to you!

LarAng
  • 1,255
  • 3
  • 18
  • 28
14

Div magic to the rescue. In case anyone is interested, you can see the solution here.

HTML:

<div id="outer">
    <div id="inner">
        <div id="text">some text</div>
    </div>
</div>
<div id="outer">
    <div id="inner">
        <div id="text">some text that will overflow</div>
    </div>
</div>

CSS:

#outer {
    display: block;
    position: relative;
    left: 100px;
    width: 100px;
    border: 1px solid black;
    background-color: silver;
}
#inner {
    /* shrink-to-fit width */
    display: inline-block;
    position: relative;
    /* shift left edge of text to center */
    left: 50%;
}
#text {
    /* shift left edge of text half distance to left */
    margin-left: -50%;
    /* text should all be on one line */
    white-space: nowrap;
}
Nathan Ryan
  • 12,893
  • 4
  • 26
  • 37
  • 4
    "Div magic to the rescue." Well, and DIV-soup to the rescue too… but a tricky solution – feeela Jul 08 '11 at 01:00
  • @feeela: agreed that divs can become a swirling mess, which is why I leave them out of the HTML and build the more complex DOM with JavaScript when the page is loaded. – Nathan Ryan Jul 08 '11 at 01:02
  • 2
    This might be an option: http://jsfiddle.net/PdER5/. I'm purposely not posting it as answer because it needs to be heavily tested to make sure it doesn't do anything weird when it's used on your actual page in any of the browsers you need to support. – thirtydot Jul 08 '11 at 01:07
  • @thirtydot: breaks if the width of the text is more than twice the "random number", though in practice it could be made large enough that it wouldn't be an issue – Nathan Ryan Jul 08 '11 at 01:10
  • @thirtydot IMHO a cooler solution, but the negative margins aren't "some random number", but the left positioning distance plus half the `DIV`s width. – feeela Jul 08 '11 at 01:11
  • @NathanRyan that sounds gross. – Charlie Dec 17 '14 at 23:04
  • This works, and it makes a lot of sense if you think about it for a little while. The top answer doesn't actually work. – Clément Aug 13 '16 at 14:22
  • I finally got it working. I needed to add 'text-align:left;' to #text div, in order to use it in a Wordpress website title (which already had a 'text-align:center;' assigned, I imagine...) – Kar.ma Jan 31 '17 at 20:48
0

To make the solution work for multi-line text, you can modify Nathan's solution by changing the #inner left from 50% to 25%.

Edmond Chui
  • 660
  • 9
  • 6
0

Give the innermost div some margin: 0 -50%. If the elements are all display block or inline-block and text alignment is centered, this provides more shoulder room for the innermost element's text. At least, it works for me.

atwixtor
  • 795
  • 10
  • 26
0

Strange requirement. I would expand the boxes to the texts size.

One possible solution might involve a negative text-indent: text-indent: -50px;, but that won't work for smaller texts (first DIV in your example). No better idea here right now.

feeela
  • 29,399
  • 7
  • 59
  • 71
0

Try

word-wrap:break-word;

instead of:

white-space:nowrap;

or do you only want it on one line?

FraserK
  • 304
  • 1
  • 3
  • 17
  • this is an odd requirement. Why do you need it spill out of the element? – FraserK Jul 08 '11 at 00:45
  • 1
    The element is effectively a shape, the text a label. I'm trying my hand at making certain kinds of charts with minimal JavaScript. – Nathan Ryan Jul 08 '11 at 00:47
  • Why not try having the background as an image and then having the image set to no-repeat and centered. for example http://jsfiddle.net/C4BBS/1/ you can see the border shows the actual width of the div but the bg is centered – FraserK Jul 08 '11 at 00:56
  • some things like the border are still messy, and some additional code would be required to handle user events on the element. – Nathan Ryan Jul 08 '11 at 00:59
  • Which events are likely? the borders are not needed but i left them there so you can see that the actual width of the element. – FraserK Jul 08 '11 at 01:02
  • mousing events (onclick, onmousemove, etc.) are a must. In my solution, the events can bubble to the smaller, outer container and be handled by checking whether the curser coordinates are within the container. Would be more difficult (though not impossible) to do with your solution, I think – Nathan Ryan Jul 08 '11 at 01:07
  • oh okay, with mouse events such as those my solution would not work :) – FraserK Jul 08 '11 at 01:08
0

this one seems to work: add a wrapper block with position relative and left:50% margin-left:-100% you can see it here Here's the code:

<style>
div {
    display: block;
    position: relative;
    left: 100px;
    height:1.5em;
    width: 100px;
    text-align: center;
    white-space: nowrap;
    border: 1px solid black;
    background-color: silver;
}
span{
    display:block;
    position:relative;
    left:50%;
    margin-left:-100%;
}
</style>
<div><span>some text</span></div>
<div><span>some text that will overflow</span></div>
malko
  • 2,292
  • 18
  • 26