DEV Community

Cover image for How to use CSS pseudo-classes for styling typographic elements
crayoncode
crayoncode

Posted on

How to use CSS pseudo-classes for styling typographic elements

Today let's work with CSS pseudo-selectors like :first-letter, :last-of-type & :after to build nice little typpgraphic elements in four different color themese that will spice up your text.

Read the full article or watch me code this on Youtube (TL;DW Speedrun):

Result

First Things First - Colors

To have all the colors at hand, each one is defined as a CSS custom property (aka variable) inside the :root scope. For a slight taste of theming the variables background-color and foreground-color are defined and used later on.

:root {
  --cc-p-1: #d4aee0;
  --cc-p-2: #8975b4;
  --cc-p-3: #64518a;
  --cc-p-4: #565190;
  --cc-b-1: #44abac;
  --cc-b-2: #2ca7d8;
  --cc-b-3: #1482ce;
  --cc-b-4: #05597c;
  --cc-g-1: #b2dd57;
  --cc-g-2: #57c443;
  --cc-g-3: #05b853;
  --cc-g-4: #19962e;
  --cc-y-1: #fdc82e;
  --cc-y-2: #fd9c2e;
  --cc-y-3: #d5385a;
  --cc-y-4: #911750;
  --cc-s-1: #d9d9d9;
  --cc-s-2: #9e9e9e;
  --cc-s-3: #666666;
  --cc-s-4: #2b2b2b;

  --foreground-color: white;
  --background-color: var(--cc-s-4);
}
Enter fullscreen mode Exit fullscreen mode

Color Themes

There will be four different color themes for the typographic elements: Amethyst (purple), sapphire (blue), emerald (green) and amber (yellow/orange/red). To make these themes easily usable, a <section> element must have one of the four classes given below, whereas each class simply defines a set of CSS variables which are later used for the gradients.

section {
  &.amethyst {
    --c-1: var(--cc-p-1);
    --c-2: var(--cc-p-2);
    --c-3: var(--cc-p-3);
    --c-4: var(--cc-p-4);
  }

  &.sapphire {
    --c-1: var(--cc-b-1);
    --c-2: var(--cc-b-2);
    --c-3: var(--cc-b-3);
    --c-4: var(--cc-b-4);
  }

  &.emerald {
    --c-1: var(--cc-g-1);
    --c-2: var(--cc-g-2);
    --c-3: var(--cc-g-3);
    --c-4: var(--cc-g-4);
  }

  &.amber {
    --c-1: var(--cc-y-1);
    --c-2: var(--cc-y-2);
    --c-3: var(--cc-y-3);
    --c-4: var(--cc-y-4);
  }
}
Enter fullscreen mode Exit fullscreen mode

Basic Principle

CSS allows us to specify multiple linear-gradients which are then nicely blended into each other. Luckily also background-size & background-position accept multiple, comma separated values, so each gradient can be sized and positioned inidividually. However, this time we're not intersted in creating actual gradients, but tiny mosaic squares each having a unique, so the gradients are created with two times the same color. So in order to create a background containing four squares, the background property is setup to have four linear gradients with two times the same color. Also note that setting background-origin to border-box is essential for this to work.

<selector> {
  background:
    linear-gradient(
      var(--c-1),
      var(--c-1)
    ),
    linear-gradient(
      var(--c-2),
      var(--c-2)
    ),
    linear-gradient(
      var(--c-3),
      var(--c-3)
    ),
    linear-gradient(
      var(--c-4),
      var(--c-4)
    );
  background-origin: border-box;
  background-repeat: no-repeat;
}
Enter fullscreen mode Exit fullscreen mode

Now each gradient is positioned in the top left, top right, bottom left and bottom right corner which is achived by providing four x/y pairs tothe background-position property:

<selector> {
  ... 

  background-position:
    0% 0%,
    100% 0%,
    0% 100%,
    100% 100%;
  background-size: 50% 50%;
}
Enter fullscreen mode Exit fullscreen mode

SASS Mixins for Reusability

Since we'll be using the gradient setup from above multiple times, we'll group it into two mixins for easy reusing:

@mixin mosaic-base() {
  background:
    linear-gradient(
      var(--c-1),
      var(--c-1)
    ),
    linear-gradient(
      var(--c-2),
      var(--c-2)
    ),
    linear-gradient(
      var(--c-3),
      var(--c-3)
    ),
    linear-gradient(
      var(--c-4),
      var(--c-4)
    );
  background-origin: border-box;
  background-repeat: no-repeat;
}

@mixin mosaic() {
  @include mosaic-base;

  background-position:
    0% 0%,
    100% 0%,
    0% 100%,
    100% 100%;
  background-size: 50% 50%;
}
Enter fullscreen mode Exit fullscreen mode

Headline

The headline is going to have a bar below itself having four partial lines positioned one after another:

<section>
  <h2>Mosaic Typographic Elements</h2>
</section>
Enter fullscreen mode Exit fullscreen mode

The mosaic gradients are simply applied to an ::after pseudo-class so there is no additional markup needed. Since the h2 styles are nested within the section selector, the variables for the color theme defined there can be used perfectly well.

section {
  h2 {
    display: block;
    font-weight: 300;
    text-align: center;
    font-size: 2rem;

    position: relative;

    &::after {
      --width: 8rem;
      --height: 2px;

      content: "";

      display: inline-block;
      width: var(--width);
      height: var(--height);

      position: absolute;
      left: 50%;
      bottom: -1rem;
      transform: translate(-50%, -50%);

      @include mosaic-base;
      background-position:
        0% 0%,
        33% 0%,
        67% 0%,
        100% 0%;
      background-size:
        25% 100%,
        26% 100%,
        25% 100%,
        25% 100%;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

First Letter Styling

In order to style each first letter that appears after a heading let's use the so called adjacent sibling selector to identity each paragraph of text <p> coming directly after a heading <h2>. The :first-letter pseudo-class allows us to apply styles very selectively to - as the name strongly indicates - the very first letter of the paragraph. In order to have text flowing nicely around the letter setting float: right; is necessary. The rest is simply adjusting font size and spacings to make it look nice.

section {
  h2 + p:first-letter {
    font-weight: 900;
    font-size: 1.6em;
    float: left;
    margin-right: 0.1em;
    margin-top: 0.2em;
    padding: 0em 0.1em;

    color:
      var(--background-color);


    @include mosaic;
  }
}
Enter fullscreen mode Exit fullscreen mode

Ruler Styling

The HTML <hr> element alows us to put a horizontal ruler for dividing e.g. paragraphs or any other elements from each other.

<hr>
Enter fullscreen mode Exit fullscreen mode

So, here we'll be overriding the styling of the <hr> element to have a mosaic in its center tilted by 45 degrees. Again, we're using the ::after pseudo-class to create the necessary element for the mosaic without requiring additional markup.

section {
  hr {
    --size: 1rem;

    width: 60%;
    height: 1px;
    border: none;
    background: var(--cc-s-2);

    &::after {
      content: '';
      display: inline-block;
      width: var(--size);
      height: var(--size);

      position: absolute;
      left: 50%;
      transform:
        translate(-50%, -50%)
        rotate(45deg);

      border: 4px solid var(--background-color);

      @include mosaic;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Tombstone (you read that right)

A so called tombstone appears at the end of e.g. an article letting the reader know, that the end was reached. The :last-of-type pseudo-class helps us to identify the last element of a given type, so e.g. the last paragraph of text in a section, which is exactly what we need. Now, all we have to do is to simply add another ::after pseudo-class containing the mosaic gradients and being floated to the right. And done! 😎

section {
  p:last-of-type::after {
    --size: 0.5em;
    content: '';

    float: right;
    width: var(--size);
    height: var(--size);
    position: relative;
    top: 0.5em;

    @include mosaic;
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
emanuel152020 profile image
Emanuel152020

Hello CrayonCode, I am delighted with your article, I would like to talk about programming, are you willing?

Collapse
 
crayoncode profile image
crayoncode

Hello Emanuel,
What's your main field of interest (web, datastructures, coding practices,...)? What kind of discussion/talk do you have in mind?

Collapse
 
emanuel152020 profile image
Emanuel152020

Web programming