DEV Community

Cover image for 180 Days of Frontend Development Challenge: Day 35 CSS Pseudo-classes and Pseudo-elements
CodeWithDhanian
CodeWithDhanian

Posted on

180 Days of Frontend Development Challenge: Day 35 CSS Pseudo-classes and Pseudo-elements

Greetings, diligent developers! We've made incredible strides in mastering CSS layouts with Flexbox and Grid. Today, on Day 35, we're taking a slightly different turn, but one that is equally crucial for dynamic and interactive styling: CSS Pseudo-classes and Pseudo-elements.

These powerful CSS features allow you to style elements based on their state (like when a link is hovered over) or to style specific parts of an element without needing to add extra HTML. Think of them as CSS superpowers that let you target elements or even parts of elements that don't have unique IDs or classes, or that change based on user interaction.

The Magic of Pseudo-Selectors

At first glance, pseudo-classes and pseudo-elements might sound intimidating due to their names. But in practice, they are incredibly intuitive and open up a world of possibilities for more engaging and accessible user interfaces. They help you respond to user actions and create richer visual details.

Key Concepts We'll Demystify Today:

Pseudo-classes (: single colon): These select elements based on a state or characteristic that is not directly available in the document tree (i.e., not a class or ID). They describe a special state of the selected element.

  1. User Action Pseudo-classes:
  * **`:hover`**: Styles an element when the user's mouse pointer is over it.
  * **`:active`**: Styles an element when it is being activated by the user (e.g., a button being clicked down).
  * **`:focus`**: Styles an element when it has focus (e.g., an input field selected by tabbing). Essential for accessibility\!
  * **`:visited`**: Styles links that the user has already visited.
  * **`:link`**: Styles unvisited links. (Often you'll see `:link` and `:visited` combined with `:hover` and `:active` in the "LVHA" order to ensure proper styling: Link, Visited, Hover, Active).
Enter fullscreen mode Exit fullscreen mode
  1. Structural Pseudo-classes: These select elements based on their position within the document structure.
  * **`:first-child`**: Selects the first child of its parent.
  * **`:last-child`**: Selects the last child of its parent.
  * **`:nth-child(n)`**: Selects children based on their position. `n` can be a number (e.g., `3`), a keyword (e.g., `odd`, `even`), or a formula (e.g., `2n` for every second child, `2n+1` for every odd child). This is incredibly versatile for striping tables or grids\!
  * **`:nth-last-child(n)`**: Similar to `nth-child`, but counts from the last child.
  * **`:only-child`**: Selects an element if it is the *only* child of its parent.
Enter fullscreen mode Exit fullscreen mode
  1. Form Pseudo-classes:
  * **`:checked`**: Selects radio buttons or checkboxes that are checked.
  * **`:disabled`**: Selects input elements that are disabled.
  * **`:enabled`**: Selects input elements that are enabled.
  * **`:valid`**: Selects input elements whose content validates correctly (e.g., an email input with a valid email format).
  * **`:invalid`**: Selects input elements whose content is invalid.
Enter fullscreen mode Exit fullscreen mode

Pseudo-elements (:: double colon): These select and style a part of an element. They create a "virtual" element that isn't in your HTML but exists in the rendering.

  1. ::before: Inserts content before the content of an element. Requires the content property. Often used for decorative icons, clearfixes, or purely CSS-generated content.
  2. ::after: Inserts content after the content of an element. Also requires the content property. Similar uses to ::before.
  3. ::first-line: Styles the first line of a block-level element. The length of the "first line" depends on the browser window size.
  4. ::first-letter: Styles the first letter of a block-level element. Great for drop caps!
  5. ::selection: Styles the portion of an element that is selected by the user (highlighted with the mouse).

Let's Get Our Hands Dirty (Code Examples):

HTML:

<nav class="main-nav">
    <a href="#" class="nav-link">Home</a>
    <a href="#" class="nav-link">About</a>
    <a href="#" class="nav-link visited-link">Services</a>
    <a href="#" class="nav-link">Contact</a>
</nav>

<form class="my-form">
    <label for="name">Name:</label>
    <input type="text" id="name" required>

    <label for="email">Email:</label>
    <input type="email" id="email" required>

    <label>
        <input type="checkbox" id="newsletter"> Subscribe to newsletter
    </label>
    <button type="submit" disabled>Submit</button>
</form>

<ul class="product-list">
    <li>Product A</li>
    <li>Product B</li>
    <li>Product C</li>
    <li>Product D</li>
    <li>Product E</li>
</ul>

<p class="intro-paragraph">
    This is an introduction paragraph where we will demonstrate the power of
    pseudo-elements. We can style the first letter and even the first line
    of this text to create some interesting visual effects.
</p>

<button class="custom-button">Click Me</button>
Enter fullscreen mode Exit fullscreen mode

CSS:

/* --- Pseudo-classes Examples --- */

/* Basic link styling */
.main-nav .nav-link {
    color: blue;
    text-decoration: none;
    padding: 10px 15px;
    margin: 5px;
    border: 1px solid blue;
    display: inline-block;
    transition: background-color 0.3s, color 0.3s; /* Smooth transitions */
}

/* 1. User Action Pseudo-classes */
.main-nav .nav-link:hover {
    background-color: lightblue;
    color: white;
}

.main-nav .nav-link:active {
    background-color: darkblue;
    color: white;
    transform: translateY(1px); /* Little press effect */
}

.main-nav .nav-link:focus {
    outline: 2px dashed orange; /* Accessibility focus indicator */
}

.main-nav .visited-link:visited {
    color: purple; /* Styling for visited links */
    border-color: purple;
}

/* 2. Structural Pseudo-classes */
.product-list {
    list-style: none;
    padding: 0;
    margin-top: 20px;
    width: 300px;
    border: 1px solid #eee;
}

.product-list li {
    padding: 10px;
    background-color: #f9f9f9;
    border-bottom: 1px dashed #ddd;
}

.product-list li:first-child {
    font-weight: bold;
    color: darkgreen;
}

.product-list li:last-child {
    font-style: italic;
    color: darkred;
    border-bottom: none; /* Remove last border */
}

.product-list li:nth-child(odd) {
    background-color: #e0f2f7; /* Zebra striping */
}

.product-list li:nth-child(2n) { /* Same as even */
    /* background-color: #cceeff; */
}

.product-list li:only-child {
    background-color: gold; /* If there's only one list item */
}

/* 3. Form Pseudo-classes */
.my-form {
    margin-top: 30px;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    width: 300px;
}

.my-form input {
    margin-bottom: 10px;
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.my-form input:focus {
    border-color: dodgerblue;
    box-shadow: 0 0 5px rgba(30, 144, 255, 0.5);
}

.my-form input:required {
    border-left: 5px solid lightcoral; /* Visual cue for required fields */
}

.my-form input:valid {
    border-left-color: lightgreen; /* Green border when valid */
}

.my-form input:invalid:not(:focus) { /* Style invalid fields only when not focused */
    border-left-color: red; /* Red border when invalid */
}

.my-form #newsletter:checked + label { /* Styles the label next to a checked checkbox */
    font-weight: bold;
    color: darkblue;
}

.my-form button:disabled {
    background-color: #ccc;
    color: #666;
    cursor: not-allowed;
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    margin-top: 15px;
}

.my-form button:enabled {
    background-color: #28a745;
    color: white;
    cursor: pointer;
}


/* --- Pseudo-elements Examples --- */

/* ::before and ::after */
.custom-button {
    background-color: #4CAF50; /* Green */
    color: white;
    padding: 12px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
    position: relative; /* Needed for positioning pseudo-elements */
    overflow: hidden; /* To hide content that overflows */
    margin-top: 30px;
}

.custom-button::before {
    content: "✨ "; /* Add a sparkle emoji before the text */
    /* You can also use background images or shapes */
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0;
    transition: left 0.3s, opacity 0.3s;
}

.custom-button:hover::before {
    left: 5px; /* Move sparkle slightly on hover */
    opacity: 1;
}

.custom-button::after {
    content: " Click Me!"; /* Add extra text or icon after the button text */
    font-size: 0.8em;
    color: #eee;
}

/* ::first-line and ::first-letter */
.intro-paragraph {
    width: 400px;
    line-height: 1.5;
    margin-top: 30px;
    background-color: #f5f5f5;
    padding: 15px;
    border-left: 5px solid teal;
}

.intro-paragraph::first-letter {
    font-size: 3em;
    font-weight: bold;
    color: teal;
    float: left; /* Create a drop cap effect */
    margin-right: 5px;
    line-height: 1;
}

.intro-paragraph::first-line {
    font-weight: bold;
    color: #333;
    text-transform: uppercase;
}

/* ::selection */
::selection {
    background-color: yellow; /* Custom highlight color */
    color: black;
}

/* For Firefox compatibility */
::-moz-selection {
    background-color: yellow;
    color: black;
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Pseudo-classes allow us to react to user interactions (:hover, :active, :focus) or to the inherent state of an element (:visited, :checked, :disabled, :valid, :invalid). They're also great for styling elements based on their position (:first-child, :nth-child, :only-child). Notice how you don't need to add a class="odd" to every other list item; :nth-child(odd) does it automatically!
  • Pseudo-elements (::before, ::after) are unique because they let you inject content or styling without modifying the HTML. This is fantastic for decorative purposes, iconography (like the sparkle on the button), or even implementing layout hacks like clearfix (though Flexbox and Grid have largely made clearfix less necessary). ::first-letter and ::first-line are excellent for typographic flair. ::selection is a cool way to customize the user's text highlighting experience.

Your Challenge for Day 35:

  1. Create a set of navigation links. Apply :link, :visited, :hover, and :active styles to them. Pay attention to the order (LVHA recommended) to ensure all states work correctly.
  2. Design a simple form with various input types (text, email, checkbox, radio button).
    • Style input:focus with a distinct border or shadow.
    • Use :valid and :invalid to provide visual feedback for required fields.
    • Style a checkbox or radio button when it is :checked.
    • Style a submit button when it is :disabled and enabled.
  3. Create an unordered list with at least 5 list items.
    • Style the :first-child and :last-child differently.
    • Implement "zebra striping" on the list items using :nth-child(odd) and :nth-child(even).
  4. Take a paragraph of text.
    • Style its ::first-letter to create a prominent drop cap.
    • Style its ::first-line with a different font weight or color.
  5. Create a button or a div element.
    • Use ::before to add a small icon or a decorative shape before its content.
    • Use ::after to add some extra text or a border after its content. Make these pseudo-elements appear or change on :hover.
  6. Bonus: Try to implement a custom scrollbar style using pseudo-elements like ::-webkit-scrollbar (note: these are non-standard but widely supported in WebKit browsers).

Pseudo-classes and pseudo-elements are truly indispensable tools in a front-end developer's kit. They enable highly interactive and visually rich designs without cluttering your HTML. Experiment, play, and see how much more dynamic your web pages can become!

Keep up the fantastic work! We're building a strong foundation, brick by CSS brick. What creative uses for pseudo-elements can you imagine for your next project?

Top comments (0)