Fundamentals
class and id in CSS?id is unique — only one element per page should have a given id. It has higher specificity. class can be reused on multiple elements. In CSS, id is targeted with #name and class with .name. Prefer classes for styling and reserve ids for JavaScript targeting or anchor links.
Every HTML element is a box made of four layers (from inside out): content (the actual text/image), padding (space inside the border), border (the edge), and margin (space outside the border). By default, width applies to the content only. Set box-sizing: border-box to make width include padding and border, which is almost always what you want.
Specificity determines which CSS rule wins when multiple rules target the same element. The hierarchy (from lowest to highest): type selectors (p, div) → class selectors, attribute selectors, pseudo-classes (.class, [attr], :hover) → id selectors (#id) → inline styles (style="") → !important. When two rules have equal specificity, the last one in the stylesheet wins.
display: none and visibility: hidden?display: none removes the element from the document flow entirely — it takes up no space. visibility: hidden hides the element but keeps its space in the layout. Use display: none when you want to completely hide something; visibility: hidden when you want to hide it but maintain its layout impact.
em, rem, and px?px is an absolute unit — fixed size. em is relative to the font-size of the parent element — it cascades and can compound. rem (root em) is relative to the font-size of the root element (<html>) — predictable and consistent. Use rem for most font sizes and spacing; em for components that should scale with their own font-size.
box-sizing: border-box do?By default (content-box), the width property only sets the content width — padding and border add to the total size. With border-box, width includes padding and border, so the element stays exactly the size you set. It is best practice to apply it globally: *, *::before, *::after { box-sizing: border-box; }
Layout
Flexbox is one-dimensional — it arranges items in a row OR a column. Grid is two-dimensional — it controls rows AND columns simultaneously. Use Flexbox for components (nav bars, card rows, centering); use Grid for page layouts and two-dimensional structures.
/* Modern: Flexbox */
.parent {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* Modern: CSS Grid */
.parent {
display: grid;
place-items: center;
min-height: 100vh;
}position: absolute and position: fixed?absolute positions an element relative to its nearest positioned ancestor (parent with position other than static). fixed positions an element relative to the browser viewport — it stays in place when the user scrolls. Both are removed from normal document flow.
z-index and when does it work?z-index controls the stacking order of positioned elements. Higher values appear on top. It only works on elements with a position value other than static (so: relative, absolute, fixed, or sticky). It also works on flex and grid children.
A media query applies CSS rules conditionally based on device characteristics — most commonly screen width. Example: @media (max-width: 768px) { /* mobile styles */ }. They are the foundation of responsive web design.
max-width and width?width sets a fixed width. max-width allows the element to be up to that size but no wider — it can still shrink on smaller screens. Using max-width: 1200px; width: 100% on a container is the standard pattern for responsive page layouts.
Selectors & Pseudo-classes
:nth-child() and :nth-of-type()?:nth-child(n) selects elements that are the nth child of their parent, regardless of type. :nth-of-type(n) selects the nth element of its specific type within the parent. Example: p:nth-child(2) selects a <p> only if it is the 2nd child; p:nth-of-type(2) selects the 2nd <p> regardless of its position among siblings.
* selector do?The universal selector (*) matches every element in the document. It has zero specificity. It is commonly used in the CSS reset: *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
::before and ::after pseudo-element?They insert content before or after an element's content without adding HTML. They require the content property to exist. Common uses: decorative shapes, quote marks, clear floats, custom counters, and icon insertions. They are actual DOM nodes but not real HTML elements.
Performance & Best Practices
CSS variables store reusable values. They are defined with --variable-name: value (usually on :root) and used with var(--variable-name). They cascade like regular CSS, can be changed with JavaScript, and allow theme switching without touching multiple rules. Example: :root { --primary: #6d28d9; }
transition and animation?transition animates a property change between two states (triggered by a state change like :hover). animation with @keyframes runs automatically, can loop, and defines multiple intermediate states. Use transitions for simple hover effects; use animations for continuous or complex motion.
will-change property?will-change hints to the browser that an element will be animated, allowing it to optimize (create a GPU layer) in advance. Example: will-change: transform, opacity. Use it sparingly — only on elements that you know will animate. Overuse wastes memory.
img {
max-width: 100%;
height: auto; /* maintains aspect ratio */
display: block; /* removes inline spacing */
}inline, block, and inline-block?block elements take up the full width, start on a new line, and respect width/height/margin/padding fully (div, p, h1). inline elements flow with text, ignore width/height, and only respect horizontal margin/padding (span, a, strong). inline-block flows inline but respects all box model properties — useful for buttons and badges.
Advanced
A CSS preprocessor extends CSS with features like variables, nesting, mixins, and functions, then compiles to plain CSS. Popular examples: Sass/SCSS (most popular), Less, and Stylus. Modern CSS now has many of these features natively (custom properties, nesting in newer browsers), reducing the need for preprocessors.
BEM (Block-Element-Modifier) is a CSS naming convention that makes styles scalable and readable. Format: .block__element--modifier. Example: .card__title--highlighted. It prevents specificity conflicts and makes the relationship between elements clear from class names alone.
clamp() in CSS?clamp(min, preferred, max) constrains a value between a minimum and maximum. Most used for fluid typography: font-size: clamp(1rem, 2.5vw, 2rem) — the font size is at least 1rem, scales with the viewport, and never exceeds 2rem. Eliminates the need for multiple media query breakpoints for font sizes.
object-fit property?object-fit controls how an image or video fills its container. Values: fill (default — stretches), contain (fits inside, letterboxes), cover (fills container, crops to fit), none (original size), scale-down (whichever is smaller: none or contain). Use cover for hero images.
!important?!important overrides all other specificity — including inline styles. It should be used sparingly, as it makes debugging very difficult (you need another !important to override it). Legitimate uses: utility classes that must always win, browser print styles, third-party style overrides.
flex-grow, flex-shrink, and flex-basis?flex-basis sets the initial size of a flex item before free space is distributed. flex-grow determines how much the item grows relative to siblings when there is extra space. flex-shrink determines how much the item shrinks when there is not enough space. These are combined in the shorthand: flex: grow shrink basis (e.g., flex: 1 1 auto).
A stacking context is a three-dimensional conceptual layer in which elements are stacked. Elements within the same stacking context are sorted by z-index relative to each other. A new stacking context is created by elements with: position (not static) + z-index not auto, opacity less than 1, transform, filter, will-change, and others.
Grid areas let you name regions of your grid and place items using those names with grid-template-areas. This makes complex layouts extremely readable. Example: defining "header header / sidebar main / footer footer" and then assigning elements with grid-area: header.
position: sticky and why might it not work?Sticky positioning acts like relative until the element hits a scroll threshold, then sticks like fixed within its parent. Common reasons it fails: (1) Parent has overflow: hidden or overflow: auto. (2) No top/left/right/bottom value set. (3) The parent is not tall enough to scroll past the element.
The cascade is the algorithm that determines which CSS rule applies when multiple rules target the same element. It considers (in order of priority): origin (browser default vs author vs user), importance (!important), specificity (id > class > element), and source order (later rules win at equal specificity). Understanding the cascade is fundamental to debugging CSS.