liveBook · Manning

Style creep

As explained in Web Components in Action

Style creep is the unintended spread of CSS rules beyond the elements or component boundaries they were meant to affect.

Style creep occurs when CSS rules affect elements beyond their intended targets. A selector such as `button` can style unrelated page content, while a component-scoped selector can still reach nested component descendants. section 9.1

A stepper caught by global button styles

A numerical stepper needs red buttons flush against its number. Defining its rules as `sample-component button` limits ordinary selector matching to the component, but a page-wide `button` rule can still alter its appearance. Shadow DOM prevents outside selectors from penetrating the component, although inherited styles from an ancestor such as `body` can still affect its contents. Use `:host` for the host itself, and `:host { all: initial; }` when the component must reset inherited styling. section 9.1 section 9.2

Useful boundaries and cautions include:

  • Scope selectors to the component when working without Shadow DOM. section 9.1
  • Use Shadow DOM to block outside selectors from matching internal classes and elements. section 9.2
  • Remember that inherited ancestor styles can cross the boundary even when selectors cannot. section 9.2
Listing 9.3. Using the Shadow DOM to protect our stepper component’s style
class SampleComponent extends HTMLElement {
   connectedCallback() {
       const root =                                             #1
           this.attachShadow({mode: 'open'});
       root.innerHTML = `<button class="big-button">-</button>
                         <span class="increment-number">5</span>
                         <button class="big-button">+</button>
           <style>
                sample-component {
                   display: flex;
                }

                span {                                          #2
                   font-size: 24px;
                   background-color: #770311;
                   color: white;
                   font-family: Helvetica;
                   display: inline-block;
                   padding: 11px;
                   border: none;
                }
                button {
                   border-radius: 0 50px 50px 0;
                   border: none;
                   width: 50px;
                   height: 50px;
                   font-size: 36px;
                   font-weight: bold;
                   background: none;
                   background-color: red;
                   color: white;
               }

               button:first-child {
                   border-radius: 50px 0 0 50px;
               }

               button:active {
                   background-color: #960000;
               }

               button:focus {
                   outline: thin dotted;
               }

           </style>`;
   }
}

Inspect the stepper implementation that moves its markup into an open Shadow DOM and demonstrates component-local selectors. section 9.2

How Web Components in Action covers it

How deep it goes
Works through selector scope, nested components, Shadow DOM, `:host`, and inherited styles, but stops short of broader CSS architecture.
Examples
Uses a numerical stepper, global button rules, nested buttons, inherited body text, and `:host { all: initial; }`.
What it assumes
Assumes basic CSS selectors and Web Components while demonstrating Shadow DOM behavior through a minimal JavaScript component.
What you can do after
Apply it via scoped selectors and Shadow DOM boundaries to contain component styles and diagnose inherited-style surprises.
How it connects
Connects CSS selectors with Web Components, Shadow DOM, CSS encapsulation, inheritance, and specificity.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Web Components in Action. The section links point to the parts of the book it draws on.