Search code examples
csspseudo-element

Change color of ::before pseudo-element based on contextual text in CSS


I've got this CSS code snippet which is designed to apply a gradient background to specific text elements. The gradient's configuration is determined by the width of the tag. Since there isn't an alternative method to directly access the contextual text of any element using pure CSS, this width-based approach is being utilized:

span {
    width: fit-content !important;
    color: #0000;
    background:
        linear-gradient(rgb(247, 117, 110) 0 0) 0/calc(70px - 100%) 100%,
        linear-gradient(hsl(123, 90%, 40%) 0 0) 0/calc(100px - 100%) 100%;
    -webkit-background-clip: text;
    background-clip: text;
}

span::before {
    border-radius: 50%;
    content: "";
    display: inline-block;
    margin-right: 0.5em;
    width: 0.5em;
    height: 0.5em;
    vertical-align: 0.1em;
    background: #d2d7f5;
}
<span>Upcoming</span>
<span>Past</span>
<span>Upcoming</span>
<span>Past</span>

Is there a way to change the background color of the ::before pseudo-element based on the element as well?


Solution

  • Solution

    Although background property isn't inheritable, text related properties usually are. Assign text to the content property of the pseudo-element ::before and it will inherit the text color of the <span>, see Figure I1.

    Figure I

    span::before {
      content: "●" /* OR "\0025cf" ¹ */
    }
    

    Corrections

    Figure II is a list of discrepancies that you should be aware of.

    Figure II

    CSS Discrepancy Correction


    width: fit-content !important;


    <span> is an inline element which already behaves like width: fit-content, also the use of !important is highly discouraged. Remove it.

    background-clip: text

    Not needed with -webkit-background-clip: text; and -webkit-text-fill-color: transparent;2. Remove it.

    span::before

    Focus on the text content, not the shape of the pseudo-element. Remove everything but margin and change content to text.

    1 For additional ascii characters, see this search.

    2 For details, see this article.

    Example

    /**
     * Any font-size assigned to <html> will be the reference size for 1rem.
     * ex. 2ch = 1rem.
     * ch units is used because 1ch equals the width of a zero: 0
     * font-family: Consolas is a monospace type -- which means all characters
     * are the same size.
     * All of the above styles makes it easier to make more accurate lengths for
     * text widths using rems.
     */
    :root {
      font: 2ch/1 Consolas;
    }
    
    span {
      display: inline-flex;
      align-items: center;
      background: 
        /* Red - 1 to 5 characters */
        linear-gradient(#F7756E 0 0) 0 / calc(5rem - 100%) 100%, 
        /* Green - 6 to 11 characters */
        linear-gradient(#45D14B 0 0) 0 / calc(8rem - 100%) 100%, 
        /* Blue - 12 to 19 characters */
        linear-gradient(#27A7E9 0 0) 0 / calc(12rem - 100%) 100%, 
        /* Orange - 20 to 28 characters */
        linear-gradient(#FF8B00 0 0) 0 / calc(17rem - 100%) 100%;
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    }
    
    span::before {
      content: "●";
      margin: 0 0.5rem;
    }
    <span>012345</span>
    <span>0123456</span>
    <span>0123456789abc</span>
    <span>0123456789abcdef0123</span>