Chapter 9: Modular CSS and scope
The introduction explains why broad effects from CSS changes make organization important and identifies the modules layer as the place to organize most styles into manageable pieces.
After this chapter you will be able to
- Role of the Modules Layer. Describe how the introduction positions the modules layer within the chapter’s approach to organizing CSS.
- Modular CSS and encapsulation. Explain why modular CSS divides a page into reusable parts and gives each part responsibility for its own styles.
- Module identity and composition. Describe how the section identifies individual modules in the DOM and combines them into a page.
- Global styles before modules. Explain why the page needs reset and global styles before building specific modules.
- Class-Based Message Module. Describe how the message module is marked up and styled, and explain why its selector contains only the module’s class name.
- Reuse and Visual Consistency. Explain how reusing one module reduces repeated CSS and keeps similar UI elements visually consistent.
- Module modifier application. Explain how to create and use a variant of a module: put the main module class and a modifier class on the same element, and let the modifier override only the styles that change.
- Location independent module styling. Justify using a directly applied modifier such as dropdown--dark instead of a selector such as .page-header .dropdown to change a module based on its location.
- Media module subelements. Describe the media module’s container, image, body, and title, and explain how BEM-style subelement class names identify an element’s role and parent module.
- Media module right variant. Explain how the media--right variant is added to the media module and how a variant can target a subelement when its styling needs to change.
- Module selector tradeoffs. Distinguish when a subelement class can replace a descendant selector, when a specific tag selector is an acceptable shortcut, and why overly generic tag selectors are risky.
- Single responsibility in modules. Explain why each module should have one concise purpose, and apply the section’s rule of thumb to the dropdown-menu example without treating it as a strict rule.
- Dropdown and menu responsibilities. Explain why the dropdown controls whether its container is visible while the menu styles the list of links, and describe how placing the menu inside the dropdown composes the interface. Explain why the author separates them here without treating every possible split as mandatory.
- Dynamic dropdown state. Trace how clicking the toggle changes the dropdown’s state class and how that class changes its appearance. Describe the purpose and naming convention of state classes.
- Conceptual module names. Explain why a module name should express what the module represents rather than its current use or appearance, using the media module as an example.
- Meaningful variant class names. Explain how to name module variants so their names remain meaningful when a design changes, including when relative size names are acceptable.
- Browser-enforced modular boundaries. Explain how @scope offers an alternative to class-naming conventions for keeping module styles from conflicting.
- Scoped selectors and root. Describe how a scope selector, the rules inside its block, and :scope target the media module.
- Nested scope precedence. Explain how the cascade resolves conflicting declarations from nested scopes: selector specificity takes precedence, then the nearer scope, then source order. Describe why the media module’s heading remains dark gray inside a highlight block.
- Scoping Limit Boundaries. Explain how the `to` keyword gives an `@scope` rule an inner boundary and why that prevents styles from reaching into nested content.
- Proximity Versus Exclusion. Distinguish proximity precedence from a scoping limit when an outer module and an inner module style the same content.
- Selective Module Reach. Describe how scoping limits protect nested modules and how two `@scope` rules can give different selectors different reach.
- Implicit scope from parent. Explain how a selectorless @scope rule in a style tag inside a scope root gets its scope.
- Scope and specificity precedence. Explain why an inner scope does not automatically override an outer scope, and how a scoping limit or selector specificity can control whether a parent module affects a child module.
- Layers alongside scope. Describe how cascade layers provide another way to set precedence alongside scope, including the section’s example of module sublayers.
- Page assembly from existing modules. Explain how reusable CSS modules change the way a developer builds a page: they can assemble it from existing modules by using the required HTML structure and class names, often without writing new CSS.
- Pattern library as module inventory. Describe a pattern library as separate development documentation that showcases the CSS modules available in a project, helping the team find modules to use when building the site.
- Pattern library development sequence. Trace how to build a page using a CSS-first workflow: look for existing modules, build any missing module or variant in the pattern library, then return to the page to use it.
- Reuse and isolated module design. Explain how the workflow encourages a consistent interface and more general, reusable modules.
- CSS modules and HTML structure. Explain why the author frames CSS-first development around reusable styles rather than HTML that is merely easy to style.
- Module deprecation and migration. Explain why the author often deprecates an incompatible module and creates a new one instead of immediately changing every use of the old module. Describe why the team should be consulted before modules are deprecated or deleted.
- Semantic CSS version numbers. Describe what the three semver numbers communicate for this stylesheet, including which changes prompt patch, minor, and major releases.
- Application controlled stylesheet upgrades. Explain how keeping CSS versions available lets an application choose when to adopt a breaking release, and relate that choice to the CSS-first separation of HTML and CSS.
What it builds on
- Modules layer (chapter 8) · Introduces the modules layer in the recommended layer organization.
- Reset layer (chapter 8) · The earlier discussion of a reset layer.
- Global layer (chapter 8) · The earlier discussion of a global layer.
- Manipulating the cascade with layers (chapter 8) · The earlier introduction to cascade layers.
- Ems and rems (chapter 2) · Assumes familiarity with em units.
- Selector specificity (chapter 1) · Assumes that selector specificity affects which styles win.
- Absolute positioning (chapter 6) · Introduces absolute positioning.
- Source order (chapter 1) · Assumes familiarity with source order.
Section by section
Introduction
The introduction explains why broad effects from CSS changes make organization important and identifies the modules layer as the place to organize most styles into manageable pieces.
- Unintended Effects of CSS Changes: Explain why changing an existing stylesheet calls for care about both intended and unintended effects across a site.
Why it matters: This is the problem that motivates organizing the stylesheet. - Role of the Modules Layer: Describe how the introduction positions the modules layer within the chapter’s approach to organizing CSS.
Why it matters: It connects layer-based priority control to the chapter’s focus on organizing the bulk of the stylesheet.
Key terms: stylesheet, elements, layers, modules layer, modular pieces of code
9.1 Defining modules
This section defines modular CSS as a way to build a page from reusable, self-contained components whose styles do not interfere with one another.
- Modular CSS and encapsulation: Explain why modular CSS divides a page into reusable parts and gives each part responsibility for its own styles.
Why it matters: Keeping styles independent makes a growing stylesheet easier to change without unintended effects elsewhere. - Module identity and composition: Describe how the section identifies individual modules in the DOM and combines them into a page.
Why it matters: A recognizable module structure lets separate components be assembled into a complete page.
Key terms: modular CSS, module, encapsulation, unique class name, DOM element, child elements, nest modules
9.1.1 Modules and global styles
The section establishes reset and global styles as a starting point for building modules while clarifying that modular CSS does not require cascade layers.
- Global styles before modules: Explain why the page needs reset and global styles before building specific modules.
Why it matters: A shared page-wide starting point makes it easier to focus on each module’s styles. - Layers as an option: State whether cascade layers are required to write modular CSS.
Why it matters: You can use the modular approach even when you choose not to use layers.
Key terms: resets, global styles, modules, layers, modular CSS, browser support
9.1.2 A simple module
A simple message module shows how a class-only selector makes CSS reusable and why that reuse improves consistency.
- Class-Based Message Module: Describe how the message module is marked up and styled, and explain why its selector contains only the module’s class name.
Why it matters: A class-only selector lets you place the same message module wherever it is needed. - Reuse and Visual Consistency: Explain how reusing one module reduces repeated CSS and keeps similar UI elements visually consistent.
Why it matters: One shared set of styles prevents small differences from accumulating across the interface.
Key terms: module, message class, selector, ruleset, reusable module, consistent UI, visual consistency
9.1.3 Variations of a module
This section shows how modifier classes create reusable module variants and why they are preferable to selectors that change a module based on where it appears.
- Module modifier application: Explain how to create and use a variant of a module: put the main module class and a modifier class on the same element, and let the modifier override only the styles that change.
Why it matters: You can offer variations without copying the whole module’s CSS. - BEM modifier naming: Describe how the BEM double-hyphen convention names a modifier and why it makes the relationship between a module and its variant clearer.
Why it matters: Clear names make variants easier to recognize in a stylesheet with many modules. - Composable button variants: Describe how the button module combines size and color modifiers, including why changing font size also changes its em-based padding and border radius.
Why it matters: A small set of modifiers can produce several useful button variants. - Location independent module styling: Justify using a directly applied modifier such as dropdown--dark instead of a selector such as .page-header .dropdown to change a module based on its location.
Why it matters: Keeping variants independent of page location helps prevent an increasingly difficult-to-maintain stylesheet.
Key terms: module, modifier, module class, BEM, block, double-hyphen, size modifiers, color modifiers, em, font size
9.1.4 Modules with multiple elements
This section shows how to build a multi-element media module, combine its subelement classes with a variant, and choose selectors that remain useful as the module changes.
- Media module subelements: Describe the media module’s container, image, body, and title, and explain how BEM-style subelement class names identify an element’s role and parent module.
Why it matters: Subelement names make a multi-part module easier to recognize and style. - Media module right variant: Explain how the media--right variant is added to the media module and how a variant can target a subelement when its styling needs to change.
Why it matters: A variant changes a module’s presentation without requiring a separate module for the alternate arrangement. - Module selector tradeoffs: Distinguish when a subelement class can replace a descendant selector, when a specific tag selector is an acceptable shortcut, and why overly generic tag selectors are risky.
Why it matters: Selector choices affect how easily a reusable module can accommodate new markup.
Key terms: media module, subelement, media__image, media__body, BEM, variant, media--right, descendant selectors, media__body > h4, generic tag types
9.2 Modules composed into larger structures
This section explains why CSS modules should have focused responsibilities and how to spot a module that may need splitting.
- Single responsibility in modules: Explain why each module should have one concise purpose, and apply the section’s rule of thumb to the dropdown-menu example without treating it as a strict rule.
Why it matters: A focused purpose makes a module easier to describe, understand, and maintain.
Key terms: module, responsibility, encapsulation, Single Responsibility Principle
9.2.1 Dividing multiple responsibilities among modules
The section builds a dropdown menu from separate dropdown and menu modules, then explains how to keep their responsibilities, state, positioning, and styles manageable.
- Dropdown and menu responsibilities: Explain why the dropdown controls whether its container is visible while the menu styles the list of links, and describe how placing the menu inside the dropdown composes the interface. Explain why the author separates them here without treating every possible split as mandatory.
Why it matters: Clear responsibilities make modules easier to understand, change, and reuse in new combinations. - Module-contained positioning: Describe how the dropdown establishes a containing block for its positioned parts and why the author keeps related positioning within the same module.
Why it matters: Keeping related positioning inside the module makes its behavior more predictable wherever it is used. - Dynamic dropdown state: Trace how clicking the toggle changes the dropdown’s state class and how that class changes its appearance. Describe the purpose and naming convention of state classes.
Why it matters: A state class lets JavaScript signal a change while the module’s CSS defines how that state looks. - Separate module style files: Explain how a preprocessor can support modular CSS by keeping module styles in separate files while producing one stylesheet for the browser.
Why it matters: This keeps source files manageable without requiring a separate browser request for every module.
Key terms: dropdown module, menu module, compose, standalone, containing block, position: relative, absolutely positioned, ::after pseudo-element, state class, is-open
9.2.2 Naming modules
This section explains how to name CSS modules and variants so their names remain useful across contexts and redesigns, and briefly contrasts naming conventions with CSS-in-JS approaches.
- Conceptual module names: Explain why a module name should express what the module represents rather than its current use or appearance, using the media module as an example.
Why it matters: A stable name lets you reuse or redesign a module without renaming it throughout the HTML. - Distinct memorable module names: Describe why module names should be simple and memorable while still distinguishing UI elements that might otherwise receive the same generic name.
Why it matters: Clear, distinct names help teammates discuss and reuse modules without mixing up unrelated components. - Meaningful variant class names: Explain how to name module variants so their names remain meaningful when a design changes, including when relative size names are acceptable.
Why it matters: A variant named for its role can survive a color change, while a relative size name can survive resizing if it remains accurate. - CSS-in-JS naming alternative: Describe the naming problem CSS in JS addresses and its basic approach and tradeoff as presented here.
Why it matters: Generated names can prevent class-name collisions, but choosing that approach also constrains the application and its tooling.
Key terms: module, media, running-tip, media-tile, headline-tile, variant classes, button--danger, button--success, button--large, button--20px
9.3 CSS scope
Introduces @scope as a browser-enforced way to keep a module’s styles within its part of the page, then shows how scoped selectors and their specificity work.
- Browser-enforced modular boundaries: Explain how @scope offers an alternative to class-naming conventions for keeping module styles from conflicting.
Why it matters: This is why scope can make modular styles less dependent on team-wide naming discipline. - Scoped selectors and root: Describe how a scope selector, the rules inside its block, and :scope target the media module.
Why it matters: It explains why the media module can use shorter selectors without styling matching elements elsewhere. - Scope selector specificity: Explain why the selector defining a scope does not increase the specificity of selectors inside its block.
Why it matters: A scope boundary restricts a rule’s reach without making its selector harder to override through added specificity.
Key terms: scope, @scope, BEM, modular styles, scope selector, :scope, scope root, .media, specificity, img
9.3.1 Scope proximity
Explains how scope proximity resolves conflicts between nested CSS modules and why that helps preserve a module’s own styles.
- Nested scope precedence: Explain how the cascade resolves conflicting declarations from nested scopes: selector specificity takes precedence, then the nearer scope, then source order. Describe why the media module’s heading remains dark gray inside a highlight block.
Why it matters: It lets you predict which module’s styles will win when modules are nested. - Modular styling protection: Justify why scope proximity is useful when reusable CSS modules are placed inside other modules.
Why it matters: Reusable modules are easier to compose when their styles are not unexpectedly displaced by containing modules.
Key terms: scope proximity, selector specificity, source order, innermost scope, modular CSS, modules, HTML structure
9.3.2 Scoping limit
This section explains how scoping limits keep a module’s selectors out of nested modules while retaining the flexibility of the CSS cascade.
- Scoping Limit Boundaries: Explain how the `to` keyword gives an `@scope` rule an inner boundary and why that prevents styles from reaching into nested content.
Why it matters: A clear stopping point helps a reusable module avoid unexpectedly styling modules placed inside it. - Proximity Versus Exclusion: Distinguish proximity precedence from a scoping limit when an outer module and an inner module style the same content.
Why it matters: Winning a conflict is not the same as protecting an inner module from all outer selectors. - Selective Module Reach: Describe how scoping limits protect nested modules and how two `@scope` rules can give different selectors different reach.
Why it matters: A module can protect its nested modules without giving up every intentional influence over deeper content. - Cascade And Shadow Isolation: Distinguish CSS scope from Shadow DOM and state what a scoping limit does not block.
Why it matters: This distinction helps you choose between modules that share a page’s styling and components that need stronger isolation. - Module Root Naming: Explain which class-name collisions remain when modules are scoped and describe the suggested root-naming approaches.
Why it matters: Distinct module roots and consistent inner boundaries make it easier to compose modules without internal selector collisions.
Key terms: scoping limit, to keyword, upper bound, lower bound, donut scoping, proximity, conflicting styles, nested modules, dropdown module, tabs module
9.3.3 Implicit scope
This subsection explains how an embedded style tag can use implicit CSS scope and when that approach is useful.
- Implicit scope from parent: Explain how a selectorless @scope rule in a style tag inside a scope root gets its scope.
Why it matters: It lets you recognize what limits an embedded style rule without an explicit scope selector. - Embedded styles versus reuse: Describe when implicit scope may be convenient and why it is not usually the default for modules.
Why it matters: The distinction helps you choose embedded scoped styles without duplicating CSS for reusable modules.
Key terms: @scope rule, implicit scope, scope’s root element, one-off content, modules, reuse
9.3.4 Scope and layers
This section explains how scoping limits, selector specificity, and cascade layers can be combined to control which modular CSS styles take precedence.
- Scope and specificity precedence: Explain why an inner scope does not automatically override an outer scope, and how a scoping limit or selector specificity can control whether a parent module affects a child module.
Why it matters: It helps you choose whether to isolate a child module or let its styles compete with its parent’s. - Layers alongside scope: Describe how cascade layers provide another way to set precedence alongside scope, including the section’s example of module sublayers.
Why it matters: It gives you another way to control precedence without relying on scope alone.
Key terms: specificity, inner scope, outer scope, scoping limit, cascade layers, modules layer, sublayers, modules.base, modules.ui
9.4 Pattern libraries
This section explains how reusable CSS modules change page-building and why teams document those modules in a pattern library.
- Page assembly from existing modules: Explain how reusable CSS modules change the way a developer builds a page: they can assemble it from existing modules by using the required HTML structure and class names, often without writing new CSS.
Why it matters: Reusing modules can make later pages quicker to assemble. - Pattern library as module inventory: Describe a pattern library as separate development documentation that showcases the CSS modules available in a project, helping the team find modules to use when building the site.
Why it matters: An inventory makes reusable modules easier for a team to discover and use.
Key terms: modules, class names, stylesheet, pattern library, inventory, CSS module
9.4.1 Using a CSS-first workflow
This section explains a CSS-first workflow in which developers build and document reusable modules in a pattern library before using them on pages.
- Pattern library development sequence: Trace how to build a page using a CSS-first workflow: look for existing modules, build any missing module or variant in the pattern library, then return to the page to use it.
Why it matters: This sequence helps you avoid writing page-specific CSS when an existing module will do. - Reuse and isolated module design: Explain how the workflow encourages a consistent interface and more general, reusable modules.
Why it matters: The workflow makes it less likely that similar pages acquire different styles for the same purpose. - CSS modules and HTML structure: Explain why the author frames CSS-first development around reusable styles rather than HTML that is merely easy to style.
Why it matters: It clarifies what “CSS-first” changes about the relationship between styles and markup. - Teamwork and current documentation: Describe how developing modules in the pattern library supports CSS specialists and keeps module documentation current.
Why it matters: The library gives teammates a shared, up-to-date place to hand off and check modules.
Key terms: CSS-first development, pattern library, module, variant, existing styles, consistent interface, reusable solution, CSS-first, well-structured HTML, documentation
9.4.2 Refactoring and breaking changes
The section explains how to change modular CSS without unexpectedly breaking existing pages, using deprecation, versioning, coordinated upgrades, and a pattern library.
- Module deprecation and migration: Explain why the author often deprecates an incompatible module and creates a new one instead of immediately changing every use of the old module. Describe why the team should be consulted before modules are deprecated or deleted.
Why it matters: A replacement can be introduced without forcing every page to change at once. - Semantic CSS version numbers: Describe what the three semver numbers communicate for this stylesheet, including which changes prompt patch, minor, and major releases.
Why it matters: The version number tells developers what kind of CSS change a release contains. - Application controlled stylesheet upgrades: Explain how keeping CSS versions available lets an application choose when to adopt a breaking release, and relate that choice to the CSS-first separation of HTML and CSS.
Why it matters: A CSS release need not force an immediate, breaking HTML migration. - Modularity versus additive CSS: Explain why CSS can become additive-only and how modules and a pattern library make existing styles easier to maintain.
Why it matters: Organized modules make it less tempting to solve every change by adding another override.
Key terms: deprecate, module, pattern library, semver, major, minor, patch, versioning, CSS-first development, decoupled
9.5 Summary
Where this is used later
- Containers and modular CSS (chapter 10) · Establishes what it means for a module to work in different contexts.
- Using container size queries (chapter 10) · Introduces variations of a CSS module.
- Decoupling a module from its container (chapter 10) · Module variants defined with an additional class.
- Building the layout without animations (chapter 17) · Modules can be composed into larger structures with separate responsibilities.
Concepts explained in this chapter
- moduleA module is a reusable, relatively small unit of page structure and styling that is independent of its surrounding page context.
- CSS scopeCSS scope is the @scope language feature that limits which elements a set of style rules can match within a defined region of a document.
- modular cssModular CSS is an approach to organizing styles into reusable, relatively independent modules rather than applying one undifferentiated set of global rules.
- modifier classA modifier class is a CSS class that represents a variation of a component or changes its appearance or behavior.
- scoping limitAn inner scoping limit is a boundary in a scoped CSS rule that prevents the rule from applying within descendant scopes.
- BEMBlock-Element-Modifier is the expanded name of the BEM CSS naming methodology.
- BEM elementA BEM element is a child or descendant part of a block identified by a class combining the block name with a double underscore.
- descendant selectorA descendant selector is a CSS selector that matches an element occurring anywhere inside an ancestor matched by another selector.
- pattern libraryA pattern library is a separate collection of documentation pages that showcases reusable interface patterns and their implementation.
- context-dependent selectorA context-dependent selector is a CSS selector whose matching or styling intent depends on an element's ancestor or location in the document structure.
- css-first developmentCSS-first development is a workflow in which styles are developed before HTML consumes them, while HTML authors control adoption and upgrades.
- state classA state class is a CSS class convention whose presence represents the current state of a component and can trigger corresponding styles.
- Shadow DOMShadow DOM is a web platform mechanism that creates an isolated DOM subtree with encapsulated structure and styles.
- variant classA variant class is a CSS class that represents a named variation of a component's appearance or behavior.
- CSS-in-JSCSS-in-JS is a styling technique that uses JavaScript to define styles and generate or manage CSS class names.
- scope proximityScope proximity is the cascade criterion based on how close a scoped style is to the element it targets in the DOM.
- CSSCSS is a stylesheet language for describing the presentation of structured documents such as HTML pages.
- specificityA numeric representation of a selector's counts of IDs, classes, and tags, ordered from highest to lowest priority.
- block-level elementA block-level element generates block-level content that starts on its own line and normally fills the available width of its container.
- absolute positioningAbsolute positioning removes an element from normal flow and positions it relative to a containing block, typically established by a positioned ancestor.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
