Limit text length through gradient

    image

    Consider creating the effect of leaving the text in transparency as an alternative to trimming text with ellipsis.

    Surely you noticed, or maybe even used in practice such a technique as cutting long words with ellipses, so that they fit into the design.

    A frequent case for limiting text length is the username. At the same time, letters that go beyond the permissible limits are not always cut to the root. The user can somehow see the whole name, for example, when hovering over the mouse, a tooltip with the full name is shown to him.

    But ellipsis is not the only solution. For example, we in the team liked the option of leaving long names smoothly in transparency (Fig. 1) [1].

    Example 1
    Fig. 1

    Ways to implement it further and consider. As an example, we will use the contents of the figure above (Fig. 1). We will describe everything using HTML and CSS. Without React and webpack, sorry.

    Solution 1. CSS (linear-gradient function)


    The first thing that comes to mind is to use the CSS function linear-gradient.

    We describe the rectangle:

    • height is equal to the size;
    • the width is N (N depends on how much we want to cover the area with the gradient);
    • depending on the background color, set the gradient (one of the points is completely transparent, the other is solid);
    • by absolute positioning we fix to the right edge of the block with the text.

    Using this algorithm, we recreate our example. Remember, we have turquoise text on a white background.

    Markup:

    Johnny Sm

    Stylization:

    .text-eclipse {
      position: relative;
    }
    .text-eclipse::after {
      content: "";
      position: absolute;
      top: 0;
      right: 0;
      width: 45%; /* 1 */
      height: 100%;
      background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%); /* 2 */
    }
    

    1. the width is better set in relative units, so as not to do unnecessary operations when changing the font size;
    2. by standard transparent- this is actually an abbreviation of rgba(0, 0, 0, 0)[3]. In this regard, a bug is observed in Safari [4].

    As a result, we get our result (Fig. 1).

    But what happens if we repaint the background? (Fig. 2)


    Fig. 2

    In this case, we need to remember to redefine the gradient of our rectangle that overlaps the text (Fig. 3).


    Fig. 3

    It was a solid background. We omit the probability that it changes dynamically, but we should not exclude the fact that the background can be set as a gradient (Fig. 4).


    Fig. 4

    Here it is already difficult for us to choose colors for the gradient of our rectangle. I could not close my eyes to this problem, since in our design the background in some places flowed into a gradient (radial, to be precise).

    So, the disadvantages of this method:

    • the gradient color is tied to the background color, and you need to know and remember;
    • if a gradient is applied to the background, then we can’t do anything.

    Solution 1.1. CSS (property "background-clip")


    CSS has a property background-clip(at the time of writing, it is included in the CR [2] status in the specification), which takes three values ​​by the standard border-box, padding-boxand content-box. If you add a prefix to the property -webkit-, one more will appear text(Fig. 5). Just what we need.


    Fig. 5

    The figure (Fig. 5) clearly shows how each value works. It is important that in example c the texttransparent font color is also set, otherwise the application of the property would lose its meaning, because we would not see the background cropped at all.

    Due to this behavior of the background, background-clipwe can solve our problem. Set the font color through the gradient using background(Fig. 6).

    Markup:

    Johnny Sm

    Stylization:

    .text-eclipse {
      background: linear-gradient(to right, rgb(0, 186, 187) 50%, rgba(0, 186, 187, 0) 100%);
      -webkit-background-clip: text;
      color: transparent;
    }
    


    Fig. 6

    Now we are in no way dependent on the background color.

    But, of course, everything is not “perfect”. There are at least two minuses:

    • it is problematic to change the color of the text due to use linear-gradient. I wish that he was inherited and did not care about us;
    • if you need support for IE and Edge [5], then the value of texty background-clipdoes not satisfy this condition, because of which there will simply be a shaded figure (Fig. 7).


    Fig. 7

    Solution 2. SVG


    Before the desire to finally write a Javascript superlibrary that will solve this trivial task prevails, it is worth remembering the beloved and flexible SVG about everyone. Its capabilities are not limited to creating only primitive figures and curves. We are specifically interested in the element .

    We note the following in advance:

    • SVG elements can not determine its size, are responsible for it width, heightand viewBox(if widthand heightto be announced). That is, in our case, no matter how long the text is, it will not affect the parent;
    • There are two main attributes for styling any SVG elements: fill(fill color) and stroke(stroke color). If we draw an analogy with CSS, then the first is immediately both backgound, and color, and the second - border-color. It turns out that we can calmly fill the gradient with fill.

    Let us first describe the gradient:


    This is equivalent to writing linear-gradient(to right, rgb(0, 186, 187) 50%, rgba(0, 186, 187, 0) 100%).

    Apply a gradient to the text:

    Johnny Sm

    As a result, we obtain (Fig. 8):


    Fig. 8

    Hmm, something went wrong. Let's figure it out.

    With the dimensions, everything is clear: we did not specify them, so the default sizes (300x150) were applied. Then the problem is with the positioning of the text.

    There is an attribute for vertical positioning y. Let’s give it half the height of the SVG. As with the method of vertical positioning of blocks through, top: 50%we need to do something like this transform: translateY(-50%). The attribute of dythe element will help us . We will set the relative unit. This is approximately 0.3emthe size of the font (Fig. 9).

    Markup:

    Johnny Sm


    Fig. 9

    Now let's deal with the sizes. Since the elements cannot resize the SVG, we will create an HTML element with the same text, and we will position the SVG absolutely relative to it.

    Markup:

    Johnny SmJohnny Sm

    Stylization:

    .text-eclipse {
      position: relative;
      display: inline-block;
    }
    .text-eclipse svg {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
    .text-eclipse span {
      color: transparent;
    }
    

    Now the color is wired in the element , but we would like it to be inherited from color. For this we need to ask stop-color: currentColorfor .

    Stylization:

    .text-eclipse stop {
      stop-color: currentColor;
    }
    

    In principle, everything. Let's polish some points and add ARIA attributes.

    Markup:

    Johnny Sm

    Note:

    • just in case, we set width="0"and height="0"so that the page does not jump before applying CSS;
    • aria-hidden="true" hide from screen readers;

    Stylization:

    .text-eclipse {
      position: relative;
      display: inline-block;
    }
    .text-eclipse svg {
      position: absolute;
      top: 0;
      left: 0;
      z-index: 0;
      width: 100%;
      height: 100%;
    }
    .text-eclipse stop {
      stop-color: currentColor;
    }
    .text-eclipse span {
      position: relative;
      z-index: 5; /* 1  */
      color: transparent;
    }
    

    1. make the HTML element the main one in the stream, since the SVG acts only as a "mask".


    Demo

    And here it is not without problems:

    • the value dyfor vertical alignment is strictly dependent on the font family used;
    • depending on the font, the “tail” of the first letter in the word may be truncated (you can specify overflow: visibley , but this will not work in IE and Safari);
    • as in SVG masks, gradients, patterns, etc. there must be a unique id for their use, for a new id should be generated in order to avoid conflicts between several such elements. To put in one gradient does not work, so we inherit the color from the concrete ;
    • there is no way to change the font color through CSS for hover, focus, etc.

    If we talk about cross-browser compatibility, it should work wherever SVG 1.0 is supported.

    Total


    Of the solutions considered, I, of course, give my preference to the SVG option, since it is much more flexible than the others. Neither the background color nor the gradient bothers us at all. We work with plain text, and SVG is fine-tuned.

    In general, the task is really simple, you only need attentiveness and good knowledge to solve it quickly.

    If you have comments or suggestions, then please share them in the comments to the article.

    Thanks.

    UPD:
    • Added a note to the support of Edge properties background-clip: text. Thanks monochromer .
    • It was rightly noticed about the moment with the selection of text that I missed. Thanks questor
    • He answered in the thread about the remark “What about multi-line text?” . Thanks kazmiruk . Created a demo .
    • Fixes for Solution 3: fixed bugs in SVG and CSS code; added a link to codepen with a demo; added another drawback to the third color change solution.

    Note


    1. In the example, we have a limit of 9 characters. The task of cutting off excess characters on the server or on the client is purely individual.
    2. CR - Candidate Recommendation.
    3. CSS Image Values ​​and Replaced Content Module Level 3; 4.4 Gradient Color-Stops
    4. Bug with transparent in Safari
    5. background-clip: text does not work in versions of Edge <12

    Also popular now: