What CSS Actually Is
You wrote color: red; the text is still blue. Before anything else, CSS makes sense once you understand it's not a list of rules you write β it's a scoring competition between rules, and the browser always plays fair by its own math.
Last Updated
April 2026
Read Time
14 min
Level
Beginner
What CSS Actually Is
CSS (Cascading Style Sheets) is the language that describes how HTML content should be presented β colors, spacing, layout, typography, animation. HTML says what a page contains; CSS says how it should look. It's maintained as a set of modular specifications by the W3C's CSS Working Group, which is why you'll see references to "CSS Grid Level 1" or "Selectors Level 4" rather than one single version number the way you'd talk about Python 3.13.
The first CSS specification (Level 1) was proposed by HΓ₯kon Wium Lie in 1994 and became a W3C Recommendation in December 1996. Before CSS existed, styling was done with HTML attributes like <font color="red"> scattered through every page β CSS separated content from presentation, which is the single most important idea in the entire language and the reason it's called cascading: rules from different sources cascade together, and CSS has explicit, predictable rules for which one wins.
That word β cascading β is not decorative. It's the actual algorithm the browser runs on every single element: gather every rule that could apply, sort them by origin, importance, specificity, and source order, and apply the winner. Most "my CSS isn't working" confusion is really just not knowing this algorithm exists.
The Cascade β How the Browser Decides Which Rule Wins
When two rules target the same element and the same property, the browser doesn't pick randomly or just take "whichever loaded last." It runs through a strict sequence of tie-breakers, in this exact order:
- βΆ
1. Origin & Importance β user-agent (browser default) styles lose to author (your) styles, which lose to user styles marked !important, which lose to author styles marked !important. In practice: your normal CSS beats the browser's defaults, and !important beats almost everything, which is exactly why overusing it turns a stylesheet into a maintenance nightmare β you end up needing !important to beat your own earlier !important.
- βΆ
2. Specificity β a numeric score calculated per selector (covered in detail below). Higher score wins, full stop, regardless of which rule appears first or last in the file.
- βΆ
3. Source Order β only reached when specificity is exactly tied. The rule that appears later in the stylesheet (or in a later <link>/<style> block) wins.
This ordering explains a specific, very common bug: you add a new CSS rule at the very bottom of your file, expecting it to override an earlier one because "it comes later" β but it doesn't apply, because the earlier rule has a higher specificity score. Source order is the last tie-breaker, not the first.
Specificity, With the Actual Math
Specificity is usually taught as an abstract concept. It's actually just arithmetic β a 3-column score, conventionally written as (A, B, C), calculated per selector:
- βΆ
A β count of ID selectors (
#header). Each one = 1 point in this column. - βΆ
B β count of class selectors (
.btn), attribute selectors ([type="text"]), and pseudo-classes (:hover). Each one = 1 point in this column. - βΆ
C β count of type/element selectors (
div,p) and pseudo-elements (::before). Each one = 1 point in this column.
Columns are compared left to right, never added across columns β a single ID selector (1,0,0) beats fifty combined class selectors (0,50,0), because you compare column A first and A already decides it.
/* Specificity (0,1,1) β one class + one element */
nav.primary-menu { color: navy; }
/* Specificity (0,2,0) β two classes, no element */
/* This WINS over the rule above: (0,2,0) > (0,1,1) at column B */
.site-header .primary-menu { color: crimson; }
/* Specificity (1,0,0) β one ID */
/* This wins over BOTH rules above, regardless of order in the file */
#main-nav { color: forestgreen; }Inline styles (style="color: red" written directly in HTML) beat every selector-based rule regardless of specificity score β they aren't even part of this A/B/C system, they sit above it. !important goes a level above even that. Both exist as escape hatches; relying on either routinely is usually a sign the underlying CSS architecture needs rethinking, not a normal styling technique.
The Box Model β Where 90% of Layout Bugs Actually Come From
Every single element on a page is a rectangular box made of four layers, from inside out: content, padding, border, and margin. The bug that catches nearly every beginner is this: by default, width and height apply only to the content box β padding and border get added on top, making the element's actual rendered size larger than what you set.
.card {
width: 300px;
padding: 20px;
border: 2px solid #ccc;
/* Rendered width is actually 300 + 20+20 + 2+2 = 344px, NOT 300px */
}
.card-fixed {
box-sizing: border-box; /* width now INCLUDES padding + border */
width: 300px;
padding: 20px;
border: 2px solid #ccc;
/* Rendered width is exactly 300px, content area shrinks to fit */
}This is common enough that most CSS resets β including the popular modern-normalize approach and Josh Comeau's widely-used reset β apply box-sizing: border-box to every element globally as one of the first rules in the entire stylesheet:
*, *::before, *::after {
box-sizing: border-box;
}Flexbox vs Grid β Which One, and When
This gets asked constantly and the honest answer is that they solve different shaped problems, not competing versions of the same problem. My rule of thumb after years of picking wrong in both directions: if you're arranging items along a single line β a navbar, a row of buttons, a sidebar next to content β reach for Flexbox first. The moment you're thinking in rows AND columns simultaneously β a photo gallery, a dashboard, a page-level layout β Grid is almost always less code and fewer nested wrapper divs.
.product-grid {
display: grid;
/* auto-fit + minmax: as many 240px-min columns as fit, no media query needed */
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1.5rem;
}That single repeat(auto-fit, minmax(...)) line is doing what used to take three or four separate media query breakpoints in pre-Grid CSS β the grid recalculates its own column count as the viewport resizes, with zero JavaScript and zero @media rules.
What's Genuinely New in CSS by 2026
CSS has shipped more practically useful features in the last five years than in the decade before that. These aren't experimental β all of the following have solid cross-browser support as of 2026.
@container lets a component adapt based on the size of its own parent container, not the entire viewport. A sidebar widget can now be genuinely responsive regardless of where it's dropped on the page β something media queries structurally couldn't do.
--primary-color: #2563eb; defined once and reused via var(--primary-color) everywhere, including reactive updates via JavaScript at runtime β unlike Sass variables, which are compiled away and frozen at build time.
card:has(img) selects a .card only if it contains an img element. For over 20 years CSS had no way to style a parent based on its children; :has() finally closes that gap without JavaScript.
color-mix(in srgb, blue 70%, white) blends colors directly in CSS β no more maintaining a separate hardcoded palette of every tint and shade you might need.
font-size: clamp(1rem, 2vw + 0.5rem, 2.5rem); scales text fluidly between a minimum and maximum, replacing a pile of font-size media query breakpoints with one line.
animation-timeline: scroll(); ties an animation's progress directly to scroll position, natively β a parallax or reveal-on-scroll effect that used to require a JS library like AOS or GSAP ScrollTrigger.
grid-template-columns: subgrid; lets a nested grid item align its own rows/columns to its parent grid's tracks β solving the long-standing pain of nested cards not lining up with the outer grid.
aspect-ratio: 16 / 9; reserves the correct box size for an image or video before it loads, preventing the layout-shift jump that used to require padding-top percentage hacks.
Do You Still Need Sass in 2026?
This is a genuinely different answer than it would have been in 2019. Sass became popular because vanilla CSS had no variables, no nesting, and no mixins. Native CSS now has custom properties (variables), and nesting shipped natively in all major browsers in 2023. A lot of what teams reached for Sass to get is now just... CSS.
My honest take: for a small to mid-size project, I'd skip adding a Sass build step in 2026 purely for variables and nesting β native CSS covers that now, and one less build tool is one less thing to configure and maintain. Where Sass still earns its place is generating large sets of repetitive utility classes with @each loops across a big design system, which native CSS genuinely can't do yet.
Writing Your First Stylesheet
CSS reaches an HTML page in one of three ways: an external .css file linked via <link> (the standard, maintainable approach), a <style> block inside the HTML <head>, or inline via the style attribute on a single element. For anything beyond a one-off test, external stylesheets are the only one worth using in real projects β they're cacheable by the browser and keep structure and presentation separated.
body {
font-family: system-ui, sans-serif;
margin: 0;
background-color: #f8fafc;
}
.hero-title {
color: #1e293b;
font-size: clamp(1.75rem, 4vw, 3rem);
text-align: center;
}Output
Renders as a centered heading, sized fluidly between roughly 28px and 48px depending on viewport width.Practice This Code β Live Editor
Bugs You'll Hit in Your First Week With CSS
- βΆ
Margin collapsing between stacked elements β two vertically adjacent block elements with margin-bottom: 20px and margin-top: 20px don't add up to 40px of gap; adjacent vertical margins collapse into a single 20px gap (the larger of the two). This trips up nearly everyone the first time they measure the actual rendered spacing and it doesn't match their math.
- βΆ
"display: none vs visibility: hidden" confusion β display: none removes the element from layout entirely, as if it doesn't exist; visibility: hidden keeps its space reserved but makes it invisible. Using the wrong one is a very common cause of "my layout shifted when I hid this element" bugs.
- βΆ
Percentage heights not working β height: 50% on a child does nothing unless the parent has an explicit height set. Percentage heights resolve against the parent's computed height, and if the parent's height is itself auto (sized by its content), there's nothing concrete to take 50% of.
- βΆ
z-index doing nothing β z-index only has an effect on elements with a position value other than static (relative, absolute, fixed, or sticky). Setting z-index: 999 on a statically positioned element is silently ignored by the browser.
- βΆ
Forgetting the universal box-sizing reset β without box-sizing: border-box applied globally, every width calculation involving padding or border needs manual mental math, which is exactly the trap covered in the box model section above.
Where CSS Skill Actually Shows Up on the Job
At most product companies β think mid-size D2C brands, fintech dashboards, SaaS admin panels β CSS isn't a separate role anymore; it's assumed baseline knowledge for any frontend developer. What differentiates a junior from a senior frontend dev in interviews at these companies is rarely "do you know Flexbox" and almost always can you debug a live layout bug you've never seen before β reading computed styles in DevTools, understanding why a specificity conflict is winning, spotting a stray margin collapse.
- βΆ
π₯οΈ Product & SaaS Dashboards β dense data tables, responsive charts, and form-heavy admin panels live or die on disciplined CSS architecture (BEM naming, utility classes, or CSS Modules) that scales across a large, multi-developer codebase without specificity wars.
- βΆ
ποΈ E-commerce & D2C Storefronts β product grids, filter sidebars, and checkout flows need pixel-precise, fast-loading CSS since even small layout-shift regressions measurably hurt conversion rates tracked via Core Web Vitals (CLS specifically).
- βΆ
π§ Email Template Development β a genuinely different, much harder discipline: email clients (Outlook especially) support only a small, inconsistent subset of CSS, so email developers still write table-based layouts with inline styles, closer to how the web looked in 2005.
- βΆ
π¨ Design Systems & Component Libraries β teams building shared UI libraries (used across dozens of internal apps) invest heavily in CSS custom properties and design tokens so a single brand-color change propagates everywhere without touching component code.
CSS Interview Questions That Actually Get Asked
Test Yourself
1. Given .card { color: blue; } and #hero .card { color: red; }, which color wins and why?
Easy2. Two stacked <p> elements have margin-bottom: 30px and margin-top: 10px respectively. How much vertical gap actually appears between them?
Medium3. A child element has height: 50%; but appears to have zero height on the page. What's the most likely cause?
Medium4. Why might display: grid with grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) sometimes leave unexpected empty gaps at the end of a row, and how would you fix it?
Hard5. What's the difference between em and rem units, and why do many teams prefer rem for font sizing?
MediumWhere This Actually Leaves You
CSS has a reputation for being "not real programming," usually from people who've never had to debug a specificity conflict across a 200-component design system at 11pm before a release. The cascade, the box model, and the sizing algorithm behind Flexbox and Grid are genuinely deterministic systems β once you understand the rules, "CSS is being weird" mostly stops happening, because it was never being weird. It was following its rules exactly; you just hadn't learned them yet.
The fastest way to actually internalize the cascade and specificity is to break something on purpose: take the specificity example in this article, open your browser's DevTools, and watch the computed styles panel show you exactly which rule won and why, struck-through rules and all. That one habit will teach you more in twenty minutes than another article's worth of theory.