Section 3: Modern CSS Architecture
In Parts 1 and 2, you wrote CSS the way most developers start — a long stylesheet that grows rule by rule. That approach works fine for a small site, but as projects grow, styles start conflicting with each other in unpredictable ways. One rule overrides another unexpectedly. You add !important to fix it. Then another !important to fix that. Before long, the stylesheet is fragile and difficult to maintain.
In this section, you will learn four modern CSS tools that solve these problems cleanly — no frameworks, no JavaScript. These are the tools professional developers use in 2026 to keep stylesheets scalable, readable, and conflict-free.
CSS @layer — Organizing Styles Without Conflicts
What is @layer and why does it matter?
Every CSS rule has a specificity. This is a score the browser uses to decide which rule wins when two rules target the same element. The higher the specificity, the more the rule wins. This is why developers end up writing overly complicated selectors, or adding !important everywhere, to force their styles to apply.
@layer gives you a better tool. Instead of fighting specificity, you define named layers and tell the browser the order in which those layers should be applied. Rules in a later layer always win over rules in an earlier layer, regardless of selector complexity. This means you can write simple, clean selectors and still have full control over which styles take priority.
Three layers that cover every business website
For a site like ours, three layers are all we need, namely:
- base layer: These are browser reset and root variables. They are the foundation every other style builds on.
- components layer: These are reusable sections such as navigation, cards, footer, and forms.
- Utilities: They are single-purpose overrides like spacing tweaks, alignment, and display adjustments.
The rule is simple: utilities always beat components, components always beat base. You declare this once at the top of the stylesheet, and the browser respects it everywhere.
Step 1 — Declare the layer order
Open css/styles.css. Add the following as the very first line of the file, before any other CSS:
@layer base, components, utilities;
This line comes first because declaring layers before any rules locks in their priority order. If you declare layers inside rule blocks later, the order becomes unpredictable.
Step 2 — Move the base reset into the base layer
Find the CSS reset at the top of your stylesheet, that is, the block that removes default margins and padding. Wrap it inside @layer base like this:
@layer base {
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, sans-serif;
color: var(--color-text);
background: var(--color-bg);
line-height: 1.6;
}
}
Step 3 — Move component styles into the components layer
Everything that styles a specific part of the site, including the header, navigation, hero, services cards, and footer belongs in the components layer. Wrap all of that existing CSS like this:
@layer components {
/* Header & Navigation */
header { ... }
nav { ... }
.nav-links { ... }
/* Hero Section */
.hero { ... }
.cta-button { ... }
/* Services */
.services-grid { ... }
.service-card { ... }
/* Footer */
.site-footer { ... }
/* ... all other existing component styles ... */
}
Note: You are not rewriting any CSS here. You are only wrapping the existing rules inside @layer components { }. Every style you already wrote continues to work the same way.
Step 4 — Create a utilities layer for quick overrides
Add a new utilities layer at the end of the stylesheet. This is where you put small, single-purpose classes that you use across the site for quick adjustments. For example, add the following:
@layer utilities {
.text-center { text-align: center; }
.mt-sm { margin-top: 1rem; }
.mt-md { margin-top: 2rem; }
.mt-lg { margin-top: 4rem; }
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
}The .visually-hidden class is a professional accessibility tool. It hides content from the screen visually, but keeps it readable by screen readers. You can use it to add descriptive labels to icons and decorative elements without showing them visually on the page.
With layers in place, you can now add a utility class to any element, and it will always win over a component style without any !important, and without writing complex selectors. The layers handle the priority automatically.
The :has() Selector — Context-Aware Components
Until recently, CSS could only select elements based on what they are or what class they have, not based on what they contain. If you wanted to style a card differently when it had a featured badge inside it, you needed JavaScript to add an extra class to the card element itself.
:has() changes this. It lets you select an element based on what it contains. The :has() pseudo-class lets you style a parent element based on its children. It is read as, “select this element if it has this inside it.” No JavaScript required.
Example — Highlight a featured Service card
In Part 1, we built a service card. With :has(), we can style one of the cards differently. The card styles itself based on what is inside it. Add the following CSS in the @layer components.
/* In @layer components */
/* Style the parent grid if it contains a .badge card */
.service-grid:has(.badge) {
background-color: #f9fcff;
padding: 2rem;
border: 2px solid #edeef0;
}
/* Style the badge card itself */
.service-grid article.badge {
background-color: #f0f8ff;
border-color: #007acc;
box-shadow: 0 4px 12px rgba(0, 122, 204, 0.2);
border-radius: 20px;
padding: 10px 20px 10px 20px;
}
Now add a badge to whichever card you want to feature. The card styles itself automatically. You can move the badge to a different card and that card becomes featured instead, no CSS changes needed.
Add this HTML inside one of the <article> tags in the services section of index.html:
<article class="badge">
<h3>Development</h3>
<p>Fast and scalable websites built with clean code.</p>
</article>
This is a typical example. You can also use :has() in other ways, such as styling a form when user input is invalid, or style the nav differently depending on whether the mobile checkbox is checked.
Note that: :has() is supported in all modern browsers — Chrome 105+, Safari 15.4+, Firefox 121+. This covers well over 95% of users in 2026. No fallback is needed for a new business site.

