text-overflow in Firefox and everything, everything, everything

    Many probably encountered a problem when some text needed to be displayed on one line. In this case, the text can be very long, and the width of the block in which this text is located is usually limited, at least by the same size of the browser window. For these cases, the text-overflow property was invented , which was included in the CSS3 recommendation , and was first implemented in IE6, a very long time ago. If this property is used for a block, if its text is wider than the block itself, then the text is cut off and an ellipsis is set at the end. Although not everything is so simple here, we will return to this a bit later.
    With Internet Explorer, everything is clear, what about other browsers? And although at the moment from the CSS3 specificationthe text-overflow property is excluded, Safari supports it (at least in version 3), Opera also (since version 9, the truth is called the -o-overflow-text property). And Firefox - no, it doesn’t support it, and even in the 3rd version it won’t. Sad but true. But can you do something?



    Of course, you can do it. When I searched the Internet about this property, and as with Firefox, I came across an article with a simple solution. The essence of the solution:
    1. Limit the block by width via max-width or just width.
    2. Using :: after, we create auto-generated content that contains an ellipsis (three dots).

    That's all. Read the details in the article.
    The solution is not bad, but there are problems:
    1. The text can be cut off in the middle (relatively speaking) of the letter, and we will see its “stump”.
    2. The ellipsis is always displayed, even when the text is less than the width of the block (that is, it does not drop out of the block and the ellipsis is not needed).


    Step one



    To begin with, we will focus on the second problem, namely, how to avoid displaying dots when it is not needed. Breaking his head and experimenting “a little”, I found some solution. I’ll try to explain.
    The bottom line is that we need a separate block with an ellipsis, which will only appear when the text takes up too much space in width. Then I came up with the idea of ​​a falling floating block. Although it sounds scary, it just means a block, which is always there, and is pressed to the right, but when the width of the text becomes large, the text pushes the block to the next line.
    Let's move on to practice, otherwise it's hard to explain. Let's set the HTML structure:
    very long text

    Not very compact, but the smaller I did not succeed. So, we have a block container DIV.ellipsis, a block with our text and another block that will contain an ellipsis. Note that the “ellipsis block” is actually empty, because we do not need the extra three dots when we copy the text. Also, do not be afraid of the absence of additional classes, since this structure is well addressed through CSS selectors. And here is the CSS itself:
        .ellipsis
        {
          overflow: hidden;
          white-space: nowrap;
          line-height: 1.2em;
          height: 1.2em;
          border: 1px solid red;
        }
        .ellipsis> DIV: first-child
        {
          float: left;
        }
        .ellipsis> DIV + DIV
        {
          float: right;
          margin-top: -1.2em;
        }
        .ellipsis> DIV + DIV :: after
        {
          background-color: white;
          content: '...';
        }
    

    That's all. We check and make sure that in Firefox, Opera, Safari works as intended. In IE, a very strange, but predictable, result. In IE6, everything went away, but in IE7 it just doesn’t work, since it does not support generated content. But we will return to IE.

    In the meantime, we will analyze what has been done. First, we set the line-height and height of the main block, since we need to know the height of the block and the height of the text line. We set the same value for the margin-top block with an ellipsis, but with a negative value. Thus, when the block is not “dropped” to the next line, it will be above the line of text (one line), when it is reset, it will be at its level (in fact, it is lower, we just pull one line up). To hide unnecessary, especially when you do not need to show the ellipsis, we do overflow: hidden for the main block, so when the ellipsis is above the line, it will not be shown. This also allows us to remove text that falls outside the block (to the right). So that the text does not suddenly wrap and push the block with the ellipses lower and lower, we do white-space: nowrap, thereby prohibiting hyphens - our text will always be in one line. For the block with text, we set float: left so that it would not immediately dump the block with ellipsis and occupy the minimum width. Since both blocks are floating (float: left / right) inside the main block (DIV.ellipsis), the main block will collapse when the block with the text is empty, so for the main block we set a fixed height (height: 1.2em). And finally, we use the pseudo-element :: after to display the ellipsis. For this pseudo-element, we also set the background to overlap the text that appears under it. We set the frame for the main unit, only to see the dimensions of the unit, later we will remove it. so that he does not immediately dump the block with the ellipsis and occupies the minimum width. Since both blocks are floating (float: left / right) inside the main block (DIV.ellipsis), the main block will collapse when the block with the text is empty, so for the main block we set a fixed height (height: 1.2em). And finally, we use the pseudo-element :: after to display the ellipsis. For this pseudo-element, we also set the background to overlap the text that appears under it. We set the frame for the main unit, only to see the dimensions of the unit, later we will remove it. so that he does not immediately dump the block with the ellipsis and occupies the minimum width. Since both blocks are floating (float: left / right) inside the main block (DIV.ellipsis), the main block will collapse when the block with the text is empty, so for the main block we set a fixed height (height: 1.2em). And finally, we use the pseudo-element :: after to display the ellipsis. For this pseudo-element, we also set the background to overlap the text that appears under it. We set the frame for the main unit, only to see the dimensions of the unit, later we will remove it. use the :: after pseudo-element to display the ellipsis. For this pseudo-element, we also set the background to overlap the text that appears under it. We set the frame for the main unit, only to see the dimensions of the unit, later we will remove it. use the :: after pseudo-element to display the ellipsis. For this pseudo-element, we also set the background to overlap the text that appears under it. We set the frame for the main unit, only to see the dimensions of the unit, later we will remove it.
    If Firefox, as well supported pseudo-elements as Opera and Safari, in terms of their positioning (job for them position / float etc), then we could not use a separate block for ellipsis. Try replacing the last 3 rules with the following:
        .ellipsis> DIV: first-child :: after
        {
          float: right;
          content: '...';
          margin-top: -1.2em;
          background-color: white;
          position: relative;
        }
    

    Look in Opera and Safari, everything works as before, and without an additional block with an ellipsis. Firefox is a disappointment, however. But it is for him that we make the decision. Well - you have to do with the original HTML structure.

    Second step



    As you may have noticed, we got rid of the problem of the appearance of ellipsis when the text fits in a block. However, we still have one more problem - the text is cut off in the middle of the letters. And besides, this does not work in IE. To overcome both, you need to use the native text-overflow rule for browsers, and only for Firefox use the solution described above (there is no alternative). We will figure out how to make a “Firefox only” solution later, but now let's try to get what works using text-overflow. CSS tweak:
        .ellipsis
        {
          overflow: hidden;
          white-space: nowrap;
          line-height: 1.2em;
          height: 1.2em;
          border: 1px solid red;
          text-overflow: ellipsis;
          -o-text-overflow: ellipsis;
          width: 100%;
        }
        .ellipsis *
        {
          display: inline;
        }
        / *
        .ellipsis> DIV: first-child
        {
          float: left;
        }
        .ellipsis> DIV + DIV
        {
          float: right;
          margin-top: -1.2em;
        }
        .ellipsis> DIV + DIV :: after
        {
          background-color: white;
          content: '...';
        }
        * /
    

    Edit, as it turned out, not much. Three lines were added to the style of the main unit. Two of them include text-overflow. Setting width: 100% is necessary for IE, so that the text does not push the block to infinity, and the text-overflow property works; in fact, we have limited the width. In principle, the DIV, like all block elements, is stretched across the entire width of the container, and width: 100% is useless, and even harmful, but IE has a layout problem, since the container is always stretched to fit the content, so it cannot be otherwise. We also made all the internal elements inline, because for some browsers (Safari & Opera) text-overflow would not work otherwise, since there are block elements inside. We commented on the last three rules, since in this case they are not needed and they break everything (conflict). These rules will be needed only for Firefox.
    Let's see what happened and continue.


    Step three



    When I once again looked at the page (before I was going to write this article), mentioned at the very beginning, then, for the sake of interest, I looked through the comments on the subject of clever related ideas. And found an interesting link, in a comment that mentioned another solution that works in Firefox and IE (apparently, for this person, as well as for the author of the first article, other browsers do not exist). So, in this solution, the author is struggling with this phenomenon in a slightly different way (lack of text-overflow) by hanging handlers on overflow and underflow events for elements for which it was necessary to put an ellipsis if necessary. Not bad, but it seems to me that this solution is very expensive (in terms of resources), especially since it somewhat mutes it. However, understanding how he achieved this, I came across an interesting thing, namely the CSS property -moz-binding. As I understand it, this is an analog behavior in IE, only with a different sauce and better. But we will not go into details, we will only say that in this way you can hang a JavaScript handler on an element using CSS. Sounds weird, but it works. What are we doing:
        .ellipsis
        {
          overflow: hidden;
          white-space: nowrap;
          line-height: 1.2em;
          height: 1.2em;
          border: 1px solid red;
          text-overflow: ellipsis;
          -o-text-overflow: ellipsis;
          width: 100%;
          -moz-binding: url (moz_fix.xml # ellipsis);
          zoom: 1;
        }
        .ellipsis *
        {
          display: inline;
        }
        
        .moz-ellipsis> DIV: first-child
        {
          float: left;
          display: block;
        }
        .moz-ellipsis> DIV + DIV
        {
          float: right;
          margin-top: -1.2em;
          display: block;
        }
        .moz-ellipsis> DIV + DIV :: after
        {
          background-color: white;
          content: '...';
        }
    

    As you can see, we again made not many changes. At this step in IE7 there is a strange glitch, everything is skewed if you do not set zoom: 1 for the main unit (the easiest option). If you remove (delete, comment out) the rule .ellipsis * or .moz-ellipsis> DIV + DIV (which does not concern IE7 at all), then the glitch disappears. All this is strange, if anyone knows what’s the matter, let me know. In the meantime, get around zoom: 1 and move on to Firefox.
    The -moz-binding property includes the moz_fix.xml instruction file with the ellipsis identifier. The contents of this xml file are as follows:

    All that this constructor does is to add the moz-ellipsis class to the element for which the selector has worked. This will only work in Firefox (gecko browsers?), So only in it will the moz-ellipsis class be added to the elements, and we can add additional rules for this class. What did they achieve. I'm not quite sure about the need for this.style.mozBinding = '', but from experience with expression it is better to play it safe (in general I am not familiar with this side of Firefox, therefore I can be mistaken).
    You may be warned that this technique uses an external file and generally JavaScript. Do not be scared. Firstly, if the file does not load and / or JavaScript is disabled and does not work, it's okay, the user just won’t see the ellipsis at the end, the text will be cut at the end of the block. That is, in this case we get a "unobtrusive" solution. You can see for yourself .

    Thus, we got a style for the Big Four browsers that implements text-overflow for Opera, Safari & IE, and for Firefox it emulates, not so hot, but it's better than nothing.

    Fourth step



    It would be possible to put an end to this place, but I would like to improve our solution a little. Since we can hang a constructor on any block and accordingly get control over it, why not take advantage of it. Simplify our structure:
    very long text

    Oh yeah! I think you will agree with me - this is what you need!
    Now let's remove everything superfluous from the style:
        .ellipsis
        {
          overflow: hidden;
          white-space: nowrap;
          line-height: 1.2em;
          height: 1.2em;
          text-overflow: ellipsis;
          -o-text-overflow: ellipsis;
          width: 100%;
          -moz-binding: url (moz_fix.xml # ellipsis);
        }
        .moz-ellipsis> DIV: first-child
        {
          float: left;
        }
        .moz-ellipsis> DIV + DIV
        {
          float: right;
          margin-top: -1.2em;
        }
        .moz-ellipsis> DIV + DIV :: after
        {
          background-color: white;
          content: '...';
        }
    

    We finally removed the red frame :)
    And now, let's add our moz_fix.xml a little:

    What's going on here? We recreate our initial HTML structure. That is, those difficulties with blocks are done automatically, and only in Firefox. JavaScript code is written in the best tradition :)
    Unfortunately, we can’t avoid a situation where the text is cut off in the middle of the letter (though, maybe temporarily, since my solution is still very raw, and it may work out in the future). But we can smooth this effect a little. To do this, we need an image (white background with a transparent gradient), and some changes to the style:
        .moz-ellipsis> DIV: first-child
        {
          float: left;
          margin-right: -26px;
        }
        .moz-ellipsis> DIV + DIV
        {
          float: right;
          margin-top: -1.2em;
          background: url (ellipsis.png) repeat-y;
          padding-left: 26px;
        }
    

    We look and enjoy life.

    On this and put an end.

    Conclusion



    I will give a small example for third-party layout. I took the table of contents of one of the Wikipedia pages (the first thing turned up), and applied the method described above for it.
    In general, this solution can be called universal only with a stretch. It all depends on your layout and its complexity. You may need a file, or maybe a tambourine. Although in most cases, I think it will work. And then, you now have a starting point;)
    I hope you learned something interesting and useful from the article;) Learn, experiment, share.
    Good luck

    Also popular now: