Search code examples
htmlcsspseudo-class

html label:after content needs to have different colors in the text


I have the display name of my model properties set, but I need them to display with a colon if they're not required and a colon and a red asterisk if they are.

I didn't want to add the colon to the display name since I don't want the colon to appear in error messages and I may want to display them somewhere without it.

I used the following style in my HTML file for adding the colon:

.my-label > label:after {
        content: ": ";
}

However I can't figure out how to get a red asterisk to display after that if the field is required.

I could create another style class to include the asterisk, however if I change the color it's either all red or all black. I'm not sure I want to set the actual model property to be required because I'm not sure I want a universal rule stating that it is required.

Any suggestions of a better way to handle this would be welcome.


Solution

  • The problem

    It is not possible to use different colours in a single pseudo element. In this case you are able to output :* using the :after pseudo element but are not able to make the characters different colours.

    Solution 1

    One possible way to achieve what you are after is to use the :before pseudo element. The overriding issue, of course is that this will put the asterisk at the beginning of the label. You can fix this by making the label use the flexbox model. This will allow the order of the pseudo elements to be changed allowing you to place the :before element at the end of the label:

    .my-label > label {
      display: inline-flex;
    }
    .my-label.required > label:before {
      color: red;
      content: "*";
      order: 1;
    }
    .my-label > label:after {
      content: ":";
    }
    <div class="my-label">
      <label>Not required</label>
      <input type="text" />
    </div>
    <div class="my-label required">
      <label>Required</label>
      <input type="text" />
    </div>

    The drawbacks

    The drawbacks to this solution is that if the user is using a browser that does not support flexbox or IE (where a bug stops the flexbox rules being applied to pseudo elements) the asterisk will be displayed before the label.

    Solution 2

    A second way to achieve this would be to use absolute positioning. By setting label to position: relative; you can position the :before element at its end by making it position: absolute; and right: 0;. By adding some right padding you can "reserve" space for the element so the text doesn't overlap.

    .my-label > label {
      /*10px is for old browsers which don't support the ch unit*/
      padding-right: 10px;
      padding-right: 1ch;
      position: relative;
    }
    .my-label.required > label:before {
      color: red;
      content: "*";
      position: absolute;
      right: 0;
    }
    .my-label > label:after {
      content: ":";
    }
    <div class="my-label">
      <label>Not required</label>
      <input type="text" />
    </div>
    <div class="my-label required">
      <label>Required</label>
      <input type="text" />
    </div>

    The drawbacks

    Not many drawbacks to this method as it should work in the majority of browsers (even older ones).