AD JB Toolbox 01 EN

CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

Maintainable CSS separates shared values, base styles, components, and conditional adjustments according to their roles. Native nesting scopes related selectors, while cascade layers explicitly order groups of rules and introduce their own precedence rules.

Reduce duplication and assign file responsibilities

First, look for duplicates of the same color and spacing, deprecated selectors, and nearly identical button rules. Values with the same role are grouped into variables, and different buttons divide common rules and necessary differences. It may be better to keep two independent components rather than creating complex conditions to eliminate all duplication. When grouping common values, check the scope and inheritance conditions of the variable in CSS Variables: var(), Scope, Inheritance, and Fallbacks.

/* Before cleanup: Same value repeated in multiple places */
.lesson-button { padding: .65rem 1rem; color: #166b92; }
.notice-button { padding: .65rem 1rem; color: #166b92; }

/* After organizing: sharing common shapes and roles */
.button { padding: .65rem 1rem; color: var(--accent); }
.button.text-alert { color: #9d2632; }

The above comparison is partial code explaining the cleanup direction. A common button class must also be attached to the actual HTML, and if you only rename the CSS and leave the HTML as is, the appearance may disappear. The entire exercise below runs this configuration broken down into files and layers.

file responsibility Judgment when revising
tokens.css Common colors and spacing Is it a value shared by multiple components?
base.css Font, default margin, focus display Is this the default behavior for the entire document?
layout.css Content area and layout Is it the positional relationship of the components?
components.css Shape and status of cards and buttons Is it tied to one component?
utilities.css Small, explicit auxiliary classes Is this an exception that will only apply in a few places?

For small documents, it is sufficient to divide a comment section into one file. Consider separating files when multiple people modify different components or when the scope of reuse increases. The file name is a separator for navigation, and just dividing the file does not eliminate selector conflicts. HTML connection paths and cascades must also be managed.

Distinguish the parent and descendants in nesting

Native CSS nesting is interpreted directly by the browser. This is different from the way preprocessors like Sass generate different CSS during the build phase. The code below places the title of the .card close to the state of the card itself.

.card {
  & h2 { color: var(--accent); }
  &:hover { border-color: var(--accent); }
}

& h2 represents the h2 inside the card, and &:hover represents the hover of the card itself. If you insert a space like & :hover, the result will be different because it selects the hovered descendant. Also distinguish between &.warning , which selects a auxiliary class of the same element, and & .warning , which selects descendants.

/* The simple overlap above is expanded */
.card h2 { color: var(--accent); }
.card:hover { border-color: var(--accent); }

With this single parent selector, the nesting can be compared directly with the expanded rules. A comma-separated parent list can make the nested selector's specificity depend on the most specific selector in that list. Complex nesting is therefore not simple string concatenation. Avoid unnecessary depth that ties CSS to a rigid HTML hierarchy. For further detail, see MDN nesting usage guide, nesting and priority explanation.

Check the nesting support of the browser you need to support, and if you need an environment that does not support it, choose expanded CSS as above or an appropriate build tool. Just because you use a new syntax, don't assume it applies to all your visitors.

Compare cascade layers before specificity

For regular declarations of the same author style, out-of-layer declarations take precedence over in-layer declarations. Within layers, later layers take precedence over previous layers in a predetermined order. So the class rules in the back layer can beat the ID rules in the front layer. If other comparison conditions such as the same layer and importance are the same, conditions such as CSS Inheritance, Specificity, and the Cascade, scoping proximity, and declaration order are subsequently judged.

@layer tokens, base, layout, components, utilities;
@layer base { #layer-target { color: #183044; } }
@layer utilities { .text-alert { color: #9d2632; } }

The example button matches both selectors. In the general declaration, utilities come after, so the color red applies. Predicting the result just because a button has a high ID priority can be wrong. The order of layers is determined by the order in which their names are first registered, and even if you open the same layer again later, that layer will not be moved to the back.

!important declarations take precedence over general declarations, and the layer order for important declarations is reversed. Important things in the front layer take precedence over important things in the back layer, and important things within a layer take precedence over important things outside the layer. This example is limited to comparing layers of same-author CSS and their properties. It does not expand to other conditions of the cascade, such as user/browser styles, inline declarations, and running transitions, saying, “You only need to look at the layers.” You can check the full conditions in MDN layer document.

Create the HTML and five CSS files

Create the structure below in an empty folder. All files are saved as UTF-8. Since index.html uses the relative path styles/..., the CSS file must be in the styles subfolder. You can open index.html with a browser without a separate server or external library. If you cannot read the file, compare the file location and connection address with Apply CSS with Inline, Internal, and External Styles.

stylesheet-project/
  index.html
  styles/
    tokens.css
    base.css
    layout.css
    components.css
    utilities.css

index.html contains the actual link tags and classes. The comparison button is not a button to execute an action, but is for practice purposes to check the applied text color and focus.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>CSS files and layers by responsibility</title>
  <link rel="stylesheet" href="styles/tokens.css">
  <link rel="stylesheet" href="styles/base.css">
  <link rel="stylesheet" href="styles/layout.css">
  <link rel="stylesheet" href="styles/components.css">
  <link rel="stylesheet" href="styles/utilities.css">
</head>
<body>
  <main class="demo">
    <h1>Organizing a small stylesheet</h1>
    <article class="card">
      <h2>Scope nested rules to the card</h2>
      <p>The card heading uses the accent color. Compare it with the heading outside the card.</p>
      <button class="button" type="button">Regular button</button>
    </article>
    <section><h2>Heading outside the card</h2><p>Use the default font color.</p></section>
    <button id="layer-target" class="button text-alert" type="button">Layer comparison button</button>
  </main>
</body>
</html>

styles/tokens.css registers the layer order first and declares common values. Another file opens a layer with the same name to add rules to it.

@layer tokens, base, layout, components, utilities;
@layer tokens {
  :root { --ink: #183044; --accent: #166b92; --space-card: 1.25rem; }
}

styles/base.css places the default document appearance and focus indicator. ID rules are devices put in place to compare the impact of layers on priority.

@layer base {
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; padding: 1rem; color: var(--ink); font-family: sans-serif; line-height: 1.6; }
  h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
  button { font: inherit; cursor: pointer; }
  :focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
  #layer-target { color: #183044; }
}

styles/layout.css manages spacing between content areas and sections.

@layer layout {
  .demo { display: grid; gap: 1rem; max-width: 44rem; margin-inline: auto; }
  .demo > h1 { margin-block: 0 .5rem; }
  .demo > button { justify-self: start; }
}

styles/components.css manages cards and buttons. The title color only applies to the inside of the card, and the border changes when you hover over the card or focus on the button inside it.

@layer components {
  .card {
    padding: var(--space-card); border: 2px solid #90a4b2; border-radius: .5rem;
    & h2 { margin-top: 0; color: var(--accent); }
    &:hover, &:focus-within { border-color: var(--accent); }
  }
  .button {
    padding: .65rem 1rem; color: var(--accent); background: #eaf4fa;
    border: 1px solid #166b92; border-radius: .3rem;
  }
}

styles/utilities.css manages an auxiliary class for the compare button. General declarations in this file take precedence over ID/button rules in previous layers.

@layer utilities {
  .text-alert { color: #9d2632; }
}

Test files, nesting, and layers independently

  1. On the main screen, make sure the card title and general button are blue, the title outside the card is the default color, and the comparison button is red. Tab to see if the button has a focus indicator.
  2. Comment out only the & h2 rule inside the card in components.css. Card titles also return to their default colors. After confirmation, uncomment it.
  3. Let's attach the text-alert class to both buttons in HTML. The buttons inside the card will also be red. Restores only the inner button's extra classes by removing them.
  4. At the end of components.css, add only .button { color: #28633b; } outside the @layer block. Both buttons will turn green. This results in out-of-layer general declarations preceding the layer order. After confirmation, delete the new rule.
  5. Add important only to the ID color declaration in base.css. The comparison button changes to the default color. In that state, if you add important to the color of utilities.css, the basic color of the previous layer will be maintained. After comparing, we remove both important ones.
  6. Just temporarily remove the components.css link from the HTML. The component shapes of the card and button disappear. Reconnect the path to its original state and refresh to restore it.

Diagnose missing styles

Check for file separation issues and selector conflicts separately. First look at Network or Sources in your browser developer tools to see if the file was actually loaded, then select the element to see if the rules match in Styles and if any declarations have been overwritten. If you don't see the file, check the relative path, file name, and extension, and if you don't see the rule, check the class and syntax support.

Even if there is a matching rule, if a strikethrough occurs, the layer, important, selector, scope, and order are compared. If common variables are not as expected, also look at the variable declaration scope. After separation, it is helpful for maintenance to recheck the main screen and focus/hover, and to fix responsibility divisions and selectors that caused conflicts instead of continuing to add unnecessary important declarations.

More in This Category
CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

CSS Tutorial / Organize CSS with Shared Styles, Nesting, and Layers

Refactor a small stylesheet without changing its layout, compare nesting and cascade layers, and check relative file paths and selector specificity.

CSS Tutorial / CSS Background Colors and Images: cover and contain

CSS Tutorial / CSS Background Colors and Images: cover and contain

Create and load a local background image, compare repetition, cover, contain, and position, and diagnose image-path and cropping problems.

CSS Tutorial / CSS Borders, Rounded Corners, and Shadows

CSS Tutorial / CSS Borders, Rounded Corners, and Shadows

Build cards with borders and shadows, compare circles and ellipses, and inspect how ancestor overflow changes visible shadows.

CSS Tutorial / Flexbox Basics: Containers, Items, and Axes

CSS Tutorial / Flexbox Basics: Containers, Items, and Axes

Create a Flexbox container, distinguish direct children from nested content, and compare row, column, and their main and cross axes.

CSS Tutorial / CSS position: relative, absolute, fixed, and sticky

CSS Tutorial / CSS position: relative, absolute, fixed, and sticky

Compare positioning modes in a complete example, identify containing blocks, and troubleshoot sticky limits and overlapping content.

CSS Tutorial / CSS Fonts, Font Sizes, and Line Height

CSS Tutorial / CSS Fonts, Font Sizes, and Line Height

Build a readable font stack, compare line-height inheritance, and use browser tools to identify the fonts actually rendering your text.

CSS Tutorial / CSS Form States: Focus, Validation, disabled, and readonly

CSS Tutorial / CSS Form States: Focus, Validation, disabled, and readonly

Compare form states, create accessible labels and error messages, and inspect which enabled, disabled, and read-only fields enter submitted form data.

CSS Tutorial / CSS Keyframe Animations, Fill Modes, and Pausing

CSS Tutorial / CSS Keyframe Animations, Fill Modes, and Pausing

Build a complete animation example, compare end states and delays, pause decorative motion, and check a prefers-reduced-motion alternative.

CSS Tutorial / Build a Responsive Website with HTML and CSS

CSS Tutorial / Build a Responsive Website with HTML and CSS

Create a complete two-file learning website with responsive cards and navigation, then test long text, keyboard focus, zoom, and reduced motion.

CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes

CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes

Choose basic selectors for a small page, combine conditions correctly, and inspect whether each rule matches the intended elements.