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 / 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 / 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.

CSS Tutorial / CSS Paragraph and List Styling

CSS Tutorial / CSS Paragraph and List Styling

Style paragraphs and ordered or unordered lists, compare inside and outside markers, and check spacing and wrapped text on narrow screens.

CSS Tutorial / CSS Link States and Visible Keyboard Focus

CSS Tutorial / CSS Link States and Visible Keyboard Focus

Compare link states in a working multi-file example, inspect keyboard focus, and understand browser privacy restrictions on visited-link styles.

CSS Tutorial / CSS Grid Basics: Tracks, Lines, and Item Placement

CSS Tutorial / CSS Grid Basics: Tracks, Lines, and Item Placement

Create a two-dimensional grid, distinguish lines, tracks, cells, and areas, and use fr, minmax(), and spans to place items.

CSS Tutorial / Check Responsive CSS with Width, Zoom, and Keyboard Tests

CSS Tutorial / Check Responsive CSS with Width, Zoom, and Keyboard Tests

Follow a repeatable browser checklist, test breakpoint boundaries and longer text, and record layout problems before changing CSS rules.

CSS Tutorial / Inspect CSS with DevTools: Styles and Computed

CSS Tutorial / Inspect CSS with DevTools: Styles and Computed

Use Styles, Computed, and the box model display to diagnose CSS, compare temporary edits, and transfer a confirmed change to the correct source file.

CSS Tutorial / CSS Tables: Borders, Sizing, and table-layout

CSS Tutorial / CSS Tables: Borders, Sizing, and table-layout

Style semantic tables, compare automatic and fixed layout with long content, and provide horizontal scrolling when a table needs more space.

CSS Tutorial / Flexbox Alignment, Wrapping, gap, grow, and shrink

CSS Tutorial / Flexbox Alignment, Wrapping, gap, grow, and shrink

Compare Flexbox alignment and wrapping, distribute space with flex values, and prevent long content from blocking item shrinkage.

CSS Tutorial / Responsive Images and Video: aspect-ratio and object-fit

CSS Tutorial / Responsive Images and Video: aspect-ratio and object-fit

Compare original image proportions, cover, contain, and object-position, then test responsive video sizing with a downloadable sample.