[Special Summer Sale] 40% OFF All Magento 2 Themes

Cart

Is it possible to apply CSS to half of a character?

  • This topic is empty.
Viewing 6 posts - 16 through 21 (of 21 total)
  • Author
    Posts
  • #9121
    David Hoang
    Keymaster

    This can be achieved with just CSS :before selector and content property value.

    .halfed, .halfed1 {
      float: left;
    }
    
    .halfed, .halfed1 {
      font-family: arial;
      font-size: 300px;
      font-weight: bolder;
      width: 200px;
      height: 300px;
      position: relative; /* To help hold the content value within */
      overflow: hidden;
      color: #000;
    }
    
    
    
    
    .halfed:before, .halfed1:before   {
      width: 50%; /* How much we'd like to show */
      overflow: hidden; /* Hide what goes beyond our dimension */  
      content: 'X'; /* Halfed character */
      height: 100%;
      position: absolute;
      color: #28507D;
    
    }
    
    
    
    /* For Horizontal cut off */ 
    
    .halfed1:before   {
      width: 100%;
      height: 55%;
      
    }
    <div class="halfed"> X </div>
    
    <div class="halfed1"> X </div>

    >> See on jsFiddle

    #9119
    David Hoang
    Keymaster

    You can use below code. Here in this example I have used h1 tag and added an attribute data-title-text="Display Text" which will appear with different color text on h1 tag text element, which gives effect halfcolored text as shown in below example

    enter image description here

    body {
      text-align: center;
      margin: 0;
    }
    
    h1 {
      color: #111;
      font-family: arial;
      position: relative;
      font-family: 'Oswald', sans-serif;
      display: inline-block;
      font-size: 2.5em;
    }
    
    h1::after {
      content: attr(data-title-text);
      color: #e5554e;
      position: absolute;
      left: 0;
      top: 0;
      clip: rect(0, 1000px, 30px, 0);
    }
    <h1 data-title-text="Display Text">Display Text</h1>
    #9123
    David Hoang
    Keymaster

    How about something like this for shorter text?

    It could even work for longer text if you did something with a loop, repeating the characters with JavaScript. Anyway, the result is something like this:

    Is it possible to apply CSS to half of a character?

    p.char {
      position: relative;
      display: inline-block;
      font-size: 60px;
      color: red;
    }
    
    p.char:before {
      position: absolute;
      content: attr(char);
      width: 50%;
      overflow: hidden;
      color: black;
    }
    <p class="char" char="S">S</p>
    <p class="char" char="t">t</p>
    <p class="char" char="a">a</p>
    <p class="char" char="c">c</p>
    <p class="char" char="k">k</p>
    <p class="char" char="o">o</p>
    <p class="char" char="v">v</p>
    <p class="char" char="e">e</p>
    <p class="char" char="r">r</p>
    <p class="char" char="f">f</p>
    <p class="char" char="l">l</p>
    <p class="char" char="o">o</p>
    <p class="char" char="w">w</p>
    #9118
    David Hoang
    Keymaster

    Just for the record in history!

    I’ve come up with a solution for my own work from 5-6 years ago, which is Gradext ( pure javascript and pure css, no dependency ) .

    The technical explanation is you can create an element like this:

    <span>A</span>
    

    now if you want to make a gradient on text, you need to create some multiple layers, each individually specifically colored and the spectrum created will illustrate the gradient effect.

    for example look at this is the word lorem inside of a <span> and will cause a horizontal gradient effect ( check the examples ):

     <span data-i="0" style="color: rgb(153, 51, 34);">L</span>
     <span data-i="1" style="color: rgb(154, 52, 35);">o</span>
     <span data-i="2" style="color: rgb(155, 53, 36);">r</span>
     <span data-i="3" style="color: rgb(156, 55, 38);">e</span>
     <span data-i="4" style="color: rgb(157, 56, 39);">m</span>
    

    and you can continue doing this pattern for a long time and long paragraph as well.

    enter image description here

    But!

    What if you want to create a vertical gradient effect on texts?

    Then there’s another solution which could be helpful. I will describe in details.

    Assuming our first <span> again. but the content shouldn’t be the letters individually; the content should be the whole text, and now we’re going to copy the same ‍‍<span> again and again ( count of spans will define the quality of your gradient, more span, better result, but poor performance ). have a look at this:

    <span data-i="6" style="color: rgb(81, 165, 39); overflow: hidden; height: 11.2px;">Lorem ipsum dolor sit amet, tincidunt ut laoreet dolore magna aliquam erat volutpat.</span>
    <span data-i="7" style="color: rgb(89, 174, 48); overflow: hidden; height: 12.8px;">Lorem ipsum dolor sit amet, tincidunt ut laoreet dolore magna aliquam erat volutpat.</span>
    <span data-i="8" style="color: rgb(97, 183, 58); overflow: hidden; height: 14.4px;">Lorem ipsum dolor sit amet, tincidunt ut laoreet dolore magna aliquam erat volutpat.</span>
    <span data-i="9" style="color: rgb(105, 192, 68); overflow: hidden; height: 16px;">Lorem ipsum dolor sit amet, tincidunt ut laoreet dolore magna aliquam erat volutpat.</span>
    <span data-i="10" style="color: rgb(113, 201, 78); overflow: hidden; height: 17.6px;">Lorem ipsum dolor sit amet, tincidunt ut laoreet dolore magna aliquam erat volutpat.</span>
    <span data-i="11" style="color: rgb(121, 210, 88); overflow: hidden; height: 19.2px;">Lorem ipsum dolor sit amet, tincidunt ut laoreet dolore magna aliquam erat volutpat.</span>
    

    enter image description here

    Again, But!

    what if you want to make these gradient effects to move and create an animation out of it?

    well, there’s another solution for it too. You should definitely check animation: true or even .hoverable() method which will lead to a gradient to start based on cursor position! ( sounds cool xD )

    enter image description here

    this is simply how we’re creating gradients ( linear or radial ) on texts. If you liked the idea or want to know more about it, you should check the links provided.


    Maybe this is not the best option, maybe not the best performant way to do this, but it will open up some space to create exciting and delightful animations to inspire some other people for a better solution.

    It will allow you to use gradient style on texts, which is supported by even IE8!

    Here you can find a working live demo and the original repository is here on GitHub as well, open source and ready to get some updates ( 😀 )

    This is my first time ( yeah, after 5 years, you’ve heard it right ) to mention this repository anywhere on the Internet, and I’m excited about that!


    [Update – 2019 August:] Github removed github-pages demo of that repository because I’m from Iran! Only the source code is available here tho…

    #9116
    David Hoang
    Keymaster

    enter image description here

    Here is a CSS only solution for a full line of text, not just a character element.

    div {
        position: relative;
        top: 2em;
        height: 2em;
        text-transform: full-width;
    }
    
    div:before,
    div:after {
        content: attr(data-content);
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
    }
    
    div:after {
        color: red;
        /* mask for a single character. By repeating this mask, all the string becomes masked */
        -webkit-mask-image: linear-gradient(to right, transparent 0, transparent .5em, white .5em, white 1em);
        -webkit-mask-repeat: repeat-x;  /* repeat the mask towards the right */
        -webkit-mask-size: 1em;         /* relative width of a single character */ 
        
        /* non-vendor mask settings */
        mask-image: linear-gradient(to right, transparent 0, transparent .5em, white .5em, white 1em);
        mask-repeat: repeat-x;
        mask-size: 1em;
    }
    
    
    /* demo purposes */
    input[name="fontSize"]:first-of-type:checked ~ div {
        font-size: 1em;
    }
    
    input[name="fontSize"]:first-of-type + input:checked ~ div {
        font-size: 2em;
    }
    
    input[name="fontSize"]:first-of-type + input + input:checked ~ div {
        font-size: 3em;
    }
    Font-size:
      <input type="radio" name="fontSize" value="1em">
      <input type="radio" name="fontSize" value="2em" checked>
      <input type="radio" name="fontSize" value="3em">
    
      <div data-content="A CSS only solution..."></div>
      <div data-content="Try it on Firefox!"></div>

    The idea is to apply an horizontal CSS mask for each character, that hides the first half of it [0 – 0.5em] and shows the second half [0.5em – 1em].

    The width of the mask is mask-size: 1em to match the width of the very first character in the string.
    By using the mask-repeat: repeat-x, the same mask is applied to the second, third character and so on.

    I thought that using the font monospace would solve the problem of using same-width letters, but I was wrong.
    Instead, I solved it by using the text-transform: full-width, that unfortunatelly is only supported by Firefox, I believe.

    The use of relative unit em allows the design to scale up/down depending on the font-size.

    Vanilla JavaScript solution for all browsers

    If Firefox is not an option, then use this script for the rescue.

    It works by inserting a child span for each character. Inside each span, a non-repeated CSS mask is placed from [0% – 50%] and [50% – 100%] the width of the letter (which is the width of the span element).

    This way we don’t have anymore the restriction of using same-width characters.

    const
        dataElement = document.getElementById("data"),
        content = dataElement.textContent,
        zoom = function (fontSize) {
            dataElement.style['font-size'] = fontSize + 'em';           
        };
    
    while (dataElement.firstChild) {
        dataElement.firstChild.remove()
    }
    for(var i = 0; i < content.length; ++i) {
        const
            spanElem = document.createElement('span'),
            ch = content[i];    
        spanElem.setAttribute('data-ch', ch);
        spanElem.appendChild(document.createTextNode(ch === ' ' ? '\u00A0' : ch));
        data.appendChild(spanElem);
    }
    #data {
        position: relative;
        top: 2em;
        height: 2em;
        font-size: 2em;
    }
    
    #data span {
        display: inline-block;
        position: relative;
        color: transparent;
    }
    
    #data span:before,
    #data span:after {
        content: attr(data-ch);
        display: inline-block;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        text-align: center;
        color: initial;
    }
    
    #data span:after {
        color: red;
        -webkit-mask-image: linear-gradient(to right, transparent 0, transparent 50%, white 50%, white 100%);
        mask-image: linear-gradient(to right, transparent 0, transparent 50%, white 50%, white 100%);
    }
    Font-size:
    <input type="range" min=1 max=4 step=0.05 value=2 oninput="zoom(this.value)" onchange="zoom(this.value)">
    
    <div id="data">A Fallback Solution...For all browsers</div>
    #9117
    David Hoang
    Keymaster

    All solutions work by splitting letters and wrapping them in <span>. We don’t have to split letters in two cases:

    • If font is monospace.
    • If vertical layout is used.
    div {
      font-size: 80px;
      font-weight: bolder;
      color: transparent;
      padding: 0;
      margin: 0;
      background: linear-gradient(90deg, rgb(34, 67, 143) 0% 50%, #409FBF 50%);
      background-clip: text;
      -webkit-background-clip: text;
    }
    
    .one {
      font-family: 'Nova Mono';
      background-repeat: repeat-x;
      background-size: 45px;
    }
    
    .two {
      font-family: 'Gideon Roman';
      writing-mode: vertical-lr;
      text-orientation: upright;
      letter-spacing: -35px;
      height: 500px;
    }
    <!-- get the fonts -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Nova+Mono&display=swap" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Gideon+Roman&display=swap" rel="stylesheet">
    
    
    <div id='one' class="one">X-RAY Winter</div>
    <div class="two">Minty</div>

    Expected output, in case the fonts are not available:

    enter image description here

    I know use of background-clip and gradient has been already demonstrated in other answers, just putting the cases where you don’t have to split the letters.

Viewing 6 posts - 16 through 21 (of 21 total)
  • You must be logged in to reply to this topic.